How to Control servo motor 3 Axis with mpu6050


 Connection Diagram 


        👇Code here👇 


 /* 

 * 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