This is the code to implement a quadcopter. PID controller tuning is necessary.

Dependencies:   PwmIn mbed MPU6050IMU

Committer:
kcherfou
Date:
Tue Oct 08 00:06:09 2019 +0000
Revision:
0:6038ca525e44
Child:
1:2021161b8fd2
This program is used to control a quadcopter.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kcherfou 0:6038ca525e44 1
kcherfou 0:6038ca525e44 2 #include "mbed.h"
kcherfou 0:6038ca525e44 3 #include "rtos.h"
kcherfou 0:6038ca525e44 4 #include "MPU6050.h"
kcherfou 0:6038ca525e44 5 #include "PwmIn.h"
kcherfou 0:6038ca525e44 6
kcherfou 0:6038ca525e44 7 //Functions
kcherfou 0:6038ca525e44 8 void PID1(void const *argument); //PID Control
kcherfou 0:6038ca525e44 9 void PeriodicInterruptISR(void); //Periodic Timer Interrupt Serive Routine
kcherfou 0:6038ca525e44 10 //Processes and Threads
kcherfou 0:6038ca525e44 11 osThreadId PiControlId; // Thread ID
kcherfou 0:6038ca525e44 12 osThreadDef(PID1, osPriorityRealtime, 1024); // Declare PiControlThread as a thread, highest priority
kcherfou 0:6038ca525e44 13
kcherfou 0:6038ca525e44 14 void receiver_data();
kcherfou 0:6038ca525e44 15 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 16
kcherfou 0:6038ca525e44 17 //System Definitions:
kcherfou 0:6038ca525e44 18 #define PWM_Period 20000 //in micro-seconds
kcherfou 0:6038ca525e44 19 #define ESC_ARM 1000 // this set the PWM signal to 50% duty cycle for a signal period of 2000 micro seconds
kcherfou 0:6038ca525e44 20 #define dt 0.005 // periodic interrupt each 20 ms... 50 Hz refresh rate of quadcopter motor speeds
kcherfou 0:6038ca525e44 21
kcherfou 0:6038ca525e44 22
kcherfou 0:6038ca525e44 23 // Controller Gains, and boundaries
kcherfou 0:6038ca525e44 24 //Roll
kcherfou 0:6038ca525e44 25 #define uRollMax 300
kcherfou 0:6038ca525e44 26 //Pitch
kcherfou 0:6038ca525e44 27 #define uPitchMax 300
kcherfou 0:6038ca525e44 28 // Throttle
kcherfou 0:6038ca525e44 29 #define MaxThrottle 1600 // 1600 micro seconds
kcherfou 0:6038ca525e44 30 #define MinThrottle 1100 // 1100 micro seconds
kcherfou 0:6038ca525e44 31 // Yaw
kcherfou 0:6038ca525e44 32 #define uYawMax 200
kcherfou 0:6038ca525e44 33
kcherfou 0:6038ca525e44 34 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 35
kcherfou 0:6038ca525e44 36 //Port Configuration:
kcherfou 0:6038ca525e44 37 // These are PWM In's that define the system's desired points and other control commands
kcherfou 0:6038ca525e44 38 // Note: the ports of the following PWM input pins have to be interrupt enabled (Port A and D are the only
kcherfou 0:6038ca525e44 39 // interrupt enabled ports for KL25z).
kcherfou 0:6038ca525e44 40 PwmIn channel1(PTA5); // Roll
kcherfou 0:6038ca525e44 41 PwmIn channel2(PTA13); // {itch
kcherfou 0:6038ca525e44 42 PwmIn channel3(PTA16); // Throttle
kcherfou 0:6038ca525e44 43 PwmIn channel4(PTA17); // Yaw
kcherfou 0:6038ca525e44 44
kcherfou 0:6038ca525e44 45 //PWM Outputs
kcherfou 0:6038ca525e44 46 // Configuration of motors:
kcherfou 0:6038ca525e44 47 // Motor4 Motor1
kcherfou 0:6038ca525e44 48 // . ^ .
kcherfou 0:6038ca525e44 49 // . | .
kcherfou 0:6038ca525e44 50 // . | .
kcherfou 0:6038ca525e44 51 // . .
kcherfou 0:6038ca525e44 52 // Motor3 Motor2
kcherfou 0:6038ca525e44 53 PwmOut PWM_motor1(PTB3); //PWM Motor1
kcherfou 0:6038ca525e44 54 PwmOut PWM_motor3(PTB1); //PWM Motor3
kcherfou 0:6038ca525e44 55 PwmOut PWM_motor2(PTB2); //PWM Motor2
kcherfou 0:6038ca525e44 56 PwmOut PWM_motor4(PTB0); //PWM Motor4
kcherfou 0:6038ca525e44 57
kcherfou 0:6038ca525e44 58 // MPU6050 gyroscope and accelerometer
kcherfou 0:6038ca525e44 59 // Note the library MPU6050.h must be modified to match the chosen I2C pins
kcherfou 0:6038ca525e44 60 // defined in the hardware design
kcherfou 0:6038ca525e44 61 MPU6050 mpu6050;
kcherfou 0:6038ca525e44 62
kcherfou 0:6038ca525e44 63 //Timer Interrupts
kcherfou 0:6038ca525e44 64 Timer t;
kcherfou 0:6038ca525e44 65 Ticker PeriodicInt; // Declare a timer interrupt: PeriodicInt
kcherfou 0:6038ca525e44 66 Serial pc(USBTX, USBRX); // tx, rx
kcherfou 0:6038ca525e44 67 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 68
kcherfou 0:6038ca525e44 69 //Gloabal Variables Definitions:
kcherfou 0:6038ca525e44 70
kcherfou 0:6038ca525e44 71 // PID
kcherfou 0:6038ca525e44 72 //Throttle
kcherfou 0:6038ca525e44 73 float desiredThrottle;
kcherfou 0:6038ca525e44 74 //Roll
kcherfou 0:6038ca525e44 75 float eRoll, desiredRoll, desRoll, actualRoll, eDerRoll, elastRoll, eIntRoll, uRoll;
kcherfou 0:6038ca525e44 76 float KpRoll, KdRoll, KiRoll;
kcherfou 0:6038ca525e44 77 //Pitch
kcherfou 0:6038ca525e44 78 float ePitch, desiredPitch, desPitch, actualPitch, eDerPitch, elastPitch, eIntPitch, uPitch;
kcherfou 0:6038ca525e44 79 float KpPitch, KdPitch, KiPitch;
kcherfou 0:6038ca525e44 80
kcherfou 0:6038ca525e44 81 //Yaw
kcherfou 0:6038ca525e44 82 float eYaw, desiredYaw, desYaw, actualYaw, eDerYaw, elastYaw, eIntYaw, uYaw;
kcherfou 0:6038ca525e44 83 float KpYaw, KdYaw, KiYaw;
kcherfou 0:6038ca525e44 84
kcherfou 0:6038ca525e44 85 // control speeds of the motors
kcherfou 0:6038ca525e44 86 float v1, v2, v3, v4;
kcherfou 0:6038ca525e44 87
kcherfou 0:6038ca525e44 88 // Gyro Stuff
kcherfou 0:6038ca525e44 89 float sum = 0;
kcherfou 0:6038ca525e44 90 uint32_t sumCount = 0;
kcherfou 0:6038ca525e44 91
kcherfou 0:6038ca525e44 92
kcherfou 0:6038ca525e44 93 float RollCalibration, PitchCalibration, YawCalibration;
kcherfou 0:6038ca525e44 94 float actRoll, actPitch, actYaw;
kcherfou 0:6038ca525e44 95
kcherfou 0:6038ca525e44 96 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 97
kcherfou 0:6038ca525e44 98 int main() {
kcherfou 0:6038ca525e44 99
kcherfou 0:6038ca525e44 100 // System setup
kcherfou 0:6038ca525e44 101 // this sets up the periodic interrupt, the UART baud rate communication with the PC, as well as
kcherfou 0:6038ca525e44 102 // setting up the PWM signal period of each motor.
kcherfou 0:6038ca525e44 103 pc.baud(9600); // Set max uart baud rate
kcherfou 0:6038ca525e44 104 pc.printf("We have good serial communication! :D\n");
kcherfou 0:6038ca525e44 105
kcherfou 0:6038ca525e44 106 //Initializing Threads for interrupts
kcherfou 0:6038ca525e44 107 PiControlId = osThreadCreate(osThread(PID1), NULL); //Create Thread for PID1
kcherfou 0:6038ca525e44 108 PeriodicInt.attach(&PeriodicInterruptISR, dt); //Periodic timer interrupt every dt seconds as defined above
kcherfou 0:6038ca525e44 109
kcherfou 0:6038ca525e44 110 //PWM Period
kcherfou 0:6038ca525e44 111 PWM_motor1.period_us(PWM_Period); // This sets the PWM period to [PWM_Period]
kcherfou 0:6038ca525e44 112 PWM_motor2.period_us(PWM_Period); //
kcherfou 0:6038ca525e44 113 PWM_motor3.period_us(PWM_Period); //
kcherfou 0:6038ca525e44 114 PWM_motor4.period_us(PWM_Period); //
kcherfou 0:6038ca525e44 115
kcherfou 0:6038ca525e44 116 // this sets all motor PWM signals to 50% to arm the esc's for operation
kcherfou 0:6038ca525e44 117 PWM_motor1.pulsewidth_us(2000); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 118 PWM_motor2.pulsewidth_us(2000); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 119 PWM_motor3.pulsewidth_us(2000); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 120 PWM_motor4.pulsewidth_us(2000); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 121
kcherfou 0:6038ca525e44 122 wait(10);
kcherfou 0:6038ca525e44 123 PWM_motor1.pulsewidth_us(ESC_ARM); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 124 PWM_motor2.pulsewidth_us(ESC_ARM); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 125 PWM_motor3.pulsewidth_us(ESC_ARM); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 126 PWM_motor4.pulsewidth_us(ESC_ARM); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 127
kcherfou 0:6038ca525e44 128 KpRoll = .55;
kcherfou 0:6038ca525e44 129 KdRoll = 0;
kcherfou 0:6038ca525e44 130 KiRoll = 0;
kcherfou 0:6038ca525e44 131
kcherfou 0:6038ca525e44 132 KpPitch = KpRoll;
kcherfou 0:6038ca525e44 133 KdPitch = KdRoll;
kcherfou 0:6038ca525e44 134 KiPitch = KiRoll;
kcherfou 0:6038ca525e44 135
kcherfou 0:6038ca525e44 136 //Set up I2C
kcherfou 0:6038ca525e44 137 i2c.frequency(400000); // use fast (400 kHz) I2C
kcherfou 0:6038ca525e44 138 t.start();
kcherfou 0:6038ca525e44 139 // Read the WHO_AM_I register, this is a good test of communication
kcherfou 0:6038ca525e44 140 uint8_t whoami = mpu6050.readByte(MPU6050_ADDRESS, WHO_AM_I_MPU6050); // Read WHO_AM_I register for MPU-6050
kcherfou 0:6038ca525e44 141 pc.printf("I AM 0x%x\n\r", whoami); pc.printf("I SHOULD BE 0x68\n\r");
kcherfou 0:6038ca525e44 142
kcherfou 0:6038ca525e44 143 if (whoami == 0x68){ // WHO_AM_I should always be 0x68
kcherfou 0:6038ca525e44 144
kcherfou 0:6038ca525e44 145 pc.printf("MPU6050 is online...");
kcherfou 0:6038ca525e44 146 wait(1);
kcherfou 0:6038ca525e44 147 mpu6050.MPU6050SelfTest(SelfTest); // Start by performing self test and reporting values
kcherfou 0:6038ca525e44 148 pc.printf("x-axis self test: acceleration trim within : ");
kcherfou 0:6038ca525e44 149 pc.printf("%f \n\r", SelfTest[0]);
kcherfou 0:6038ca525e44 150 pc.printf("y-axis self test: acceleration trim within : ");
kcherfou 0:6038ca525e44 151 pc.printf("%f \n\r", SelfTest[1]);
kcherfou 0:6038ca525e44 152 pc.printf("z-axis self test: acceleration trim within : ");
kcherfou 0:6038ca525e44 153 pc.printf("%f \n\r", SelfTest[2]);
kcherfou 0:6038ca525e44 154 pc.printf("x-axis self test: gyration trim within : ");
kcherfou 0:6038ca525e44 155 pc.printf("%f \n\r", SelfTest[3]);
kcherfou 0:6038ca525e44 156 pc.printf("y-axis self test: gyration trim within : ");
kcherfou 0:6038ca525e44 157 pc.printf("%f \n\r", SelfTest[4]);
kcherfou 0:6038ca525e44 158 pc.printf("z-axis self test: gyration trim within : ");
kcherfou 0:6038ca525e44 159 pc.printf("%f \n\r", SelfTest[5]);
kcherfou 0:6038ca525e44 160
kcherfou 0:6038ca525e44 161 wait(1);
kcherfou 0:6038ca525e44 162
kcherfou 0:6038ca525e44 163 if(SelfTest[0] < 1.0f && SelfTest[1] < 1.0f && SelfTest[2] < 1.0f && SelfTest[3] < 1.0f && SelfTest[4] < 1.0f && SelfTest[5] < 1.0f){
kcherfou 0:6038ca525e44 164 mpu6050.resetMPU6050(); // Reset registers to default in preparation for device calibration
kcherfou 0:6038ca525e44 165 mpu6050.calibrateMPU6050(gyroBias, accelBias); // Calibrate gyro and accelerometers, load biases in bias registers
kcherfou 0:6038ca525e44 166 mpu6050.initMPU6050(); pc.printf("MPU6050 initialized for active data mode....\n\r"); // Initialize device for active mode read of acclerometer, gyroscope, and temperature
kcherfou 0:6038ca525e44 167
kcherfou 0:6038ca525e44 168 wait(2);
kcherfou 0:6038ca525e44 169 }
kcherfou 0:6038ca525e44 170 else {
kcherfou 0:6038ca525e44 171 pc.printf("Device did not the pass self-test!\n\r");
kcherfou 0:6038ca525e44 172 }
kcherfou 0:6038ca525e44 173 }
kcherfou 0:6038ca525e44 174
kcherfou 0:6038ca525e44 175 else{
kcherfou 0:6038ca525e44 176 pc.printf("Could not connect to MPU6050: \n\r");
kcherfou 0:6038ca525e44 177 pc.printf("%#x \n", whoami);
kcherfou 0:6038ca525e44 178 while(1) ; // Loop forever if communication doesn't happen
kcherfou 0:6038ca525e44 179 }
kcherfou 0:6038ca525e44 180
kcherfou 0:6038ca525e44 181 wait(10); // wait 10 seconds to make sure esc's are armed and ready to go
kcherfou 0:6038ca525e44 182
kcherfou 0:6038ca525e44 183 // counter for mpu calibration
kcherfou 0:6038ca525e44 184 int counter = 0;
kcherfou 0:6038ca525e44 185 //Loop Forever
kcherfou 0:6038ca525e44 186 while (1) {
kcherfou 0:6038ca525e44 187
kcherfou 0:6038ca525e44 188
kcherfou 0:6038ca525e44 189 // If data ready bit set, all data registers have new data
kcherfou 0:6038ca525e44 190 if(mpu6050.readByte(MPU6050_ADDRESS, INT_STATUS) & 0x01) { // check if data ready interrupt
kcherfou 0:6038ca525e44 191 mpu6050.readAccelData(accelCount); // Read the x/y/z adc values
kcherfou 0:6038ca525e44 192 mpu6050.getAres();
kcherfou 0:6038ca525e44 193
kcherfou 0:6038ca525e44 194 // Now we'll calculate the accleration value into actual g's
kcherfou 0:6038ca525e44 195 ax = (float)accelCount[0]*aRes - accelBias[0]; // get actual g value, this depends on scale being set
kcherfou 0:6038ca525e44 196 ay = (float)accelCount[1]*aRes - accelBias[1];
kcherfou 0:6038ca525e44 197 az = (float)accelCount[2]*aRes - accelBias[2];
kcherfou 0:6038ca525e44 198
kcherfou 0:6038ca525e44 199 mpu6050.readGyroData(gyroCount); // Read the x/y/z adc values
kcherfou 0:6038ca525e44 200 mpu6050.getGres();
kcherfou 0:6038ca525e44 201
kcherfou 0:6038ca525e44 202 // Calculate the gyro value into actual degrees per second
kcherfou 0:6038ca525e44 203 gx = (float)gyroCount[0]*gRes; // - gyroBias[0]; // get actual gyro value, this depends on scale being set
kcherfou 0:6038ca525e44 204 gy = (float)gyroCount[1]*gRes; // - gyroBias[1];
kcherfou 0:6038ca525e44 205 gz = (float)gyroCount[2]*gRes; // - gyroBias[2];
kcherfou 0:6038ca525e44 206
kcherfou 0:6038ca525e44 207 tempCount = mpu6050.readTempData(); // Read the x/y/z adc values
kcherfou 0:6038ca525e44 208 temperature = (tempCount) / 340. + 36.53; // Temperature in degrees Centigrade
kcherfou 0:6038ca525e44 209 }
kcherfou 0:6038ca525e44 210
kcherfou 0:6038ca525e44 211 Now = t.read_us();
kcherfou 0:6038ca525e44 212 deltat = (float)((Now - lastUpdate)/1000000.0f) ; // set integration time by time elapsed since last filter update
kcherfou 0:6038ca525e44 213 lastUpdate = Now;
kcherfou 0:6038ca525e44 214
kcherfou 0:6038ca525e44 215 sum += deltat;
kcherfou 0:6038ca525e44 216 sumCount++;
kcherfou 0:6038ca525e44 217
kcherfou 0:6038ca525e44 218 if(lastUpdate - firstUpdate > 10000000.0f) {
kcherfou 0:6038ca525e44 219 beta = 0.04; // decrease filter gain after stabilized
kcherfou 0:6038ca525e44 220 zeta = 0.015; // increasey bias drift gain after stabilized
kcherfou 0:6038ca525e44 221 }
kcherfou 0:6038ca525e44 222
kcherfou 0:6038ca525e44 223 // Pass gyro rate as rad/s
kcherfou 0:6038ca525e44 224 mpu6050.MadgwickQuaternionUpdate(ax, ay, az, gx*PI/180.0f, gy*PI/180.0f, gz*PI/180.0f);
kcherfou 0:6038ca525e44 225
kcherfou 0:6038ca525e44 226
kcherfou 0:6038ca525e44 227 // Define output variables from updated quaternion---these are Tait-Bryan angles, commonly used in aircraft orientation.
kcherfou 0:6038ca525e44 228 // In this coordinate system, the positive z-axis is down toward Earth.
kcherfou 0:6038ca525e44 229 // Yaw is the angle between Sensor x-axis and Earth magnetic North (or true North if corrected for local declination, looking down on the sensor positive yaw is counterclockwise.
kcherfou 0:6038ca525e44 230 // Pitch is angle between sensor x-axis and Earth ground plane, toward the Earth is positive, up toward the sky is negative.
kcherfou 0:6038ca525e44 231 // Roll is angle between sensor y-axis and Earth ground plane, y-axis up is positive roll.
kcherfou 0:6038ca525e44 232 // These arise from the definition of the homogeneous rotation matrix constructed from quaternions.
kcherfou 0:6038ca525e44 233 // Tait-Bryan angles as well as Euler angles are non-commutative; that is, the get the correct orientation the rotations must be
kcherfou 0:6038ca525e44 234 // applied in the correct order which for this configuration is yaw, pitch, and then roll.
kcherfou 0:6038ca525e44 235 // For more see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles which has additional links.
kcherfou 0:6038ca525e44 236 yaw = atan2(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
kcherfou 0:6038ca525e44 237 pitch = -asin(2.0f * (q[1] * q[3] - q[0] * q[2]));
kcherfou 0:6038ca525e44 238 roll = atan2(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
kcherfou 0:6038ca525e44 239 actPitch = pitch * 180.0f / PI;
kcherfou 0:6038ca525e44 240 actYaw = yaw * 180.0f / PI;
kcherfou 0:6038ca525e44 241 actRoll = roll * 180.0f / PI;
kcherfou 0:6038ca525e44 242
kcherfou 0:6038ca525e44 243 if (counter < 800){
kcherfou 0:6038ca525e44 244 counter++;
kcherfou 0:6038ca525e44 245 RollCalibration = actRoll;
kcherfou 0:6038ca525e44 246 PitchCalibration= actPitch;
kcherfou 0:6038ca525e44 247 YawCalibration = actYaw;
kcherfou 0:6038ca525e44 248 }
kcherfou 0:6038ca525e44 249 else{
kcherfou 0:6038ca525e44 250
kcherfou 0:6038ca525e44 251 actRoll = actRoll - RollCalibration;
kcherfou 0:6038ca525e44 252 actualRoll = actPitch - PitchCalibration;
kcherfou 0:6038ca525e44 253 actualYaw = actYaw - YawCalibration;
kcherfou 0:6038ca525e44 254
kcherfou 0:6038ca525e44 255 if(actRoll > 180){
kcherfou 0:6038ca525e44 256 actualPitch=-(actRoll-360);
kcherfou 0:6038ca525e44 257 }
kcherfou 0:6038ca525e44 258 if(actRoll < -180){
kcherfou 0:6038ca525e44 259 actualPitch=-(actRoll+360);
kcherfou 0:6038ca525e44 260 }
kcherfou 0:6038ca525e44 261 if ((actRoll > -180) && actRoll < 180) {
kcherfou 0:6038ca525e44 262 actualPitch=-actRoll;
kcherfou 0:6038ca525e44 263 }
kcherfou 0:6038ca525e44 264
kcherfou 0:6038ca525e44 265
kcherfou 0:6038ca525e44 266 // Measuring receiver values
kcherfou 0:6038ca525e44 267 desRoll = 1000000 * channel1.pulsewidth(); // desired point for roll
kcherfou 0:6038ca525e44 268 desPitch = 1000000 * channel2.pulsewidth(); // desired point for pitch
kcherfou 0:6038ca525e44 269 desiredThrottle = 1000000 * channel3.pulsewidth(); // desired point for throttle
kcherfou 0:6038ca525e44 270 desYaw = 1000000 * channel4.pulsewidth(); // desired point for yaw
kcherfou 0:6038ca525e44 271
kcherfou 0:6038ca525e44 272 // The desired roll, pitch and yaw has a range between 1000 to 2000 microseconds
kcherfou 0:6038ca525e44 273 // we will map these values to limit the desired input between -45deg to +45deg for roll and pitch
kcherfou 0:6038ca525e44 274 // As for yaw, the desired input will range between -180 to 180 deg
kcherfou 0:6038ca525e44 275 //
kcherfou 0:6038ca525e44 276 // The equaion below maps the PWM value to a desired deg value, then it is shifter by some amount of degree so that
kcherfou 0:6038ca525e44 277 // the 1000 us is equivalent to -45deg, and the 2000 us point is equivalent to 45deg.
kcherfou 0:6038ca525e44 278 // The same logic is used for the Yaw equation
kcherfou 0:6038ca525e44 279 desiredRoll = (90 * (abs(desRoll -1000))/1000) - 45;
kcherfou 0:6038ca525e44 280 desiredPitch= (90 * (abs(desPitch-1000))/1000) - 45;
kcherfou 0:6038ca525e44 281 desiredYaw = (360* (abs(desYaw -1000))/1000) - 180;
kcherfou 0:6038ca525e44 282 }
kcherfou 0:6038ca525e44 283 // pc.printf("%f %f %f\n\r", actualPitch, desiredPitch, ePitch);
kcherfou 0:6038ca525e44 284 // pc.printf("%f %f %f %f\n\r ", uRoll, uPitch, eRoll, ePitch);
kcherfou 0:6038ca525e44 285
kcherfou 0:6038ca525e44 286 pc.printf("%f %f %f %f\n\r", v1, v2, v3, v4);
kcherfou 0:6038ca525e44 287 // pc.printf("%f %f %f %f %f %f \n\r\n\r\n\r", actualRoll, desiredRoll, actualPitch, desiredPitch, actualYaw, eYaw );
kcherfou 0:6038ca525e44 288 /*
kcherfou 0:6038ca525e44 289 pc.printf("%f \n\r", v1);
kcherfou 0:6038ca525e44 290 pc.printf("%f \n\r", v2);
kcherfou 0:6038ca525e44 291 pc.printf("%f \n\r", v3);
kcherfou 0:6038ca525e44 292 pc.printf("%f \n\r \n\r", v4);
kcherfou 0:6038ca525e44 293
kcherfou 0:6038ca525e44 294 pc.printf("error in roll %f \n\r \n\r", eRoll);
kcherfou 0:6038ca525e44 295 pc.printf("error in pitch %f \n\r \n\r", ePitch);
kcherfou 0:6038ca525e44 296 pc.printf("error in yaw %f \n\r \n\r", eYaw);*/
kcherfou 0:6038ca525e44 297 /*
kcherfou 0:6038ca525e44 298 pc.printf("Pulse width Roll value %f \n\r",desRoll);
kcherfou 0:6038ca525e44 299 pc.printf("Pulse width Pitch value %f \n\r",desPitch);
kcherfou 0:6038ca525e44 300 pc.printf("Pulse width Throttle value %f \n\r",desiredThrottle);
kcherfou 0:6038ca525e44 301 pc.printf("Pulse width Yaw value %f \n\r",desYaw);
kcherfou 0:6038ca525e44 302 */
kcherfou 0:6038ca525e44 303 /*
kcherfou 0:6038ca525e44 304 pc.printf("Desired Roll: %f \n\r", desiredRoll);
kcherfou 0:6038ca525e44 305 pc.printf("Desired Pitch: %f \n\r", desiredPitch);
kcherfou 0:6038ca525e44 306 pc.printf("Desired Throttle: %f \n\r", desiredThrottle);
kcherfou 0:6038ca525e44 307 pc.printf("Desired Yaw: %f \n\r", desiredYaw);
kcherfou 0:6038ca525e44 308 */
kcherfou 0:6038ca525e44 309 myled= !myled;
kcherfou 0:6038ca525e44 310 count = t.read_ms();
kcherfou 0:6038ca525e44 311 sum = 0;
kcherfou 0:6038ca525e44 312 sumCount = 0;
kcherfou 0:6038ca525e44 313
kcherfou 0:6038ca525e44 314 //wait(.5);
kcherfou 0:6038ca525e44 315
kcherfou 0:6038ca525e44 316 }
kcherfou 0:6038ca525e44 317
kcherfou 0:6038ca525e44 318
kcherfou 0:6038ca525e44 319
kcherfou 0:6038ca525e44 320 }
kcherfou 0:6038ca525e44 321
kcherfou 0:6038ca525e44 322
kcherfou 0:6038ca525e44 323
kcherfou 0:6038ca525e44 324 // Updated on: Sept 19 2019
kcherfou 0:6038ca525e44 325 // Koceila Cherfouh
kcherfou 0:6038ca525e44 326 // Deescription
kcherfou 0:6038ca525e44 327 // periodic time interrupt that controls the speed of the motor based on the gyro and accelerometer readings using a PID controller.
kcherfou 0:6038ca525e44 328 //
kcherfou 0:6038ca525e44 329 // Update and whats left to do:
kcherfou 0:6038ca525e44 330 // make sure all variables are declared. define max values, and gain values for each PID controllers.
kcherfou 0:6038ca525e44 331 // define the motor speed assignment based on the system's kinematic model
kcherfou 0:6038ca525e44 332 // test and tune the controller gain
kcherfou 0:6038ca525e44 333
kcherfou 0:6038ca525e44 334 // ******** Periodic Thread ********
kcherfou 0:6038ca525e44 335 void PID1(void const *argument){
kcherfou 0:6038ca525e44 336
kcherfou 0:6038ca525e44 337 while(true){
kcherfou 0:6038ca525e44 338 osSignalWait(0x1, osWaitForever); // Go to sleep until signal is received.
kcherfou 0:6038ca525e44 339
kcherfou 0:6038ca525e44 340 if (desiredThrottle > 1050){ // 1050 micro seconds will serve as the activation throttle
kcherfou 0:6038ca525e44 341 // 1- PID roll
kcherfou 0:6038ca525e44 342 eRoll= desiredRoll - actualRoll;
kcherfou 0:6038ca525e44 343 eDerRoll = eRoll - elastRoll; // derivative of error
kcherfou 0:6038ca525e44 344 uRoll = (KpRoll * eRoll) + (KdRoll * eDerRoll) + (KiRoll * eIntRoll); // computing the pitch control input
kcherfou 0:6038ca525e44 345 // this part of the code limits the integrator windeup. an effect that takes place when
kcherfou 0:6038ca525e44 346 if (uRoll > uRollMax){
kcherfou 0:6038ca525e44 347 uRoll = uRollMax;
kcherfou 0:6038ca525e44 348 }
kcherfou 0:6038ca525e44 349 if (uRoll < -uRollMax){
kcherfou 0:6038ca525e44 350 uRoll = -uRollMax;
kcherfou 0:6038ca525e44 351 }
kcherfou 0:6038ca525e44 352 else {
kcherfou 0:6038ca525e44 353 eIntRoll += eRoll; // Computing the integral sum
kcherfou 0:6038ca525e44 354 }
kcherfou 0:6038ca525e44 355 elastRoll = eRoll;
kcherfou 0:6038ca525e44 356 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 357 // 2- PID pitch
kcherfou 0:6038ca525e44 358 ePitch = desiredPitch - actualPitch; // error
kcherfou 0:6038ca525e44 359 eDerPitch = ePitch - elastPitch ; // derivative of error
kcherfou 0:6038ca525e44 360 uPitch = (KpPitch * ePitch) + (KdPitch * eDerPitch) + (KiPitch * eIntPitch); // computing the pitch control input
kcherfou 0:6038ca525e44 361 // this part of the code limits the integrator windeup. an effect that takes place when
kcherfou 0:6038ca525e44 362 if (uPitch > uPitchMax){
kcherfou 0:6038ca525e44 363 uPitch = uPitchMax;
kcherfou 0:6038ca525e44 364 }
kcherfou 0:6038ca525e44 365 if (uPitch < -uPitchMax){
kcherfou 0:6038ca525e44 366 uPitch = -uPitchMax;
kcherfou 0:6038ca525e44 367 }
kcherfou 0:6038ca525e44 368 else {
kcherfou 0:6038ca525e44 369 eIntPitch += ePitch; // Computing the integral sum
kcherfou 0:6038ca525e44 370 }
kcherfou 0:6038ca525e44 371 elastPitch = ePitch;
kcherfou 0:6038ca525e44 372 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 373 // 4- PID yaw
kcherfou 0:6038ca525e44 374 /* eYaw= desiredYaw - actualYaw;
kcherfou 0:6038ca525e44 375 eDerYaw = eYaw - elastYaw ; // derivative of error
kcherfou 0:6038ca525e44 376 uYaw = (KpYaw * eYaw) + (KdYaw * eDerYaw) + (KiYaw * eIntYaw); // computing the pitch control input
kcherfou 0:6038ca525e44 377 // this part of the code limits the integrator windeup. an effect that takes place when
kcherfou 0:6038ca525e44 378 if (uYaw > uYawMax){
kcherfou 0:6038ca525e44 379 uYaw = uYawMax;
kcherfou 0:6038ca525e44 380 }
kcherfou 0:6038ca525e44 381 else {
kcherfou 0:6038ca525e44 382 eIntYaw += eYaw; // Computing the integral sum
kcherfou 0:6038ca525e44 383 }
kcherfou 0:6038ca525e44 384 elastYaw = eYaw; */
kcherfou 0:6038ca525e44 385 //-------------------------------------------------------------------------------------------------------------
kcherfou 0:6038ca525e44 386 // Now that all pid control inputs are computed. send the PWM control input using the kinematic model to the ESC's
kcherfou 0:6038ca525e44 387 v1= desiredThrottle - uPitch - uRoll - uYaw; //Calculate the pulse for esc 1 (front-right - CCW)
kcherfou 0:6038ca525e44 388 v2= desiredThrottle + uPitch - uRoll + uYaw; //Calculate the pulse for esc 2 (rear-right - CW)
kcherfou 0:6038ca525e44 389 v3= desiredThrottle + uPitch + uRoll - uYaw; //Calculate the pulse for esc 3 (rear-left - CCW)
kcherfou 0:6038ca525e44 390 v4= desiredThrottle - uPitch + uRoll + uYaw; //Calculate the pulse for esc 4 (front-left - CW)
kcherfou 0:6038ca525e44 391
kcherfou 0:6038ca525e44 392 if ( v1 > 2000 ){
kcherfou 0:6038ca525e44 393 v1=2000;
kcherfou 0:6038ca525e44 394 }
kcherfou 0:6038ca525e44 395 if ( v1 < 1000){
kcherfou 0:6038ca525e44 396 v1=1000;
kcherfou 0:6038ca525e44 397 }
kcherfou 0:6038ca525e44 398 if ( v2 > 2000 ){
kcherfou 0:6038ca525e44 399 v2=2000;
kcherfou 0:6038ca525e44 400 }
kcherfou 0:6038ca525e44 401 if ( v2 < 1000){
kcherfou 0:6038ca525e44 402 v2=1000;
kcherfou 0:6038ca525e44 403 }
kcherfou 0:6038ca525e44 404 if ( v3 > 2000 ){
kcherfou 0:6038ca525e44 405 v3=2000;
kcherfou 0:6038ca525e44 406 }
kcherfou 0:6038ca525e44 407 if ( v3 < 1000){
kcherfou 0:6038ca525e44 408 v3=1000;
kcherfou 0:6038ca525e44 409 }
kcherfou 0:6038ca525e44 410 if ( v4 > 2000 ){
kcherfou 0:6038ca525e44 411 v4=2000;
kcherfou 0:6038ca525e44 412 }
kcherfou 0:6038ca525e44 413 if ( v4 < 1000){
kcherfou 0:6038ca525e44 414 v4=1000;
kcherfou 0:6038ca525e44 415 }
kcherfou 0:6038ca525e44 416 }
kcherfou 0:6038ca525e44 417 else{ // In the case where desired throttle is <1050 microseconds, we want to deactivate all motors
kcherfou 0:6038ca525e44 418 v1= desiredThrottle;
kcherfou 0:6038ca525e44 419 v2= desiredThrottle;
kcherfou 0:6038ca525e44 420 v3= desiredThrottle;
kcherfou 0:6038ca525e44 421 v4= desiredThrottle;
kcherfou 0:6038ca525e44 422 }
kcherfou 0:6038ca525e44 423
kcherfou 0:6038ca525e44 424 // outputing the necessary PWM value to the motors
kcherfou 0:6038ca525e44 425 PWM_motor1.pulsewidth_us(abs(v1)); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 426 PWM_motor2.pulsewidth_us(abs(v2)); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 427 PWM_motor3.pulsewidth_us(abs(v3)); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 428 PWM_motor4.pulsewidth_us(abs(v4)); //Set the Pulsewidth output
kcherfou 0:6038ca525e44 429
kcherfou 0:6038ca525e44 430 }
kcherfou 0:6038ca525e44 431
kcherfou 0:6038ca525e44 432 }
kcherfou 0:6038ca525e44 433
kcherfou 0:6038ca525e44 434
kcherfou 0:6038ca525e44 435 // ******** Periodic Interrupt Handler 1********
kcherfou 0:6038ca525e44 436 void PeriodicInterruptISR(void){
kcherfou 0:6038ca525e44 437 osSignalSet(PiControlId,0x1); // Activate the signal, PiControl, with each periodic timer interrupt.
kcherfou 0:6038ca525e44 438 }
kcherfou 0:6038ca525e44 439