Nano 33, heading keeps on dropping while resting

Hello all,

I’ve played around with my new Nano 33 BLE, based on this post I use the code below to determine the Orientation, the problem is while the board is resting the heading value keeps on dropping down (see video) while the other two values are as they should, the only change I have done was to use:

#include <Arduino_LSM9DS1.h>

instead of

#include <Arduino_LSM6DS3.h>

is that the root of the problem? or I’m missing something else here?

#include <Arduino_LSM9DS1.h>
#include <MadgwickAHRS.h>

// initialize a Madgwick filter:
Madgwick filter;
// sensor's sample rate is fixed at 104 Hz:
const float sensorRate = 104.00;

void setup() {
 Serial.begin(9600);
 // attempt to start the IMU:
 if (!IMU.begin()) {
   Serial.println("Failed to initialize IMU");
   // stop here if you can't access the IMU:
   while (true);
 }
 // start the filter to run at the sample rate:
 filter.begin(sensorRate);
}

void loop() {
 // values for acceleration & rotation:
 float xAcc, yAcc, zAcc;
 float xGyro, yGyro, zGyro;
  
 // values for orientation:
 float roll, pitch, heading;
 // check if the IMU is ready to read:
 if (IMU.accelerationAvailable() &&
     IMU.gyroscopeAvailable()) {
   // read accelerometer & gyrometer:
   IMU.readAcceleration(xAcc, yAcc, zAcc);
   IMU.readGyroscope(xGyro, yGyro, zGyro);
    
   // update the filter, which computes orientation:
   filter.updateIMU(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc);

   // print the heading, pitch and roll
   roll = filter.getRoll();
   pitch = filter.getPitch();
   heading = filter.getYaw();
   Serial.print("Orientation: ");
   Serial.print(heading);
   Serial.print(" ");
   Serial.print(pitch);
   Serial.print(" ");
   Serial.println(roll);
 }
}

Many thanks in advance!
Ram

some more info (no progress)

according to this post, it states:

The Nano 33 IoT’s accelerometer’s range is fixed at +/-4G by this library, and its gyrometer’s range is set at +/-2000 degrees per second (dps). The sampling rate for both is set to 104 Hz by the library. Other IMUs may have differing ranges. You need to know at least the sampling rate when you want to use a different IMU with this exercise. If you know that information, though, it’s easy to swap one IMU for another in the Madgwick library.

so i was looking to find the sampling rate for the Nano 33 BLE and found this:

default range for acceleration is +/-4g, sampling rate is 119 Hz

i tried to change the

const float sensorRate = 119.00;

but no joy...

Your sketch is not using a compass/magnetometer to read the heading? It is dead-reckoning the heading from the gyro and accelerometer readings? If so, I'm not surprised that it does not work so well. I would expect it to drift off continuously whether stationary or moving. Pitch and yaw can be determined from the accelerometer when stationary, but heading will have nothing to keep it fixed.

Thank you for your reply!!

since I have tried (from looking at the code here) to call the:

void update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz);
filter.update(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc, xMag, yMag, zMag);

that includes the Magnetic values also, the result was drifting on all three axis
from reading about it here, it said that:

Magnetometer Output data rate is fixed at 20 Hz

changing the sample rate to 20 and edited the if to:

if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable() && IMU.magneticFieldAvailable()) {
.
.
.

but that also didn't work.... I'm quite lost.

Magnetometers must be individually calibrated, in order to work as an electronic compass.

The very best calibration procedure is described at Tutorial: How to calibrate a compass (and accelerometer) with Arduino | Underwater Arduino Data Loggers

But before you go through that process, make sure that you can read out all nine IMU sensor values correctly, and that they make sense.

thank you for the link!

On the LSM9DS1, the axes for the accelerometer and gyro are NOT THE SAME as the axes for the magnetometer. The diagram on the LSM9DS1 data sheet is atrocious, but it appears that the magnetometer X and Y axes are swapped and inverted with respect to the acc/gyro. Furthermore, the coordinate systems for the acc/gyro are left handed as drawn.

You need to check that drawing and carefully apply axial transformations to the data, to ensure all three sensor coordinate systems agree in spatial direction and are right handed, or you will never be able to get any useful orientation measurements out of the sensor.

The MPU-9250 has the same catch, which is why Kris Winer's Madgwick and Mahoney AHRS code gives nonsensical orientation angles. He refuses to fix this fatal flaw, most likely because he does not understand the issue.

Dear jremington,

sorry for the late reply, just saw your super informative reply!! i'll look into this.

once again, thank you!

I'm also experimenting the the same device. I'm noticing similar drift when using the magwick filter. I've tried using motioncal to check out the mag sensors and I can see they need to be calibrated.

Have you had any luck applying the forementioned transformations and/or runtime calibrations?

If anyone has any calibration code for the nano 33 I would be indebted.
Cheers
Michael

To have little drift you need to use:

   IMU.readAcceleration(x, y, z);
    acceleration[0] = x;
    acceleration[1] = y;
    acceleration[2] = z;
    IMU.readGyroscope(x, y, z);
    dps[0] = x;
    dps[1] = y;
    dps[2] = z;
    IMU.readMagneticField(x, y, z);
    magneticField[0] = -x;
    magneticField[1] = y;
    magneticField[2] = z;

Then you have to remove the gyro offset before sending it to MadgwickAHRS library with "filter.update(…)"

How do you calibrate the magnetometer with motioncal?

Donatello

Did you ever get this to produce anything useful with the magnetometer? I'm stuck with the same problem if the data drifts then it is essentially worthless.

thanks.

Hi @DonatelloX, can you tell me how/if

   IMU.readMagneticField(x, y, z);
   magneticField[0] = -x;
   magneticField[1] = y;
   magneticField[2] = z;

is supposed to align the magnetometer axis with the others?

Seems to me that it should be

   IMU.readMagneticField(x, y, z);
   magneticField[0] = -y;
   magneticField[1] = -x;
   magneticField[2] = z;

based on the data sheet diagram kindly attached by jremington.

I ask because my objective is to align the axes (believing I need to) in order to do 9DOF sensor fusion to hopefully arrive at an accurate 3DOF tracking on a Nano 33 BLE Sense.

Thanks to all.

Seems to me that it should be

IMU.readMagneticField(x, y, z);
magneticField[0] = -y;
magneticField[1] = -x;
magneticField[2] = z;

based on the data sheet diagram kindly attached by jremington.

The above appears correct to align the magnetometer with the accelerometer. But I still don't understand why the accelerometer is defined with a left handed coordinate system, which must also be corrected. The magnetometer is defined with a right handed system. I'm not even sure that I believe that diagram, but I don't have the Nano 33 BLE to work this out (and don't intend to buy one, either).

I recommend the Pololu AltIMU 9 and 10 series, and have recently posted working, tested Madgwick/Mahony AHRS code for them.

Thank you jremington! It's good to hear some confirmation since I was having trouble verifying it's not more complicated than that.

Thanks also for the info about the Pololu and your working Madgwick code. I will check that out for sure. I did notice the left handed chirality and thought it could be a problem for the Madgwick/Mahoney algorithms. Hoping I can fix it just by rotating back to right handed if needed.

Hoping I can fix it just by rotating back to right handed if needed.

You can't. To change the handedness, one of the axes needs to be reflected. According to the diagram in the data sheet, the gyro axial system also appears to be defined as left handed.

Here is what I suggest to try for the Nano 33 BLE sensor: reindex the gyro and accelerometer axes based on the right-handed magnetometer coordinate system:

   IMU.readAcceleration(x, y, z);
    acceleration[0] = -y;
    acceleration[1] = -x;
    acceleration[2] = z;
    IMU.readGyroscope(x, y, z);
    dps[0] = -y*scale_gyro; //"dps" must be in radians/sec for Madgwick/Mahony
    dps[1] = -x*scale_gyro; // choose scale_gyro accordingly
    dps[2] = z*scale_gyro;
    IMU.readMagneticField(x, y, z);
    magneticField[0] = x;  //magnetic North
    magneticField[1] = y;  //West
    magneticField[2] = z;  //Up

Edit: NWU instead of NED world coordinate frame.

I hope I don’t bring in more confusion. Here is an URL for a blog post showing how to reassign the axes to match the align the coordinate systems. https://www.lythaniel.fr/index.php/2016/08/20/lsm9ds1-madgwicks-ahr-filter-and-robot-orientation/

The blog article linked in reply #16 agrees with my interpretation of the data sheet (reply #15).

However, the sensor orientation suggested in that article will end up with magnetic North (yaw angle zero) aligned with the accelerometer Y axis, not with the magnetometer X axis, as chosen in reply #15. Either way should work!

@jremington I tried with your version.
Though what I changed is the the conversion from degrees/s to radian/s as in my understanding the Arduino Madgwick library does this itself:

void Madgwick::update(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) {
...

// Convert gyroscope degrees/sec to radians/sec
	gx *= 0.0174533f;
	gy *= 0.0174533f;
	gz *= 0.0174533f;

...

So the code is now as following:

#include <Arduino_LSM9DS1.h>
#include <MadgwickAHRS.h>


// initialize a Madgwick filter:
Madgwick filter;
// sensor's sample rate is fixed at 104 Hz:
const float sensorRate = 20.00;

void setup() {
 Serial.begin(115200);
 // attempt to start the IMU:
 if (!IMU.begin()) {
   Serial.println("Failed to initialize IMU");
   // stop here if you can't access the IMU:
   while (true);
 }
 // start the filter to run at the sample rate:
 filter.begin(sensorRate);
}

void loop() {
 // values for acceleration & rotation:
 float xAcc, yAcc, zAcc;
 float xGyro, yGyro, zGyro;
 float xMag, yMag, zMag;

 float acceleration[3], dps[3], magneticField[3];
  
 // values for orientation:
 float roll, pitch, heading;
 // check if the IMU is ready to read:

 
 if (IMU.accelerationAvailable() &&
     IMU.gyroscopeAvailable() && IMU.magneticFieldAvailable()) {
   // read accelerometer & gyrometer:
   //IMU.readAcceleration(xAcc, yAcc, zAcc);
   //IMU.readGyroscope(xGyro, yGyro, zGyro);

    IMU.readAcceleration(xAcc, yAcc, zAcc);
    acceleration[0] = -yAcc;
    acceleration[1] = -xAcc;
    acceleration[2] = zAcc;
    IMU.readGyroscope(xGyro, yGyro, zGyro);
    dps[0] = -yGyro; 
    dps[1] = -xGyro; 
    dps[2] = zGyro;
    IMU.readMagneticField(xMag, yMag, zMag);
    magneticField[0] = xMag;  //magnetic North
    magneticField[1] = yMag;  //West
    magneticField[2] = zMag;  //Up

   xAcc = acceleration[0];
   yAcc = acceleration[1];
   zAcc = acceleration[2];

   xGyro = dps[0];
   yGyro = dps[1];
   zGyro = dps[2];

   xMag = magneticField[0];
   yMag = magneticField[1];
   zMag = magneticField[2];
  
   // update the filter, which computes orientation:
   filter.update(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc, xMag, yMag, zMag);

   // print the heading, pitch and roll
   roll = filter.getRoll();
   pitch = filter.getPitch();
   heading = filter.getYaw();
   Serial.print("Orientation: ");
   Serial.print(heading);
   Serial.print(" ");
   Serial.print(pitch);
   Serial.print(" ");
   Serial.println(roll);
 }
}

Unfortunately all Axis still drift.
I have not done the calibration yet. I don’t think this drift is caused by a lacking calibration is it it?

It appears to be working now after i added the scale factor for the Gyro.

I added the scale constant

#define gscale 8.75e-3*(PI/180.0)

and scaling the Gyro accordingly

    IMU.readGyroscope(xGyro, yGyro, zGyro);
    dps[0] = yGyro * gscale; 
    dps[1] = xGyro * gscale; 
    dps[2] = zGyro * gscale;

If the board is placed now stable on surface it won't drift.
What is interesting though is that when moved calculated orientation is slowly approaching a new stable value. It can take several seconds after the movement until it stabilizes.

@jremington: Is this normal?

All this still without calibration...