手機拍照穩定器項目_代碼解析

這是一個非常簡單的代碼,用於學習可以,但是實際應用並不是很順暢。

具體解析如下:

/*
  DIY Gimbal - MPU6050 Arduino Tutorial
  by Dejan, www.HowToMechatronics.com
  Code based on the MPU6050_DMP6 example from the i2cdevlib library by Jeff Rowberg:
  https://github.com/jrowberg/i2cdevlib
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
 
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file 如果使用MotionApps包含文件,則沒有必要
 
// 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
#include <Servo.h>
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here 特定的I2C地址可以作爲參數在這裏傳遞
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
 
// Define the 3 servo motors 定義3個伺服電機
Servo servo0;
Servo servo1;
Servo servo2;
float correct;
int j = 0;
 
#define OUTPUT_READABLE_YAWPITCHROLL
 
#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards  定義中斷引腳,UNO和大多數板子是pin 2
 
bool blinkState = false;
 
// MPU control/status vars 微處理機控制/狀態變量
bool dmpReady = false;  // set true if DMP init was successful 如果DMP 初始化成功,則設置爲true
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU 保持從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) 預期的DMP包大小(默認爲42字節)
uint16_t fifoCount;     // count of all bytes currently in FIFO 當前FIFO中所有字節的計數
uint8_t fifoBuffer[64]; // FIFO storage buffer FIFO存儲緩衝區
 
// 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 用於InvenSense茶壺演示包結構
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 指示MPU中斷引腳是否高
void dmpDataReady() {
  mpuInterrupt = true;
}
 
// ================================================================
// ===                      INITIAL SETUP    初始化設置                   ===
// ================================================================
 
void setup() {
  // join I2C bus (I2Cdev library doesn't do this automatically) 加入I2C總線(I2Cdev庫不會自動這樣做)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties 400千赫I2C時鐘。如果有編譯困難,請註釋這一行
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif
 
  // initialize serial communication 初始化串行通信
  // (115200 chosen because it is required for Teapot Demo output, but it's  選擇115200是因爲茶壺演示輸出需要它,但它是
  // really up to you depending on your project) 取決於你的項目)
  Serial.begin(38400);
  while (!Serial); // wait for Leonardo enumeration, others continue immediately 等待列奧納多枚舉,其他立即繼續
 
  // initialize device 初始化設備
  //Serial.println(F("Initializing I2C devices..."));
  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); // 1688 factory default for my test chip 我的測試芯片1688工廠默認值
 
  // make sure it worked (returns 0 if so) 確保它工作正常(如果工作正常返回0)
  if (devStatus == 0) {
    // turn on the DMP, now that it's ready  打開DMP,現在它已經準備好了
    // Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);
 
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
 
    // set our DMP Ready flag so the main loop() function knows it's okay to use it 設置我們的DMP就緒標誌,以便主循環()函數知道可以使用它
    //Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;
 
    // get expected DMP packet size for later comparison 獲取預期的DMP包大小,以便以後進行比較
    packetSize = mpu.dmpGetFIFOPacketSize();
  }

else {
    // ERROR! 錯誤
    // 1 = initial memory load failed 初始內存加載失敗
    // 2 = DMP configuration updates failed DMP配置更新失敗
    // (if it's going to break, usually the code will be 1) (如果它要崩潰,通常代碼是1)
    // Serial.print(F("DMP Initialization failed (code ")); 串口輸出(F(“DMP初始化失敗(代碼)”);
    //Serial.print(devStatus);
    //Serial.println(F(")"));
  }
 
  // Define the pins to which the 3 servo motors are connected 定義連接3個伺服電機的引腳
  servo0.attach(10);
  servo1.attach(9);
  servo2.attach(8);
}
// ================================================================
// ===                    MAIN PROGRAM LOOP     主程序循環                 ===
// ================================================================
 
void loop() {
  // if programming failed, don't try to do anything 如果編程失敗了,不要嘗試做任何事情
  if (!dmpReady) return;
 
  // wait for MPU interrupt or extra packet(s) available 等待MPU中斷或額外的包可用
  while (!mpuInterrupt && fifoCount < packetSize) {
    if (mpuInterrupt && fifoCount < packetSize) {
      // try to get out of the infinite loop 試着跳出無限循環
      fifoCount = mpu.getFIFOCount();
    }
  }
 
  // reset interrupt flag and get INT_STATUS byte 重置中斷標誌並獲取INT_STATUS字節
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();
 
  // get current FIFO count 獲取當前FIFO計數
  fifoCount = mpu.getFIFOCount();
 
  // check for overflow (this should never happen unless our code is too inefficient) 檢查溢出(除非我們的代碼效率太低,否則不應該發生這種情況)
  if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
    // 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) 否則,檢查DMP數據準備中斷(這應該經常發生)
  } 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 從FIFO中讀取數據包
    mpu.getFIFOBytes(fifoBuffer, packetSize);
 
    // track FIFO count here in case there is > 1 packet available 跟蹤先進先出計數在這裏,如果有> 1包可用
    // (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) 跳過300個讀數(自校準過程)
    if (j <= 300) {
      correct = ypr[0]; // Yaw starts at random value, so we capture last value after 300 readings 偏航從隨機值開始,所以我們捕獲300個讀數後的最後一個值
      j++;
    }
    // After 300 readings 在300個讀數後
    else {
      ypr[0] = ypr[0] - correct; // Set the Yaw to 0 deg - subtract  the last random Yaw value from the currrent value to make the Yaw 0 degrees 設置偏航爲0度-從當前值中減去最後一個隨機偏航值,使偏航爲0度
      // Map the values of the MPU6050 sensor from -90 to 90 to values suatable for the servo control from 0 to 180 將MPU6050傳感器的值從-90映射到可用於0到180的伺服控制的值
      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);
      
      // Control the servos according to the MPU6050 orientation 根據MPU6050方向控制伺服系統
      servo0.write(servo0Value);
      servo1.write(servo1Value);
      servo2.write(servo2Value);
    }
#endif
  }
}

 

/*
  DIY Gimbal - MPU6050 Arduino Tutorial
  by Dejan, www.HowToMechatronics.com
  Code based on the MPU6050_DMP6 example from the i2cdevlib library by Jeff Rowberg:
  https://github.com/jrowberg/i2cdevlib
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
 
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
 
// 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
#include <Servo.h>
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
 
// Define the 3 servo motors
Servo servo0;
Servo servo1;
Servo servo2;
float correct;
int j = 0;
 
#define OUTPUT_READABLE_YAWPITCHROLL
 
#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
 
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
 
  // initialize serial communication
  // (115200 chosen because it is required for Teapot Demo output, but it's
  // really up to you depending on your project)
  Serial.begin(38400);
  while (!Serial); // wait for Leonardo enumeration, others continue immediately
 
  // initialize device
  //Serial.println(F("Initializing I2C devices..."));
  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); // 1688 factory default for my test chip
 
  // 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..."));
    mpu.setDMPEnabled(true);
 
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
    mpuIntStatus = mpu.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 = mpu.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(")"));
  }
 
  // Define the pins to which the 3 servo motors are connected
  servo0.attach(10);
  servo1.attach(9);
  servo2.attach(8);
}
// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================
 
void loop() {
  // if programming failed, don't try to do anything
  if (!dmpReady) return;
 
  // wait for MPU interrupt or extra packet(s) available
  while (!mpuInterrupt && fifoCount < packetSize) {
    if (mpuInterrupt && fifoCount < packetSize) {
      // try to get out of the infinite loop
      fifoCount = mpu.getFIFOCount();
    }
  }
 
  // reset interrupt flag and get INT_STATUS byte
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();
 
  // get current FIFO count
  fifoCount = mpu.getFIFOCount();
 
  // check for overflow (this should never happen unless our code is too inefficient)
  if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
    // 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; // Set the Yaw to 0 deg - subtract  the last random Yaw value from the currrent value to make the Yaw 0 degrees
      // Map the values of the MPU6050 sensor from -90 to 90 to values suatable for the servo control from 0 to 180
      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);
      
      // Control the servos according to the MPU6050 orientation
      servo0.write(servo0Value);
      servo1.write(servo1Value);
      servo2.write(servo2Value);
    }
#endif
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章