Calculating Pitch and Roll gives wrong values

I have the following widget: https://github.com/TimZander/slope-widget

The goal is to display the slope angle based on the watch face.

I am calculating pitch and roll here: https://github.com/TimZander/slope-widget/blob/main/source/SlopeWidgetView.mc#L71

var accel = sensorInfo.accel;
xAccel = accel[0];
yAccel = accel[1];
zAccel = accel[2];

pitch = 180 * Math.atan2(yAccel, Math.sqrt(Math.pow(xAccel, 2) + Math.pow(zAccel, 2)));
roll = 180 * Math.atan2(-xAccel, zAccel);

But when I run this with the watch face flat I am getting pitch: -10deg, roll: -24deg which seems really off.

I'm not sure what I'm doing wrong.

Thanks for any advice

  • FYI I figured this out, I was converting radians to degrees incorrectly. In case someone else is struggling with this you need to divide by Math.PI as you can now see in the github repo

  • can you post te fixed code snippet?

  • I think this is it:

    [https://github.com/TimZander/slope-widget/blob/fc0d8c0872a60b2beceb0806a6a7a904e07bcfab/source/CalculateInclinations.mc#L15-L47]

        function calculate() {
            var sensorInfo = Sensor.getInfo();
            if (sensorInfo has :accel && sensorInfo.accel != null) {
                noData = false;
                var accel = sensorInfo.accel;
                xAccel = accel[0];
                yAccel = accel[1];
                zAccel = accel[2];
            }
            else{
                noData = true;
                //test inputs
                xAccel = -921;
                yAccel = -37;
                zAccel = -305;
            }
            var pitchRad = Math.atan2(yAccel, Math.sqrt(Math.pow(xAccel, 2) + Math.pow(zAccel, 2)));
            var rollRad = Math.atan2(-xAccel, zAccel);
            var inclinationRad = Math.atan(Math.sqrt(Math.pow(Math.tan(pitchRad), 2) + Math.pow(Math.tan(rollRad), 2)));
            pitch = Math.toDegrees(pitchRad);
            roll = Math.toDegrees(rollRad);
            
            if(roll > 90){
                rollNormalized = roll - 180;
            }
            else if(roll < -90){
                rollNormalized = roll + 180; 
            }
            else{
                rollNormalized = roll;
            }
            
            inclination = Math.toDegrees(inclinationRad);

  • Interesting - wonder if I can use this on an EDGE to help improve Grade calcs? Trying....

  • if you are able to smooth the data enough to do some meaningful calculations, you'll need to add a calibration step (and every time the edge is moved on the handlebar or used on another bike the user will need to recalibrate) on a smooth (0%) surface, to know the position of the edge compared to the 0%.

    However if one would use this on a mountainbike while on rough surface it'll oscillate almost as the raw data you saw in the barometer... It makes no sense to display every bump over a tree root or stone, so you'll have to do some "smoothing", and then probably you'll be able to do it easier using the barometer data, because there you could just compare the "previous" and "current" barometer reading, while using the accelerometer would give you the "current" angle, but that won't be very useful IMHO.

    And then I'll add that using the baro your algorithm should work on a watch as well, but using accelerometer it will be even harder if not impossible.

  • Yeah that all makes sense. Watches would not work and rough terrain would not work - only a fixed EDGE on a smooth road. I could auto calibrate the EDGE device's install angle, waiting for sustained movement with a steady barometric value (flat road), and then calibrate pitch to zero. Then use a smoothed Pitch to help validate barometric grade. I'll play with it but thinking this won't really help. 

  • Sounds strange to use the baro to calibrate the pitch angle for improving the grade calculations that the baro is not good enough for :)