3 Axis Mobile Gimbal

 

 Connection Diagram 

                  Code 

    /* 


 * A 3D printed DIY gimbal - fitted with 3 FS90 Micro servo motors - is controlled using an MPU6050 


 * inertial measurement unit (IMU) sensor in order to keep 3D printed platform stable during rotation in 


 * any axis. 


 * 


 * All of these components are connected to an Arduino Nano and powered via a 9V battery - stepped down 


 * to 5V using a buck converter.


 * 


 */




#include "I2Cdev.h"


#include "MPU6050_6Axis_MotionApps20.h"


#include "Wire.h"


#include <Servo.h>




// MPU control/status variables


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


int16_t rawValue[6]; // Raw sensor values for accelerometer and gyroscope for each axis: {ax, ay, az, gx, gy, gz}




// Orientation/motion variables


Quaternion q; // [w, x, y, z] Quaternion container


VectorFloat gravity; // [x, y, z] Gravity vector


float ypr[3]; // [yaw, pitch, roll] Yaw/pitch/roll container and gravity vector




// Interrupt detection routine


volatile bool mpuInterrupt = false; // Indicates whether MPU interrupt pin has gone high


void dmpDataReady() {


    mpuInterrupt = true;


}




#define INTERRUPT_PIN 2  


MPU6050 accelgyro; // Instantiate an MPU6050 object




// Servo definitions


Servo servoYaw;


Servo servoPitch;


Servo servoRoll;




void setup() {


  


  // Initialize Wire library and join i2c bus


  Wire.begin();


  Wire.setClock(400000); 


 


  // Initialize serial communication


  Serial.begin(38400);




  // Initialize device


  Serial.println(F("Initializing I2C devices..."));


  accelgyro.initialize();


  pinMode(INTERRUPT_PIN, INPUT);




  // Verify connection


  Serial.println(F("Testing device connections..."));


  Serial.println(accelgyro.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));




  // Load and configure the DMP


  Serial.println(F("Initializing DMP..."));


  devStatus = accelgyro.dmpInitialize();




  // Set device offsets obtained from mpu6050_offsets.ino sketch


  accelgyro.setXGyroOffset(-203);//-203


  accelgyro.setYGyroOffset(-95); //-95


  accelgyro.setZGyroOffset(-48); //-48


  accelgyro.setZAccelOffset(1933); //1933


  


  // Make sure it worked (returns 0 if so)


  if (devStatus == 0) {


    


    // Calibrate and fine tune MPU6050 with the offsets set above


    accelgyro.CalibrateAccel(6);


    accelgyro.CalibrateGyro(6);


    accelgyro.PrintActiveOffsets();


    


    // Turn on the DMP, now that it's ready


    Serial.println(F("Enabling DMP..."));


    accelgyro.setDMPEnabled(true);




    // Enable Arduino interrupt detection


    Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));


    Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));


    Serial.println(F(")..."));


    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);


    mpuIntStatus = accelgyro.getIntStatus();




    // 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(")"));


  }




  // Attach servos to digital pins


  servoYaw.attach(5);


  servoPitch.attach(10);


  servoRoll.attach(4);


}




void loop() {




  // If programming failed, don't try to do anything


  if (!dmpReady) return;


  


  // Read latest packet from FIFO buffer


  if (accelgyro.dmpGetCurrentFIFOPacket(fifoBuffer)) {


    


    // Obtain quaternion values from buffer


    accelgyro.dmpGetQuaternion(&q, fifoBuffer);


    accelgyro.dmpGetGravity(&gravity, &q);


    


    // Convert quaternion to ypr angles


    accelgyro.dmpGetYawPitchRoll(ypr, &q, &gravity);




    // Read raw accel/gyro measurements from device


    accelgyro.getMotion6(&rawValue[0], &rawValue[1], &rawValue[2], &rawValue[3], &rawValue[4], &rawValue[5]);




    // Printout raw accel/gyro measurements after sensor calibration


    Serial.println("\nSensor values after calibration");


    Serial.println("-------------------------------");


    Serial.print("az: ");


    Serial.print(rawValue[2]); Serial.print("\n");


    Serial.print("gx: ");


    Serial.print(rawValue[3]); Serial.print("\n");


    Serial.print("gy: ");


    Serial.print(rawValue[4]); Serial.print("\n");


    Serial.print("gz: ");


    Serial.print(rawValue[5]); Serial.print("\n"); 




    // Convert Yaw, Pitch and Roll values from radians to degrees


    ypr[0] = ypr[0] * 180 / M_PI;


    ypr[1] = ypr[1] * 180 / M_PI;


    ypr[2] = ypr[2] * 180 / M_PI;




    /* Map the MPU6050 movement to the angular movements of the servo motors: -90 to 90 degrees from the MPU6050 to 


     * 0 to 180 for the servos.


     *  


     * This mapping has to be done for the servos


       to move in the opposite direction of the MPU6050 orientation, for each respective axis, to attempt


       stabilizing the gimbal platform. 


    */


    int yawValue = map(ypr[0], -90, 90, 0, 180);            


    int pitchValue = map(ypr[1], -90, 90, 180, 0);            


    int rollValue = map(ypr[2], -90, 90, 180, 0);




    // Control servos according to the MPU6050 orientation


    servoYaw.write(yawValue);


    servoPitch.write(pitchValue);


    servoRoll.write(rollValue);


  }


}


Post a Comment

Previous Post Next Post

Contact Form