Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!




problem using MPU-6...
 
Share:
Notifications
Clear all

[Solved] problem using MPU-6050 Accel/Gyro with ESP32

98 Posts
3 Users
3 Likes
24 K Views
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

I am having problems getting the MPU-6050 Accelerometer & Gyro to work with my Heltec ESP32 Development board.

I can run the I2C scanner and it detects the MPU-6050 at 0x68

If I run any of the example sketches that came with the MPU6050.h library it does not get data from the MPU-6050

I tried the MPU6050_DMP6.ino and have tried various examples from the web. But it is an issue with the ESP32
The MPU-6050 works fine using the sketch on my Arduino Nano but not the ESP32

I have the MPU-6050 connected as follows:
MPU-6050 o left ESP32 on right
VCC to 3.3V
GND to GND
SDA to Pin 21
SCL to Pin 22

Any help is greatly appreciated


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2660
 

Unfortunately, I do not have an ESP32 and I do not have an MPU-6050.
While trying to find a solution, I did find this project, which seems straight forward.
I have no idea if you already tried that one. Just being curious ... What are pin 21 and 22?


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

@hansSorry about that.  Attached are the front and back pics of the board with pins labeled.
Also attached is the board pinout.  I will take a look at that project. 

The board is different.  The Helte board has a built-i I2C display so that complicates things a little


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

I tried the code from the page you listed and the MPU6050 still does not work.   I had the MPU connected as per the Circuit Digest page you linked to.

The code does not initialize the MPU and does not pull accelerometer or gyro data


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2660
 

I've been staring at the pictures and document for a while now and can't come up with a sensible answer.
I personally would try another GPIO pin, but some are input only (not sure if this would be sufficient), and you'll have to pay attention to the once already in use for the display and the touch of the display.


   
ReplyQuote


 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

It certainly can't hurt to try.  I did try the same I2C pins that the display uses and it didn't work


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

Progress.  I was able to get the MPU6050 to initialize.  I don't know if it will work on any pin but I will have to test that after I get the interrupt to work.

I do not know how to setup and use a pin as an Interrupt on the ESP32.  The accel/gyro generates an interrupt when data is available.  Then I can view the readings when I figure this out.

I moved the MPU6050 to the first I2C bus, the one that the display is connected to. 
This is SDA-Pin4 and SCL-Pin 15

The steps are as follows:
1) Load the heltec library
#include "heltec.h"

2) Now you can enable the built-in OLED display with this line
Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/);

3) The key to getting I2C to work seems to be that now you have to initialize the display then other devices can be used
Heltec.display -> display();

4) It is time to start the wire.  It defaults to SDA-Pin4 and SCL-Pin 15
Wire.begin();

5) Now you can initialize the MPU6050
mpu.initialize();

The next step would be to enable the interrupt.  On the Arduino Uno all you have to do is plug the MPU6050 INT pin into Uno pin 2 and it worked right away.

But I am not sure how to setup and use a GPIO pin as an Interrupt on the Heltec  board

 

 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2660
 

You've gotten further than would have - excellent that we are seeing progress. 👍 

I wasn't aware that something like that (MPU-6050) could trigger an interrupt. Good to know though.

The ESP32 documentation may be useful though (this page) - looks like the function "gpio_intr_enable(pin)" may be what you're looking for?
(the documentation is a little bit of a confusing read if you ask me)

Hope this helps ...


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

I looked at that page and it is still not working.

Here is the code I added:
#define INTERRUPT_PIN 35

pinMode(INTERRUPT_PIN, INPUT_PULLUP);
attachInterrupt(INTERRUPT_PIN, dmpDataReady, RISING);


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

After a lot of testing I figured it out.  The issue was not with the code the problem was the pin used.
In addition the code to configure a pin as an interrupt is working.

The data found on the internet for the Heltec WiFi32 board is misleading because some features of this board operate differently from the other ESP32 boards.

For example some docs I found say that any pin can on an ESP32 board can be configured as an interrupt.  But on the Heltec board not all pins actually work.  Maybe there is extra coding or whatever.

I tested most of the pins on the Heltec board and results are as follows
(Pin numbers are based on the Heltec pinout previiusly provided)
36, 37, 38, 39 - SEE NOTE
34 - NG
35 - NG
32 - OK
33 - OK
19 - OK
18 - OK
5 - OK
2 - OK

36, 37, 38, 39 exhibited strange behavior.  They did work when configured as an interrupt but they activated in pairs.
For example if I configured Pin 37 as an interrupt Pin 36 also triggered an interrupt.  Same condition for Pair 38 & 39.

The code snipets for the MPU6050 interrupt are as follows (dmpDataReady is interrupt routine)
#define INTERRUPT_PIN 39

void setup() {
          pinMode(INTERRUPT_PIN, INPUT);
          attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
                     }

 

Now I need to work this conde into my GPS Data Logger. 
Question: The uBlox GPS Module uses two pins for data TX and RX.  If the MPU6050 Accel/Gyro generates an interrupt will it cause issues with the sketch dropping GPS Data?


   
ReplyQuote


 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2660
 

Ah cool! Yeah I figured the pin would be the issue, especially since the display and such seem to be connected to certain pins.

Thanks for posting your findings! 👍  Others (maybe even myself) will have a use for it for sure.

As for the interrupt question: In general an interrupt will disrupt receiving GPS data.
It may very well be that the GPS is buffered and received anyway, you'll have to test that.
Best approach would be to keep the interrupt code as quick and short as possible.
Maybe flag a variable (boolean) to true when there was data from the MPU6050, and handle actual reading in the regular code where you're reading the GPS data if this global variable is true.

This is what I did for the web control for my LED Effects project.

Alternatively, maybe even easier, is by not using an interrupt.
Just read MPU data each time you read GPS data. This way it will not interrupt the GPS data at all.


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

Happy to help.  I will post more code when available.
You have helped me more then the egotists on the arduino forum.  All they do is criticize and complain.  I deleted my accounts since they did nothing but waste my time.  Someone would post a useless message complaining that I did not do something right.

Anyway, on to the project.

I was thinking along the same line.  Currently the interrupt routine does one thing, set a variable to true when an interrupt occurs then returns.

The main loop basically does this:
read GPS data
display GPS data
write GPS to SD card file

I was going essentially duplicate these features with the accelerometer data similar to this
if interrupt is true then
     display accelerometer x y z
     write accelerometer to sd card
end if

When I fix my laptop I will work on adding these lines to the main loop.   I will post the code when I have it tested

Thanks


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

I was able to get the MPU6050 Accelerometer working without an interrupt.  The basic code reads date from the MPU6050 and displays it live on the OLED.  It also keeps track of Max G for X,Y,X and displays that on the OLED

In case I forgot the MPU6050 library is from Electronic Cats.   The MPU6050 code is based on the MPU6050-DMP6 example from the Electronic Cats library.

Here is the code.  Comments added to explain code functions

Any advice or suggestions is greatly appreciated
Next up is to have this write the live and Max G values to an SD card

 

//
// Display Max G on OLED
//DOES NOT USE INTERRUPT
//

#include "heltec.h"
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

SSD1306AsciiWire oled;

MPU6050 mpu;

bool dmpReady = false; // set true if DMP init was successful
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

float MaxGx = 0, MaxGy = 0, MaxGz = 0;

// orientation motion variables
Quaternion q; // [w, x, y, z] quaternion container
//VectorInt16 aa; // [x, y, z] accel sensor measurements
//VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
//VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
//VectorFloat gravity; // [x, y, z] gravity vector
//float euler[3]; // [psi, theta, phi] Euler angle container
//float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector

// ==========
// === SETUP ===
// ==========

void setup() {
Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/);
//Heltec.display -> display();
oled.begin(&Adafruit128x64, 0x3C, 16);
oled.setFont(System5x7);
oled.clear();
oled.setCursor(15,3);
oled.print("G-force Monitor");
delay(1000);
oled.clear();

Wire.begin(); //pin 21 and 22 for ESP32
Wire.setClock(400000); // 400kHz I2C clock

// initialize serial monitor
Serial.begin(115200);

// initialize I2C devices
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();

// verify I2C device connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

// load and configure the DMP
Serial.println(F("Initializing DMP..."));
oled.setCursor(0,0);
oled.println("Calibrate Acc/Gyro");
devStatus = mpu.dmpInitialize();

// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

// make sure it worked (returns 0 if MPU6050 working)
if (devStatus == 0) {
// Calibration Time: generate offsets and calibrate our MPU6050
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
oled.print("Accel/Gyro Ready");
delay(1000);
oled.clear();
mpu.setDMPEnabled(true);

// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready!"));
dmpReady = true;

// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}

// ===================
// === MAIN PROGRAM LOOP ===
// ===================
void loop() {
// if MPU6050nprogramming failed, don't do anything
if (!dmpReady) return;

// wait for MPU extra packet(s) available
while (fifoCount < packetSize) {
if (fifoCount < packetSize) {
// try to get out of the infinite loop
fifoCount = mpu.getFIFOCount();
}
}

// get current FIFO count
fifoCount = mpu.getFIFOCount();
if(fifoCount < packetSize){
}
// check for FIFO overflow
else if (fifoCount >= 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
// fifoCount = mpu.getFIFOCount(); // will be zero after reset
Serial.println(F("FIFO overflow!"));
}
{

// read a packet from FIFO
while(fifoCount >= packetSize){
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count in case there is > 1 packet available
fifoCount -= packetSize;
}

// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("ACCEL\t");
//Serial.print(q.w);
//Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);

//calculate Max Accel X,Y,Z
if (abs(q.x) > abs(MaxGx))
{
MaxGx = q.x;
} else{
MaxGx = MaxGx;
}

if (abs(q.y) > abs(MaxGy))
{
MaxGy = q.y;
} else{
MaxGy = MaxGy;
}

if (abs(q.z) > abs(MaxGz))
{
MaxGz = q.z;
} else{
MaxGz = MaxGz;
}

//FOR DEBUGGING Serial.println(("MAX X=") + String(MaxGx) + (" Y=") + String(MaxGy) + (" Z=") + String(MaxGz));

//display Accel G data on OLED
oled.setCursor(0,0);
oled.clearToEOL();
oled.println("ACCEL X Y Z");
oled.setCursor(0,1);
oled.clearToEOL();
oled.setCursor(20,1);
oled.print(q.x,2);
oled.setCursor(60,1);
oled.print(q.y,2);
oled.setCursor(95,1);
oled.println(q.z,2);

//display MAX G on OLED
oled.setCursor(0,4);
oled.println("MaxG X Y Z");
oled.setCursor(0,5);
oled.clearToEOL();
oled.setCursor(20,5);
oled.print(MaxGx);
oled.setCursor(60,5);
oled.print(MaxGy);
oled.setCursor(95,5);
oled.println(MaxGz);

}
}


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2660
 

That is awesome! Good to hear you've gotten it to work, and glad I could be of help. 👍 

Yeah, not a big fan of some people on the Internet in general. There is no need to be rude, or an *sshole, when someone asks for help. Either help or shut up is my motto haha ... 😉 

I actually enjoy helping and/or discussing options, especially when it comes to electronics and/or computer stuff.
By no means am I an expert, but I do like a good challenge and I'm sure people like those egoists will have something to bitch about when it comes to how do things. 😉 

p.s. the forum isn't the best when posting code, so I tried reformatting your code a little to make it look better and I noticed that in line 131 and line 199 you may have accolades that are not needed (marked red below).
It will work fine though. Maybe a leftover of an if-then or something like that.

//
// Display Max G on OLED
// DOES NOT USE INTERRUPT
//

#include "heltec.h"
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

SSD1306AsciiWire oled;

MPU6050 mpu;

bool dmpReady = false; // set true if DMP init was successful
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

float MaxGx = 0, MaxGy = 0, MaxGz = 0;

// orientation motion variables
Quaternion q; // [w, x, y, z] quaternion container
//VectorInt16 aa; // [x, y, z] accel sensor measurements
//VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
//VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
//VectorFloat gravity; // [x, y, z] gravity vector
//float euler[3]; // [psi, theta, phi] Euler angle container
//float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector

// ==========
// === SETUP ===
// ==========

void setup() {
  Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/);
  //Heltec.display -> display();
  oled.begin(&Adafruit128x64, 0x3C, 16);
  oled.setFont(System5x7);
  oled.clear();
  oled.setCursor(15,3);
  oled.print("G-force Monitor");
  delay(1000);
  oled.clear();

  Wire.begin(); //pin 21 and 22 for ESP32
  Wire.setClock(400000); // 400kHz I2C clock

  // initialize serial monitor
  Serial.begin(115200);

  // initialize I2C devices
  Serial.println(F("Initializing I2C devices..."));
  mpu.initialize();

  // verify I2C device connection
  Serial.println(F("Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  // load and configure the DMP
  Serial.println(F("Initializing DMP..."));
  oled.setCursor(0,0);
  oled.println("Calibrate Acc/Gyro");
  devStatus = mpu.dmpInitialize();

  // supply your own gyro offsets here, scaled for min sensitivity
  mpu.setXGyroOffset(220);
  mpu.setYGyroOffset(76);
  mpu.setZGyroOffset(-85);
  mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

  // make sure it worked (returns 0 if MPU6050 working)
  if (devStatus == 0) {
    // Calibration Time: generate offsets and calibrate our MPU6050
    mpu.CalibrateAccel(6);
    mpu.CalibrateGyro(6);
    mpu.PrintActiveOffsets();
    // turn on the DMP, now that it's ready
    Serial.println(F("Enabling DMP..."));
    oled.print("Accel/Gyro Ready");
    delay(1000);
    oled.clear();
    mpu.setDMPEnabled(true);

    // set our DMP Ready flag so the main loop() function knows it's okay to use it
    Serial.println(F("DMP ready!"));
    dmpReady = true;

    // get expected DMP packet size for later comparison
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    // ERROR!
    // 1 = initial memory load failed
    // 2 = DMP configuration updates failed
    // (if it's going to break, usually the code will be 1)
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }
}

// ===================
// === MAIN PROGRAM LOOP ===
// ===================
void loop() {
  // if MPU6050nprogramming failed, don't do anything
  if (!dmpReady) return;

  // wait for MPU extra packet(s) available
  while (fifoCount < packetSize) {
    if (fifoCount < packetSize) {
      // try to get out of the infinite loop
      fifoCount = mpu.getFIFOCount();
    }
  }

  // get current FIFO count
  fifoCount = mpu.getFIFOCount();
  
  if(fifoCount < packetSize){
  }
  // check for FIFO overflow
  else if (fifoCount >= 1024) {
    // reset so we can continue cleanly
    mpu.resetFIFO();
    // fifoCount = mpu.getFIFOCount(); // will be zero after reset
    Serial.println(F("FIFO overflow!"));
  }
  { // redundant
  // read a packet from FIFO
  while(fifoCount >= packetSize){
    mpu.getFIFOBytes(fifoBuffer, packetSize);
    // track FIFO count in case there is > 1 packet available
    fifoCount -= packetSize;
  }

  // display quaternion values in easy matrix form: w x y z
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  Serial.print("ACCEL\t");
  //Serial.print(q.w);
  //Serial.print("\t");
  Serial.print(q.x);
  Serial.print("\t");
  Serial.print(q.y);
  Serial.print("\t");
  Serial.println(q.z);

  //calculate Max Accel X,Y,Z
  if (abs(q.x) > abs(MaxGx))
  {
    MaxGx = q.x;
  } else {
    MaxGx = MaxGx;
  }

  if (abs(q.y) > abs(MaxGy))
  {
    MaxGy = q.y;
  } else {
    MaxGy = MaxGy;
  }

  if (abs(q.z) > abs(MaxGz))
  {
    MaxGz = q.z;
  } else {
    MaxGz = MaxGz;
  }

  //FOR DEBUGGING Serial.println(("MAX X=") + String(MaxGx) + (" Y=") + String(MaxGy) + (" Z=") + String(MaxGz));

  //display Accel G data on OLED
  oled.setCursor(0,0);
  oled.clearToEOL();
  oled.println("ACCEL X Y Z");
  oled.setCursor(0,1);
  oled.clearToEOL();
  oled.setCursor(20,1);
  oled.print(q.x,2);
  oled.setCursor(60,1);
  oled.print(q.y,2);
  oled.setCursor(95,1);
  oled.println(q.z,2);

  //display MAX G on OLED
  oled.setCursor(0,4);
  oled.println("MaxG X Y Z");
  oled.setCursor(0,5);
  oled.clearToEOL();
  oled.setCursor(20,5);
  oled.print(MaxGx);
  oled.setCursor(60,5);
  oled.print(MaxGy);
  oled.setCursor(95,5);
  oled.println(MaxGz);

  } // redundant
}

 

Either way: apologies for the late reply (I was traveling), and thank you for the kind words, and for posting the code!! 👍 


   
ReplyQuote
 tvr4
(@tvr4)
Estimable Member
Joined: 4 years ago
Posts: 122
Topic starter  

I like how you marked the redundant code.  It does not show up very well in the notification email but it is very easy to read on the forum.  I will remove that when I add the code to write the Accelerometer data to the SD card.

I will post that when completed.  Thanks!


   
ReplyQuote


Page 1 / 7

Like what you see and you'd like to help out? 

The best way to help is of course by assisting others with their questions here in the forum, but you can also help us out in other ways:

- Do your shopping at Amazon, it will not cost you anything extra but may generate a small commission for us,
- send a cup of coffee through PayPal ($5, $10, $20, or custom amount),
- become a Patreon,
- donate BitCoin (BTC), or BitCoinCash (BCH).

Share: