For a school project I have to get the acceleration and the filtered angle data from the acc+gyro (GY-521) sensor send through my Arduino nano v3 to my laptop (macbook with lion - OSX 10.7.5) into Excel to analyze them. Today (for a quick test) I was hoping to let Processing create a simple CSV with the x-accelerations in there, one on each row, but I can't get it to work... I have tried many things, but all of them didn't gave me the ouput I wanted. The Processing sketch does make the CSV file, but it's empty! It drives me nuts..
Can somebody help me?
Thanks!
This is the Processing sketch I used:
import processing.serial.*; Serial mySerial; PrintWriter output; int accel_x; void setup() { mySerial = new Serial( this, "/dev/cu.usbserial-AM02744T", 19200 ); output = createWriter( "documents/datalauran.txt" ); } void draw() { if (mySerial.available() > 0 ) { String value = mySerial.readString(); if ( value != null ) { output.println(accel_x); } } } void keyPressed() { output.flush(); // Writes the remaining data to the file output.close(); // Finishes the file exit(); // Stops the program }
And this is the Arduino sketch (I had to cut out a piece because else it was too long) I used:
// MPU-6050 Accelerometer + Gyro // ----------------------------- // // By arduino.cc user "Krodal". // June 2012 // Open Source / Public Domain // // Using Arduino 1.0.1 // It will not work with an older version, // since Wire.endTransmission() uses a parameter // to hold or release the I2C bus. // // Documentation: // - The InvenSense documents: // - "MPU-6000 and MPU-6050 Product Specification", // PS-MPU-6000A.pdf // - "MPU-6000 and MPU-6050 Register Map and Descriptions", // RM-MPU-6000A.pdf or RS-MPU-6000A.pdf // - "MPU-6000/MPU-6050 9-Axis Evaluation Board User Guide" // AN-MPU-6000EVB.pdf // // The accuracy is 16-bits. // // Temperature sensor from -40 to +85 degrees Celsius // 340 per degrees, -512 at 35 degrees. // //------PIECE CUT OUT BECAUSE IT WAS TOO LONG--------//
// // Declaring an union for the registers and the axis values. // The byte order does not match the byte order of // the compiler and AVR chip. // The AVR chip (on the Arduino board) has the Low Byte // at the lower address. // But the MPU-6050 has a different order: High Byte at // lower address, so that has to be corrected. // The register part "reg" is only used internally, // and are swapped in code. typedef union accel_t_gyro_union { struct { uint8_t x_accel_h; uint8_t x_accel_l; uint8_t y_accel_h; uint8_t y_accel_l; uint8_t z_accel_h; uint8_t z_accel_l; uint8_t t_h; uint8_t t_l; uint8_t x_gyro_h; uint8_t x_gyro_l; uint8_t y_gyro_h; uint8_t y_gyro_l; uint8_t z_gyro_h; uint8_t z_gyro_l; } reg; struct { int x_accel; int y_accel; int z_accel; int temperature; int x_gyro; int y_gyro; int z_gyro; } value; };
// Use the following global variables and access functions to help store the overall // rotation angle of the sensor unsigned long last_read_time; float last_x_angle; // These are the filtered angles float last_y_angle; float last_z_angle; float last_gyro_x_angle; // Store the gyro angles to compare drift float last_gyro_y_angle; float last_gyro_z_angle;
// Use the following global variables and access functions // to calibrate the acceleration sensor float base_x_accel; float base_y_accel; float base_z_accel;
int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) { // Read the raw values. // Read 14 bytes at once, // containing acceleration, temperature and gyro. // With the default settings of the MPU-6050, // there is no filter enabled, and the values // are not very stable. Returns the error value
int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro));
// Swap all high and low bytes. // After this, the registers values are swapped, // so the structure name like x_accel_l does no // longer contain the lower byte. uint8_t swap; #define SWAP(x,y) swap = x; x = y; y = swap
// The sensor should be motionless on a horizontal surface // while calibration is happening void calibrate_sensors() { int num_readings = 10; float x_accel = 0; float y_accel = 0; float z_accel = 0; float x_gyro = 0; float y_gyro = 0; float z_gyro = 0; accel_t_gyro_union accel_t_gyro;
//Serial.println("Starting Calibration");
// Discard the first set of values read from the IMU read_gyro_accel_vals((uint8_t *) &accel_t_gyro);
// Read and average the raw values from the IMU for (int i = 0; i < num_readings; i++) { read_gyro_accel_vals((uint8_t *) &accel_t_gyro); x_accel += accel_t_gyro.value.x_accel; y_accel += accel_t_gyro.value.y_accel; z_accel += accel_t_gyro.value.z_accel; x_gyro += accel_t_gyro.value.x_gyro; y_gyro += accel_t_gyro.value.y_gyro; z_gyro += accel_t_gyro.value.z_gyro; delay(100); } x_accel /= num_readings; y_accel /= num_readings; z_accel /= num_readings; x_gyro /= num_readings; y_gyro /= num_readings; z_gyro /= num_readings;
// Store the raw calibration values globally base_x_accel = x_accel; base_y_accel = y_accel; base_z_accel = z_accel; base_x_gyro = x_gyro; base_y_gyro = y_gyro; base_z_gyro = z_gyro;
//Serial.println("Finishing Calibration"); }
void setup() { int error; uint8_t c;
Serial.begin(19200); /* Serial.println(F("InvenSense MPU-6050")); Serial.println(F("June 2012")); */ // Initialize the 'Wire' class for the I2C-bus. Wire.begin();
// default at power-up: // Gyro at 250 degrees second // Acceleration at 2g // Clock source at internal 8MHz // The device is in sleep mode. //
// According to the datasheet, the 'sleep' bit // should read a '1'. But I read a '0'. // That bit has to be cleared, since the sensor // is in sleep mode at power-up. Even if the // bit reads '0'. error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1); /* Serial.print(F("PWR_MGMT_2 : ")); Serial.print(c,HEX); Serial.print(F(", error = ")); Serial.println(error,DEC); */
// Clear the 'sleep' bit to start the sensor. MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);
// The temperature sensor is -40 to +85 degrees Celsius. // It is a signed integer. // According to the datasheet: // 340 per degrees Celsius, -512 at 35 degrees. // At 0 degrees: -512 - (340 * 35) = -12412 /* Serial.print(F("temperature: ")); dT = ( (double) accel_t_gyro.value.temperature + 12412.0) / 340.0; Serial.print(dT, 3); Serial.print(F(" degrees Celsius")); Serial.println(F(""));
// Apply the complementary filter to figure out the change in angle - choice of alpha is // estimated now. Alpha depends on the sampling rate... float alpha = 0.96; float angle_x = alpha*gyro_angle_x + (1.0 - alpha)*accel_angle_x; float angle_y = alpha*gyro_angle_y + (1.0 - alpha)*accel_angle_y; float angle_z = gyro_angle_z; //Accelerometer doesn't give z-angle
// Update the saved data with the latest values set_last_read_angle_data(t_now, angle_x, angle_y, angle_z, unfiltered_gyro_angle_x, unfiltered_gyro_angle_y, unfiltered_gyro_angle_z);
// Send the data to the serial port /* Serial.print(F("DEL:")); //Delta T Serial.print(dt, DEC); Serial.print(F("#ACC:")); //Accelerometer angle Serial.print(accel_angle_x, 2); Serial.print(F(",")); Serial.print(accel_angle_y, 2); Serial.print(F(",")); Serial.print(accel_angle_z, 2); Serial.print(F("#GYR:")); Serial.print(unfiltered_gyro_angle_x, 2); //Gyroscope angle Serial.print(F(",")); Serial.print(unfiltered_gyro_angle_y, 2); Serial.print(F(",")); Serial.print(unfiltered_gyro_angle_z, 2); Serial.print(F("#FIL:")); //Filtered angle Serial.print(angle_x, 2); Serial.print(F(",")); Serial.print(angle_y, 2); Serial.print(F(",")); Serial.print(angle_z, 2); Serial.println(F("")); */
Serial.println(accel_x, 2);
// Delay so we don't swamp the serial port delay(500); }
// -------------------------------------------------------- // MPU6050_read // // This is a common function to read multiple bytes // from an I2C device. // // It uses the boolean parameter for Wire.endTransMission() // to be able to hold or release the I2C-bus. // This is implemented in Arduino 1.0.1. // // Only this function is used to read. // There is no function for a single byte. // int MPU6050_read(int start, uint8_t *buffer, int size) { int i, n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS); n = Wire.write(start); if (n != 1) return (-10);
n = Wire.endTransmission(false); // hold the I2C-bus if (n != 0) return (n);
// Third parameter is true: relase I2C-bus after data is read. Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true); i = 0; while(Wire.available() && i<size) { buffer[i++]=Wire.read(); } if ( i != size) return (-11);
return (0); // return : no error }
// -------------------------------------------------------- // MPU6050_write // // This is a common function to write multiple bytes to an I2C device. // // If only a single register is written, // use the function MPU_6050_write_reg(). // // Parameters: // start : Start address, use a define for the register // pData : A pointer to the data to write. // size : The number of bytes to write. // // If only a single register is written, a pointer // to the data has to be used, and the size is // a single byte: // int data = 0; // the data to write // MPU6050_write (MPU6050_PWR_MGMT_1, &c, 1); // int MPU6050_write(int start, const uint8_t *pData, int size) { int n, error;
Wire.beginTransmission(MPU6050_I2C_ADDRESS); n = Wire.write(start); // write the start address if (n != 1) return (-20);
n = Wire.write(pData, size); // write data bytes if (n != size) return (-21);
error = Wire.endTransmission(true); // release the I2C-bus if (error != 0) return (error);
return (0); // return : no error }
// -------------------------------------------------------- // MPU6050_write_reg // // An extra function to write a single register. // It is just a wrapper around the MPU_6050_write() // function, and it is only a convenient function // to make it easier to write a single register. // int MPU6050_write_reg(int reg, uint8_t data) { int error;