Auto calibrate an Accelerometer

I have an accelerometer connected to an ARM STm32F40 which I need to auto calibrate within a vehicle.
That is acquire the direction it is mounted as it can be mounted arbitrarily.

What I have as of right now:
I can get the effect of gravity (9.81ms^2) immediately to give the ‘z-axis’ in relation to its mounting.

I can also get the driver to drive forward and brake quickly and I will capture the readings from the accelerometer as they do this (which will give me the forward x-axis).
But once I have these readings can I extrapolate out which elements of x may be on the y/z plain and vice versa if it is not mounted perfectly perpendicular?

Has anyone done this before or have an idea as to the maths involved?
I saw this similar topic which may work


Hiya Tim. Welcome.
Fun problem. :slight_smile:

Is there a reason this cannot be resolved instead? :slight_smile:

When the driver pulls this maneuver, will he be able to provide you with his final speed before he braked and the time that he took to do it? :oncoming_automobile:

Why do you need to know which is x and which is y? I’m not saying this isn’t useful in some situations, just trying to figure out what problem specifically this needs to solve. :nerd_face:


Hi Pixmusix
They will ‘try’ and mount it as flat as they can but it will depend on the vehicle as there will be a few variants.
But inevitably there will be slight tilting going on.
Yes I have stated that he must exceed 30kph then hit 20 kph within 1.5 secs. All these params will be configurable, if the criteria is not met then we cannot calibrate.
At the moment they must state what direction the unit is mounted based on arrows on the device.
They no longer want to do this hence we need to auto-calibrate. So once we are in “auto-cal mode” we can immediately get gravity (z-axis) then we wait on the braking maneuver above to get the remainder.
This will give us a calibration vector that can be applied to the raw data for ever more.
Just getting this calibration vector is my issue.

This is looking solvable with a shear linear transformation..
You can skew either X or Y to distinguish them.
Are you using C like languages?
C and C++ libraries for linear algebra, like Eigen, use memory allocation.
Is that going to be OK for this project?

Also, just to clarify, the driver is always facing the same direction, right?

The vehicle will be driven in the same manner but the device housing the acc can be mounted any way they like but once it is mounted it will never move from that position.

The only thing we will know is 9.81 m/s^2 when the device is at rest gives us the ‘z-axis’
Then when they drive and brake it will give us the axis in which the forward movement aligns but this could be components of x and y or z depending on its mounting if it is slightly tilted if you see what I mean.

So the calibration vector should cleanly give x,y and z when applied to the raw data.
But once found the device will never move from this position so it will be a one shot calibration once done.

Embedded C yes.

Here is what I’m proposing.

  1. Shear the readings coming out of your accelerometer. A shear is just a transformation of a matrix such that area is preserved but the relative weight of the basis vectors are askew.

  2. Seems like you have the z axis under enough control to be satisfactory. However we are going to scale all three of your basis vectors i,j,k by 9.8 such that the vector created by gravity is a unit vector in the Z axis. Now if we want to know the acceleration of something we can have a reference point against the whole space.

  3. If the driver accelerates to some vector (x,y) it will feels like (x,my) because of our shear. With the basis vectors being 9.8, we must remember that some vector, like (1,3) is really (9.8, 3*9.8m).

  4. Suppose you know that the acceleration of the car is 0-100 in 5 seconds, which is about 5m/s2. That’s circa half gravity, so if you see exactly i/2 or half gravity popping out of the accelerometer that must be the no sheared axis, which in our example above is the X axis. If you instead see readings of m * 5m/s2 that is the y axis in our example. because it was scewed. (so if m is 1/2 then we would read 2.5m/s2).

Oh boy is it all very messy, and it’s a lot of math.
but if that’s the only way I think it would work… although I obviously don’t have a car to test with :stuck_out_tongue:. No promises here, this will require research.

Are we sure we don’t have a mechanical solution here?
Like can’t we just put a linear actuator motor inside the device oriented in a know vector to calibrate against on boot? Just a quick internal wiggle of the accelerometer and BAM. you have X,Y,Z every time.
That feels SOOOO much easier than using the car.

Isn’t there some tech that can check for magnetic north that could feed that into the STm32F40.
I love doing linear algebra on my weekend and everything… but… ya know. :smile:

If it was me, I’d mount it on the windscreen wipers. :rofl:
Pix :heavy_heart_exclamation:



Oh. Just ran back because I had a quick thought.

Because a shear maintains area you will still be able to use the data for location, total distance traveled, stuff like that.

However a shear does not preserve the scale of a vector, that is the length of an individual vector from the origin. In this case I figured that’s fine because our basis vectors defined by the acceleration of the Z axis at boot, assumed to be gravity, and I assume you won’t need to know the acceleration of the device at a single point in time because… that’s what the accelerometer in the car is for?.. right?

1 Like

Thanks for the input.
They want to be able to forget about this once installed and have s/w do it all unfortunately.

No all I need is x/y/z direction, speed and gps etc will all be handled elsewhere.
So this shear may be an option. I will need to research for a while, thank you

1 Like

Hi Tim,

The most common accelerometer I can think of also boasts a gyroscope. You could work out how the accelerometer moved while the car was breaking and extrapolate that to the x,y,z components of your accelerometer.


Hi Jack

Hope it doesn’t “break” up too much while you are in it. Try “braking” instead.

Just being picky. Will put it down to the damn auto complete function in this Forum. Nuisance sometimes (read most times).
Cheers Bob

1 Like

Thanks Jack
I believe there may be a mathematical solution here.
Vector maths or trigonometry that can be applied or a shear vector as Pixmusix states.
I think I need to go deep into a maths rabbithole for a bit :slight_smile:

1 Like

Im trying to work out how this all works, so the following could be completely wrong.
My key assumption is the device reports the force currently applied to each axis (X,Y,Z)
So if the device was not moving and 100% perfectly orientated, in my head, that means the (X,Y,Z) = (0, 0, 9.8) (i.e. Z force is gravity)
If that is true, the any value on X,Y would mean its NOT orientated correctly; as part of the Z (g) force would be applied to X and/or Y.

Any chance I get get some sample data from the sensor ?
approx. but as close as you can

  1. Correctly orientated
  2. 90 Deg off one one axis
  3. 45 Deg off on both the all axis
    4 and 5 just random (possible orientations)

If i can get the sample data, I can run some math to check

1 Like

If the only force being applied is gravity (the vehicle is stationery) then OP can calibrate out the roll and pitch, giving the 0,0,9.8 you mention. That gives a baseline for horizontal. Then, if you know that the vehicle is moving in a straight line on a level road, you can assume that any acceleration in X and Y is in line with the vehicle - you don’t need to know the orientation of the sensor around Z. If the calibration is mechanical you only need X and Y. If the calibration is done in math then Z deviation from 9.8 will need to be part of the calculation of horizontal acceleration.

Getting movement in a straight and level line maybe difficult.

1 Like

(edited…sorry i had X,Y,X previously in the vectors)

Hi Michael
Yes you are correct although we measure in milliG so 1000 will represent 1G (1 G is 9.81m/s^2 i.e. the force of gravity which is a constant).

So below when the unit is perfectly flat:
(X,Y,Z) = (0,0,1000)

90 degree tilted on the x-axis so the unit facing upward:
(X,Y,Z) = (991,0,2)

45 degree so unit pointing upward and to the side on a 45 degrees tilt
(X,Y,Z) = (-500,600,500)

Unit mounted flat in a vehicle or as flat as they can
(X,Y,Z) = (-32,100,1018)

You can see here it will never be completely flat but close enough to 1G on the z-axis that we would know which axes is ‘down’…z

Unit mounted flat on the vehicle side wall:
(X,Y,Z) = (0,-977,-7)
You can see here we know now the y axis is been affected by gravity.

So we can immediately get the axis affected by gravity.
If we move forward and brake suddenly we can, by observing the max g in one of the other 2 axis get the direction of travel.

That assumes the unit is oriented correctly, which is the whole problem. You can’t get the direction of travel unless you know the orientation of the module to the vehicle. But you can get acceleration in one direction by integrating the X and Y accelerations, and assume that direction, whatever it is, is in line with the vehicle.


Based on my understanding and the rotation math, I get the following results.
Note 1: This was rough and ready, more testing should happen an tune as needed. It was more a guide to get you started.
Note 2: X and Y Angle are in radians and would be the angle used to rotate the sampled vector to map back to the “correct” X,Y,Z values.
Note 3: the the final vector would be the 2nd one in each, I was just showing the output after just the X correction, then after the Y Correction.

(X,Y,Z) = (0,0,1000)  
X Angle : -0.0000
Post X Correction : (0.0000, 0.0000, 1000.0000)
Y Angle : 0.0000
Post Y Correction : (0.0000, 0.0000, 1000.0000)
(X,Y,Z) = (991,0,2)
X Angle : -1.5688
Post X Correction : (0.0000, 0.0000, 991.0020)
Y Angle : 0.0000
Post Y Correction : (0.0000, 0.0000, 991.0020)
(X,Y,Z) = (-500,600,500)
X Angle : 0.7854
Post X Correction : (-0.0000, 600.0000, 707.1068)
Y Angle : 0.7036
Post Y Correction : (-0.0000, 0.0000, 927.3619)
(X,Y,Z) = (-32,100,1018)
X Angle : 0.0314
Post X Correction : (0.0000, 100.0000, 1018.5028)
Y Angle : 0.0979
Post Y Correction : (0.0000, -0.0000, 1023.4002)
X Angle : 0.0000
Post X Correction : (0.0000, -997.0000, -7.0000)
Y Angle : 1.5638
Post Y Correction : (0.0000, 0.0000, -997.0246)

So in theory now you have the stationary X,Y Rotation Angles. using those same angles on a moving vector should adjust that moving vector back to an aligned X,Y; but we don’t have an Z adjustment.

i.e. which way is forward/front. In theory we should be able to get that by simply getting a sample when moving forwards and some then apply the X,Y correction Angle from above, that should leave the us with the data to work out the rotation around Z.

rough test code (from c++builder as a windows apps, so I/O from windows objects; Im sure you can clean that )

	AnsiString S1,S2;
	double XAngle, YAngle;

	float  X,  Y,  Z;
	float nX, nY, nZ;

	X = frmX->Text.ToDouble();
	Y = frmY->Text.ToDouble();
	Z = frmZ->Text.ToDouble();

	// Find angle to rotate around Y
	// tan -1 (X/Z)

	XAngle = -1 * atan(X/Z);

	//XAngle = -1 * atan(Z/X);
	Memo1->Lines->Add("X Angle : "+S2.sprintf ("%0.4f",XAngle));

	// Rotate around Y by XAngle
	nX =      (X * cos (XAngle)) + (Z * sin (XAngle));
	nY =                         Y;
	nZ = (-1 * X * sin (XAngle)) + (Z * cos (XAngle));

	Memo1->Lines->Add("Post X Correction : "+S2.sprintf ("(%0.4f, %0.4f, %0.4f)",nX,nY,nZ));

	X = nX;
	Y = nY;
	Z = nZ;

	// Find angle to rotate around X
	// tan (X/Z)
	YAngle = atan(Y/Z);
	Memo1->Lines->Add("Y Angle : "+S2.sprintf ("%0.4f",YAngle));

	// Rotate around X by YAngle
	nX =                    X;
	nY = (Y * cos (YAngle)) - (Z * sin (YAngle));
	nZ = (Y * sin (YAngle)) + (Z * cos (YAngle));

	Memo1->Lines->Add("Post Y Correction : "+S2.sprintf ("(%0.4f, %0.4f, %0.4f)",nX,nY,nZ));

edit: Ref to rotation math


Thanks for taking the time to do this Michael !!
This should get me started

1 Like