Nano BLE 33 Sense lsm9ds1 gyroscope - unexpected orientation range

Hi,

I'm in the process of teaching myself about IMUs. I've got a Nano BLE 33 Sense with an lsm9ds1 sensor, and I'm working through different measures of orientation. So far I've got this from the accelerometer using trigonometry, and now I'm trying to dead reckon the gyro position with the formula (gyro output in degrees/second)*(time from millis since last reading in seconds.)

I'm expecting to get a fair amount of drift from the gyro but at least the angle ranges should be in the right ballpark. However with both roll and pitch I'm turning the sensor right through 180 degrees and consistently only seeing about 150 degrees of variance.

I don't know if this might be to do with my data types, imprecise implementation of the timer, or something else entirely. I could just multiply the final output such that the 150 I'm seeing shows as the 180 I'm moving through, but as a learning exercise I'd like to fix it properly if I can.

Thanks. Here is my code:

#include <Arduino_LSM9DS1.h>

float dt = 0;
float millisOld = 0;

float thetaM = 0;
float phiM = 0;
float thetaFold=0;
float thetaFnew = 0;
float phiFold = 0;
float phiFnew = 0;
float thetaG = 0;
float phiG = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");
  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println(" Hz");
  Serial.print("Magnetic field sample rate = ");
  Serial.print(IMU.magneticFieldSampleRate());
  Serial.println(" uT");
  Serial.println("Acceleration in G's");
  Serial.println("Gyroscope in degrees/second");
  Serial.println("Magnetic Field in uT");  

}

void loop() {
  float a_x, a_y, a_z, g_x, g_y, g_z, m_x, m_y, m_z;


  //get raw values from each sensor 
  if (IMU.accelerationAvailable() || IMU.gyroscopeAvailable() || IMU.magneticFieldAvailable()) {
    IMU.readAcceleration(a_x, a_y, a_z);    
    IMU.readGyroscope(g_x, g_y, g_z);
    IMU.readMagneticField(m_x, m_y, m_z);

  //Update clock
    dt = (millis() - millisOld)/1000;  
    millisOld = millis();    

  //compute accelerometer Theta (inverse tan of x acc over y acc, divided by 57.3 into degrees from radians) and phi (same in other plane)
    thetaM = atan2(a_x,a_z)*57.295779513;
    phiM = atan2(a_y,a_z)*57.295779513;

  //Filter accelerometer theta and phi to remove noise
    thetaFnew = 0.9*thetaFold + 0.1*thetaM ;
    phiFnew = 0.9*phiFold + 0.1*phiM ;

  //compute gyro theta and phi
    thetaG = thetaG + (g_y * dt);
    phiG = phiG + (g_x * dt);

  //Print raw values from each sensor 
    Serial.print(a_x);
    Serial.print(',');
    Serial.print(a_y);
    Serial.print(',');
    Serial.print(a_z);
    Serial.print(',');
    Serial.print(g_x);
    Serial.print(',');
    Serial.print(g_y);
    Serial.print(',');
    Serial.print(g_z);
    Serial.print(',');
    Serial.print(m_x);
    Serial.print(',');
    Serial.print(m_y);
    Serial.print(',');
    Serial.print(m_z);

  //Print accelerometer angles raw
    Serial.print(',');
    Serial.print(thetaM);
    Serial.print(',');
    Serial.print(phiM);

  //Print accelerometer angles filtered
    Serial.print(',');
    Serial.print(thetaFnew);
    Serial.print(',');
    Serial.print(phiFnew);

  //Print gyro angles raw
    Serial.print(',');
    Serial.print(thetaG);
    Serial.print(',');
    Serial.print(phiG);  

  //Debugging    
    Serial.print(',');
    Serial.println(dt*100000); 

  //Update filter memory
    thetaFold = thetaFnew;
    phiFold = phiFnew; 
  }  
}

isambardify:
I'm trying to dead reckon the gyro position with the formula (gyro output in degrees/second)*(time from millis since last reading in seconds.)

You will get closer to the proper integration of the rate if you use:
((gyro output in degrees/second at the start of the interval) +
(gyro output in degrees/second at the start of the interval)) / 2

  • (duration of the interval in seconds)

In other words, use the average of the rate at the start and end of each interval instead of just the rate at the end.

Thanks. I've rewritten my gyro code to take regular readings and average the most recent 2. It doesn't seem to have solved the problem though. If anything sensitivity seems slightly worse. :confused:

Do you know of anything else I could try?

#include <Arduino_LSM9DS1.h>

unsigned long oldmillis = 0;
const long sensorinterval = 20;

float thetaG = 0;
float phiG = 0;
float yawG = 0;

float oldx = 0;
float oldy = 0;
float oldz = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println(" Hz");
  Serial.println();
  Serial.println("Gyroscope in degrees/second");
  Serial.println("X\tY\tZ");
}

void loop() {
  float x, y, z;
  
  unsigned long currentmillis = millis();
  
  if (currentmillis - oldmillis >= sensorinterval) {
    oldmillis = currentmillis;
    
    IMU.readGyroscope(x, y, z);

   thetaG = thetaG + (((y + oldy) / 2) * (sensorinterval / 1000.));
   phiG = phiG + (((x + oldx) / 2) * (sensorinterval / 1000.));
   yawG = yawG + (((x + oldz) / 2) * (sensorinterval / 1000.));

    oldy = x;
    oldy = y;
    oldy = z;

    Serial.print(x);
    Serial.print(',');
    Serial.print(y);
    Serial.print(',');
    Serial.print(z);
    Serial.print(',');
    Serial.print(thetaG);
    Serial.print(',');
    Serial.print(phiG);
    Serial.print(',');
    Serial.println(yawG);
  }    
 }

Hey,
there is two things that you need to do
1.calibrate your imu with this library : GitHub - FemmeVerbeek/Arduino_LSM9DS1: LSM9DS1 Library for Arduino
2.use this library to get quaternion data or euler angles : GitHub - jremington/LSM9DS1-AHRS: Mahony 3D fusion filter and tilt compensated compass, with sensor calibration code
and your done.
1000% sure that its work cause i did it.
if you had any questions just let me know.

Hey, I get an error about SPI clock when I try this AHRS code you linked to. Did you change anything to make it work?

Hi @LazaroFilm
No I didn't change anything , but I run it on I2C.
Not an expert one in this field but I think it can cause problem.
Also I linked a wrong address for calibrating the sensor, I edited that and its okay now.
If you had any questions your welcome to ask.
Mason

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.