0% found this document useful (0 votes)
77 views

Drone Hacker 123

This document describes software for controlling a quadcopter drone. It includes code for initializing sensors, reading radio control inputs, running PID controllers to stabilize roll and pitch based on IMU sensor data, and mapping the PID outputs to motor speeds. Tuning parameters are provided for aggressive and conservative PID settings. The code also includes logic for arming motors and debugging sensor and radio control values.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
77 views

Drone Hacker 123

This document describes software for controlling a quadcopter drone. It includes code for initializing sensors, reading radio control inputs, running PID controllers to stabilize roll and pitch based on IMU sensor data, and mapping the PID outputs to motor speeds. Tuning parameters are provided for aggressive and conservative PID settings. The code also includes logic for arming motors and debugging sensor and radio control values.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 13

/*

* DroneHacker (c) 2016 Anibal Gomez


* Software Controlador De Vuelo
* Quadcoptero
* - Eje Y -
* RX
* TL TR
* |\ /|
* (\ /)
* \ (_) /
* ) _ ( - Eje X -
* /()\
* (/ \)
* |/ \|
* BL BR
* (Caracteristicas aun no implementada)
* Armado: 3 segundos Aileron y Elevator hacia abajo ambos.
* Segunda palanca hacia la parte inferior izquierda por 3 segundos.
* Roll: 1960
* Pitch: 1108
* MEJORAS
* =======
* 07/02/2016: Para la gente que probó el código antes de ésta fecha:
* + El código tenia un error y los valores estaban invertidos y se ha mejorado.
* + Setpoint: Corresponde al valor de entrada (MPU).
* + Input: Corresponde al valor de entrada del radio control.
* Si deseas saber más investiga un poco más acerca de "Controladores P.I.D.".
* ---------------------------------
* [email protected]
* ---------------------------------
* LICENSE
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
**/
#include <PinChangeInt.h>
#include <Servo.h>
#include "I2Cdev.h"
#include <PID_v1.h>
static uint16_t unThrottleIn;
static uint16_t unPitchIn;
static uint16_t unRollIn;
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
int outputTL, outputTR, outputBR, outputBL, auxTL, auxTR, auxBR, auxBL;
int mpuYaw, mpuPitch, mpuRoll;
/***************************
* Ganancia De PID a Motor *
* Mapeo de 1000 a 2000 *
* (Se cuidadoso aqui) *
**************************/
int motorGain = 70;
/**************
* CHECADOR *
* SEÑAL *
**************/
int power = 0;
/*******************************************
* VALOR DONDE SE ACTIVARA EL ESTABILIZADOR *
********************************************/
#define MPU_STABILIZER_ACTIVATION 2
/******************
* RADIO CONTROL *
* RX/TX *
* PINS *
*******************/
#define THROTTLE_IN_PIN 3 // Gas
#define PITCH_IN_PIN 4 // Elevator
#define ROLL_IN_PIN 5 // Aileron
/********************************
* Electronic Speed Controllers *
* SERVO *
* PINS *
*********************************/
#define MOTORTL_OUT_PIN 8
#define MOTORTR_OUT_PIN 9
#define MOTORBR_OUT_PIN 11
#define MOTORBL_OUT_PIN 13
Servo servoMotorTL;
Servo servoMotorTR;
Servo servoMotorBR;
Servo servoMotorBL;
/********************************
* PID *
* CALIBRACION *
* kp = Proporcional *
* ki = Integrativo *
* kd = Derivativo *
*********************************
* Prefijo agg = agresivo *
* Prefijo cons = conservativo *
*********************************/
//float kp = .20;
//float ki = .040;
//float kd = .100;
// Tuning Parametros
// http://diydrones.com/page/pid-tuning-demos
double PitchaggKp=.40, PitchaggKi=0.02, PitchaggKd=.9;
double PitchconsKp=.53, PitchconsKi=0.02, PitchconsKd=0.12;
double RollaggKp=.40, RollaggKi=0.02, RollaggKd=.9;
double RollconsKp=.53, RollconsKi=0.02, RollconsKd=0.12;
/*************************
* PID *
* LIMITES *
*************************/
#define OUTPUT_LIMITS 30
double pitchSetpoint, pitchInput, pitchOutput;
double rollSetpoint, rollInput, rollOutput;
/**************
* X: Pitch *
* Y: Roll *
* Z: Yaw *
**************/
//Specify the links and initial tuning parameters
PID pitchPID(&pitchInput, &pitchOutput, &pitchSetpoint, PitchconsKp, PitchconsKi, PitchconsKd, DIRECT);
PID rollPID(&rollInput, &rollOutput, &rollSetpoint, RollconsKp, RollconsKi, RollconsKd, DIRECT);
/**************
* MPU *
**************/
MPU6050 mpu;
bool dmpReady = false;
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorInt16 aa;
VectorInt16 aaReal;
VectorInt16 aaWorld;
VectorFloat gravity;
float euler[3];
float ypr[3];
/**************
* RX/TX *
**************/
#define THROTTLE_FLAG 1
#define PITCH_FLAG 1
#define ROLL_FLAG 1
volatile uint8_t bUpdateFlagsShared;
volatile uint16_t unThrottleInShared;
volatile uint16_t unPitchInShared;
volatile uint16_t unRollInShared;
uint32_t ulThrottleStart;
uint32_t ulPitchStart;
uint32_t ulRollStart;
volatile bool mpuInterrupt = false;
void dmpDataReady() {
mpuInterrupt = true;
}
void setup(){
/*****************
* PID *
* INICIALIZACION *
******************/
pitchInput = 0;
rollInput = 0;
pitchPID.SetMode(AUTOMATIC);
rollPID.SetMode(AUTOMATIC);
pitchPID.SetOutputLimits(0, OUTPUT_LIMITS);
rollPID.SetOutputLimits(0, OUTPUT_LIMITS);
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24;
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
Serial.println("multiChannels");
servoMotorTL.attach(MOTORTL_OUT_PIN);
servoMotorTR.attach(MOTORTR_OUT_PIN);
servoMotorBL.attach(MOTORBL_OUT_PIN);
servoMotorBR.attach(MOTORBR_OUT_PIN);
PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle, CHANGE);
PCintPort::attachInterrupt(PITCH_IN_PIN, calcPitch, CHANGE);
PCintPort::attachInterrupt(ROLL_IN_PIN, calcRoll, CHANGE);
/**
* INICIAR ARMADO DE MOTORES
*/
arm();
mpu.initialize();
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
devStatus = mpu.dmpInitialize();
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788);

if (devStatus == 0) {
mpu.setDMPEnabled(true);
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
dmpReady = true;
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}

}
void loop() {
static uint8_t bUpdateFlags;
if (!dmpReady) return;
while (!mpuInterrupt && fifoCount < packetSize) {
}
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
fifoCount = mpu.getFIFOCount();
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
mpu.resetFIFO();
} else if (mpuIntStatus & 0x02) {
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
mpu.getFIFOBytes(fifoBuffer, packetSize);
fifoCount -= packetSize;
}
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
mpuYaw = ypr[0] * 180/M_PI;
mpuRoll = ypr[1] * 180/M_PI;
mpuPitch = ypr[2] * 180/M_PI;
if(bUpdateFlagsShared) {
power = 0;
noInterrupts();
bUpdateFlags = bUpdateFlagsShared;
if(bUpdateFlags & THROTTLE_FLAG) {
unThrottleIn = unThrottleInShared;
}
if(bUpdateFlags & PITCH_FLAG) {
unPitchIn = unPitchInShared;
}
if(bUpdateFlags & ROLL_FLAG) {
unRollIn = unRollInShared;
}
bUpdateFlagsShared = 0;
interrupts();
}
if(!bUpdateFlags) {
// Iniciar contador
power++;
}
if(power > 2) {
Serial.println("No Signal!");
outputTL = 1000;
outputTR = 1000;
outputBL = 1000;
outputBR = 1000;
delay(500);
}
// RADIO CONTROLLER DEBUG
//Serial.println("Pitch value: ");
//Serial.println(unPitchIn);
//Serial.println("Roll value: ");
//Serial.println(unRollIn);
pitchSetpoint = mpuPitch; // Valor Deseado (en grados)
pitchInput = map(unPitchIn, 900, 2000, -30, 30); // Valor de entrada (necesita convertirse a grados)
double Pitchgap = abs(pitchSetpoint-pitchInput); // Distancia hasta setpoint (Error)
if(Pitchgap<5) { // Estamos lejos del setpoint, usar parametros conservativos
pitchPID.SetTunings(PitchconsKp, PitchconsKi, PitchconsKd);
} else {
// Estamos muy cerca del setpoint, usa parametros agresivos
pitchPID.SetTunings(PitchaggKp, PitchaggKi, PitchaggKd);
}
pitchPID.Compute();
rollSetpoint = mpuRoll; // Valor deseado (necesita convertirse a grados)
rollInput = map(unRollIn, 900, 2000, -30, 30); // Valor de entrada (necesita convertirse a grados)
double Rollgap = abs(rollSetpoint-rollInput); // Distancia hasta setpoint (Error)
if(Rollgap<5) { // Estamos lejos del setpoint, usar parametros conservativos
rollPID.SetTunings(RollconsKp, RollconsKi, RollconsKd);
} else {
// Estamos muy cerca del setpoint, usa parametros agresivos
rollPID.SetTunings(RollaggKp, RollaggKi, RollaggKd);
}
rollPID.Compute();
// MPU DEBUG
/**
//Serial.println(pitchOutput);
Serial.println("Pitch: ");
Serial.println(mpuPitch);
Serial.println("Roll: ");
Serial.println(mpuRoll);
//Serial.println(rollOutput);
**/
if(bUpdateFlags & THROTTLE_FLAG) {
if(servoMotorTL.readMicroseconds() && servoMotorTR.readMicroseconds()
&& servoMotorBL.readMicroseconds() && servoMotorBR.readMicroseconds()
!= unThrottleIn) {
outputTR = unThrottleIn;
outputTL = unThrottleIn;
outputBL = unThrottleIn;
outputBR = unThrottleIn;
auxTR = unThrottleIn;
auxTL = unThrottleIn;
auxBL = unThrottleIn;
auxBR = unThrottleIn;
/**
* ESTABILIZADOR
* AUTOMATICO
*/
// EJE "X" // ROLL
// Girar Izquierda (Regresa Grados Positivos)
if(mpuRoll > 0) {
outputTL = unThrottleIn + (rollOutput + motorGain); // Convertir grados a RPMs
outputBL = unThrottleIn + (rollOutput + motorGain);
}
// Girar Derecha (Regresa Grados Negativos)
if(mpuRoll < 0) {
outputTR = unThrottleIn + (rollOutput + motorGain); // Convertir grados a RPMs
outputBR = unThrottleIn + (rollOutput + motorGain);
}
// Inclinar Adelante (Grados negativos)
if(mpuPitch < 0) {
outputTL = unThrottleIn + (pitchOutput + motorGain); // Convertir grados a RPMs
outputTR = unThrottleIn + (pitchOutput + motorGain);
}
// Inclinar Atras (Grados Positivos)
if(mpuPitch > 0) {
outputBL = unThrottleIn + (pitchOutput + motorGain); // Convertir grados a RPMs
outputBR = unThrottleIn + (pitchOutput + motorGain);
}
/**
* FIN
* ESTABILIZADOR
* AUTOMATICO
*/
}
}
/**
if(bUpdateFlags & PITCH_FLAG) {
if(servoMotorTL.readMicroseconds() && servoMotorTR.readMicroseconds()
&& servoMotorBL.readMicroseconds() && servoMotorBR.readMicroseconds()
!= unPitchIn) {
//Serial.println(unPitchIn);
pitchInput = map(unPitchIn, 900, 2000, -30, 30); // Valor deseado (necesita convertirse a grados)
pitchSetpoint = mpuPitch; // Valor deseado en grados
double gap = abs(pitchSetpoint-pitchInput); //distance away from setpoint
if(gap<5)
{ //we're close to setpoint, use conservative tuning parameters
pitchPID.SetTunings(PitchconsKp, PitchconsKi, PitchconsKd);
}
else
{
//we're far from setpoint, use aggressive tuning parameters
pitchPID.SetTunings(PitchaggKp, PitchaggKi, PitchaggKd);
}
pitchPID.Compute();
// Ir A Derecha
if(unPitchIn > 1550) {
outputTL = auxTL + (pitchOutput + motorGain); // Convertir grados a RPMs
outputBL = auxTL + (pitchOutput + motorGain);
}
// Ir A La Izquierda
if(unPitchIn < 1450) {
outputTR = auxTR + (pitchOutput + motorGain);
outputBR = auxBR + (pitchOutput + motorGain);
}
}
}
if(bUpdateFlags & ROLL_FLAG) {
if(servoMotorTL.readMicroseconds() && servoMotorTR.readMicroseconds()
&& servoMotorBL.readMicroseconds() && servoMotorBR.readMicroseconds()
!= unRollIn) {
//Serial.println(unRollIn);
rollInput = map(unRollIn, 900, 2000, -30, 30); // Valor deseado (necesita convertirse a grados)
rollSetpoint = mpuRoll; // Valor deseado en grados
double gap = abs(rollSetpoint-rollInput); //distance away from setpoint
if(gap<5)
{ //we're close to setpoint, use conservative tuning parameters
rollPID.SetTunings(RollconsKp, RollconsKi, RollconsKd);
}
else
{
//we're far from setpoint, use aggressive tuning parameters
rollPID.SetTunings(RollaggKp, RollaggKi, RollaggKd);
}
pitchPID.Compute();
if(unRollIn > 1550) {
outputTL = auxTL + (rollOutput + motorGain);
outputTR = auxTR + (rollOutput + motorGain);
}
if(unRollIn < 1450) {
outputBL = auxBL + (rollOutput + motorGain);
outputBR = auxBR + (rollOutput + motorGain);
}
}
}
**/

initMotors(
outputTL,
outputTR,
outputBR,
outputBL
);
bUpdateFlags = 0;
}
void calcThrottle() {
if(digitalRead(THROTTLE_IN_PIN) == HIGH) {
ulThrottleStart = micros();
} else{
unThrottleInShared = (uint16_t)(micros() - ulThrottleStart);
bUpdateFlagsShared |= THROTTLE_FLAG;
}
}
void calcPitch() {
if(digitalRead(PITCH_IN_PIN) == HIGH) {
ulPitchStart = micros();
} else{
unPitchInShared = (uint16_t)(micros() - ulPitchStart);
bUpdateFlagsShared |= PITCH_FLAG;
}
}
void calcRoll() {
if(digitalRead(ROLL_IN_PIN) == HIGH) {
ulRollStart = micros();
} else{
unRollInShared = (uint16_t)(micros() - ulRollStart);
bUpdateFlagsShared |= ROLL_FLAG;
}
}
void initMotors(int tl, int tr, int br, int bl) {
Serial.println(tl);
Serial.println(tr);
Serial.println(br);
Serial.println(bl);
servoMotorTL.writeMicroseconds(tl);
servoMotorTR.writeMicroseconds(tr);
servoMotorBR.writeMicroseconds(br);
servoMotorBL.writeMicroseconds(bl);
}
void arm() {
servoMotorTL.writeMicroseconds(1000);
servoMotorTR.writeMicroseconds(1000);
servoMotorBL.writeMicroseconds(1000);
servoMotorBR.writeMicroseconds(1000);
}

/********************************************************
* PID Adaptive Tuning Example
* One of the benefits of the PID library is that you can
* change the tuning parameters at any time. this can be
* helpful if we want the controller to be agressive at some
* times, and conservative at others. in the example below
* we set the controller to use Conservative Tuning Parameters
* when we're near setpoint and more agressive Tuning
* Parameters when we're farther away.
********************************************************/
#include <PID_v1.h>
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Define the aggressive and conservative Tuning Parameters
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
void setup()
{
//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 100;
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
Input = analogRead(0);
double gap = abs(Setpoint-Input); //distance away from setpoint
if(gap<10)
{ //we're close to setpoint, use conservative tuning parameters
myPID.SetTunings(consKp, consKi, consKd);
}
else
{
//we're far from setpoint, use aggressive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
}
myPID.Compute();
analogWrite(3,Output);
}

/********************************************************
* PID Basic Example
* Reading analog input 0 to control analog PWM output 3
********************************************************/
#include <PID_v1.h>
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
void setup()
{
//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 100;
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
Input = analogRead(0);
myPID.Compute();
analogWrite(3,Output);
}
/********************************************************
* PID RelayOutput Example
* Same as basic example, except that this time, the output
* is going to a digital pin which (we presume) is controlling
* a relay. the pid is designed to Output an analog value,
* but the relay can only be On/Off.
* to connect them together we use "time proportioning
* control" it's essentially a really slow version of PWM.
* first we decide on a window size (5000mS say.) we then
* set the pid to adjust its output between 0 and that window
* size. lastly, we add some logic that translates the PID
* output into "Relay On Time" with the remainder of the
* window being "Relay Off Time"
********************************************************/
#include <PID_v1.h>
#define RelayPin 6
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int WindowSize = 5000;
unsigned long windowStartTime;
void setup()
{
windowStartTime = millis();
//initialize the variables we're linked to
Setpoint = 100;
//tell the PID to range between 0 and the full window size
myPID.SetOutputLimits(0, WindowSize);
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
Input = analogRead(0);
myPID.Compute();
/************************************************
* turn the output pin on/off based on pid output
************************************************/
if(millis() - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}

You might also like