Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

multiple tinyMPU6050 #23

Closed
jorritxl opened this issue Jul 25, 2020 · 5 comments
Closed

multiple tinyMPU6050 #23

jorritxl opened this issue Jul 25, 2020 · 5 comments
Labels
question Further information is requested

Comments

@jorritxl
Copy link

Hello Gabriel,

How can I edit the library or my own arduino code to access 2 MPU6050's (0x68 and 0x69) while using the tinyMPU6050 libary?

Thankx

@gabriel-milan
Copy link
Owner

Hi @jorritxl thanks for writing.

You do not need to edit anything. You can use the constructor as follows:

MPU6050 (TwoWire &w, int i2cAddress = MPU6050_ADDRESS);

As you can see, the i2cAddress parameter is optional, but you can set it to either 0x68 or 0x69. That way, you can have two MPU6050 objects, which you can manage separately. Just remember to call the Execute method for both of them in this case.

If you need further help, please let me know.

@jorritxl
Copy link
Author

Thanks for the fast response!

Unfortunately, I am not able to fully understand your answer.

This is the code which I want to convert to do the same for 2 MPU's at the same time:

/*

  • Mandatory includes
    */
    #include <Arduino.h>
    #include <TinyMPU6050.h>

/*

  • Constructing MPU-6050
    */

MPU6050 mpu (Wire);
float myNum[200];
float sampleSum = 0;
int SAMPLES = 199;

/*

  • Setup
    */
    void setup() {

// Initialization
mpu.Initialize();

// Calibration
Serial.begin(9600);
Serial.println("=====================================");
Serial.println("Starting calibration...");
mpu.Calibrate();
Serial.println("Calibration complete!");
Serial.println("Offsets:");
Serial.print("GyroX Offset = ");
Serial.println(mpu.GetGyroXOffset());
Serial.print("GyroY Offset = ");
Serial.println(mpu.GetGyroYOffset());
Serial.print("GyroZ Offset = ");
Serial.println(mpu.GetGyroZOffset());
}

/*

  • Get sensor data
    */
    void loop() {
    for(int i = 0; i < SAMPLES; i++){
    mpu.Execute();
    myNum[i] = mpu.GetAngX();
    sampleSum += myNum[i];
    //Serial.println(myNum[i]);
    delay(20);
    }

/*

  • Get statistics every x reading
    */
    float meanSample = sampleSum/float(SAMPLES);

float sqDevSum = 0.0;

for(int i = 0; i < SAMPLES; i++) {
// pow(x, 2) is x squared.
sqDevSum += pow((meanSample - float(myNum[i])), 2);
}

float stDev = sqrt(sqDevSum/float(SAMPLES));
Serial.print("stdev:");
Serial.println(stDev, 4);
Serial.print("mean: ");
Serial.println(meanSample, 4);
Serial.println("------");

sampleSum = 0;
sqDevSum = 0.0;
meanSample = 0;

}

I tried to replace
MPU6050 mpu (Wire);
into
MPU6050 mpu1 (TwoWire &w, int i2cAddress = 0x68);
MPU6050 mpu2 (TwoWire &w, int i2cAddress = 0x69);

But I get an error.

Can you tell me how I can make it work?

Thankx

@gabriel-milan
Copy link
Owner

gabriel-milan commented Jul 25, 2020

Markdown formatting tip

Whenever you write code on your issue, please wrap it using three backticks, like this:

```
my_code_goes_here
```

That way, it gets more readable. The output would be this:

my_code_goes_here

Anyway, let's now focus on your issue.

TL;DR

  • Replace
MPU6050 mpu (Wire);

with

MPU6050 mpu0 (Wire, 0x68);
MPU6050 mpu1 (Wire, 0x69);
  • Call both mpu0.Initialize();mpu0.Calibrate(); and mpu1.Initialize();mpu1.Calibrate(); on setup

  • Whenever you used to call mpu.Execute(), call mpu0.Execute();mpu1.Execute();

  • Your code will look like that thing on the end of this answer.

Full explanation

The constructor I've shown previously:

MPU6050 (TwoWire &w, int i2cAddress = MPU6050_ADDRESS);

is only shown for better understanding of the parameters passed when constructing the MPU6050 object.
On your original code, you said you had this:

MPU6050 mpu (Wire);

which maps onto the constructor &w = Wire and i2cAddress = null, which would then be mapped as i2cAddress = 0x68, which is the default value for MPU6050_ADDRESS set on the library header.

If you want to construct an object using that constructor I've shown, you'll need something like this:

MPU6050 mpu0 (Wire, 0x68);
MPU6050 mpu1 (Wire, 0x69);

That way, for both of them, &w will be assigned to Wire, and that's correct, but the i2cAddress will be different on each of them, meaning that for mpu0 we'll communicate through I²C address 0x68 and for mpu1 we'll do it through 0x69, which is what you want.

But then remember that, for each method you'd call on mpu, on your original code (e.g. mpu.Initialize()) , you'd need to do it for both of mpu0 and mpu0. Please note that (assuming you're using Arduino IDE), on setup, you'll need to call both Initialize and Calibrate methods and, on loop, you'll need to call Execute` so values we'll get updated.

Finally, your code would look like this:

/*
 * Mandatory includes
 */
#include <Arduino.h>
#include <TinyMPU6050.h>

/*
 *	Constant values
 */
#define MPU6050_ADDRESS_ZERO  0x68
#define MPU6050_ADDRESS_ONE   0x69

/*
 * Constructing MPU-6050
 */
MPU6050 mpu0 (Wire, MPU6050_ADDRESS_ZERO);
MPU6050 mpu1 (Wire, MPU6050_ADDRESS_ONE);

float myNum[200];
float sampleSum = 0;
int SAMPLES = 199;

/*
 * Setup
 */
void setup() {

  // Initialization
  mpu0.Initialize();
  mpu1.Initialize();

  // Calibration
  Serial.begin(9600);
  Serial.println("=====================================");
  Serial.println("Calibrating device #0...");
  mpu0.Calibrate();
  Serial.println("Calibrating device #1...");
  mpu1.Calibrate();
  Serial.println("Calibration complete!");

  // I've removed printing offsets for shorting the code
}

/*
 * Get sensor data
 */
void loop() {

  for(int i = 0; i < SAMPLES; i++){
    mpu0.Execute();
    mpu1.Execute();
    // TODO> Please set here from which MPU device you'd like to extract data
    // myNum[i] = mpuX.GetAngX();
    // sampleSum += myNum[i];
    delay(20);
  }
	
  /*
   * Get statistics every x reading
   */
  float meanSample = sampleSum/float(SAMPLES);
  float sqDevSum = 0.0;

  for(int i = 0; i < SAMPLES; i++) {
    // pow(x, 2) is x squared.
    sqDevSum += pow((meanSample - float(myNum[i])), 2);
  }

  float stDev = sqrt(sqDevSum/float(SAMPLES));
  Serial.print("stdev:");
  Serial.println(stDev, 4);
  Serial.print("mean: ");
  Serial.println(meanSample, 4);
  Serial.println("------");

  sampleSum = 0;
  sqDevSum = 0.0;
  meanSample = 0;
}

@gabriel-milan gabriel-milan added the question Further information is requested label Jul 25, 2020
@gabriel-milan gabriel-milan pinned this issue Jul 25, 2020
@jorritxl
Copy link
Author

I'd like to thank you for your help Gabriel! Fully understood.

When you have the time, continue reading otherwise, don't bother.

Another question about the complimentary filtering out of curiosity:

I found the following lines which are about the filtering:
,,,
angX = angle_average(filterAccelCoeff, angAccX, filterGyroCoeff, angX + gyroX * dt);

static float angle_average(float wa, float a, float wb, float b)
{
return wrap(wa * a + wb * (a + wrap(b-a)));
}
,,,

Can you explain how these lines are increasing the accuracy of the MPU6050?

Thanx

@gabriel-milan
Copy link
Owner

Glad I could help with that.

Now answering your other question, the angle_average function refers to the PR #14. The function itself is not related to accuracy.

On the other hand, when you do

angX = angle_average(filterAccelCoeff, angAccX, filterGyroCoeff, angX + gyroX * dt);

you're averaging the angle computed using the accelerometer data (angAccX) and the angle computed as the integration of angular velocity data over time (angX + gyroX * dt). This happens to increase the accuracy of the angles computation due to the very solid concept of a complementary filter.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants