Help with IMU

Greetings all!

I have been doing this awesome game controller project now for a few months, and now everything is together and working pretty darn well! The problem that I am having is with the Gyroscopic movement that I am getting. It moves well slow, and in medium to medium fast movement , but if I try a really quick turn the rotation rate drops to zero! Its very strange. At first i thought this was the arduino just not being fast enough, so I bought a Due, (which is awesome BTW), but before I even changed out the board for it...OH BTW I am using a "Leonardo" :O)....

Here is the IMU:

and here is the CODE I am using :

and here is the datasheet for the Gyro(The other datasheets links are on the IMU page) :

So as I was saying, I had not put in the new board, and I was looking over the data sheet and I noticed a few things...take alook:

void Gyro_Init()
{
  // Power up reset defaults
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x3E);
  WIRE_SEND(0x80);
  Wire.endTransmission();
  delay(5);
  
  // Select full-scale range of the gyro sensors
  // Set LP filter bandwidth to 42Hz
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x16);
  WIRE_SEND(0x1B);  // DLPF_CFG = 3, FS_SEL = 3
  Wire.endTransmission();
  delay(5);
  
  // Set sample rato to 50Hz
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x15);
  WIRE_SEND(0x0A);  //  SMPLRT_DIV = 10 (50Hz)
  Wire.endTransmission();
  delay(5);

  // Set clock to PLL with z gyro reference
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x3E);
  WIRE_SEND(0x00);
  Wire.endTransmission();
  delay(5);
}

// Reads x, y and z gyroscope registers
void Read_Gyro()
{
  int i = 0;
  byte buff[6];
  
  Wire.beginTransmission(GYRO_ADDRESS); 
  WIRE_SEND(0x1D);  // Sends address to read from
  Wire.endTransmission();
  
  Wire.beginTransmission(GYRO_ADDRESS);
  Wire.requestFrom(GYRO_ADDRESS, 6);  // Request 6 bytes
  while(Wire.available())  // ((Wire.available())&&(i<6))
  { 
    buff[i] = WIRE_RECEIVE();  // Read one byte
    i++;
  }
  Wire.endTransmission();
  
  if (i == 6)  // All bytes received?
  {
      gyro[0] = -1 * ((((int) buff[2]) << 8) | buff[3]);    // X axis (internal sensor -y axis)
      gyro[1] = -1 * ((((int) buff[0]) << 8) | buff[1]);    // Y axis (internal sensor -x axis)
      gyro[2] = -1 * ((((int) buff[4]) << 8) | buff[5]);    // Z axis (internal sensor -z axis)
     
  }
  else
  {
    num_gyro_errors++;
    if (output_errors) Serial.println("!ERR: reading gyroscope");
  }
}

I notice they don't use the Sensitivity Scale Factor of 14.375 anywhere in this so shouldn't the recieved bytes look like this?:

gyro[0] = -1 * ((((int) buff[2]) << 8) | buff[3]) / 14.375;    // X axis (internal sensor -y axis)
        gyro[1] = -1 * ((((int) buff[0]) << 8) | buff[1]) / 14.375;    // Y axis (internal sensor -x axis)
        gyro[2] = -1 * ((((int) buff[4]) << 8) | buff[5]) / 14.375;    // Z axis (internal sensor -z axis)

...and after looking closer I think that some of the register values are wrong, but not being very familiar with this type of thing I thought i should lay this all out and ask for help.

What I NEED is to make this run as fast as possible sampling as many time per sec so I can track very fast movements. Would someone help me set this Gyro code up so that it is doing just that, I would very much appreciate it!

~Bobby

well looking closer I see the
#define GYRO_GAIN 0.06957 can't believe I missed that!(1 / 14.375)
But something IS still off

Reading the datasheet I see that : "Parameters:
SMPLRT_DIV Sample rate divider: 0 to 255 "

Currently the code for that reads:

 // Set sample ratio to 50Hz
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x15);
  WIRE_SEND(0x0A);  //  SMPLRT_DIV = 10 (50Hz)
  Wire.endTransmission();
  delay(5);

So can I just change it to :

 // Set sample ratio to 256Hz?
  Wire.beginTransmission(GYRO_ADDRESS);
  WIRE_SEND(0x15);
  WIRE_SEND(0xFF);  //  SMPLRT_DIV = 255 Now will this give me better tracking?
  Wire.endTransmission();
  delay(5);

Will making this change give me more samples so that I don't loose tracking for very fast movements? Also is this all I have to change? I am trying to help myself by writing this all down here, and others, so please if anyone has some valuable input feel free to jump in at any time :OD

OK so I tried that but it just gave me one reading then stopped in its tracks. So I changed it back, and tried a few other values but nothing seemed to change anything, that made a difference in tracking.

Unless you are doing calculations which require actual SI units, there is not much need to scale things unnecessarily.

And float calculations on the arduino are slow.

And float division is even worse.

How do you even know that you are actually successfully communicating on the i2c ?

Well I get full mouse movement and YPR(yaw, pitch, roll) from the serial as expected :smiley: , and the IMU is attached to the i2c pins. I was using just INT at first, but the gave hitchy, sort of jumpy movement from the mouse, letting it have decimal number is extreemy smooth, but like I said very fast movements result in weirdness....is it the way I am doing the final mouse move do you think?

Mouse.move(gyroZ_out * 64, gyroY_out * 64, 0);

If I don't add a multiplier then the movement is the it is just very slight and that isn't good for making large turns :wink:
I appreciate you looking at it btw :slight_smile:

You need a better understanding of what movement you are trying to sense or control. You gyro sensor is only going to detect rotation.

What you have got there isn't "an IMU". It is sensors for an IMU. If you want an orientation solution or a estimator of location, that sensor isn't it. You need a complicated algorithm to determine the orientation or position estimating, using the sensor inputs from your gadget.

As far as i know that library already does the sensor fusion calculations, you need to try to get a yaw pitch roll readings which combine your accelerometer gyro and magnetometer readings, from your yaw pitch and roll you can look at the change, from this you can determine the mouse direction and speed. (yaw pitch and roll may suffer from gimble lock using quaternions may be a better solution)
The following video gives a good basis on understanding the foundations for these techniques.

Hi.

I too am new to this sort of stuff but a couple of things I would like to add:

1 - you gave an example of some code in an early post:
WIRE_SEND(0x0A); // SMPLRT_DIV = 10 (50Hz)

Then you went on to say:
WIRE_SEND(0xFF); // SMPLRT_DIV = 255 Now will this give me better tracking?

Ok, I'll bite. How do you get that?

I accept that 0A (hex) is 10 decimal; and with an unseen equation you get 50 Hz from it.
But FF (hex) is 255 decimal, and you get 255 Hz sampling? Care to check that reasoning?

2 - You are waning FAST readings.
You then go on to say you are making the numbers LONG.
Going from INT to LONG isn't going to make it quicker. As someone said, it will actually slow it down, as LONG takes more time to compute.

What I THINK you want to do is keep things simple and leave the values as INT but sample them quicker.

End of my two thoughts on that.

Couple of other things I suggest:

Get the I2C scanner program and check it is being seen. Make sure the address is correctly "modified" in the routine.
I had all sorts of problems when I was playing with the I2C bus and an external IC and the address.
The address seen and reported by I2C scanner is NOT the same address as needed in the code.
You have to rotate/shift the address 1 bit ..... left I think. So, for instance, 37 (hex) becomes 6D.
Or something like that.

Next thing is to work on only one axis at a time.
FORGET the other two for now!
I had all sorts of problems and I discovered that I had the X and Z reversed.
Set the controller in the "neutral" position and read data from it.
Move it 45 degrees on what you want to call the X axis.
Watch for changes.
That is your X readings.

Check that there isn't an "offset" value you can set.
So, if your thing is always showing +20 when it is level, you enter 20 (be it -20 or +20) as the offset and then it reads ZERO.

Anyway, good luck.
Hope you get it working.

I am not sure I was clear, sorry for that. I have an IMU its a SparkFun 9 Degrees of Freedom - Sensor Stick - SEN-10724 - SparkFun Electronics? Thought I mentioned that. Anyway the part I was looking at was the initialization of the gyro because at the end of my 'Kalman' filter( that I know is working)( Both my Magnetometer giving proper(calibrated)Yaw, and The pitch and Roll are VERY accurate, but I like the way the Kalman fixed Gyro moves the mouse. Moving the gyro with the mouse is perfect really, as the faster you move it the larger the values get. if you have these values as your mouse movements its quite nice. The ONLY problem is just sampling rate and trying to increase it, unless you know of another way for me to capture more gyro data? Or another solution that I would explore would be knowing how to make the yaw & pitch move the mouse in this way like the Gyro...I can make it move relate...it has a center point in the middle of you screen that is the dead spot, the mouse or camera moves in what ever direction you point but will only stop when you move back to that dead/center point. Movement Needs to stop ON then angles, and only move when there is movement.

Here is a video of the mouse movement if youd like to see the project...just ignore the sound its RAW video to be edited later, and my daughter is young...and loud lol;O)

The ONLY problem is just sampling rate and trying to increase it, unless you know of another way for me to capture more gyro data?

Again, I shall state that if you go from INT to LONG you are NOT making the samples faster, but slower because there are more numbers to "crunch".

You didn't explain your reasoning on sample rates I mentioned. (Notes 1 and 2 in my first post)

Good luck with it all and I really hope you get it going.

I am not sure I was clear, sorry for that. I have an IMU its a SparkFun 9 Degrees of Freedom - Sensor Stick - SEN-10724 - SparkFun Electronics?

You are obvious still NOT CLEAR. It is not an IMU, it is the sensor for an IMU.

@lost_and_confused

Sorry the last one wasn't for you. Anyway, in my first post I post a link to the Board. I also posted the link for the Datasheet, but on the link for the board ALL of the data sheets for ALL of the chips are there. THAT is where the information I got for those values you asked about above. I guess the help I am looking for is deciphering the data sheets lol.

On number 2 . That is great I dead, I used the good scanner example that does multiple speeds showing the addresses, and I give that a go thanks!

http://forum.arduino.cc/index.php/topic,21419.0.html

I think this is some of my problem, and I DID notice a slight increase in tracking when I changed the Wire lib values, so it IS definitely something to do with speed over the USB I think