3

I need help getting my MPU 6050 to actually give me data. As of right now, my program is only reading 0s from the gyroscope and when I move it, the values all go to -1 and the program just stops until I close and reopen the serial monitor. I know this question has been asked multiple times before, but I've already looked at each of those questions and tried all of the fixes listed there, but not a single one has worked. The I2C scanner does find the sensor at 0x68, but that's only thing that works. These are all brand new boards that I got a couple days ago.

I've tried every library and every example sketch I could find. I've switched to 2 new boards. I've even tried looking at the datasheet for the MPU 6050 and reading/writing the registers directly and still I'm getting no results. The serial monitor either stays blank, shows only 0s or -1s, or just gives me garbage values that change randomly. Please help me.

I've wired the sensor like this (I'm currently on an Arduino Uno):

VCC ==> 5V
GND ==> GND
SCL ==> A5
SDA ==> A4
AD0 ==> digital 13 (set to LOW)

And the code I'm using is this:

#include <Wire.h>

const int addressPin = 13;

int gyroX, gyroY, gyroZ;

void setup() { Wire.begin(); Serial.begin(9600);

//designating pins as I/O pinMode(addressPin, OUTPUT);

//setting IMU address to 0x68 (LOW) digitalWrite(addressPin, LOW);

initializeSensor(); }

void loop() { readGyro();

Serial.print(gyroX); Serial.print(" "); Serial.print(gyroY); Serial.print(" "); Serial.println(gyroZ); }

void initializeSensor() { //performing full device reset, disables temperature sensor, disables SLEEP mode Wire.beginTransmission(0x68);

Wire.write(0x6B); Wire.write(0b10001000);

Wire.endTransmission();

//writing to gyro config register Wire.beginTransmission(0x68);

Wire.write(0x1B); Wire.write(0b00001000);

Wire.endTransmission(); }

void readGyro() { //requesting data from gyro data registers Wire.beginTransmission(0x68);

Wire.write(0x43);

Wire.endTransmission();

Wire.requestFrom(0x68, 6);

gyroX = Wire.read()<<8|Wire.read(); gyroY = Wire.read()<<8|Wire.read(); gyroZ = Wire.read()<<8|Wire.read(); }

P.S. I few weeks ago I posted a question about I2C devices and in it, I said I had managed to successfully read data from the sensor, but I found out later those were garbage numbers. :(

Tobias Guo
  • 35
  • 1
  • 6

3 Answers3

3

From the MPU-6000/MPU-6050 Register Map and Descriptions:

  • Section 4.28, Register 107 – Power Management 1 PWR_MGMT_1, pages 40 to 41:

    Note:
    When using SPI interface, user should use DEVICE_RESET (register 107) as well as SIGNAL_PATH_RESET (register 104) to ensure the reset is performed properly. The sequence used should be:

    1. Set DEVICE_RESET = 1 (register PWR_MGMT_1)
    2. Wait 100ms
    3. Set GYRO_RESET = ACCEL_RESET = TEMP_RESET = 1 (register SIGNAL_PATH_RESET)
    4. Wait 100ms
  • Section 4.26, Register 104 – Signal Path Reset SIGNAL_PATH_RESET, page 37:

    Note: This register does not clear the sensor registers. The reset initializes the serial interface as well.

  • Section 3, Register Map, page 8:

    The reset value is 0x00 for all registers other than the registers below.

    • Register 107: 0x40.
    • Register 117: 0x68.

This means that the PWR_MGMT_1 register defaults to sleep mode after a reset so it needs to be rewritten to disable sleep mode after commanding a reset.

void initializeSensor()
{
  //
  // Perfrom full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41.
  //

// performing full device reset, disables temperature sensor, disables SLEEP mode Wire.beginTransmission(0x68); // Device address. Wire.write(0x6B); // PWR_MGMT_1 register. Wire.write(0b10001000); // DEVICE_RESET, TEMP_DIS. Wire.endTransmission(); delay(100); // Wait for reset to complete.

Wire.beginTransmission(0x68); // Device address. Wire.write(0x68); // SIGNAL_PATH_RESET register. Wire.write(0b00000111); // GYRO_RESET, ACCEL_RESET, TEMP_RESET. Wire.endTransmission(); delay(100); // Wait for reset to complete.

// Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8. Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x6B); // PWR_MGMT_1 register. Wire.write(0b00001000); // SLEEP = 0, TEMP_DIS = 1. Wire.endTransmission(); }

In the following code I've:

  1. Modified readGyro() to implement 3 states (Request, Wait, and Read) and return true when 6 bytes have been read from the MPU-6050.

  2. Added Blink Without Delay to loop() to see whether the MCU freezes which requires changing the ADO pin from pin 13 (the built-in led) to another pin, i.e. pin 12.

  3. Added several Serial.print() statements for debugging to see where things go wrong.

  4. Tweaked the code in response to comments.

#include <Wire.h>

const byte IMUAddress = 0x68; // Added for readability and maintainability. const byte addressPin = 12; // Changed from 13 to 12 because 13 is built-in LED.

int gyroX, gyroY, gyroZ;

void setup() { Wire.begin(); Serial.begin(115200); Serial.println(F("\n\nMPU-6050 Test\n"));

// Designating pins as I/O. pinMode(addressPin, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); // Added LED for heartbeat signal.

// Setting IMU address to 0x68 (LOW). digitalWrite(addressPin, IMUAddress & 1); // Added bit mask of bit 0.

initializeSensor(); }

void loop() { // // TASK 1: Blink without delay to indicate that MCU hasn't frozen. // const unsigned int INTERVAL = 250; unsigned long current_timestamp = millis(); static unsigned long previous_timestamp = current_timestamp; static bool led_state = false; if (current_timestamp - previous_timestamp >= INTERVAL) { led_state = !led_state; digitalWrite(LED_BUILTIN, led_state); previous_timestamp += INTERVAL; }

// // TASK 2: Read gyro. // if (readGyro()) { Serial.print(gyroX); Serial.print(F(" ")); Serial.print(gyroY); Serial.print(F(" ")); Serial.println(gyroZ); } }

void initializeSensor() { // // Perform full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41. //

Serial.print(F("Performing full reset of MPU-6050..."));

Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x6B); // PWR_MGMT_1 register. Wire.write(0b10001000); // DEVICE_RESET, TEMP_DIS. Wire.endTransmission(); delay(100); // Wait for reset to complete.

Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x68); // SIGNAL_PATH_RESET register. Wire.write(0b00000111); // GYRO_RESET, ACCEL_RESET, TEMP_RESET. Wire.endTransmission(); delay(100); // Wait for reset to complete.

Serial.println(F(" Done."));

// Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8. Serial.print(F("Disabling sleep mode of MPU-6050...")); Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x6B); // PWR_MGMT_1 register. Wire.write(0b00001000); // SLEEP = 0, TEMP_DIS = 1. Wire.endTransmission(); Serial.println(F(" Done."));

// // Writing to gyro config register. // Serial.print(F("Configuring gyro of MPU-6050...")); Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x1B); // GYRO_CONFIG register. Wire.write(0b00001000); // +/-500 deg/s. Wire.endTransmission(); Serial.println(F(" Done.")); }

typedef enum State { Request, Wait, Read };

bool readGyro() { static State state = State::Request;

switch (state) { case State::Request: // Request data from gyro data registers. Serial.print(F("Requesting data from gyro...")); Wire.beginTransmission(IMUAddress); // Device address. Wire.write(0x43); // GYRO_XOUT_H register. Wire.endTransmission(false); // Restart connection, i.e. keep alive. Wire.requestFrom(IMUAddress, 6); // GYRO_XOUT_H, GYRO_XOUT_L, GYRO_YOUT_H, GYRO_YOUT_L, GYRO_ZOUT_H, GYRO_ZOUT_L. Serial.println(F(" Done.")); state = State::Wait; Serial.print(F("Waiting for data from gyro...")); break;

case State::Wait:
  // Wait for data to arrive into buffer.
  if(Wire.available() &lt; 6)
  {
    //Serial.print(F(&quot;.&quot;));
    Serial.print(F(&quot; &quot;));
    Serial.print(Wire.available());  // Added to show bytes received.
  }
  else
  {
    Serial.print(F(&quot; &quot;));
    Serial.print(Wire.available());  // Added to show bytes received.
    Serial.println(F(&quot; Done.&quot;));
    state = State::Read;
  }
  break;

case State::Read:
  // Read data from gyro registers.
  Serial.print(F(&quot;Reading gyro data...&quot;));
  gyroX = Wire.read() &lt;&lt; 8 | Wire.read();
  gyroY = Wire.read() &lt;&lt; 8 | Wire.read();
  gyroZ = Wire.read() &lt;&lt; 8 | Wire.read();
  Serial.println(F(&quot; Done.&quot;));
  state = State::Request;
  return true;  // Indicate data was received.
  break;

}

return false; // Indicate no data received yet. }

Update based upon RowanP's answer

While concentrating on the software issues I missed a crucial piece of information from the other datasheet (MPU-6000/MPU-6050 Product Specification), i.e. the electrical characteristics in Sections 6.3 and 6.4 on pages 14 and 15 showing a Vdd range of 2.375 V to 3.46 V:

Electrical Characteristics of MPU-6050 Vdd power supply of MPU-6050

6.4 Electrical Specifications, Continued Digital inputs and outputs of MPU-6050

This will require level shifters on the signals between the 3.3 V MPU-6050 and the 5 V Arduino.

tim
  • 699
  • 6
  • 15
3

A while ago while figuring out I2C difficulties of my own I did some research and listed out all the failure modes and test techniques I could think of regarding I2C. See I2C protocol doesn't work properly. I routinely go through the list now to tick off the things I need to check to get a new I2C connection working, usually it's something simple (fingers crossed). Do you have access to an oscilloscpe?

(Edit) This old post seems to describe a similar problem (only getting zeros) MPU6050 doesn't work. The consensus there was that the 3.3V MPU6050 had been connected to a 5V UNO, frying the MPU6050 chip. That sounds very like your situation.

RowanP
  • 869
  • 6
  • 21
2

I used 5 V from my Arduino to power the MPU6050, and it was fine. Check out: https://www.instructables.com/How-to-Make-a-Robot-Car-Drive-Straight-and-Turn-Ex/, which has very similar code.

Also, I typically avoid pin 13, since it performs some special additional function, unlike pin 2 to 12.

ocrdu
  • 1,795
  • 3
  • 12
  • 24
J Z
  • 31
  • 4