cancel
Showing results for 
Search instead for 
Did you mean: 

LSM303AGR Calibration

Aquatwix1
Associate II

Hello everyone,

I'm contacting you today in order to understand my error during the calibration of my LSM303AGR sensor located on a PCB. The ultimate goal is to create a compass with tilt compensation but I try to get a good precision with magnetometer first. Of course, I took care to read up on the Internet before opening this post, but all the ideas seem to be divergent and I can't find my way around.

First, I got the raw acceleration and magnitude data from my sensor. So far, so good. As part of my calibration, I generated a data set during which I rotate the sensor in all possible directions to cover all angles. I then measured the hard iron to eliminate offsets on each axis :

 

 

 

def calculate_hard_iron(data):
    max_vals = np.max(data, axis=0)
    min_vals = np.min(data, axis=0)
    return (max_vals + min_vals) / 2

 

 

 

Then I calculated the soft iron by normalizing my data while preserving the centering :

 

 

 

def calculate_soft_iron(data):

    # Centering data
    mean = np.mean(data, axis=0)
    centered_data = data - mean

    # Find the scaling factors for each axis
    ranges = np.ptp(centered_data, axis=0)  # peak to peak range
    scale_factors = np.max(ranges) / ranges
    
    # Normalize
    corrected_data = centered_data * scale_factors
    avg_radius = np.mean(np.sqrt(np.sum(corrected_data**2, axis=1)))
    scale = 1.0 / avg_radius
    
    # Apply final scaling
    corrected_data = corrected_data * scale
    transformation_matrix = np.diag(scale_factors * scale)
    
    return corrected_data, transformation_matrix

 

 

 

I arrive at the following resultt :

Aquatwix1_0-1740583867072.png

Following this, I am able to identify my hard iron vector and my soft iron matrix :

Hard Iron Offset: [-368.0, 390.5, 185.5]

Soft Iron Matrix:
[[0.0020697, 0, 0]
[0, 0.00216311, 0]
[0, 0, 0.00205197]]

Apriori, I should be able to interpret a movement using the parameters calculated in the calibration step. So I decide to generate a dataset in which I perform a 360° turn on XY plan, and here is the result :

Aquatwix1_1-1740584081813.png

What stands out is that the offset problem in the data set subsequently caused a loss of information. However, I did deduce the data from the offset measured during the calibration phase. What did I do wrong ?

Thank you for your attention.

 

7 REPLIES 7
Andrea VITALI
ST Employee

From your plot it is evident that hard-iron offset has not been compensated correctly. When you perform a rotation around the vertical, with the mag in the horizontal flat plan, the mag data points always describe a circle/ellipse in a 2D horizontal plane, all points will have the same Z coordinate.

When hard-iron is successfully compensated, the points in the X-Y plot will describe a circle/ellipse centered in the origin which is not the case looking at your plot. This is the biggest source of error (soft-iron effects are usually minor) and this is evident in your case: the scaling factors along the diagonal are very similar to each other. Note that the absolute scaling of the compensated mag does not matter because when computing the orientation (yaw/heading angle) only ratios matters (usually atan2 function is utilized on tilt-compensated data as explained in design tip DT0058).

The method to compute the hard-iron is ok but accuracy will highly depend on how good is the sweep on each axis. Similarly for the method used to compute the scaling factors. A more robust method is discussed in design tip DT0059.

 

Dear @Andrea VITALI ,

Thank you for your reply. I appreciate your help ! In fact, the last screens I shared were about a rotation on the XY plane with a tilt. That's why the z was not constant. However, the problem is the same with or without tilt.

I read DT0058 and DT0059 and tried to apply the approach. However, the result is the same even if it seems better than my version. The offsets are not fully compensated.

Here's the calibration step, which looks clean :

Aquatwix1_0-1741795824831.png

I can get the parameters required for my application :

- Hard-Iron : [-559.5, 373.5, 1081.0 ]
- Gain : [499.5, 529.5, 561.0 ]

Here is an example in a 360° configuration in 2D without tilt. I stopped the rotation every 90 degrees for few seconds. I get this :

Aquatwix1_1-1741795980740.png

Aquatwix1_3-1741796305838.png

Here is an example in a 360° configuration in 2D with tilt. I stopped the rotation every 90 degrees for few seconds. I get this :

Aquatwix1_2-1741796042152.png

Aquatwix1_4-1741796351037.png

If you have any ideas on how to solve this problem, I would be grateful.

Regards

The hard-iron is compensated when you do the calibration. But when you do the 2D rotation in the horizontal plane (no tilt) it is clear there is hard-iron.

Are you changing the location of the magnetometer?

The calibration should be performed in the same environment where the mag is utilized. Generally speaking, it is not possible to calibrate 'at the factory' and then utilize 'in the field' because the magnetic environment can be dramatically different.

Possible sources of hard-iron are: permanent magnets, ferromagnetic materials that become magnetized (iron, steel and such alloys), wires (including neighboring PCB tracks) that carry large currents.

Is there anything like that in the environment where you do the 2D rotation?

 

 

The LSM303AGR is located on a PCB, close to other components such as resistors and capacitors, but none of these should cause interference. It is placed on a daughter board, with the main board 2/3cm below. As for the calibration location, I have never tried to calibrate the sensor anywhere other than in my office. I isolated the system from disturbances, away from the computer, etc. I have never tried to calibrate the sensor at another location because I can't transport the system and read the data.

I will try to make some tests at another location to eliminate the suspicion of interference in my office.

tobidelbruck
Associate

This post is very useful, thanks for detailed measurements! Did you resolve this?

I am having a lot of trouble making sense of my magnetometer output. I align each axis with the local earth magnetic field (measured with high quality conventional hiker's compass) and expect to see each axis have maximum positive and negative reading with other axes zero when the axis is aligned with earth field. But nothing makes sense here. When I looked at the data from these calibration attempts, it looked reasonable, fairly spherical but with a significant 20-30uT offset from origin. But when I tried to use first  min/max and then fancy ellipsoid calibration, nothing worked to make a useful magnetic compass (I'm only interested in a boat compass, essentially 2d compass heading).

Later I got a clue from a youtube video where the presenter suggested to check header pins and socket used to connect daughterboard to motherboard. I checked my pins and they are indeed weakly magnetic (you can test by setting them up at a slight angle and see if a magnet pulls them over). However, now it appears that I magnetized my pins or perhaps the magnetometer itself and I now have a very large DC offset.

I can post some data later, but I'm curious if you resolved things to your satisfaction?

tobidelbruck
Associate

I realized now something that I did something without thinking; I placed my 9-DOF IMU  daughterboard very close to my dual coil power relay on my PCB. The relay has a magnet (or two) that holds the relay in each latched state. That causes a huge hard iron offset of about 250uT.  Not sure if this can be compensated.

Hello @tobidelbruck,

I am glad to see that this article can help people think things through.

In fact, I managed to solve my problem after running a few tests in a different environment. The data had been generated with the IMU on the printed circuit board, inside the main system, and in a laboratory equipped with a few devices that could cause interference.

I decided to test the sensor in a suitable environment by removing the daughter board from the main system and performing my tests in an open space, without any potential sources of interference.

The results were significantly better, even though the final result (azimuth) still had a small error (3-4°) depending on the quality of the calibration. In any case, I considered this result sufficient for my application.

I hope you find the source of your problem, but be careful of interference, as I mentioned. I spent a lot of time on the software, when the problem was elsewhere. Feel free to share your results ! :)