├── connection.png ├── LICENSE ├── README.md ├── NRF24__transmitter_code └── NRF24__transmitter_code..ino └── NRF24_receiver_code ├── NRF24_receiver_code(no_PID).ino └── PID_receiver.ino /connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manojsharma221/Airplane--Fixed-Wing-UAV/HEAD/connection.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manoj Sharma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Airplane--Fixed-Wing-UAV 2 | An arduino based remote controlled airplane with PID control loop using MPU6050
3 | 4 | It is a fully Arduino based RC plane.Flight controller, Transmitter all are made using Arduino.The range is more than 1KM.
5 | Transmitter and receiver system are made using arduino and NRF24 transreceiver and there is also a LCD display showing the pitch and roll trim values on the transmitter. There was also an MPU6050 gyro and accelerometer sensor installed on the plane for PID control, self-balancing the airplane in strong winds. 6 | 7 | # DEMO: https://www.youtube.com/playlist?list=PLtB2X1q31Kq5JVEsOvBol5XOvkQDj3aM6 8 | # THINGS USED: 9 | A2212 1000kv brushless motor with 10x4.5 propeller.
10 | 30A simonk ESC.
11 | One 9g plastic servo on the elevators.
12 | One MG90S metal gear servo for the aileron.
13 | Battery meter.
14 | 15 | # FLIGHT CONTROLLERS/RECEIVER: 16 | Arduino Nano
17 | NRF24l01(PCB Type)
18 | 19 | # TRANSMITTER: 20 | Arduino UNO
21 | nRF24L01+ PA/LNA(antenna type)
22 | MB102 3.3v regulator
23 | 2 analog joysticks
24 | 25 | ## NOTE 26 | * The code is commented enough to understand everything.
27 | 28 | * If the transmitter doesn't transmit connect a 100 microfarad capacitor on the NRFantenna module.If it doesn't work even after that then using the non-antenna type PCB NRF24 module on the transmitter will be the only solution I guess.The reason is that the antenna type gives too much of issues regarding power, noise, etc. 29 | -------------------------------------------------------------------------------- /NRF24__transmitter_code/NRF24__transmitter_code..ino: -------------------------------------------------------------------------------- 1 | /*A basic 4 channel transmitter using the nRF24L01 module.*/ 2 | /* Like, share and subscribe, https://www.youtube.com/channel/UCNMdGm2BwTYoPvY7Yus1QpA */ 3 | /* Channel Name Manoj Sharma...(yes, I know I need to change it. */ 4 | 5 | /* First include the libraries.Google and Download it. 6 | * Install the NRF24 library to your IDE 7 | * Upload this code to the Arduino UNO 8 | * Connect a NRF24 module to it: 9 | 10 | Module // Arduino UNO 11 | 12 | GND -> GND 13 | Vcc -> 3.3V 14 | CE -> D9 15 | CSN -> D10 16 | CLK -> D13 17 | MOSI -> D11 18 | MISO -> D12 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /*Create a unique pipe out. The receiver has to 26 | wear the same unique code*/ 27 | 28 | const uint64_t pipeOut = 0xE8E8F0F0E1LL; //IMPORTANT: The same as in the receiver 29 | 30 | RF24 radio(9, 10); // select CSN pin 31 | 32 | // The sizeof this struct should not exceed 32 bytes 33 | // This gives us up to 32 8 bits channals 34 | struct MyData { 35 | byte throttle; 36 | byte pitch; 37 | byte roll; // we will be only using 3 channels Throttle, one servo for roll and one for pitch control. 38 | }; 39 | 40 | MyData data; 41 | 42 | void resetData() 43 | { 44 | //This are the start values of each channal 45 | // Throttle is 0 in order to stop the motors 46 | //127 is the middle value of the 10ADC. 47 | 48 | data.throttle = 0; 49 | data.pitch = 127; 50 | data.roll = 127; 51 | 52 | } 53 | 54 | void setup() 55 | { 56 | //Start everything up 57 | radio.begin(); 58 | radio.setAutoAck(false); 59 | radio.setDataRate(RF24_250KBPS); 60 | radio.openWritingPipe(pipeOut); 61 | radio.setPALevel(RF24_PA_MAX); //if the connection does'nt work change it to LOW or MIN( options LOW,MIN,HIGH,MAX) 62 | radio.stopListening(); 63 | resetData(); 64 | } 65 | 66 | /**************************************************/ 67 | 68 | // Returns a corrected value for a joystick position that takes into account 69 | // the values of the outer extents and the middle of the joystick range. 70 | int mapJoystickValues(int val, int lower, int middle, int upper, bool reverse) 71 | { 72 | val = constrain(val, lower, upper); 73 | if ( val < middle ) 74 | val = map(val, lower, middle, 0, 128); 75 | else 76 | val = map(val, middle, upper, 128, 255); 77 | return ( reverse ? 255 - val : val ); 78 | } 79 | 80 | void loop() 81 | { 82 | // The calibration numbers used here should be measured 83 | // for your joysticks till they send the correct values. 84 | data.throttle = mapJoystickValues( analogRead(A0), 13, 524, 1015, true );//connect the middle pin of the throttle potentionmeter to analog pin A0 and the other two pins to ground and +5v or arduino 85 | data.roll = mapJoystickValues( analogRead(A1), 12, 544, 1021, true );//do same procedure here also(anolog pin A1) 86 | data.pitch = mapJoystickValues( analogRead(A2), 34, 522, 1020, true );//and here too(Analog pin A2) 87 | radio.write(&data, sizeof(MyData)); 88 | } 89 | -------------------------------------------------------------------------------- /NRF24_receiver_code/NRF24_receiver_code(no_PID).ino: -------------------------------------------------------------------------------- 1 | /* Receiver code for the Arduino Radio control with PWM output 2 | * 3 | * THIS ONLY WORKS WITH ATMEGA328p registers!!!! 4 | * Install the NRF24 library to your IDE 5 | * Upload this code to the Arduino UNO 6 | * Connect a NRF24 module to it: 7 | 8 | Module // Arduino UNO 9 | 10 | GND -> GND 11 | Vcc -> 3.3V 12 | CE -> D9 13 | CSN -> D10 14 | CLK -> D13 15 | MOSI -> D11 16 | MISO -> D12 17 | 18 | This code receive 3 channels and create a PWM output for each one on D2, D3, D4 19 | Please, like share and subscribe : https://www.youtube.com/channel/UCNMdGm2BwTYoPvY7Yus1QpA 20 | */ 21 | 22 | #include 23 | int pin2; 24 | int pin3; 25 | int pin4; 26 | Servo esc; 27 | Servo servo1; 28 | Servo servo2; 29 | unsigned long previousMillis = 0; //Set initial timer value used for the PWM signal 30 | 31 | #include 32 | #include 33 | #include 34 | const uint64_t pipeIn = 0xE8E8F0F0E1LL; //Remember that this code is the same as in the transmitter 35 | 36 | RF24 radio(9, 10); 37 | 38 | //We could use up to 32 channels 39 | struct MyData { 40 | byte throttle; //We define each byte of data input, in this case just 3 channels 41 | byte pitch; 42 | byte roll; 43 | }; 44 | 45 | MyData data; 46 | 47 | void resetData() 48 | { 49 | //We define the inicial value of each data input 50 | //3 potenciometers will be in the middle position so 127 is the middle from 254 51 | data.throttle = 0; 52 | data.pitch = 130; 53 | data.roll = 130; 54 | } 55 | 56 | /**************************************************/ 57 | 58 | void setup() 59 | {Serial.begin(250000); 60 | esc.attach(2); // connect ESC signal pin to digital pin D2 61 | servo1.attach(3);//Aileron or roll servo to pin D3 62 | servo2.attach(4);//Pitch servo to pin D4 63 | esc.writeMicroseconds(1000); 64 | resetData(); 65 | radio.begin(); 66 | radio.setAutoAck(false); 67 | 68 | radio.setDataRate(RF24_250KBPS); 69 | radio.openReadingPipe(1,pipeIn); 70 | //we start the radio comunication 71 | radio.startListening(); 72 | } 73 | 74 | /**************************************************/ 75 | 76 | unsigned long lastRecvTime = 0; 77 | 78 | void recvData() 79 | { 80 | while ( radio.available() ) { 81 | radio.read(&data, sizeof(MyData)); 82 | lastRecvTime = millis(); //here we receive the data 83 | } 84 | } 85 | 86 | /**************************************************/ 87 | 88 | void loop() 89 | { 90 | recvData(); 91 | unsigned long now = millis(); 92 | //Here we check if we've lost signal, if we did we reset the values 93 | if ( now - lastRecvTime > 1000 ) { 94 | // Signal lost? 95 | resetData(); 96 | } 97 | 98 | pin2 = map(data.throttle, 0, 255, 1000, 2000); //PWM value on digital pin D2 99 | pin3 = map(data.roll, 0, 255, 30, 130); //(between 0 to 180(in my case i have set it to vary between 30 to 130)PWM value on digital pin D3 100 | pin4 = map(data.pitch, 0, 255, 30, 130); //PWM value on digital pin D4 101 | 102 | esc.writeMicroseconds(pin2); 103 | delay(15); 104 | servo1.write(pin3); 105 | delay(15); 106 | servo2.write(pin4); 107 | delay(15); 108 | 109 | 110 | Serial.print("Throttle: "); Serial.print(pin2); Serial.print(" "); 111 | Serial.print("Roll: "); Serial.print(data.roll); Serial.print(" "); 112 | Serial.print("Pitch: "); Serial.print(data.pitch); Serial.print(" "); 113 | Serial.print("\n"); 114 | 115 | /*To test if the wireless system is working coneect the receiver module to your PC, 116 | open the serial monitor and 117 | set baud rate to 250000 118 | Now move the joysticks on your transmitter 119 | you should see the values changing 120 | */ 121 | } 122 | 123 | 124 | -------------------------------------------------------------------------------- /NRF24_receiver_code/PID_receiver.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //RFID 5 | Servo esc; 6 | Servo pitch_servo; 7 | Servo yaw_servo; 8 | Servo roll_servoL; 9 | Servo roll_servoR; 10 | 11 | unsigned long previousMillis = 0; 12 | #include 13 | #include 14 | #include 15 | const uint64_t pipeIn = 0xE8E8F0F0E1LL; //Remember that this code is the same as in the transmitter 16 | 17 | RF24 radio(9, 10); 18 | 19 | struct MyData { 20 | byte throttle; //We define each byte of data input, in this case just 3 channels 21 | byte pitch; 22 | byte roll; 23 | byte yaw; 24 | byte TPU; 25 | byte TPD; 26 | byte TRR; 27 | byte TRL; 28 | }; 29 | MyData data; 30 | 31 | void resetData() 32 | { 33 | //We define the inicial value of each data input 34 | //3 potenciometers will be in the middle position so 127 is the middle from 254 35 | data.throttle = 0; 36 | data.pitch = 130; 37 | data.roll = 130; 38 | data.yaw=130; 39 | data.TPU=0; 40 | data.TPD=0; 41 | data.TRR=0; 42 | data.TRL=0; 43 | } 44 | 45 | 46 | 47 | 48 | 49 | 50 | /*MPU-6050 gives you 16 bits data so you have to create some 16int constants 51 | * to store the data for accelerations and gyro*/ 52 | 53 | int16_t Acc_rawX, Acc_rawY, Acc_rawZ,Gyr_rawX, Gyr_rawY, Gyr_rawZ; 54 | 55 | 56 | float Acceleration_angle[2]; 57 | float Gyro_angle[2]; 58 | float Total_angle[2]; 59 | 60 | 61 | 62 | float elapsedTime, time, timePrev; 63 | float rad_to_deg = 180/3.141592654; 64 | 65 | float errorpitch,errorroll,pwmpitch, pwmroll,PIDpitch,PIDroll, previous_errorpitch,previous_errorroll; 66 | float pidpitch_p=0; 67 | float pidpitch_i=0; 68 | float pidpitch_d=0; 69 | 70 | float pidroll_p=0; 71 | float pidroll_i=0; 72 | float pidroll_d=0; 73 | 74 | /////////////////PID CONSTANTS///////////////// 75 | double kp=1.5;//3.55 76 | double ki=0;//0.003 77 | double kd=0;;//2.05 78 | /////////////////////////////////////////////// 79 | 80 | int throttle,yaw; 81 | double pitch; 82 | double roll; 83 | /* TRIM CONSTANTS*/ 84 | float tpu,tpd,trr,trl,pitchTrim,rollTrim; 85 | float desired_angle = 0; //This is the angle in which we whant the 86 | //balance to stay steady 87 | 88 | 89 | 90 | void setup() { 91 | Wire.begin(); //begin the wire comunication 92 | Wire.beginTransmission(0x68); 93 | Wire.write(0x6B); 94 | Wire.write(0); 95 | Wire.endTransmission(true); 96 | Serial.begin(250000); 97 | esc.attach(2); 98 | roll_servoL.attach(3); 99 | roll_servoR.attach(4); 100 | pitch_servo.attach(5); 101 | yaw_servo.attach(6); 102 | esc.writeMicroseconds(1000); 103 | delay(2000); 104 | //pitchTrim=EEPROM.read(2); 105 | //yawTrim=EEPROM.read(100); 106 | resetData(); 107 | radio.begin(); 108 | radio.setAutoAck(false); 109 | 110 | radio.setDataRate(RF24_250KBPS); 111 | radio.openReadingPipe(1,pipeIn); 112 | //we start the radio comunication 113 | radio.startListening(); 114 | time = millis(); //Start counting time in milliseconds 115 | }//end of setup void 116 | 117 | unsigned long lastRecvTime = 0; 118 | 119 | void recvData() 120 | { 121 | while ( radio.available() ) { 122 | radio.read(&data, sizeof(MyData)); 123 | lastRecvTime = millis(); 124 | } 125 | } 126 | 127 | 128 | void loop() { 129 | recvData(); 130 | 131 | /////////////////////////////I M U///////////////////////////////////// 132 | timePrev = time; // the previous time is stored before the actual time read 133 | time = millis(); // actual time read 134 | elapsedTime = (time - timePrev) / 1000; 135 | 136 | if ( time - lastRecvTime > 1000 ) { 137 | // Signal lost? 138 | resetData(); 139 | } 140 | 141 | //Here we check if we've lost signal, if we did we reset the values 142 | 143 | throttle = map(data.throttle, 0, 255, 1000, 2000); //PWM value on digital pin D2 144 | pitch = map(data.pitch, 0, 255, 30, 140); //PWM value on digital pin D3 145 | roll = map(data.roll, 0, 255, 30, 140); //PWM value on digital pin D5 146 | yaw = map(data.yaw, 0, 255, 30, 140); 147 | tpu=data.TPU; 148 | tpd=data.TPD; 149 | trr=data.TRR; 150 | trl=data.TRL; 151 | 152 | /*TRIMMING*/ 153 | if (tpu==1) 154 | { 155 | pitchTrim=pitchTrim+0.1; 156 | if(pitchTrim>50) 157 | { 158 | pitchTrim=50; 159 | } 160 | // EEPROM.write(2,pitchTrim); 161 | } 162 | if(tpd==1) 163 | { 164 | pitchTrim=pitchTrim-0.1; 165 | if(pitchTrim<-50) 166 | { 167 | pitchTrim=-50; 168 | } 169 | // EEPROM.write(2,pitchTrim); 170 | } 171 | if (tpu==0||tpd==0) 172 | { 173 | pitchTrim=pitchTrim+0; 174 | } 175 | 176 | if(trr==1) 177 | { 178 | rollTrim=rollTrim+0.1; 179 | if(rollTrim>50) 180 | { 181 | rollTrim=50; 182 | } 183 | // EEPROM.write(100,yawTrim); 184 | } 185 | if(trl==1) 186 | { 187 | rollTrim=rollTrim-0.1; 188 | if(rollTrim<-50) 189 | { 190 | rollTrim=-50; 191 | } 192 | // EEPROM.write(100,yawTrim); 193 | } 194 | if(trr==0||trl==0) 195 | { 196 | rollTrim=rollTrim+0; 197 | } 198 | 199 | //Serial.print(pitchTrim);Serial.print(" ");Serial.println(rollTrim); 200 | 201 | /*The tiemStep is the time that elapsed since the previous loop. 202 | * This is the value that we will use in the formulas as "elapsedTime" 203 | * in seconds. We work in ms so we haveto divide the value by 1000 204 | to obtain seconds*/ 205 | 206 | /*Reed the values that the accelerometre gives. 207 | * We know that the slave adress for this IMU is 0x68 in 208 | * hexadecimal. For that in the RequestFrom and the 209 | * begin functions we have to put this value.*/ 210 | 211 | Wire.beginTransmission(0x68); 212 | Wire.write(0x3B); //Ask for the 0x3B register- correspond to AcX 213 | Wire.endTransmission(false); 214 | Wire.requestFrom(0x68,6,true); 215 | 216 | /*We have asked for the 0x3B register. The IMU will send a brust of register. 217 | * The amount of register to read is specify in the requestFrom function. 218 | * In this case we request 6 registers. Each value of acceleration is made out of 219 | * two 8bits registers, low values and high values. For that we request the 6 of them 220 | * and just make then sum of each pair. For that we shift to the left the high values 221 | * register (<<) and make an or (|) operation to add the low values.*/ 222 | 223 | Acc_rawX=Wire.read()<<8|Wire.read(); //each value needs two registres 224 | Acc_rawY=Wire.read()<<8|Wire.read(); 225 | Acc_rawZ=Wire.read()<<8|Wire.read(); 226 | 227 | 228 | /*///This is the part where you need to calculate the angles using Euler equations///*/ 229 | 230 | /* - Now, to obtain the values of acceleration in "g" units we first have to divide the raw 231 | * values that we have just read by 16384.0 because that is the value that the MPU6050 232 | * datasheet gives us.*/ 233 | /* - Next we have to calculate the radian to degree value by dividing 180º by the PI number 234 | * which is 3.141592654 and store this value in the rad_to_deg variable. In order to not have 235 | * to calculate this value in each loop we have done that just once before the setup void. 236 | */ 237 | 238 | /* Now we can apply the Euler formula. The atan will calculate the arctangent. The 239 | * pow(a,b) will elevate the a value to the b power. And finnaly sqrt function 240 | * will calculate the rooth square.*/ 241 | /*---X---*/ 242 | Acceleration_angle[0] = atan((Acc_rawY/16384.0)/sqrt(pow((Acc_rawX/16384.0),2) + pow((Acc_rawZ/16384.0),2)))*rad_to_deg; 243 | /*---Y---*/ 244 | Acceleration_angle[1] = atan(-1*(Acc_rawX/16384.0)/sqrt(pow((Acc_rawY/16384.0),2) + pow((Acc_rawZ/16384.0),2)))*rad_to_deg; 245 | 246 | /*Now we read the Gyro data in the same way as the Acc data. The adress for the 247 | * gyro data starts at 0x43. We can see this adresses if we look at the register map 248 | * of the MPU6050. In this case we request just 4 values. W don¡t want the gyro for 249 | * the Z axis (YAW).*/ 250 | 251 | Wire.beginTransmission(0x68); 252 | Wire.write(0x43); //Gyro data first adress 253 | Wire.endTransmission(false); 254 | Wire.requestFrom(0x68,4,true); //Just 4 registers 255 | 256 | Gyr_rawX=Wire.read()<<8|Wire.read(); //Once again we shif and sum 257 | Gyr_rawY=Wire.read()<<8|Wire.read(); 258 | 259 | /*Now in order to obtain the gyro data in degrees/seconda we have to divide first 260 | the raw value by 131 because that's the value that the datasheet gives us*/ 261 | 262 | /*---X---*/ 263 | Gyro_angle[0] = Gyr_rawX/131.0; 264 | /*---Y---*/ 265 | Gyro_angle[1] = Gyr_rawY/131.0; 266 | 267 | /*Now in order to obtain degrees we have to multiply the degree/seconds 268 | *value by the elapsedTime.*/ 269 | /*Finnaly we can apply the final filter where we add the acceleration 270 | *part that afects the angles and ofcourse multiply by 0.98 */ 271 | 272 | /*---X axis angle---*/ 273 | Total_angle[0] = 0.98 *(Total_angle[0] + Gyro_angle[0]*elapsedTime) + 0.02*Acceleration_angle[0]; 274 | /*---Y axis angle---*/ 275 | Total_angle[1] = 0.98 *(Total_angle[1] + Gyro_angle[1]*elapsedTime) + 0.02*Acceleration_angle[1]; 276 | 277 | /*Now we have our angles in degree and values from -100º to 100º aprox*/ 278 | //Serial.println(Total_angle[0]) ; Serial.println(Total_angle[1]); 279 | 280 | 281 | 282 | /*///////////////////////////P I D///////////////////////////////////*/ 283 | /*Remember that for the balance we will use just one axis. I've choose the x angle 284 | to implement the PID with. That means that the x axis of the IMU has to be paralel to 285 | the balance*/ 286 | 287 | /*First calculate the error between the desired angle and 288 | *the real measured angle*/ 289 | errorpitch = Total_angle[1] - desired_angle; 290 | errorroll = Total_angle[0] - desired_angle; 291 | 292 | 293 | /*Next the proportional value of the PID is just a proportional constant 294 | *multiplied by the error*/ 295 | 296 | pidpitch_p = kp*errorpitch; 297 | pidroll_p=kp*errorroll; 298 | /*The integral part should only act if we are close to the 299 | desired position but we want to fine tune the error. That's 300 | why I've made a if operation for an error between -2 and 2 degree. 301 | To integrate we just sum the previous integral value with the 302 | error multiplied by the integral constant. This will integrate (increase) 303 | the value each loop till we reach the 0 point*/ 304 | if(-3 140) 340 | { 341 | PIDpitch=140; 342 | } 343 | 344 | if(PIDroll < -140) 345 | { 346 | PIDroll=-140; 347 | } 348 | if(PIDroll > 140) 349 | { 350 | PIDroll=140; 351 | } 352 | 353 | /*Finnaly we calculate the PWM width. We sum the desired throttle and the PID value*/ 354 | pwmpitch = pitch - PIDpitch-pitchTrim; 355 | pwmroll = roll - PIDroll+rollTrim; 356 | 357 | 358 | /*Once again we map the PWM values to be sure that we won't pass the min 359 | and max values. Yes, we've already maped the PID values. But for example, for 360 | throttle value of 1300, if we sum the max PID value we would have 2300us and 361 | that will mess up the ESC.*/ 362 | //Right 363 | if(pwmpitch < 30) 364 | { 365 | pwmpitch= 30; 366 | } 367 | if(pwmpitch > 140) 368 | { 369 | pwmpitch=140; 370 | } 371 | //Left 372 | if(pwmroll < 30) 373 | { 374 | pwmroll= 30; 375 | } 376 | if(pwmroll > 140) 377 | { 378 | pwmroll=140; 379 | } 380 | 381 | /*Finnaly using the servo function we create the PWM pulses with the calculated 382 | width for each pulse*/ 383 | esc.writeMicroseconds(throttle); 384 | pitch_servo.write(pwmpitch); 385 | yaw_servo.write(yaw); 386 | roll_servoL.write(140-pwmroll+30); 387 | roll_servoR.write(140-pwmroll+30); 388 | previous_errorpitch = errorpitch; //Remember to store the previous error. 389 | previous_errorroll = errorroll; 390 | Serial.print("PitchTrim: "); Serial.print(pitchTrim); Serial.print(" "); 391 | Serial.print("RollTrim: "); Serial.print(rollTrim); Serial.print(" "); 392 | Serial.print("AnglePitch"); Serial.print(errorpitch); Serial.print(" "); 393 | Serial.print("AngleRoll"); Serial.print(errorroll); Serial.print(" "); 394 | Serial.print("Pitch"); Serial.print(pitch); Serial.print(" "); 395 | Serial.print("Roll"); Serial.print(roll); Serial.print(" "); 396 | Serial.print("PWM Pitch"); Serial.print(pwmpitch); Serial.print(" "); 397 | Serial.print("PWN Roll"); Serial.print(pwmroll); Serial.print(" "); 398 | Serial.print("\n"); 399 | 400 | } 401 | //end of loop void 402 | --------------------------------------------------------------------------------