I know this is long, but I've tried to be as transparent as I can so please read and give me your thoughts!
I'm pretty much a beginner to Arduino coding etc and I'm trying to combine the DMP functions of the MPU6050 accelerometer/gyroscope (GY-521 breakout board) with an SD shield bought from Adafruit (Model Adafruit Assembled Data Logging shield for Arduino : ID 1141 : $13.95 : Adafruit Industries, Unique & fun DIY electronics and kits) and a simple momentary push button in order to make a simple datalogging device. I am attempting this by combining the standard SD card libraries and code with Jeff Rowberg's DMP libraries and some of my own code using an ARDUINO MEGA 2560.
Those familiar with Jeff Rowberg's DMP code will recognise what I have posted below. I have tried to simplify it as much as possible by removing the compiler if statements and a lot of the comments. It is essentially the same code there, with the addition of some integers to perform the Yaw/Pitch/ Roll calculations before printing in case that helped stop slowing things up and causing problems.
What I want it to do:
Push the button , the program creates a new file of name "SET_XX", where XX increments from 01 upwards and data is saved from the accelerometer to that file.
Press the button again (or in this case a separate button) that stops the stream of data to the file and closes it.
Repeat
How I've tried to do this:
Create a sub-routine, where I have put most of Jeff Rowberg's code. The accel/gyro values are collected and saved to the dataFile here. This was done to clear things up visually.
Use the buttons to switch between two loops, the "Start button loop", where the program looks for the start button to be pressed, and the "Stop button loop" where the program records values and looks for the stop button to be pressed.
It's simple in concept, but something hasn't been working correctly and it's been giving me a nightmare for the last few weeks. The problem is almost certainly with the incorporation of the SD card writing and closing with the MPU6050.
What the main problems are:
In the code shown below, there are FIFO buffer "overload" statements being thrown out from time to time. There also seems to be a link between the FIFO overload and the additional debug LED staying on a little longer every once in a while as described in the notes at the bottom. I have tried to solve this by reducing the rate in which the DMP produces information by modifying a value in the "MPU6050_6Axis_MotionApps20.h" as Jeff Rowberg himself instructs. This doesn't seem to have any effect, despite saving the library and restarting the Arduino IDE.
This problem of clogging etc could be linked to the time taken for the SD card shield to write the data to the SD card and the interrupt fired by the accelerometer. I have put 200ms delays after the dataFile.print() to attempt to give the SD card more time to write but it hasn't changed anything and I don't like the idea of it. In my mind the interrupt will fire at the same time regardless and the delaying of the SD card write will only overload the FIFO buffer more. I don't have much experience with this, so please feel free to comment. NOTE: If I change the dataFile.print() to the original Serial.print() then everything seems to work fine without clogging/ overloading etc.
The button is pressed to stop the flow of data to the SD card by breaking from the "Stop loop". The serial monitor displays all of the statements meant for debugging to say it is out of the loop and that the file has been correctly closed, but when the "ON" button is pressed a second time to open a second file it jumps to the loop "error creating file". When inspecting the file on the SD card, the first file has been created but with 0mb contents. This suggests that data was written to the file, but the file was not properly closed, and as a result the File Allocation Table was not created, despite the positive statements from the serial monitor debugging. I have found that the "SD" LED of the shield sticks on; this is the indication that if I press the OPEN button an error will occur- this could show that something is happening or sticking at the SD card side of things.
Disclaimer: I have programs that have the exact code for pressing the button and creating new files without the addition of the accelerometer. This works fine and saves many incrementing filenames with a set few lines inside.
After a while, the entire system freezes. No data is saved to the particular file and I have to close and reopen SerialMonitor to begin again. Simply pressing the reset button on the Arduino does not un-freeze it.
There are a number of problems here, I understand. They are probably not cause by one single error in the code but if anyone has any pointers or thoughts at all I'd be happy to hear them. I'm sure there are some inefficiencies in my code because I'm a beginner, but I won't take offence at anyone pointing these out.
Thanks in advance,
CR
A couple of notes before reading the code below:
It may seem nonsensical to define the pins 10-13 as inputs. The SPI pins of the Adafruit datalogging shield are hardwired to use the SPI pins of an Arduino UNO. For MEGA boards, the 'hard' SPI pins are instead 50-53. Adafruit encourage you to replace the normal SD library with another called SD-master, which uses software to re-assign these pins. This works very well. Thinking it could potentially be causing a conflict somewhere, I defined the pins 10-13 as inputs and have physically connected the 'hard' SPI pins, 50-53 of the MEGA to pins 10-13. It turns out that there is no difference in performance, so I will change it back, but I have kept the code this way so that any UNO users can still use their original libraries if they were kind enough to copy and check my code at all.
This code includes two buttons to prevent ambiguity in on/off signals. Originally a debounce routine was implemented here and one button was used. This worked fine, but to reduce potential sources of error I took it out and replaced it with a second button.
There is also an LED connected to DI/O pin 6 that acts as a bit of a debugger to see when things are being clogged up. Normally it should flicker at the same rate as values are recorded. Every so often something clogs in the Yaw/Pitch/Roll calculation and it momentarily stays on for longer than usual. In the end I'd like to have all four sets of values streaming to SD at once, but for to keep things simple for the time being, I have commented all but YPR out.
void stop_button_loop()
{
while(1)
{
accelerometer_data_capture(); // Loop the datacollect and save to SD
if (digitalRead(3) == HIGH) // If OFF button is pressed
{
delay(1000);
mpu.resetFIFO(); // Reset FIFO buffer to start clean again
Serial.println("Stopped recording");
delay(1000);
Serial.println("Exiting Stop Loop");
break;
}
}
Serial.println("Out of Stop loop and closing file");
dataFile.close(); //Close and 'save' file to FAT
if (dataFile) //If dataFile happens to stil be open
{
Serial.println("Current File not closed");
dataFile.close();
}
Serial.println("file closed");
}
void accelerometer_data_capture() //Simplified Jeff Rowberg DMP Code
{
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024)
{
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
}
else if (mpuIntStatus & 0x02)
{
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
/*
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
*/
// display ypr
digitalWrite(6, HIGH); // Turn on debug LED
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
yaw = (ypr[0] * 180/M_PI);
pitch = (ypr[1] * 180/M_PI);
roll = (ypr[2] * 180/M_PI);
// Serial.println("Taking YPR");
dataFile.print("ypr\t");
dataFile.print(yaw);
dataFile.print("\t");
dataFile.print(pitch);
dataFile.print("\t");
dataFile.println(roll);
digitalWrite(6, LOW); // Turn off debug LED
/*
// display real acceleration, adjusted to remove gravity
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
Serial.print("areal\t");
Serial.print(aaReal.x);
Serial.print("\t");
Serial.print(aaReal.y);
Serial.print("\t");
Serial.println(aaReal.z);
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
*/
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState); // blink the SD LED while recording
}
}
Hi Crud9,
Were you able to resolve this issue? I am facing the same issue(FIFO overflow and then subsequent hang after 2-3 minutes) with GY-521 on Arduino UNO and I am stuck as to how to proceed?
It seems that, from my experiments, this has something more to do with the serial buffer. If you print more than 55 characters in Serial.print (); using the MPU6050 and the SDCard, stack overflow errors occur. Limit the buffer to 55 using the snprintf(); function; instead of Serial.print(); directly. Or make the serial output divided by 55 if your serial output is more than 55 per line.