MinIMU-9 AHRS code

And I’m back with guesses for more stable Euler angles:
- The main source of noise seems to be the Gyro L3GD20.
The Libraries are kept really minimalistic, so ist will not be a too big problem to refine them. :mrgreen:
I wonder why the Gyro-FIFO is not used for instance, and there is no temperature readout and compensation in the Gyro lib.
The AHRS kalman filter code itself (reliability filter) sets the gravity sensors weight to zero at below 0.5 and above 1.5 g vector sum. Questionable if optimal that way, and indeed prone to periodic accellerations, which vactor sum eventually crosses the 1.0g gravity → at that point, the accelerometer reliability is seen upon as beeing 100% in this code.
I also don’t find any physical reasonning for the Ki and Kp values, which should be directly dependant on the separate sensor noise levels.

Joern

HI, All,

maybe it’s a monologue (who cares…) but it’s concerning this little, powerful module called MinIMU9 v2.
I just made automated serial measurements of the data from the gyrometer in different bandwith/cutof-frequency modes, from the accelerometer and from the magnetometer,
all in resting state in oder to find out the best initialization parameters for the sensors for my application.
Which targets:
Best accurracy and lowest noise floor on a time scale of 10 Hz attitude information.

here the outcome, for lowest noise ground floor from the chips:

  • Initialize the gyroscope at 95 Hz data rate with cutoff-Freq at 12.5 Hz with 250 DegPerSec scale (=Device Default)
  • Initialize the magnetometer at 15 Hz output, 1,3 Gauss scale for the lowest noise-level here
  • Initialize the Accelerometer at 100Hz data rate and +/- 2g scale for most noise-free gravitational computing frame.

You did expect so?
Then you are the chip construction experts. Nothing of this is found in the official data sheets of the manufactuers.

For me it did the serial.print sensor output on a Wattuino / Arduino serial window together with the STDEV function of the OpenOffice.Calc after copy & paste.

Finally, with oversampling and averaging in 120 msec scale, I achieve the same specs as with the the sparkfun 9DOF-AHRS ($$$$$) as there are:
Yaw: 0.08° standard deviation in resting state
Roll: 0.12° standard deviation in resting state
Pitch :0.09° standard deviation in resting state.

Joern

Hi, Joern.

That is really cool. We appreciate that you shared your results with us. We are aware that our libraries are not optimized, but rather, they are intended to get people started. If you post your code, we would be happy to check it out.

- Jeremy

Hi,

I have a few questions about the MiniIMU-9.

The L3G library works fine, I can see the values on the serial monitor, but I have a doubt, if the IMU is on the same position, like lying on a table, the values varies. Is it normal, or do I need to use a filter?
G X: -9 Y: 18 Z: -15
G X: -11 Y: 13 Z: -11
G X: -15 Y: 16 Z: -11
G X: -13 Y: 21 Z: -9
G X: -11 Y: 17 Z: -11
G X: -16 Y: 19 Z: -9
G X: -11 Y: 13 Z: -10
G X: -7 Y: 13 Z: -12
G X: -11 Y: 16 Z: -8

I am having problem when I use the MinIMU9AHRS.ino, I cant get the disered answer, on the serial monitor this appears.

I dont know what is the problem, can anyone help me?

~Iò‚¡—š.P—¸¿ÒoÒ.ROêOê×ïOÀ/̗ï:COê“ÒêKñÁ:—ü/—’Ðë:I—–2I—R²K—z—hé’k:¯:ý· a0OçOå—\²#T’Koš—^
J’I.0—~ToìOš’Š—\€tl’AO¥‹¿TKҒKZ(OTO0:pOÅ:do¤T/Â*tO¿:M·Ä:e—’O¯OғžO®2EÏÛOƒïÛOϟÿϦï¦O–O¶Ü‚o¶ÏÌ:Œ’¿Ä’.4 ·Ì(.PÂÛ:@õ
Ph—pŸx0qO?’’Å҉“^ÊÏ°ÏÚO4o7: —^ÂO6O6O«—VDL..\ä:h¹äŸ’”O5àÿ×Âò—ptOÄ×SOuZað ÿ—¥.°O

Sorry for the bad english. Thanks

Hello.

The variation you are getting seems normal. Keep in mind that, with the gyro’s default sensitivity setting (250 dps), each digit of the raw output denotes a rotation of 8.75 mdps (milli-degrees per second), so the numbers you are seeing should be well within the sensor’s expected zero-rate offset and noise specifications. You can average multiple measurements and subtract a fixed offset if you need better results.

It looks like you are using the incorrect baud rate. You should be using 115200 as the baud rate for the Arduino AHRS.

- Jeremy

Thanks Jeremy.

I have another question.

For the application that I need to use, I need to have the acquisition data of the values ( roll, pitch yaw) of the IMU, not on the main loop, but on an interrupt.
I put the Timer1 on Arduino, and I is not working.
I cant get anything on the serial monitor. I used Timer1.initialize(xxx) and Timer1.attachinterruput(callback). I dont know if I am using it right. Can anyone help me?

Thanks.

Hello.

I do not know of a reason that should not work, but I have not tried it. Could you post a simplified version of your code? You might try getting something basic working with the timer and a callback first, like toggling an LED.

- Jeremy

My callback function is working Ok. If the data acquisition is on the main loop, and I only put a blinking led on the callback, it works perfectly, while giving me the roll, pitch yaw values, the led blinks.

void setup(){
.
.
//The setup is the same as the MinIMU-9AHRS code, I just added the Timer1.
.
.
 Timer1.initialize(100000);         
 Timer1.attachInterrupt(callback);
}

void callback(){

digitalWrite( 8, digitalRead( 8 ) ^ 1 );

Serial.println("Test");

if((millis()-timer)>=20)  // Main loop runs at 50Hz
  {
    counter++;
    timer_old = timer;
    timer=millis();
    if (timer>timer_old)
      G_Dt = (timer-timer_old)/1000.0;    // Real time of loop run. We use this on the DCM algorithm (gyro integration time)
    else
      G_Dt = 0;
 
Serial.println("Test2");
   
    // *** DCM algorithm
    // Data adquisition
    Read_Gyro();   // This read gyro data
    Read_Accel();     // Read I2C accelerometer
 
Serial.println("Test3");
   
    if (counter > 5)  // Read compass data at 10Hz... (5 loop runs)
      {
      counter=0;
      Read_Compass();    // Read I2C magnetometer
      Compass_Heading(); // Calculate magnetic heading  
      }

Serial.println("Test4");
    
    // Calculations...
    Matrix_update(); 
    Normalize();
    Drift_correction();
    Euler_angles();
    // ***
   
    printdata();
}
}

I think the problem is on the first “IF” on the callback, because I only get one blink on the led and only the first print of “test”.

I would like to try running your code here. Could you post the entire file as an attachment? If it is multiple files, could you upload it as a zip file? If you do not want it public, you could email us directly at support@pololu.com with the code.

- Jeremy

Here it is.

Thanks
IMU.zip (62.9 KB)

Hello, PabloKamien.

I started looking at your code, but as far as I can tell, it seems to be more or less unmodified from the original (I don’t see any callbacks or Timer1 code). I can try to implement your changes myself, but it would be more useful if you could post the exact code that you’re trying to get to work. Also, what is the “Timer1” object? Are you using this library?

- Kevin

I have uploaded the wrong one. Sorry.
I will upload what I did later, but I just put what it is on the main loop inside the callback function and delete the if((millis()-timer)>=20).

I am trying to implement to work on the interrupt in the past few days, but I am not succeeding.

Thanks

Here it is.
MinIMU-9-Arduino-AHRS-master.zip (36.1 KB)

I spent a while looking at your code and eventually realized the reason it wasn’t working: Whenever an interrupt on the ATmega328 occurs, the global interrupt enable bit is cleared (disabled). Usually, the interrupt routine executes and then global interrupts are enabled again automatically when you return from the interrupt routine. However, this caused a problem with what you were doing, because global interrupts were disabled when the Timer1 interrupt fired, and that prevented the Wire library (which is used to communicate with the sensors on the IMU) from working since it uses the TWI interrupt to do things.

Fortunately, the solution is simple: you can just call sei() inside the Timer1 callback to enable nested interrupts. I tried putting it here and that seemed to fix the problem:

    ...
    sei(); // enable nested interrupts so TWI interrupt works
    // *** DCM algorithm
    // Data adquisition
    Read_Gyro();   // This read gyro data
    Read_Accel();     // Read I2C accelerometer
    ...

- Kevin

Its working perfect here.

Thank you very much for the help and the explanation for my problem.

Could you tell me how to set this

values please? I am using Arduino AHRS code.Here are the init functions:
gyro:

void Gyro_Init()
{
  gyro.init();
  gyro.writeReg(L3G_CTRL_REG1, 0x0F); // normal power mode, all axes enabled, 100 Hz
  gyro.writeReg(L3G_CTRL_REG4, 0x20); // 2000 dps full scale
}

accel:

void Accel_Init()
{
  compass.init();
  if (compass.getDeviceType() == LSM303DLHC_DEVICE)
  {
    compass.writeAccReg(LSM303_CTRL_REG1_A, 0x47); // normal power mode, all axes enabled, 50 Hz
    compass.writeAccReg(LSM303_CTRL_REG4_A, 0x08); // high resolution output mode
    compass.writeAccReg(LSM303_CTRL_REG4_A, 0x20); // 8 g full scale: FS = 10 on DLHC
  }
  else 
  {
    compass.writeAccReg(LSM303_CTRL_REG1_A, 0x27); // normal power mode, all axes enabled, 50 Hz
    compass.writeAccReg(LSM303_CTRL_REG4_A, 0x30); // 8 g full scale: FS = 11 on DLH, DLM
  }
}

compass:

void Compass_Init()
{
  compass.writeMagReg(LSM303_MR_REG_M, 0x00); // continuous conversion mode
  // 15 Hz default
}

Hello.

Can you explain exactly what you’re having trouble with? The datasheets for the sensors describe the settings and the registers used to configure them, and our libraries provide generic functions for writing and reading registers in the devices. If you have a specific question about something you don’t understand, we can try to answer it for you. Otherwise, if you are having trouble understanding the datasheets or the library code in general, you could try asking for help from someone nearby with electronics experience.

-Jon

[quote=“JonathanKosh”]Hello.

Can you explain exactly what you’re having trouble with? The datasheets for the sensors describe the settings and the registers used to configure them, and our libraries provide generic functions for writing and reading registers in the devices. If you have a specific question about something you don’t understand, we can try to answer it for you. Otherwise, if you are having trouble understanding the datasheets or the library code in general, you could try asking for help from someone nearby with electronics experience.

-Jon[/quote]
Hi, i am having trouble ,like i sayed, with setting the sensors to a specific frequency and sensitivity.If there was someone with electronic experience nearby i wouldn’t be writing my problem in a forum.

In order to determine which value to write to each register, you’ll need to use the appropriate table that explains what the bits in the register do so you can build a value that represents all of the settings you want.

For example, we can look at Tables 19, 20, and 21 inside the gyro datasheet, which describe the CTRL_REG1 register. Values assigned to the DR1, DR0, BW1, BW0 bits determine the output data rate (ODR) and frequency cut-off as described in Table 21. So, if you are interested in an ODR of 95 Hz and a cut-off frequency of 12.5 Hz, then DR1, DR0, BW1, and BW0 should be set to 0, 0, 0, and 0, respectively. Then, you can continue to set bits that correspond to the behavior you are interested in. Let’s complete the example by putting the gyro in normal power mode and enabling all axes. To do this, you would want to write a value that corresponds to “00000111”:

DR1	DR0	BW1	BW0	PD	Zen	Xen	Yen
 0	  0	  0	  0	  0	 1	  1     1

“00000111” is 0x07 in hexadecimal, or 7 in decimal. All of those values are valid for the write function:

gyro.writeReg(L3G_CTRL_REG1, 0x07);  // hexadecimal version
gyro.writeReg(L3G_CTRL_REG1, 0b00000111);  // binary version
gyro.writeReg(L3G_CTRL_REG1, 7);  // decimal version

-Jon

Thanks! Just one more question can i break the sensor board if i write a wrong value( i mean a value that cannot be made by the DR1 DR0 BW1 BW0 PD Zen Xen Yen)For example 0b000001112 or 0b00000112?Oh, and by the way why this 0b and 0x is always put in front and why the decimal version doesn’t have 0x or 0b or something?