정보나눔

오픈소스하드웨어 프로젝트에 대한 다양한 정보를 나누는 공간입니다.

주석 달아서 다시 올렸습니다
김민섭 | 2016-09-29

#include <Servo.h>
#include <Wire.h>
#include <I2Cdev.h>
#include <SPI.h>
#include <MPU6050_6Axis_MotionApps20.h>
#include <SoftwareSerial.h>

SoftwareSerial BTSerial(12,13);

///////////////////////////////////MPU 6050 DMP 에서 추출 코드///////////////////////////////////////////
MPU6050 mpu;                           // mpu interface object

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

Quaternion q;
VectorFloat gravity;

float ypr[3];
float yprLast[3];
int16_t gyro[3];

volatile bool mpuInterrupt = false;
void dmpDataReady() {
  mpuInterrupt = true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////

Servo front, back, left, right;
double T = 0.0045; // Loop time.

////////////////////////////X,Y 축 오프셋///////////////////////////////////////////////////////////////

double Yoffset =  8.45;
double Xoffset = -3.75;


int throttle = 0;
int throttle_real = 0;
int front_output = 0, back_output = 0, left_output = 0, right_output = 0;

//////////////////////////////////// PID 게인값 셋팅 ////////////////////////////////////////////////////

double P_angle_gain_y = 4; double P_gain_y = 1.255; double I_gain_y =0.012; double D_gain_y = 0.020;
double P_angle_gain_x = 4; double P_gain_x = 1.255; double I_gain_x =0; double D_gain_x = 0.00;

////////////////////////////////////이중 PID 선언////////////////////////////////////////////////////////

double error_y;
double error_pid_y, error_pid_y1;
double P_angle_pid_y;
double P_y, I_y, D_y, PID_y;
double desired_angle_y = 0 + Yoffset;


double error_x;
double error_pid_x, error_pid_x1;
double P_angle_pid_x;
double P_x, I_x, D_x, PID_x;
double desired_angle_x = 0 + Xoffset;


////////////////////////////////MPU 6050 dmp 라이브러리에서 추출한 코드/////////////////////////////////////////////////////////

void dmpsetup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  TWBR = 12; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif
  Serial.begin(115200);
  while (!Serial);
  Serial.println(F("Initializing I2C devices..."));
  mpu.initialize();
  Serial.println(F("Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
  Serial.println(F("Initializing DMP..."));
  devStatus = mpu.dmpInitialize();
  mpu.setXGyroOffset(92);
  mpu.setYGyroOffset(21);
  mpu.setZGyroOffset(0);
  mpu.setZAccelOffset(1931);

 

  if (devStatus == 0) {
    Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);
    Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
    attachInterrupt(0, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
  }
  else {
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }
}

void setup() {
  Serial.begin(115200);
  dmpsetup();

  servoset(); //initialize settings for each motors.
  BTSerial.begin(115200);
  Serial.setTimeout(15);

}
//////////////////MPU 6050 dmp 라이브러리에서 추출한 코드/////////////////////////

void dmploop() {
  if (!dmpReady)
    return;
  while (!mpuInterrupt && fifoCount < packetSize)
  {
  }
 
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();
  fifoCount = mpu.getFIFOCount();
 
  if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
      mpu.resetFIFO();
    // Serial.println(F("FIFO overflow!"));
  }
   else if (mpuIntStatus & 0x02)
  {
    while (fifoCount < packetSize)
      fifoCount = mpu.getFIFOCount();
 
    mpu.getFIFOBytes(fifoBuffer, packetSize);
    fifoCount -= packetSize;
   
    mpu.dmpGetGyro(gyro, fifoBuffer);
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
   
    ypr[1] = (ypr[1] * 180 / M_PI); //x
    ypr[2] = (ypr[2] * 180 / M_PI); //y
    ypr[0] = (ypr[0] * 180 / M_PI); //z
    //gyro[0],gyro[1],gyro[2]//x,y,z 각속도값
  }
}

//////////////////////////////////이중 PID X축 연산 수식 코드/////////////////////////////////

void PID_control_y() {

  error_y = desired_angle_y - ypr[1]; //angle def
  P_angle_pid_y = P_angle_gain_y * error_y; //angle def + outer P control

  error_pid_y = P_angle_pid_y + gyro[1]; // Pcontrol_angle - angle rate = PID Goal

  P_y = error_pid_y * P_gain_y; // Inner P control
  D_y = (error_pid_y - error_pid_y1) / T * D_gain_y; // Inner D control
  I_y += (error_pid_y) * T * I_gain_y; // Inner I control
  I_y = constrain(I_y, -100, 100); // I control must be limited to prevent being jerk.

  PID_y = P_y + D_y + I_y;
  front_output = +PID_y + throttle;
  back_output =  -PID_y + throttle;

  front_output = constrain(front_output, 800, 1600);
  back_output = constrain(back_output, 800, 1600);

  front.writeMicroseconds(front_output);
  back.writeMicroseconds(back_output);

  error_pid_y1 = error_pid_y;
 
}

/////////////////////// 이중 PID X축 연산 수식 코드//////////////////////////////////////////////


void PID_control_x() {
  error_x = desired_angle_x - ypr[2]; //angle def
  P_angle_pid_x = P_angle_gain_x * error_x; //angle def + outer P control

  error_pid_x = P_angle_pid_x - gyro[0]; // Pcontrol_angle - angle rate = PID Goal

  P_x = error_pid_x * P_gain_x; // Inner P control
  D_x = (error_pid_x - error_pid_x1) / T * D_gain_x; // Inner D control
  I_x += (error_pid_x) * T * I_gain_x; // Inner I control
  I_x = constrain(I_x, -100, 100); // I control must be limited to prevent being jerk.

  PID_x = P_x + D_x + I_x;
 left_output =  +PID_x + throttle;
 right_output =  -PID_x + throttle;

 left_output = constrain(left_output, 800, 1600);
 right_output = constrain(right_output, 800, 1600);

 left.writeMicroseconds((left_output));
 right.writeMicroseconds((right_output));

  error_pid_x1 = error_pid_x;
 
}


////////////////////////////문제의 통신 코드/////////////////////////////////////////////

void BTSerialEvent()
{  
     if(BTSerial.available()){
        throttle_real = BTSerial.parseInt();
        BTSerial.setTimeout(15);
        
    }
    if (throttle_real > 1600 || throttle_real < 800 ) {
        throttle_real = throttle;
    }

    if (throttle_real > 900 && throttle_real < 1600) {
        throttle = throttle_real;
    }
  
  }

///////////////////////////////////////////////////////////////////////////////////////////

void loop() {
 
  dmploop(); // MPU6050 센서 값 읽어오는거 반복
 
  BTSerialEvent();

  if (throttle_real == 801 ) {
    stopped();
  }

  if (throttle_real > 810 && throttle_real < 900 )
    stopped();
  }


  if (throttle_real == 802 ) { // up
   desired_angle_x = 0 + Xoffset; //initialize other direction angle
   desired_angle_y = 5 + Yoffset;
   PID_control_x();
   PID_control_y();
  }
  if (throttle_real == 803 ) { // down
   desired_angle_x = 0 + Xoffset; //initialize other direction angle
   desired_angle_y = -5 + Yoffset;
   PID_control_x();
   PID_control_y();
  }
  if (throttle_real == 804 ) { // right
   desired_angle_y = 0 + Yoffset; //initialize other direction angle
   desired_angle_x = -5 + Xoffset;
   PID_control_x();
   PID_control_y();
  }
  if (throttle_real == 805 ) { // left
    desired_angle_y = 0 + Yoffset; //initialize other direction angle
    desired_angle_x = 5 + Xoffset;
    PID_control_x();
    PID_control_y();
  }

  if (throttle_real == 806 ) { // hovering
    desired_angle_x = 0 + Xoffset;
    desired_angle_y = 0 + Yoffset;
    PID_control_x();
    PID_control_y();
  }


  if (throttle_real >= 900) { // throttle_real 값이 900 넘으면 pid 제어 실행
    PID_control_x();
    PID_control_y();
  }

    Serial.print(throttle);
    Serial.print('\t');
    Serial.print(throttle_real);

    Serial.print('\t');
    Serial.print(ypr[1]); //ypr[1]이 y고, 2가 x다.
    Serial.print('\t');
    Serial.print(ypr[2]);
    Serial.print('\t');
    Serial.print(ypr[3]);
    Serial.print('\t');
    Serial.print(front_output);
    Serial.print('\t');
    Serial.print(back_output);
    Serial.print('\t');
    Serial.print(right_output);
    Serial.print('\t');
    Serial.print(left_output);
    Serial.print('\t');
    Serial.print(-gyro[0]);
    Serial.print('\t');
    Serial.print(-gyro[1]);
    Serial.println('\t');

  
 
}

////////////////////서보모터 멈추게할 설정 ///////////////////////////////////

void stopped() {
  front.writeMicroseconds(800);
  back.writeMicroseconds(800);
  right.writeMicroseconds(800);
  left.writeMicroseconds(800);
}

//////////// 서보모터 사용을 위한 설정 ////////////////////////////////////////

void servoset() {
  front.attach(5);
  back.attach(10);
  right.attach(11);
  left.attach(6);

 front.writeMicroseconds(800);
  back.writeMicroseconds(800);
 right.writeMicroseconds(800);
  left.writeMicroseconds(800);
}

 

 

 

이전글   |    블루투스 연동에 대해서 질문합니다. 2016-09-29
다음글   |    read a rotary encoder with interrupts를 업로드하는데 아래와 ... 2016-09-29