Since there is a growing demand to know how to use the MPU6050, instead of sending PM to fellow lightsaber builders, I give you here some hints how I use it in my lightsaber. If you integrate this code into your code, it's gonna work.
First of all what modules to include and global vars to be declared:
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
// or the next one, should be equivalent
//#include "MPU6050.h"
#include <stdlib.h>
#include <SoftwareSerial.h>
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 accelgyro;
// calibrated acc/gyro values
int16_t ax_zero, ay_zero, az_zero;
int16_t gx_zero, gy_zero, gz_zero;
// acc/gyro values of the previous cycle
int16_t ax_prev, ay_prev, az_prev;
int16_t gx_prev, gy_prev, gz_prev;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
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
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
// uncomment "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated
// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
// not so easy to parse, and slow(er) over UART.
#define OUTPUT_READABLE_ACCELGYRO
Then in the void setup():
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = accelgyro.dmpInitialize();
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
accelgyro.setDMPEnabled(true);
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
//packetSize = accelgyro.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(")"));
}
Here in the setup you can also experiment with some of the advanced options (use at your own risk, this section of the code is not fully verified).
// motion engine configuration
accelgyro.setFullScaleGyroRange(0); //0-250deg/s | 1-500deg/s | 2-1000deg/s | 3-2000deg/s
accelgyro.setFullScaleAccelRange(1); //0-2g | 1-4g | 2-8g | 3-16g
// INT_PIN_CFG register
// in the working code of MPU6050_DMP all bits of the INT_PIN_CFG are false (0)
accelgyro.setInterruptMode(false); // INT_PIN_CFG register INT_LEVEL (0-active high, 1-active low)
accelgyro.setInterruptDrive(false); // INT_PIN_CFG register INT_OPEN (0-push/pull, 1-open drain)
accelgyro.setInterruptLatch(false); // INT_PIN_CFG register LATCH_INT_EN (0 - emits 50us pulse upon trigger, 1-pin is held until int is cleared)
accelgyro.setInterruptLatchClear(false); // INT_PIN_CFG register INT_RD_CLEAR (0-clear int only on reading int status reg, 1-any read clears int)
accelgyro.setFSyncInterruptLevel(false);
accelgyro.setFSyncInterruptEnabled(false);
accelgyro.setI2CBypassEnabled(false);
// set up interrupt sources
accelgyro.setIntFreefallEnabled(false);
accelgyro.setIntMotionEnabled(true);
accelgyro.setIntZeroMotionEnabled(false);
accelgyro.setIntFIFOBufferOverflowEnabled(false);
accelgyro.setIntI2CMasterEnabled(false);
accelgyro.setIntDataReadyEnabled(false);
accelgyro.setIntMotionEnabled(true); // INT_ENABLE register enable interrupt source motion detection
accelgyro.setMotionDetectionThreshold(10); // 1mg/LSB
accelgyro.setMotionDetectionDuration(2); // number of consecutive samples above threshold to trigger int
mpuIntStatus = accelgyro.getIntStatus();
Then finally in each loop (only MPU related code included, all the rest removed):
int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t accgyro_temp[6];
else { // motion engine actions
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
accgyro_temp[0]=ax;
accgyro_temp[1]=ay;
accgyro_temp[2]=az;
accgyro_temp[3]=gx;
accgyro_temp[4]=gy;
accgyro_temp[5]=gz;
ax = ax- ax_prev;
ay = ay- ay_prev;
az = az- az_prev;
gx = gx- gx_prev;
gy = gy- gy_prev;
gz = gz- gz_prev;
ax_prev=accgyro_temp[0];
ay_prev=accgyro_temp[1];
az_prev=accgyro_temp[2];
gx_prev=accgyro_temp[3];
gy_prev=accgyro_temp[4];
gz_prev=accgyro_temp[5];
// ************************* blade movement detection ************************************
if ((abs(ax) > 1000 or abs(ay) > 1000 or (az) > 1000)) { is there any movement to trigger motion detection
if ((abs(ax) > 4000 or abs(ay) > 4000 or (az) > 4000)) { // threshold for Clash (values depend on Acceleration Range used!!!)
if (SupressCounter >= 3) {
if (verboseprint) {Serial.println("Clash") ;}
Sound_PlayClash(SoundFontIdx);
}
}
else {
if (SupressCounter >= 30) {
if (verboseprint) {Serial.println("Swing");}
Sound_PlaySwing(SoundFontIdx);
}
}
}
else {
if (verboseprint) {Serial.println(F("\nNo activity, continue hum"));}
}
// ************************* blade movement detection ends************************************
I hope it helps. Good luck with coding and experimenting.