I'm trying to update a textview based on sensorinput - more precise pitch. I have no problem getting the sensor data, converting it to degrees and displaying it in a textview.
The problem is, that I wan't different numbers displayed, based on the pitch in degrees. I have written a if-else if statement and placed it in the onsensorchanged, but apart from the initial number it does not update.
#Override
public void onSensorChanged(SensorEvent event) {
switch(event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
for(int i =0; i < 3; i++){
valuesAccelerometer[i] = event.values[i];
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i =0; i < 3; i++){
valuesMagneticField[i] = event.values[i];
}
break;
}
boolean success = SensorManager.getRotationMatrix(
matrixR,
matrixI,
valuesAccelerometer,
valuesMagneticField);
if(success){
SensorManager.getOrientation(matrixR, matrixValues);
// Float to double
double pitch = Math.toDegrees(matrixValues[1]);
// 1 decimal
pitch = Math.abs(round(pitch, 0));
//set textview vinkel to degrees
vinkel.setText(String.valueOf(pitch));
// find tubesize from edittext
String tubesizestring = tubesize.getText().toString();
if(tubesizestring=="1000"){
if(pitch>=0.6){
kwh.setText("2,69");
}else if(pitch>=1.0){
kwh.setText("3,47");
}else if(pitch>=2.0){
kwh.setText("4,90");
}else if(pitch>=5.0){
kwh.setText("7,75");
}else if(pitch>=10.0){
kwh.setText("10,96");
}else if(pitch>=20.0){
kwh.setText("15,50");
}else if(pitch>=30.0){
kwh.setText("18,99");
}else{
kwh.setText("more than 30 degrees");
}
}
}
I hope it is clear what I'm trying to do. Othervise please ask
Hope somebody can point me in the right direction
It doesn't work because your logic is fundamentally flawed. Let's assume the pitch is around 25. It's greater than 0.6 and 1.0 and so on. So obviously only the first if statement will be seen, since the others are else if statements. To get it to work, change the order of the statements.
if(pitch>=30.0){
kwh.setText("18,99");
}else if(pitch>=20.0){
kwh.setText("15,50");
}else if(pitch>=10.0){
kwh.setText("10,96");
}else if(pitch>=5.0){
kwh.setText("7,75");
}else if(pitch>=2.0){
kwh.setText("4,90");
}
else if(pitch>=1.0){
kwh.setText("3,47");
}
else if(pitch>=0.6){
kwh.setText("2,69");
}eelse{
kwh.setText("more than 30 degrees");
Related
I'm building an augmented reality app with POI.
Most of the app is done but now I am trying to find a better stabilization of my sensors, in particular the Accelerometer. I have used low pass filter, but POI are still bouncing to much. The thing I was trying to do is get 5 or more readings of accelerometer and then divide it by n. That should give me better readings but i have no idea how to make it. I can make a for loop but I can't just make for(int i=0; i<n; i++) , because i++ should be done only when the value of accelerometer has changed. If I do it with a simple for loop, I will get an error because the loop is done faster then the sensors are changed. The thing i was looking for is a timer that will changed only when the sensors are changed too.
This is what i have done so far:
static final float ALPHA = 0.15f; // if ALPHA = 1 OR 0, no filter applies.
// low level pass filter, so i can get steadier reading of mobile sensors
// using only accelerometer and compass
protected float[] lowPass(float[] input, float[] output) {
if (output == null) return input;
for (int i = 0; i < input.length; i++) {
output[i] = output[i] + ALPHA * (input[i] - output[i]);
// output[i] = input[i]*ALPHA + output[i]*(1.0f-ALPHA);
}
return output;
}
public void onSensorChanged(SensorEvent event) {
StringBuilder msg = new StringBuilder(event.sensor.getName())
.append(" ");
for (float value : event.values) {
msg.append("[").append(String.format("%.3f", value)).append("]");
}
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
lastAccelerometer = lowPass(event.values.clone(), lastAccelerometer);
accelData = msg.toString();
break;
case Sensor.TYPE_GYROSCOPE:
gyroData = msg.toString();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
lastCompass = lowPass(event.values.clone(), lastCompass);
compassData = msg.toString();
break;
}
this.invalidate();
}
I found the solution :
protected float[] getMovingAvg() {
float [] output = new float [3];
for( int i = 0; i< moveVector.size(); i++) {
output[0] += moveVector.get(i)[0];
output[1] += moveVector.get(i)[1];
output[2] += moveVector.get(i)[2];
}
output[0] = output[0]/moveVector.size();
output[1] = output[1]/moveVector.size();
output[2] = output[2]/moveVector.size();
if(moveVector.size() >= 70) {
moveVector.remove(0);
}
return output;
}
I want to change the bitmap that contains an image whenever user tap on the screen. i.e. the default image is shadow1, now what i want is that when user touched on screen then this image changed to shadow2, then again if user touched then shadow3, then on next touch the image again comes as shadow1 and it goes on and on and on. so basically there are three images and i want that when ever user touched on screen then image changes with each tap.
Following is the code that i tried but it is still not working as expected i.e. the image changes from shadow1 to shadow2 but then not changes to shadow3 or shadow1 even if i touched many times.
public void Touched(float x, float y)
{
boom = false;
try{
switch (bird.GetState()) {
case 0:
distance = 0;
bird.SetState(1);
flapped = true;
Bitmap workingBitmap = BitmapFactory.decodeResource(gameLogic.Resources(), R.drawable.shadow1);
bitmapBird = workingBitmap.copy(Bitmap.Config.ARGB_8888, false);
if (bitmapBird==workingBitmap)
{
}
riseCounter = 0;
pipeValues.clear();
//SoundManager.playSound(2, 1);
break;
case 1:
{
riseCounter = 0;
flapped = true;
t = 3;
Bitmap workingBitmappp = BitmapFactory.decodeResource(gameLogic.Resources(), R.drawable.shadow2);
bitmapBird = workingBitmappp.copy(Bitmap.Config.ARGB_8888, false);
//SoundManager.playSound(2, 1);
}
break;
case 2:
{
riseCounter = 0;
flapped = true;
t = 0;
}
break;
default:
Bitmap workingBitma = BitmapFactory.decodeResource(gameLogic.Resources(), R.drawable.shadow3);
bitmapBird = workingBitma.copy(Bitmap.Config.ARGB_8888, false);
break;
}
} catch(Exception e){}
}
I think there should be a for loop or while loop in 'case 1' and whenever user tap then image changes. Please help me with this.
You can simply use an int value to keep track of the image displayed as;
First Initialize a int at class level;
int num = 0;
then you can use it as;
if(num == 0){
loadFirstImage();
num++;
}
else if(num == 1)
{
loadSecondImage();
num++;
}
else if(num == 2){
loadThirdImage();
num = 0 ;
}
I think that you need to change the state of the bird in your second case statement.
First iteration will set the state to 1, from there, the only case statement you can hit is case 1: because you never change it.
So you need something like
case 1:
bird.SetState(2);
//....
Hope that helps
I am developing an app which accesses accelerometer in order to detect a fall by measuring the values of acceleration in x,y and z directions. Below is my code, I have applied algorithm which uses two threshold values(min and max) rest of the algo you can see in the code itself. The problem i am facing is that the app is not displaying toast i have done some mild experiments with my friend's phone.
After dropping my phone from a certain height(approximately 30 cm.) and catching it. But no toast appear on the screen.I am unable to identify whether there is a problem in my ALGO or TOAST. I don't know what to do next please help.
#Override
public void onSensorChanged(SensorEvent event) {
if (started) {
double x = event.values[0];
double y = event.values[1];
double z = event.values[2];
long timestamp = System.currentTimeMillis();
Data data = new Data(timestamp, x, y, z);
sensorData.add(data);
}
if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
double gacc=SensorManager.STANDARD_GRAVITY;
double a=event.values[0];
double b=event.values[1];
double c=event.values[2];
long mintime=System.currentTimeMillis();
boolean min = false;
boolean max = false;
int m = 0;
double xyz=Math.round(Math.sqrt(Math.pow(a,2)+Math.pow(b,2)+Math.pow(c,2)));
if(xyz<=3.0){
min = true;
}
if(min==true){
m++;
if(xyz>=14){
max=true;
}
}
if(min && max==true){
Toast.makeText(MainActivity.this,"FALL DETECTED!",Toast.LENGTH_LONG).show();
m=0;
min=false;
max=false;
}
if (m>4) {
m=0;
min=false;
max=false;
}
}
}
I am developing some application like Runtastic Pedometer using the algorithm but I am not getting any similarity between the results.
my code is as follows:
public void onSensorChanged(SensorEvent event)
{
Sensor sensor = event.sensor;
synchronized (this)
{
if (sensor.getType() == Sensor.TYPE_ORIENTATION) {}
else {
int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
if (j == 1) {
float vSum = 0;
for (int i=0 ; i<3 ; i++) {
final float v = mYOffset + event.values[i] * mScale[j];
vSum += v;
}
int k = 0;
float v = vSum / 3;
//Log.e("data", "data"+v);
float direction = (v > mLastValues[k] ? 1 : (v < mLastValues[k] ? -1 : 0));
if (direction == - mLastDirections[k]) {
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType][k] = mLastValues[k];
float diff = Math.abs(mLastExtremes[extType][k] - mLastExtremes[1 - extType][k]);
if (diff > mLimit) {
boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k]*2/3);
boolean isPreviousLargeEnough = mLastDiff[k] > (diff/3);
boolean isNotContra = (mLastMatch != 1 - extType);
if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
for (StepListener stepListener : mStepListeners) {
stepListener.onStep();
}
mLastMatch = extType;
}
else {
Log.i(TAG, "no step");
mLastMatch = -1;
}
}
mLastDiff[k] = diff;
}
mLastDirections[k] = direction;
mLastValues[k] = v;
}
}
}
}
for registering sensors:
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(
Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(mStepDetector,mSensor,SensorManager.SENSOR_DELAY_NORMAL);
in the algorithm i have different levels for sensitivity as public void
setSensitivity(float sensitivity) {
mLimit = sensitivity; // 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62
}
on various sensitivity level my result is:
sensitivity rantastic pedometer my app
10.00 3870 5500
11.00 3000 4000
11.15 3765 4576
13.00 2000 890
11.30 754 986
I am not getting any proper pattern to match with the requirement.
As per my analysis this application is using Sensor.TYPE_MAGNETIC_FIELD for steps calculation please let me know some algorithm so that I can meet with the requirement.
The first thing you need to do is decide on an algorithm. As far as I know there are roughly speaking three ways to detect steps using accelerometers that are described in the literature:
Use the Pythagorean theorem to calculate the magnitude of the acceleration vector of each sample from the accelerometer. Low-pass filter the magnitude signal to remove high frequency noise and then look for peaks and valleys in the filtered signal. You may need to add additional requirements to remove false positives. This is by far the simplest way to detect steps, it is also the way that most if not all ordinary pedometers of the sort that you can buy from a sports store work.
Use Pythagoras' like in (1), then run the signal through an FFT and compare the output from the FFT to known outputs of walking. This requires you to have access to a fairly large amount of training data.
Feed the accelerometer data into an algorithm that uses some suitable machine learning technique, for example a neural network or a digital wavelet transform. You can of course include other sensors in this approach. This also requires you to have access to a fairly large amount of training data.
Once you have decided on an algorithm you will probably want to use something like Matlab or SciPy to test your algorithm on your computer using recordings that you have made on Android phones. Dump accelerometer data to a cvs file on your phone, make a record of how many steps the file represents, copy the file to your computer and run your algorithm on the data to see if it gets the step count right. That way you can detect problems with the algorithm and correct them.
If this sounds difficult, then the best way to get access to good step detection is probably to wait until more phones come with the built-in step counter that KitKat enables.
https://github.com/bagilevi/android-pedometer
i hope this might be helpfull
I am using step detection in my walking instrument.
I get nice results of step detection.
I use achartengine to plot accelerometer data.
Take a look here.
What I do:
Analysis of magnitude vector for accelerometer sensor.
Setting a changeable threshold level. When signal from accelerometer is above it I count it as a step.
Setting the time of inactive state (for step detection) after first crossing of the threshold.
Point 3. is calculated:
arbitrary setting the maximum tempo of our walking (e.g. 120bpm)
if 60bpm - 1000msec per step, then 120bpm - 500msec per step
accelerometer passes data with certain desired frequency (SENSOR_DELAY_NORMAL, SENSOR_DELAY_GAME, etc.). When DELAY_GAME: T ~= 20ms (this is included in Android documentation)
n - samples to omit (after passing the threshold)
n = 500msec / T
n = 500 / 20 = 25 (plenty of them. You can adjust this value).
after that, the threshold becomes active.
Take a look at this picture:
This is my realization. It was written about 1.5-2 years ago. And I really don't remember all this stuff that I wrote. But it worked. And it worked good for my needs.
I know that this is really big class (some methods are deleted), but may be it will be helpful. If not, I'll just remove this answer...
public class StepDetector implements SensorEventListener
{
public static final int MAX_BUFFER_SIZE = 5;
private static final int Y_DATA_COUNT = 4;
private static final double MIN_GRAVITY = 2;
private static final double MAX_GRAVITY = 1200;
public void onSensorChanged(final SensorEvent sensorEvent)
{
final float[] values = sensorEvent.values;
final Sensor sensor = sensorEvent.sensor;
if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
magneticDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l));
}
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
accelDetector(values, sensorEvent.timestamp / (500 * 10 ^ 6l));
}
}
private ArrayList<float[]> mAccelDataBuffer = new ArrayList<float[]>();
private ArrayList<Long> mMagneticFireData = new ArrayList<Long>();
private Long mLastStepTime = null;
private ArrayList<Pair> mAccelFireData = new ArrayList<Pair>();
private void accelDetector(float[] detectedValues, long timeStamp)
{
float[] currentValues = new float[3];
for (int i = 0; i < currentValues.length; ++i)
{
currentValues[i] = detectedValues[i];
}
mAccelDataBuffer.add(currentValues);
if (mAccelDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE)
{
double avgGravity = 0;
for (float[] values : mAccelDataBuffer)
{
avgGravity += Math.abs(Math.sqrt(
values[0] * values[0] + values[1] * values[1] + values[2] * values[2]) - SensorManager.STANDARD_GRAVITY);
}
avgGravity /= mAccelDataBuffer.size();
if (avgGravity >= MIN_GRAVITY && avgGravity < MAX_GRAVITY)
{
mAccelFireData.add(new Pair(timeStamp, true));
}
else
{
mAccelFireData.add(new Pair(timeStamp, false));
}
if (mAccelFireData.size() >= Y_DATA_COUNT)
{
checkData(mAccelFireData, timeStamp);
mAccelFireData.remove(0);
}
mAccelDataBuffer.clear();
}
}
private void checkData(ArrayList<Pair> accelFireData, long timeStamp)
{
boolean stepAlreadyDetected = false;
Iterator<Pair> iterator = accelFireData.iterator();
while (iterator.hasNext() && !stepAlreadyDetected)
{
stepAlreadyDetected = iterator.next().first.equals(mLastStepTime);
}
if (!stepAlreadyDetected)
{
int firstPosition = Collections.binarySearch(mMagneticFireData, accelFireData.get(0).first);
int secondPosition = Collections
.binarySearch(mMagneticFireData, accelFireData.get(accelFireData.size() - 1).first - 1);
if (firstPosition > 0 || secondPosition > 0 || firstPosition != secondPosition)
{
if (firstPosition < 0)
{
firstPosition = -firstPosition - 1;
}
if (firstPosition < mMagneticFireData.size() && firstPosition > 0)
{
mMagneticFireData = new ArrayList<Long>(
mMagneticFireData.subList(firstPosition - 1, mMagneticFireData.size()));
}
iterator = accelFireData.iterator();
while (iterator.hasNext())
{
if (iterator.next().second)
{
mLastStepTime = timeStamp;
accelFireData.remove(accelFireData.size() - 1);
accelFireData.add(new Pair(timeStamp, false));
onStep();
break;
}
}
}
}
}
private float mLastDirections;
private float mLastValues;
private float mLastExtremes[] = new float[2];
private Integer mLastType;
private ArrayList<Float> mMagneticDataBuffer = new ArrayList<Float>();
private void magneticDetector(float[] values, long timeStamp)
{
mMagneticDataBuffer.add(values[2]);
if (mMagneticDataBuffer.size() > StepDetector.MAX_BUFFER_SIZE)
{
float avg = 0;
for (int i = 0; i < mMagneticDataBuffer.size(); ++i)
{
avg += mMagneticDataBuffer.get(i);
}
avg /= mMagneticDataBuffer.size();
float direction = (avg > mLastValues ? 1 : (avg < mLastValues ? -1 : 0));
if (direction == -mLastDirections)
{
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType] = mLastValues;
float diff = Math.abs(mLastExtremes[extType] - mLastExtremes[1 - extType]);
if (diff > 8 && (null == mLastType || mLastType != extType))
{
mLastType = extType;
mMagneticFireData.add(timeStamp);
}
}
mLastDirections = direction;
mLastValues = avg;
mMagneticDataBuffer.clear();
}
}
public static class Pair implements Serializable
{
Long first;
boolean second;
public Pair(long first, boolean second)
{
this.first = first;
this.second = second;
}
#Override
public boolean equals(Object o)
{
if (o instanceof Pair)
{
return first.equals(((Pair) o).first);
}
return false;
}
}
}
One main difference I spotted between your implementation and the code in the grepcode project is the way you register the listener.
Your code:
mSensorManager.registerListener(mStepDetector,
mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
Their code:
mSensorManager.registerListener(mStepDetector,
mSensor,
SensorManager.SENSOR_DELAY_FASTEST);
This is a big difference. SENSOR_DELAY_NORMAL is intended for orientation changes, and is therefor not that fast (ever noticed that it takes some time between you rotating the device, and the device actually rotating? That's because this is some functionality that does not need to be super fast (that would probably be pretty annoying even). The rate at which you get updates is not that high).
On the other hand, SENSOR_DELAY_FASTEST is intended for things like pedometers: you want the sensor data as fast and often as possible, so your calculations of steps will be as accurate as possible.
Try to switch to the SENSOR_DELAY_FASTEST rate, and test again! It should make a big difference.
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER ){
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
currentvectorSum = (x*x + y*y + z*z);
if(currentvectorSum < 100 && inStep==false){
inStep = true;
}
if(currentvectorSum > 125 && inStep==true){
inStep = false;
numSteps++;
Log.d("TAG_ACCELEROMETER", "\t" + numSteps);
}
}
}
Using Location.getBearing(); I seem to get randomly changing bearings.
Aka, I can turn the device around slowly and it wont notice, it just chooses its own random bearings.
I know the device is working, as the "You are here" icon in the Maps app on the tablet slowly rotates as I rotate the device.
Is there a different proper way of getting bearing? I am using the GPS. Maybe there is a better way to determine which direction you are facing.
Try to get bearing from Accelerometer sensor and Magnetic Field (G-) sensor.
Here's a tutorial: http://android-coding.blogspot.co.at/2012/03/create-our-android-compass.html
The Location.getBearing() returns the bearing that the GPS satellites computed for you. It is not a real time representation of the heading of your device. The Google Maps app uses the device's built in G-sensors to get the direction you are facing.
Following from herom's answer using the link: http://android-coding.blogspot.co.at/2012/03/create-our-android-compass.html
I extended my class to implement the sensor: extends Activity implements SensorEventListener
And implemented as suggested, but modified it to take into account, the orientation of the screen.
Here is the code I went with:
#Override
public void onSensorChanged(SensorEvent event) {
switch(event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
for(int i =0; i < 3; i++){
valuesAccelerometer[i] = event.values[i];
}
break;
case Sensor.TYPE_MAGNETIC_FIELD:
for(int i =0; i < 3; i++){
valuesMagneticField[i] = event.values[i];
}
break;
}
boolean success = SensorManager.getRotationMatrix(
matrixR,
matrixI,
valuesAccelerometer,
valuesMagneticField);
if(success){
SensorManager.getOrientation(matrixR, matrixValues);
double azimuth = Math.toDegrees(matrixValues[0]);
//double pitch = Math.toDegrees(matrixValues[1]);
//double roll = Math.toDegrees(matrixValues[2]);
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
Display mDisplay = mWindowManager.getDefaultDisplay();
Float degToAdd = 0f;
if(mDisplay.getRotation() == Surface.ROTATION_0)
degToAdd = 0.0f;
if(mDisplay.getRotation() == Surface.ROTATION_90)
degToAdd = 90.0f;
if(mDisplay.getRotation() == Surface.ROTATION_180)
degToAdd = 180.0f;
if(mDisplay.getRotation() == Surface.ROTATION_270)
degToAdd = 270.0f;
mapView.setFacingDirection((float) (azimuth + degToAdd)); //DEGREES NOT RADIANS
}
}