How can i get device tilt?
Asked Answered
C

2

1

I am trying to get device tilt (device rotation along y-axis but unfortunately i am unable to achieve my goal. I have tried a lot of stuff using TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD as a combined sensor (Sensor fusion). i have also followed Motion Sensors

What i want?

i want to get inclination of device (cell phone ) attached in a vehicle. Let say, i attached a device in a car and car is stationary. So inclination is 0 degrees.Lator on, when vehicle pass through under passes or flyovers, inclination should be accordingly. I have tried to calculate this, here is my code:

...
...
    private static float ALPHA = 0.005f
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        tv = (TextView) findViewById(R.id.tv);
        edtAlpha = (EditText) findViewById(R.id.alpha);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        accelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnetometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (accelerometer == null) {
            Toast.makeText(this, "Oh  not found", Toast.LENGTH_SHORT).show();
        }
        if (magnetometer == null) {
            Toast.makeText(this, "Oh magnetometer not found",
                    Toast.LENGTH_SHORT).show();
        }

    }

    protected float[] lowPass(float[] input, float[] output) {
        if (output == null)
            return input;
        String s = edtAlpha.getText().toString();
        if (s != null && s.length() > 0) {
            try {
                ALPHA = Float.valueOf(s);
            } catch (NumberFormatException e) {
                ALPHA = 0.005f;
            }
        } else {
            ALPHA = 0.005f;
        }
        for (int i = 0; i < input.length; i++) {
            output[i] = output[i] + ALPHA * (input[i] - output[i]);
        }
        return output;
    }

    public int getRotation(final Activity activity) {
        int result = 1;
        Method mDefaultDisplay_getRotation;
        try {
            mDefaultDisplay_getRotation = Display.class.getMethod(
                    "getRotation", new Class[] {});
            Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay();

            Object retObj = mDefaultDisplay_getRotation.invoke(display);
            if (retObj != null) {
                result = (Integer) retObj;
            }
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return result;
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        Log.d(tag, "onSensorChanged");

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            gravSensorVals = lowPass(event.values.clone(), gravSensorVals);

        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magSensorVals = lowPass(event.values.clone(), magSensorVals);
        }

        if (gravSensorVals != null && magSensorVals != null) {
            SensorManager.getRotationMatrix(RTmp, I, gravSensorVals,
                    magSensorVals);

            int rotation = getRotation(this);

            if (rotation == 1) {
                SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_X,
                        SensorManager.AXIS_MINUS_Z, Rot);
            } else {
                SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_Y,
                        SensorManager.AXIS_MINUS_Z, Rot);
            }

            SensorManager.getOrientation(Rot, results);

            float azimuth = (float) (((results[0] * 180) / Math.PI) + 180);
            float pitch = (float) (((results[1] * 180 / Math.PI)) + 90);
            float roll = (float) (((results[2] * 180 / Math.PI)));

            tv.setText("Azimuth : " + df.format(azimuth) + "\nPitch : "
                    + df.format(pitch) + "\nRoll : " + df.format(roll));
        }

        Log.d(tag, "Sensor type : " + event.sensor.getType());

    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_UI);
        mSensorManager.registerListener(this, magnetometer,
                SensorManager.SENSOR_DELAY_UI);
    }
...
...

What the issue is with my code?

When i rapidly accelerate /deaccelerate my car, angle goes rapidly increase /decrease but it shouldn't. In other words, when i accelerate/deaccelerate vehicle, there should not be any effect on angle. i have also tried to follow these tutorials: Link 1 Link 2 etc.

Counsel answered 16/6, 2014 at 11:46 Comment(0)
T
2

First of all, you should avoid using Accelerometer or Magnetometer data directly unless you REALLY know what the implications are and what data you receive from those sensors.

I personally recommend that you use the predefined ROTATION_VECTOR sensor which fuses Accelerometer, Magnetometer and Gyroscope in a Kalman-Filter. (see this how to obtain data from the ROTATION_VECTOR-sensor and this how to consume the data).

When you start from this project you can just access the quaternion and play around with it or with the rotation-matrix and apply the corresponding conversion to get the euler angles of your device (the names are not always consistent but you are quite likely interested in the bank or attitude). One final remark: Note that euler-angles suffer from gimbal lock (aka. "jumping" values).

Thistly answered 18/6, 2014 at 16:4 Comment(2)
First thank for answering my question. I have used your code in my sample application.I have used ImprovedOrientationSensor1Provider & ImprovedOrientationSensor2Provider from your code (including necessar classes).But i am getting variable results (angle) even my device (LG- Nexus 4) is laying stationary on table. Here is ,How i am using your code: Quaternion q = currentOrientationProvider.getQuaternion(); float angle = (float) (2.0f * Math.acos(q.getW()) * 180.0f / Math.PI); Log.d("angle", String.valueOf(angle)); Can you please tell me what i am doing wrong?Counsel
Here is output: 132.06401 , 132.06432 , 132.06334 , 132.06345 , 132.06252 , 132.06252 , 132.06168 , 132.06107 , 132.06134 , 132.06215 , 132.06207 , 132.06268 , 132.06332 , 132.06416 , 132.06346 , 132.06425 , 132.06326 , 132.06314 , 227.93698 , 227.93661 , 227.9361 , 227.93614 , 227.93663 , 227.93794 , 227.93845 , 227.9378 , 132.06181 , 227.93822 , 227.93892 , 132.06259 , 204.06075 , 204.06076 , 204.06076 , 204.06076 , 204.06076 , 204.06078 , 225.64037 , 225.64124 , 225.64375Counsel
S
0

As long as you use the accelerometer and the magnetometer but not the gyroscopes, your method will fail when the device goes through rapid acceleration / deceleration. You can try to be overly clever and do some ad-hoc hack that may seem to rule out this particular failure mode you have discovered but I wouldn't even try it.

The true solution is to use gyroscopes as well. In my experience, that works pretty well.

What's wrong with the TYPE_ROTATION_VECTOR?

Selmore answered 16/6, 2014 at 12:47 Comment(7)
Thanks Ali, Gyroscope gives just a change.It does not provide continuous change,e.g. vehicle moves through underpass ,then gyroscope will give you a sudden change in value.And also most of the devices have no Gyroscope. ROTATION_VACTOR : ROTATION_VACTOR is conserned with device rotation.Will be there any effect on Rotation Sensor of Acc/decell?.i think, it will have same effectCounsel
@MohammadImran Please re-read my answer. I am saying that you should use gyroscopes as well. So use accelerometer and magnetometer as before but augment it with the gyros. That's the only way to get the orientation reliably. Yes, acceleration and deceleration will slightly influence the results, hopefully you won't even notice it, thanks to the gyros. So, all in all, I am saying that the orientation sensor should be used (which presumably uses the accelerometer, magnetometer and the gyros).Selmore
Again Thanks, Can you please show here a sample code in your answer? really appreciate your response.Counsel
@MohammadImran No, I don't do Android programming myself. I implemented sensor fusion and orientation tracking in C++ on the Shimmer2 platform. However, I am not familiar with the Android API. The point I am trying to make in my answer: I will need a device with gyroscopes and you will need to use the orientation sensor; then, depending on your definition of the tilt, you can then derive the mathematical formula for the tilt.Selmore
Can you please share mathematical formulas, here?Counsel
@MohammadImran Please re-read my previous comment. As I wrote: depending on your definition of the tilt, you can then derive the mathematical formula for the tilt. I don't know how you defined the tilt in your application, so I cannot give you a formula.Selmore
Let us continue this discussion in chat.Counsel

© 2022 - 2024 — McMap. All rights reserved.