Arduino - Quad_V1
Extrait intégral de la première version du programme permettant le contrôle d'un multicopter à 4 moteurs disposés en "X". Le but est de faire un programme adapter à la carte utilisée (Drotek avec ITG3200 et BMA180). Les programmes libres genres ArduPilote, Fcwii sont trop polyvalent pour que je puisse modifier ces programmes facilement. La solution pour moi a donc été de partir de Zéro.
Programme V1 avec atmega 328p sur board Arduino Uno et arduino. Utilisation d'une bibliothèque supplémentaire "MegaServo" permettant la gestion de plus de 3 signaux pwm en sorties sans interruption sur celles-ci. Acquisition des entrées Pwm sur détection de l'état bas du signal "throttle" qui déclenche une interuption puis acquiert avec la fonction PulseIn les largeurs d'impulsion de "roll, elev, yaw, throttle et aux". La voie "aux" permet d'avoir un Gain réglable par la radio.
Code de Quad_V1.ino :
- #include
- #include
- // define input RC
- #define THROTTLEPIN 2
- #define ROLLPIN 4
- #define ELEVPIN 5
- #define YAWPIN 6
- #define AUXPIN 7
- #define I2C_PULLUPS_ENABLE PORTC |= 1<<4; PORTC |= 1<<5; // PIN A4&A5 (SDA&SCL)
- // define adress sensor
- #define ITGadr 0x68
- #define BMA180adr 64
- // define Output RC
- #define MFtL 3 //M1
- #define MFtR 10 //M2
- #define MRrR 9 //M3
- #define MRrL 11 //M4
- #define LedBoard 13
- // define limit system
- #define LIMITCORRECT 300
- #define TIMEOUT 20000 //time for pwm scan
- #define MINPWM 1120
- #define RANGE_RC 160 // velocity stick
- #define RANGE_RC_Yaw 200 // velocity stick yaw
- #define SafePWM 1030
- #define DEADZONE 2
- #define FILTRE_MOY 4
- #define CONC_ACC_GYRO 250
- // volatile, important for interruption
- volatile int throttle = 0;
- volatile int roll = 0;
- volatile int elev = 0;
- volatile int yaw = 0;
- volatile int throttle1 = 0;
- volatile int roll1 = 0;
- volatile int elev1 = 0;
- volatile int yaw1 = 0;
- volatile int aux= 0;
- volatile byte timeSlot;
- volatile int outMFtR = SafePWM, outMFtL = SafePWM, outMRrR = SafePWM, outMRrL = SafePWM;
- int SerialValue = 0;
- int BufferInt;
- char Buffer;
- int Xgyro, Ygyro, Zgyro;
- int X0gyro=0, Y0gyro=0, Z0gyro=0;
- int X1gyro, Y1gyro, Z1gyro;
- int Xacc, Yacc, Zacc;
- int X1acc, Y1acc, Z1acc;
- int X0acc=0, Y0acc=0, Z0acc=0;
- float Xcorrect, Ycorrect, Zcorrect;
- float X1correct = 0, Y1correct = 0, Z1correct = 0;
- // int Xngyro[3], Yngyro[3], Zngyro[3];
- unsigned long t1, t2, dT, Freq20ms, SpyFreq20ms, time;
- unsigned int td = 7;
- float ti = 50000000; //500000
- float Gain , Gain0;
- int Xerror, Yerror, Zerror;
- float Pterm, Iterm, Dterm;
- byte i;
- boolean ARMED, WritePwm=0;
- float filter = 0.5, filterAcc = 0.1, RCfilter = 0.8; //Gain filter
- //float tabGyro[1000];
- int LimitAcc;
- //float kxl=1, kxr=1, kyf=1, kyr=1;
- byte i_filtre = 0;
- // only for debug
- volatile unsigned int time1, time2 ;
- //define ESC
- MegaServo escMFtL; //pin drotek n°3
- MegaServo escMFtR; //pin drotek n°10
- MegaServo escMRrR; //pin drotek n°9
- MegaServo escMRrL; //pin drotek n°11
- void setup(){
- PORTD = (1<<2) | (1<<4) | (1<<5) | (1<<6) | (1<<7);
- pinMode (THROTTLEPIN, INPUT);
- pinMode (ROLLPIN, INPUT);
- pinMode (ELEVPIN, INPUT);
- pinMode (YAWPIN, INPUT);
- pinMode (AUXPIN, INPUT);
- pinMode (LedBoard, OUTPUT);
- digitalWrite(LedBoard,HIGH);
- escMFtL.attach(MFtL); escMFtR.attach(MFtR); escMRrR.attach(MRrR); escMRrL.attach(MRrL);
- SafeCmdMotor();
- attachInterrupt(0, interruptHandler, RISING); // throttle pin 2
- // Serial.begin(9600);
- Wire.begin();
- delay(100);
- I2C_PULLUPS_ENABLE;
- //Set the gyroscope scale for the outputs to +/-2000 degrees per second
- WriteDataI2C(ITGadr, 0x16, B00011001);
- //Set the sample rate to 000 => 256Hz with 8000 hz
- //Set the sample rate to 001 (1) => 188Hz with 1000 hz (5ms)
- //Set the sample rate to 010 (2) => 98Hz with 1000 hz (10ms)
- WriteDataI2C(ITGadr, 0x15, 18);
- // see page 23 datasheet - Fsample gyro = 500µs with 8KHz
- // for 10ms, put 79, Fsample gyro = 10ms with 8KHz
- // for 5ms, put 39, Fsample gyro = 5ms with 8KHz
- //WriteDataI2C(BMA180adr, 0x35, 0x03);
- delay(2000);
- X0gyro = ReadDataI2C(ITGadr, 0x1F, 0x20);
- Y0gyro = ReadDataI2C(ITGadr, 0x1D, 0x1E);
- Z0gyro = ReadDataI2C(ITGadr, 0x21, 0x22);
- X1gyro = X0gyro; Y1gyro = Y0gyro; Z1gyro = Z0gyro;
- X0acc = (ReadDataI2C(BMA180adr, 0x03, 0x02) & 0xFFF0);
- Y0acc = (ReadDataI2C(BMA180adr, 0x05, 0x04) & 0xFFF0);
- Z0acc = (ReadDataI2C(BMA180adr, 0x07, 0x06) & 0xFFF0);
- X1acc = X0acc; Y1acc = Y0acc; Z1acc = Z0acc;
- for (i=0 ;i<4; i++) { digitalWrite(LedBoard, HIGH); delay(100); digitalWrite(LedBoard, LOW); delay(100); }
- t1=micros(); SpyFreq20ms=t1;
- }
- void loop(){
- Xacc = (ReadDataI2C(BMA180adr, 0x03, 0x02) & 0xFFF0) ; Yacc = (ReadDataI2C(BMA180adr, 0x05, 0x04) & 0xFFF0) ;// Zacc = (ReadDataI2C(BMA180adr, 0x07, 0x06) & 0xFFF0);
- Xgyro = ReadDataI2C(ITGadr, 0x1F, 0x20)-X0gyro; Ygyro = ReadDataI2C(ITGadr, 0x1D, 0x1E)-Y0gyro; Zgyro = ReadDataI2C(ITGadr, 0x21, 0x22)-Z0gyro;
- // FILTER BY OUPUT=PREVIOUS_GYRO+(FILTER*(GYRO-PREVIOUS_GYRO))
- Xacc = X1acc + (filterAcc*(Xacc-X1acc)); Yacc = Y1acc + (filterAcc*(Yacc-Y1acc));
- Xgyro = X1gyro + (filter*(Xgyro-X1gyro)); Ygyro = Y1gyro + (filter*(Ygyro-Y1gyro)); Zgyro = Z1gyro + (filter*(Zgyro-Z1gyro));
- // calc delta time for 1 total cycle
- t1 = t2;
- t2 = micros();
- dT = t2-t1; // dt in millisecond time intergral and derivate Ti and Td => sec | dt ~ 56 ms
- Gain = 0.51;
- LimitAcc = map(aux,1000,2000,10,500);
- //roll
- //rotate trigo -
- //rotate time +
- Xacc = map(Xacc,-16383,16383,-LimitAcc,LimitAcc);
- Yacc = map(Yacc,-16383,16383,-LimitAcc,LimitAcc);
- //if ((Xacc > CONC_ACC_GYRO) || (Xacc <- CONC_ACC_GYRO)) {
- //Redondance before correction
- Pterm = Gain*Xgyro;
- Pterm /= 16;
- Xcorrect = Pterm+Dterm+Iterm-Xacc;
- Xcorrect = constrain(Xcorrect, -LIMITCORRECT, LIMITCORRECT);
- //ELEV
- //up => +
- //down => -
- Pterm = Gain*Ygyro;
- Pterm /= 16;
- Iterm = 0;
- Dterm = 0;
- Ycorrect = Pterm+Dterm+Iterm+Yacc;
- Ycorrect = constrain(Ycorrect, -LIMITCORRECT, LIMITCORRECT);
- Pterm = Gain*Zgyro;
- Zcorrect = Pterm;//+Iterm+Dterm;
- Pterm /= 16;
- Zcorrect = constrain(Zcorrect, -210, 210);
- // Save Mesure n-1
- X1acc = Xacc; Y1acc = Yacc; Z1acc = Zacc;
- X1gyro = Xgyro; Y1gyro = Ygyro; Z1gyro = Zgyro;
- Freq20ms = micros()-SpyFreq20ms;
- if (Freq20ms > 17500) { // refresh ~50Hz pwm, 20000µs
- if (throttle<1100) { SafeCmdMotor(); } else { WriteEscPwm(); }
- SpyFreq20ms = micros();
- }
- }
Fichier function.ino :
- void interruptHandler() {
- // time1 = micros();
- // switch ((timeSlot += 1) % 5) {
- // case 0:
- if (((timeSlot += 1) % 5)==0) {
- throttle = pulseIn(THROTTLEPIN, HIGH, TIMEOUT);
- roll = map(pulseIn(ROLLPIN, HIGH, TIMEOUT), 1000,2000,-RANGE_RC,RANGE_RC);
- roll = int(roll1+(RCfilter*(roll-roll1)));
- aux = pulseIn(AUXPIN, HIGH, TIMEOUT);
- elev = map(pulseIn(ELEVPIN, HIGH, TIMEOUT), 1000,2000,-RANGE_RC,RANGE_RC);
- elev = int(elev1+(RCfilter*(elev-elev1)));
- yaw = map(pulseIn(YAWPIN, HIGH, TIMEOUT), 1000,2000,-RANGE_RC_Yaw,RANGE_RC_Yaw);
- yaw = int(yaw1+(RCfilter*(yaw-yaw1)));
- roll1 = roll;
- elev1 = elev;
- yaw1 = yaw;
- // break;
- // default:
- // break;
- }
- // time2 = micros()-time1;
- // Serial.println(time2);
- }
- void WriteEscPwm(){
- detachInterrupt(0);
- /*
- outMFtL = throttle - elev + roll - yaw - int(kxl*Xcorrect) - int(kyf*Ycorrect) - Zcorrect;
- outMFtR = throttle - elev - roll + yaw + int(kxr*Xcorrect) - int(kyf*Ycorrect) + Zcorrect;
- outMRrR = throttle + elev - roll - yaw + int(kxr*Xcorrect) + int(kyr*Ycorrect) - Zcorrect;
- outMRrL = throttle + elev + roll + yaw - int(kxl*Xcorrect) + int(kyr*Ycorrect) + Zcorrect;
- */
- outMFtL = throttle - elev + roll - yaw - Xcorrect - Ycorrect - Zcorrect;
- outMFtR = throttle - elev - roll + yaw + Xcorrect - Ycorrect + Zcorrect;
- outMRrR = throttle + elev - roll - yaw + Xcorrect + Ycorrect - Zcorrect;
- outMRrL = throttle + elev + roll + yaw - Xcorrect + Ycorrect + Zcorrect;
- outMFtL = constrain(outMFtL, MINPWM, 2000);
- outMFtR = constrain(outMFtR, MINPWM, 2000);
- outMRrR = constrain(outMRrR, MINPWM, 2000);
- outMRrL = constrain(outMRrL, MINPWM, 2000);
- escMFtL.writeMicroseconds(outMFtL);
- escMFtR.writeMicroseconds(outMFtR);
- escMRrR.writeMicroseconds(outMRrR);
- escMRrL.writeMicroseconds(outMRrL);
- attachInterrupt(0, interruptHandler, RISING);
- }
- void SafeCmdMotor(){
- escMFtL.writeMicroseconds(SafePWM);
- escMFtR.writeMicroseconds(SafePWM);
- escMRrR.writeMicroseconds(SafePWM);
- escMRrL.writeMicroseconds(SafePWM);
- }
- void WriteDataI2C(char address, char registerAddress, char data) {
- Wire.beginTransmission(address);
- //Tell the I2C address which register we are writing to
- Wire.write(registerAddress);
- //Send the value to write to the specified register
- Wire.write(data);
- //End the communication sequence
- Wire.endTransmission();
- }
- // ***************Function : Extract I2C sensor data 8+8 bits, registrer => adress High Byte*****************
- word ReadDataI2C(int Wadress, int Wregister1, int Wregister2) {
- // extract High Byte data
- Wire.beginTransmission(Wadress);
- Wire.write(Wregister1);
- Wire.endTransmission();
- Wire.requestFrom(Wadress,1);
- byte Byte_Out_H = Wire.read();
- // extract Low Byte data
- Wire.beginTransmission(Wadress);
- Wire.write(Wregister2);
- Wire.endTransmission();
- Wire.requestFrom(Wadress,1);
- byte Byte_Out_L = Wire.read(); // & B11111110;
- return word(Byte_Out_H, Byte_Out_L);
- }