#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif #include MPU6050 mpu; Servo servo0; Servo servo1; Servo servo2; float correct; int j = 0; int joyX = 0; int joyY = 1; float joyVal1 = 0; float joyVal2 = 0; float finalVal1 = 0; float finalVal2 = 0; #define OUTPUT_READABLE_YAWPITCHROLL #define INTERRUPT_PIN 2 bool blinkState = false; // 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 // orientation/motion vars Quaternion q; // [w, x, y, z] quaternion container VectorInt16 aa; // [x, y, z] accel sensor measurements VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements VectorFloat gravity; // [x, y, z] gravity vector float euler[3]; // [psi, theta, phi] Euler angle container float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector // packet structure for InvenSense teapot demo uint8_t teapotPacket[14] = { '$', 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, '\r', '\n' }; // ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high void dmpDataReady() { mpuInterrupt = true; } // ================================================================ // === INITIAL SETUP === // ================================================================ void setup() { // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.begin(38400); while (!Serial); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT); devStatus = mpu.dmpInitialize(); // supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(17); mpu.setYGyroOffset(-69); mpu.setZGyroOffset(27); mpu.setZAccelOffset(1551); if (devStatus == 0) { mpu.CalibrateAccel(6); mpu.CalibrateGyro(6); mpu.PrintActiveOffsets(); mpu.setDMPEnabled(true); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); dmpReady = true; packetSize = mpu.dmpGetFIFOPacketSize(); } servo0.attach(10); servo1.attach(9); servo2.attach(8); } // ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ void loop() { if (!dmpReady) return; while (!mpuInterrupt && fifoCount < packetSize) { if (mpuInterrupt && fifoCount < packetSize) { fifoCount = mpu.getFIFOCount(); } } mpuInterrupt = false; mpuIntStatus = mpu.getIntStatus(); fifoCount = mpu.getFIFOCount(); if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 2048) { // reset so we can continue cleanly mpu.resetFIFO(); fifoCount = mpu.getFIFOCount(); Serial.println(F("FIFO overflow!")); // otherwise, check for DMP data ready interrupt (this should happen frequently) } else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) { // 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; // Get Yaw, Pitch and Roll values #ifdef OUTPUT_READABLE_YAWPITCHROLL mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); // Yaw, Pitch, Roll values - Radians to degrees ypr[0] = ypr[0] * 180 / M_PI; ypr[1] = ypr[1] * 180 / M_PI; ypr[2] = ypr[2] * 180 / M_PI; // Skip 300 readings (self-calibration process) if (j <= 300) { correct = ypr[0]; // Yaw starts at random value, so we capture last value after 300 readings j++; } // After 300 readings else { ypr[0] = ypr[0] - correct; int servo0Value = map(ypr[0], -90, 90, 0, 180); int servo1Value = map(ypr[1], -90, 90, 0, 180); int servo2Value = map(ypr[2], -90, 90, 180, 0); if (analogRead(joyY) >= 550 && finalVal1 < 180) { joyVal1 += 0.5; } if (analogRead(joyY) <= 470 && finalVal1 > 32) { joyVal1 -= 0.5; } //Serial.println(servoVal1); if (analogRead(joyX) >= 550 && finalVal2 > 0) { joyVal2 -= 0.5; } if (analogRead(joyX) <= 470 && finalVal2 < 180) { joyVal2 += 0.5; } finalVal1 = servo0Value + joyVal1; finalVal2 = servo1Value + joyVal2; servo0.write(finalVal1); servo1.write(finalVal2); servo2.write(servo2Value); delay(5); } #endif } }