Scaling gyroscope output (MPU6050)

Okay, so I’m working on an acc/gyro-sensor (MPU6050), and I’m having problems getting the output scaling of the gyro correct, the accelerometer output seems to be about about right though.

The gyro has a resolution of 16 bytes and is instructed to have an output range of +/- 250 deg/s, (to my understanding: +/- 250 deg/s = +/- 2^15).

I want the gyro to output in deg/s, similary as I’ve manage to get accelerometer readings relative to g’s under “void acc()”, but either it doesn’t fluctuate around 0 when the sensor is lying still on the table, or it doesn’t scale correctly.

Also, is the code under void acc() reasonable?

//MPU6050 Datasheet: http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Components/General%20IC/PS-MPU-6000A.pdf
// MP6050 Register map: http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Accelerometers/RM-MPU-6000A.pdf

#include <Wire.h>

#define MPU6050 0x68 //Device address
#define ACCEL_CONFIG 0x1C //Accelerometer configuration address
#define GYRO_CONFIG 0x1B


//Registers: Accelerometer, Temp, Gyroscope
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48


#define PWR_MGMT_1 0x6B
#define PWR_MGMT_2 0x6C

#define acc_readings 6;
#define gyro_readings 6;

#define toRead 6
byte reading[toRead];

//Sensor output scaling
#define accSens 0 // 0 = 2g, 1 = 4g, 2 = 8g, 3 = 16g
#define gyroSens 0 // 0 = 250rad/s, 1 = 500rad/s, 2 1000rad/s, 3 = 2000rad/s


void setup()
{
  Wire.begin();
  Serial.begin(115200);
  writeTo(MPU6050, PWR_MGMT_1, 0);
  writeTo(MPU6050, ACCEL_CONFIG, accSens << 3); // Specifying output scaling of accelerometer
  writeTo(MPU6050, GYRO_CONFIG, gyroSens << 3); // Specifying output scaling of gyroscope
}

void loop()
{
  //acc();
  gyro();
}


void writeTo(byte device, byte address, byte value) {
  Wire.beginTransmission(device);
  Wire.write(address);
  Wire.write(value);
  Wire.endTransmission();
}

void readFrom(byte device, byte address, byte bytes, byte reading[]) {
  Wire.beginTransmission(device);
  Wire.write(address);
  Wire.endTransmission();
  Wire.requestFrom(device, bytes);
  while (bytes > Wire.available()){
  }
  for (int i = 0; i < bytes; i++){
    reading[i] = Wire.read();
  }
}

void acc() {
  readFrom(MPU6050, ACCEL_XOUT_H, toRead, reading);
  float xacc = ((reading[0] << 8) | reading[1]);
  xacc /= (float)(1<<(16-accSens-2));
  float yacc = ((reading[2] << 8) | reading[3]);
  yacc /= (float)(1<<(16-accSens-2));
  float zacc = ((reading[4] << 8) | reading[5]);
  zacc /= (float)(1<<(16-accSens-2));
  float resultant = sqrt(pow(xacc,2) +pow(yacc,2) + pow(zacc,2));

  Serial.print(xacc,3);
  Serial.print('\t');
  Serial.print(yacc,3);
  Serial.print('\t');
  Serial.print(zacc,3);
  Serial.print('\t');
  Serial.println(resultant,3);
  delay(100);
}

void temp() {
}

void gyro() {
  readFrom(MPU6050, GYRO_XOUT_H, toRead, reading);
  float xgyro = ((reading[0] << 8) | reading[1]);
  //xgyro /= (float)(1<<(16-gyroSens))/250;
  float ygyro = ((reading[2] << 8) | reading[3]);
  // "Scale output somehow"
  float zgyro = ((reading[4] << 8) | reading[5]);

  float resultant = sqrt(pow(xgyro,2) +pow(ygyro,2) + pow(zgyro,2));

  Serial.print(xgyro,3);
  Serial.print('\t');
  Serial.print(ygyro,3);
  Serial.print('\t');
  Serial.print(zgyro,3);
  Serial.print('\t');
  Serial.println(resultant,3);
  delay(100);
}
  1. delete 2 of your 3 identical posts.

  2. Is the gyro output in degrees.decimal or degrees.mins.seconds ?

Mark

holmes4:

  1. delete 2 of your 3 identical posts.

  2. Is the gyro output in degrees.decimal or degrees.mins.seconds ?

Mark

  1. Sorry about that. I tried to press “preview”, whereupon the browser displayed “service unavailable” or something, so I tried one more time with “preview” and the last time just “post”. It seems it posted all three times, and when I try to delete my post it says I can’t delete my own posts on this forum. Anyway, sorry for the trouble.

  2. According to the datasheet the gyro should output in degrees per second in decimal values.

If you look under void acc(), I think I got it working allright there so I can choose the resolution and it scales the output accordingly. I was hoping to do the same with gyro readings as well.

The gyro has a resolution of 16 bytes and is instructed

Bytes or bits?

Mark

when the sensor is lying still on the table

if it's "still" on the table then non of the readings should change!

Mark

holmes4:

when the sensor is lying still on the table

if it's "still" on the table then non of the readings should change!

Mark

Should, but doesn't.

Turn your smart phone's sensors on and try it yourself. Definitely not static readings.

holmes4:

The gyro has a resolution of 16 bytes and is instructed

Bytes or bits?

Mark

Bits of course, my bad :-)

This article may help you. http://www.botched.co.uk/pic-tutorials/mpu6050-setup-data-aquisition/

Note the following from the end of the article.

ust beware you will need to define your own gyro sensitivities, as it depends on what scale you select in the configuration.

holmes4: This article may help you. http://www.botched.co.uk/pic-tutorials/mpu6050-setup-data-aquisition/

Note the following from the end of the article.

ust beware you will need to define your own gyro sensitivities, as it depends on what scale you select in the configuration.

I believe I made it so that it scales the accelerometer sensitivity according to the scale, but it's alot easier to check if the accelerometer is correctly scaled because I can use the gravity as reference.

Yes, but you have (you say) a problem the gyro not accel.

Mark

holmes4:
Yes, but you have (you say) a problem the gyro not accel.

Mark

I think I finally got it working, however I’m not completely sure ‘why’ it worked, it sure does output reasonable gyro readings.

The sensor gyroscope range scale is defined:

#define gyroSens 3 // 0 = 250deg/s, 1 = 500deg/s, 2 1000deg/s, 3 = 2000deg/s

Meaning: ±2000deg/s corresponds to ±2^15 (Whole range is 16 bit, thus half range is 15 bit). And that ±1deg/s corresponds to (2^15) / (2000) = (2^16) / (22000), or generally [u]±1deg/s = (2^16) / (2250*2^gyroSens).[/u]

But what I found working this:

float xgyro = ((reading[0] << 8) | reading[1]);  // this is 16 bit, full range
  xgyro /= (250 >> gyroSens); [u]// corresponds to (2^16) / (250 / 2^gyroSens).[/u]

Have I misunderstood the bitshift operation or is the math wrong?

From the datasheethttp://www.cdiweb.com/datasheets/invensense/PS-MPU-6000A.pdf

7.7 Three-Axis MEMS Gyroscope with 16-bit ADCs and Signal Conditioning
The MPU-60X0 consists of three independent vibratory MEMS rate gyroscopes, which detect rotation about
the X-, Y-, and Z- Axes. When the gyros are rotated about any of the sense axes, the Coriolis Effect causes
a vibration that is detected by a capacitive pickoff. The resulting signal is amplified, demodulated, and filtered
to produce a voltage that is proportional to the angular rate. This voltage is digitized using individual on-chip
16-bit Analog-to-Digital Converters (ADCs) to sample each axis. The full-scale range of the gyro sensors
may be digitally programmed to ±250, ±500, ±1000, or ±2000 degrees per second (dps). The ADC sample
rate is programmable from 8,000 samples per second, down to 3.9 samples per second, and user-selectable
low-pass filters enable a wide range of cut-off frequencies.

To me this looks like the chip will cope with a change in a axis of 200 deg/sec at the lowest setting and upto 2000 at the highest setting. So at the lowest setting just over 1/2 a rotation in the xaxis at the lowest settin and 2000/360 at the highest.

Meaning: ±2000deg/s corresponds to ±2^15 (Whole range is 16 bit, thus half range is 15 bit). And that ±1deg/s corresponds to (2^15) / (2000) = (2^16) / (22000), or generally ±1deg/s = (2^16) / (2250*2^gyroSens).

No wrong, the value is presented as two bytes in order to fit the maximum value in that’s all.

float xgyro = ((reading[0] << 8) | reading[1]);  // this is 16 bit, full range

Yes this is ok, but an int would be better.

xgyro /= (250 >> gyroSens); [u]// corresponds to (2^16) / (250 / 2^gyroSens).[/u]

No just plain wrong.

Mark

holmes4: xgyro /= (250 >> gyroSens); [u]// corresponds to (2^16) / (250 / 2^gyroSens).[/u]

No just plain wrong.

Mark

Hello, Why do you say that holmes4 ? Is it a wrong calculates ?