Calibrate accelerometer - accelerometer

I need to calibrate one axis of the accelerometer.
Currently I have a variable lastVal which holds the last stored value of the device rotation around that axis. And when I choose to calibrate the accelerometer, the variable compensateAccel is changed to the lastVal. Then the rotation value after calibration would be currentVal - compensateAccel.
When the device lays flat, the rotation values go from 0 to 90 back to 0 degrees. But when I calibrate it for example at 50 degrees, then those values go from 0 to (90-50=40) back to 0.
So how do I keep the previous value interval after calibration?

Related

Why does CMDeviceMotion attitude quaternion not always rotate to earth frame?

I wrote an app that writes gravity, userAcceleration, and attitude quaternion to CSV while driving in a vehicle. The intent is to capture the dynamics of the vehicle (e.g. braking, accelerating, cornering) in the earth frame using an iPhone.
Then, I sum gravity and userAcceleration, and rotate the resulting raw acceleration vector by the quaternion provided by CMAttitude to get the acceleration in the earth frame. In about 60% of recording sessions, the average z values are not +9.81m/s^2 and jump to varying magnitudes besides +9.81m/s^2. For example (each tick mark in the y-axis represents 5m/s^2):
But, I expect a plot with a consistent average value for acceleration in the z axis like the following:
When I start device motion updates, I use the xMagneticNorthZVertical attitude reference frame, like so:
motionManager.startDeviceMotionUpdates(using: .xMagneticNorthZVertical, to: OperationQueue(), withHandler: didUpdateDeviceMotion)
The following computes raw acceleration in the global frame using the attitude quaternion:
let accel = CMAcceleration(x: (motion.userAcceleration.x+motion.gravity.x), y: (motion.userAcceleration.y+motion.gravity.y), z: (motion.userAcceleration.z+motion.gravity.z))
let a = SIMD3<Double>(accel.x, accel.y, accel.z)
let a_vehicle = simd_act(attitude.quaternion, a)
I also have written the equivalent in MATLAB resulting with the same problem.
xMagneticNorthZVertical should result in an attitude that computes the direction of gravity. The direction of X or Y does not matter to me.
I do not have any magnets in the vicinity to skew the computed attitude.
In contrast: Android's rotationVector consistently rotates the accelerometer readings to the earth frame. Surely the quality of iPhone is better than Android.
What might be the cause of the attitude quaternion to not always rotate the device frame to the earth frame such that Z is in the direction of gravity?

How to turn CMRotationmatrix to initial position

I have a rotation matrix that I get from the motion manager. It rotates an object. Now I want to reset the Rotation, meaning that I press a button on the iPhone and the rotation is set back to the start without turning the iPhone to the start position.
I was able to achieve this by saving the initial values of m11 to m33 of the rotation matrix to an array and do this: (current position m11 to m33) - (position when pressing the reset button m11 to m33 - initial position of m11 to m33).
This leads to the current rotation matrix having the exact values as the initial matrix and therefore resetting the rotation. However, if I now turn the iPhone the resulting turning of the object is nonsense as are the values of the rotation matrix.
So what is the proper formula of calculating this / What is the formula to turn back the rotation matrix as many degrees in x/y/z as the iPhone has been turned until now?
Thanks a lot.
The answer is to take the initial transformation matrix and divide every new transformation matrix by it. My problem was that I did the calculation wrong. So a look at how to divide by a matrix helped.

iPhone compass presents the wrong heading pitch angle is > about 45°

This might be hard to explain the geometry so I will be careful in spelling it out. This is visible in the standard compas app and from the data in CLLocationManager.
1) When holding the phone in portrait orientation, consider the pitch angle to be 0°
2) When pointing the camera up into the sky (such as taking a picture of a cloud) the pitch angle goes from 0° -> 90° where 90 degrees is straight up.
3) when the phone is tilted upward (> 0 degrees and rotating on the "X" magnetometer axis) and when the phone is at about (but not exactly) 45 degrees, the compass heading rotates 180 degrees. So while the camera is still point "N", the compass will report "S".
4) for the next (roughly) 90 degrees, the compass heading is rotated 180 degrees.
This rotation of the heading is destructive for me and it does not align perfectly with the accelerometers. Is there a good tutorial (I did not find one off the bat) on using the the RAW data (X, Y, Z) from the CLHeading data to calculate heading data?
The end result is I want the heading of the compass to always match the heading of the camera.
You can't rely on solely the compass heading. See this answer for what you're looking for, and in particular the CMAttitude object's yaw property to compensate for the pitch angle you're talking about:
Compensating compass lag with the gyroscope on iPhone 4

Detecting the direction of the accelerometer movement on the y axis

I currently detect movement on the y axis. How does one calculate the direction it moved on the axis?
I get the same values when moving up or down.
Is the Gyro needed for this?
Do remember that the accelerometer will reflect the force of gravity. So movement up and down will generally be reflected as 9.81 m/s2 plus or minus the actual acceleration of the device relative to the Earth.

Matlab matrix translation and rotation multiple times

I have a map of individual trees from a forest stored as x,y points in a matrix. I call it fixedPositions. It's cartesian and (0,0) is the origin.
Given a velocity and a heading, i.e. .5 m/s and 60 degrees (2 o'clock equivalent on a watch), how do I rotate the x,y points, so that the new origin is centered at (.5cos(60),.5sin(60)) and 60 degrees is now at the top of the screen?
Then if I were to give you another heading and speed, i.e. 0 degrees and 2m/s, it should calculate it from the last point, not the original fixedPositions origin.
I've wasted my day trying to figure this out. I wish I took matrix algebra but I'm at a loss.
I tried doing cos(30) and even those wouldn't compute correctly, which after an hour I realize were in radians.
I'd try the following: In your object, you already have a property heading. Now you add another property, currentPosition (an maybe rename them to heading_robot and currentPos_robot). heading as well as currentPosition should always be relative to the original coordinate system
Then you add a new method, updatePosition that takes (newHeading, distance) as input. This method will update both heading and currentPosition, by first adding the angle in newHeading to the angle in heading, after which you update currentPosition by adding [distance*cos(heading),distance*sin(heading)] (check for signs of sin/cos here!) to the old value of currentPosition.
Finally, to get the view of the landscape (i.e. apparentPositions), you run bsxfun(#minus,fixedPositions,currentPosition) to move the origin to where the robot is at this moment, and then you multiply with the 2D rotation matrix using the angle stored in heading.
You just first translate the coordinates (-0.5cos(60),-0.5sin(60)) to take the origin to your target point.
Then rotate by multiplying the coordinates by a rotation matrix.
Of course, most programming languages use radians as angle units, so that instead of 60 you must enter 60 * PI / 180