I am doing a project that requires 14 GY521 IMU sensors, all interfaced through one Arduino Mega 2560. After browsing through Arduino Playground and other forum posts, it seems the only way to interface this many is to assign each AD0 to a separate digital output on the Arduino, and then set one sensor at a time to low to read each one individually. Here is my code:
#include <Wire.h> //imports Wire library
#include <MPU6050.h>
#include <Servo.h>
MPU6050 gyro; //creates new MPU6050 object
int16_t ax, ay, az; //creates angle variables
int16_t gx, gy, gz;
void setup() { //setup method
Serial.begin(9600);
Wire.begin(); //starts I2C communication
gyro.initialize(); //initializes MPU6050 sensor
for (int i = 22; i <= 35; i++) {
pinMode(i, OUTPUT); //defines pins as output pins
}
}
void loop() { //main method
for (int j = 22; j <= 35; j++) {
for (int k = 22; k <= 35; k++) {
digitalWrite(k, HIGH); //sets all sensors to high address
}
digitalWrite(j, LOW); //sets one sensor to low address
gyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //calls values from sensor
ax = map(ax, -17000, 17000, 0, 180); //maps x axis rotation values from 0 to 180
Serial.println(" ");
Serial.print(ax);
ay = map(ay, -17000, 17000, 0, 180);
Serial.print(" ");
Serial.print(ay);
az = map(az, -17000, 17000, 0, 180);
Serial.print(" ");
Serial.println(az);
}
}
For some reason I am not getting any output whatsoever when I run this program. I'm pretty sure all the sensors work, but is this the right way to go about the programming? I'm a bit new to Arduino, but it seems to me that this is the only way to go about this.
Wow, I did not realize how stupid that was. However, after I fixed that, it still does not print continuously. It prints 4 lines at most and then stops. Maybe 14 sensors is too much for I2C to take?
Attached is a basic diagram of my setup. Only 4 sensors are drawn, but it's the same setup with 14. VCC, GND, SDA, SCL are all wired in series to the Arduino. Each AD0 is attached to a different digital output.
So you're using a module with 4k7 pull up resistors.
That's a combined pull up resistance of 4700 / 14 = ~335 ohm,
while the minimum value for 3.3volt standard I2C is 1100ohm (3mA).
But wait, you're using a 5volt Arduino (Mega) for a 3.3volt module. How did you solve that.
Or did you use modules with I2C level shifters (I asked for a link to the modules you're using).
Leo..
Module seems to have a 3.3volt regulator (5-pin chip), but no level shifters on the I2C and address lines.
You might already have damaged the module(s) by connecting it to a 5volt processor.
The SDA and SCL lines have 2k2 resistors, so a combined pull up resistance of 2200/14 = 157 ohm.
I think the easiest way to solve this is with two translating (level shifting) I2C muxers.
If you go that way, you can also use a much smaller Arduino Nano/ProMini.
Leo..
The Arduino Mega 2560 has pins that can deliver 5V up to 40 mA. Pushing that into a pin of the MPU-6050 can damage it, because the MPU-6050 runs at 3.3V.
I don't like that Adafruit conversion. They remove the polyfuse. The ATmega328P can not run at 16 MHz at 3.3 V according to the datasheet. In most cases it will work though.
jremington:
What project could possibly require 14 IMUs, and even if so, why does it have to go through one Arduino? You can buy a Pro Mini on eBay for $2!
I'm making a motion tracker as input for a robotic hand. I figured it'd be easier to route all the data through one device, instead of say, 7 Pro Minis.
Wawa:
If you use a 3.3volt Arduino, then you still have the problem of the I2C pull up resistors.
You can only leave two 2k2 sets.
Leo..
I still don't understand what you mean by the I2C pull up resistors. Using 3.3V Arduino, you can set the AD0 on the sensors, no?
I still don't understand what you mean by the I2C pull up resistors.
Every sensor, and possibly also the Arduino, has a pullup resistor on each of the I2C lines. They are all in parallel, and that demands far too much current from the I/O lines.
You will have to remove both pullup resistors on at least 13 of the 14 sensors if you insist on this arrangement.
I figured it'd be easier to route all the data through one device, instead of say, 7 Pro Minis.
I'd really like to avoid using translating muxer, only as a last resort. I read on the Arduino Playground that all I have to do is connect each AD0 to a digital output:
"Using more than two MPU-6050 sensors can be achieved by connecting each of the AD0 pins to a separate output of the Arduino.
At this moment (15 July 2014) it is not known if this trick works for the MPU-6050.
Update March 25 2016: This trick is confirmed working nicely using three GY-521 breakouts along with an ESP8266 wifi/microcontroller (NodeMCU)."
The pin AD0 sets the MPU-6050 at I2C address 0x68 or 0x69.
It turns out that this is not done at power up, but AD0 can change the I2C address at any time to 0x68 or 0x69.
If all AD0 pins of all MPU-6050 chips are set HIGH (3.3V), then all the MPU-6050 chips are at I2C address 0x69.
That I2C address of 0x69 is not used at all.
The AD0 of only one MPU-6050 is turned low, and the sketch communicates via de I2C bus to I2C address 0x68.
After that, the AD0 is set HIGH, and an other MPU-6050 is selected by setting it at address 0x68.
Koepel:
The pin AD0 sets the MPU-6050 at I2C address 0x68 or 0x69.
It turns out that this is not done at power up, but AD0 can change the I2C address at any time to 0x68 or 0x69.
If all AD0 pins of all MPU-6050 chips are set HIGH (3.3V), then all the MPU-6050 chips are at I2C address 0x69.
That I2C address of 0x69 is not used at all.
The AD0 of only one MPU-6050 is turned low, and the sketch communicates via de I2C bus to I2C address 0x68.
After that, the AD0 is set HIGH, and an other MPU-6050 is selected by setting it at address 0x68.
This is what my sketch does, correct? So, if I convert my Arduino to 3.3V, it should theoretically be able to work, right?
void setup() { // setup method
Serial.begin(9600);
Wire.begin(); //starts I2C communication
for (int i = 22; i <= 35; i++) {
pinMode(i, OUTPUT); // defines pins as output pins
digitalWrite( i, HIGH); // park the sensor at 0x69
}
for (int i = 22; i <= 35; i++) {
digitalWrite( i, LOW); // set this sensor at 0x68
gyro.initialize(); //initializes MPU6050 sensor at 0x68
digitalWrite( i, HIGH); // park this sensor at 0x69
}
}
void loop() { //main method
for (int i = 22; i <= 35; i++) {
digitalWrite( i, LOW); // set this sensor at 0x68
gyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //calls values from sensor at 0x68
digitalWrite( i, HIGH); // park this sensor at 0x69
ax = map(ax, -17000, 17000, 0, 180); //maps x axis rotation values from 0 to 180
...
I don't know which library you use, but I assume that gyro.initialize has to be done for every sensor.