Line following bot using MAXREFDES89, MAX32600MBED, and Pololu QTR-RC sensor

Dependencies:   MAX14871_Shield mbed

Committer:
j3
Date:
Mon Dec 14 00:03:54 2015 +0000
Revision:
0:d2693f27f344
Child:
1:b928ca54cd1a
initial commit, ported my code over from the prop and switched from using the HB-25 motor drivers to MAXREFDES89#.  Need to redue scaling for zones and loop.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
j3 0:d2693f27f344 1 /**********************************************************************
j3 0:d2693f27f344 2 * Simple line following bot with PID to demo MAXREFDES89#
j3 0:d2693f27f344 3 * PID feedback comes from infrared led sensor from Parallax
j3 0:d2693f27f344 4 * https://www.parallax.com/product/28034
j3 0:d2693f27f344 5 **********************************************************************/
j3 0:d2693f27f344 6
j3 0:d2693f27f344 7 #include "mbed.h"
j3 0:d2693f27f344 8 #include "max14871_shield.h"
j3 0:d2693f27f344 9
j3 0:d2693f27f344 10
j3 0:d2693f27f344 11 float ramp(float val, float val_old);
j3 0:d2693f27f344 12
j3 0:d2693f27f344 13 bool run = false;
j3 0:d2693f27f344 14 DigitalOut run_led(LED_GREEN, 1); //leds have inverted logic
j3 0:d2693f27f344 15 DigitalOut stop_led(LED_RED, 0);
j3 0:d2693f27f344 16
j3 0:d2693f27f344 17 InterruptIn start_stop_button(SW3);
j3 0:d2693f27f344 18
j3 0:d2693f27f344 19 void start_stop()
j3 0:d2693f27f344 20 {
j3 0:d2693f27f344 21 run = !run;
j3 0:d2693f27f344 22 run_led = !run_led;
j3 0:d2693f27f344 23 stop_led = !stop_led;
j3 0:d2693f27f344 24 }
j3 0:d2693f27f344 25
j3 0:d2693f27f344 26
j3 0:d2693f27f344 27 int main(void)
j3 0:d2693f27f344 28 {
j3 0:d2693f27f344 29 start_stop_button.fall(&start_stop);
j3 0:d2693f27f344 30
j3 0:d2693f27f344 31 BusIn ir_bus(P4_0, P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7);
j3 0:d2693f27f344 32 DigitalOut ir_bus_enable(D3, 1); //active high enable
j3 0:d2693f27f344 33
j3 0:d2693f27f344 34 Max14871_Shield motor_shield(D14, D15, true);// Default config
j3 0:d2693f27f344 35
j3 0:d2693f27f344 36 Max14871_Shield::max14871_motor_driver_t r_motor_driver = Max14871_Shield::MD4;
j3 0:d2693f27f344 37 Max14871_Shield::max14871_motor_driver_t l_motor_driver = Max14871_Shield::MD3;
j3 0:d2693f27f344 38
j3 0:d2693f27f344 39 const float MAX_DUTY_CYCLE = 1.0;
j3 0:d2693f27f344 40 const float MIN_DUTY_CYCLE = 0.0;
j3 0:d2693f27f344 41
j3 0:d2693f27f344 42 //set point is for position relative to line, not duty cycle of pwm
j3 0:d2693f27f344 43 const float SP = 0.0;
j3 0:d2693f27f344 44 const float KP = 1.0;
j3 0:d2693f27f344 45 const float KI = 0.0;
j3 0:d2693f27f344 46 const float KD = 0.0;
j3 0:d2693f27f344 47 //const float OFFSET = 0;
j3 0:d2693f27f344 48
j3 0:d2693f27f344 49 //raw sensor data
j3 0:d2693f27f344 50 uint8_t ir_val = 0;
j3 0:d2693f27f344 51
j3 0:d2693f27f344 52 const uint8_t ZONE_8 = 0xFF;
j3 0:d2693f27f344 53 const uint8_t ZONE_7 = 0xFE;
j3 0:d2693f27f344 54 const uint8_t ZONE_6 = 0xFC;
j3 0:d2693f27f344 55 const uint8_t ZONE_5 = 0xFD;
j3 0:d2693f27f344 56 const uint8_t ZONE_4 = 0xF9;
j3 0:d2693f27f344 57 const uint8_t ZONE_3 = 0xFB;
j3 0:d2693f27f344 58 const uint8_t ZONE_2 = 0xF3;
j3 0:d2693f27f344 59 const uint8_t ZONE_1 = 0xF7;
j3 0:d2693f27f344 60 const uint8_t ZONE_0 = 0xE7;
j3 0:d2693f27f344 61 const uint8_t ZONE_N1 = 0xEF;
j3 0:d2693f27f344 62 const uint8_t ZONE_N2 = 0xCF;
j3 0:d2693f27f344 63 const uint8_t ZONE_N3 = 0xDF;
j3 0:d2693f27f344 64 const uint8_t ZONE_N4 = 0x9F;
j3 0:d2693f27f344 65 const uint8_t ZONE_N5 = 0xBF;
j3 0:d2693f27f344 66 const uint8_t ZONE_N6 = 0x3F;
j3 0:d2693f27f344 67 const uint8_t ZONE_N7 = 0x7F;
j3 0:d2693f27f344 68 const uint8_t ZONE_LT0 = 0xE0;
j3 0:d2693f27f344 69 const uint8_t ZONE_LT1 = 0xF0;
j3 0:d2693f27f344 70 const uint8_t ZONE_LT2 = 0xF8;
j3 0:d2693f27f344 71 const uint8_t ZONE_RT0 = 0x07;
j3 0:d2693f27f344 72 const uint8_t ZONE_RT1 = 0x0F;
j3 0:d2693f27f344 73 const uint8_t ZONE_RT2 = 0x1F;
j3 0:d2693f27f344 74
j3 0:d2693f27f344 75 float r_duty_cycle = 0.0;
j3 0:d2693f27f344 76 float r_duty_cycle_old = r_duty_cycle;
j3 0:d2693f27f344 77
j3 0:d2693f27f344 78 float l_duty_cycle = 0.0;
j3 0:d2693f27f344 79 float l_duty_cycle_old = l_duty_cycle;
j3 0:d2693f27f344 80
j3 0:d2693f27f344 81 float fb = 0;
j3 0:d2693f27f344 82 float current_error = 0;
j3 0:d2693f27f344 83 float previous_error = 0;
j3 0:d2693f27f344 84 float integral = 0;
j3 0:d2693f27f344 85 float derivative = 0;
j3 0:d2693f27f344 86
j3 0:d2693f27f344 87 for(;;)
j3 0:d2693f27f344 88 {
j3 0:d2693f27f344 89 //wait for start_stop button press
j3 0:d2693f27f344 90 while(!run);
j3 0:d2693f27f344 91
j3 0:d2693f27f344 92 //mode is set to forward, but duty cycle is still 0.0
j3 0:d2693f27f344 93 motor_shield.set_operating_mode(l_motor_driver, Max14871_Shield::FORWARD);
j3 0:d2693f27f344 94 motor_shield.set_operating_mode(r_motor_driver, Max14871_Shield::FORWARD);
j3 0:d2693f27f344 95
j3 0:d2693f27f344 96 while(run)
j3 0:d2693f27f344 97 {
j3 0:d2693f27f344 98 ir_val = ~(ir_bus.read());
j3 0:d2693f27f344 99
j3 0:d2693f27f344 100 //scale feedback
j3 0:d2693f27f344 101 switch(ir_val)
j3 0:d2693f27f344 102 {
j3 0:d2693f27f344 103 case(ZONE_8):
j3 0:d2693f27f344 104 if(fb < 0)
j3 0:d2693f27f344 105 {
j3 0:d2693f27f344 106 fb = -8;
j3 0:d2693f27f344 107 }
j3 0:d2693f27f344 108 else
j3 0:d2693f27f344 109 {
j3 0:d2693f27f344 110 fb = 8;
j3 0:d2693f27f344 111 }
j3 0:d2693f27f344 112 break;
j3 0:d2693f27f344 113
j3 0:d2693f27f344 114 case(ZONE_7):
j3 0:d2693f27f344 115 fb = 7;
j3 0:d2693f27f344 116 break;
j3 0:d2693f27f344 117
j3 0:d2693f27f344 118 case(ZONE_6):
j3 0:d2693f27f344 119 fb = 6;
j3 0:d2693f27f344 120 break;
j3 0:d2693f27f344 121
j3 0:d2693f27f344 122 case(ZONE_5):
j3 0:d2693f27f344 123 fb = 5;
j3 0:d2693f27f344 124 break;
j3 0:d2693f27f344 125
j3 0:d2693f27f344 126 case(ZONE_4):
j3 0:d2693f27f344 127 fb = 4;
j3 0:d2693f27f344 128 break;
j3 0:d2693f27f344 129
j3 0:d2693f27f344 130 case(ZONE_3):
j3 0:d2693f27f344 131 fb = 3;
j3 0:d2693f27f344 132 break;
j3 0:d2693f27f344 133
j3 0:d2693f27f344 134 case(ZONE_2):
j3 0:d2693f27f344 135 fb = 2;
j3 0:d2693f27f344 136 break;
j3 0:d2693f27f344 137
j3 0:d2693f27f344 138 case(ZONE_1):
j3 0:d2693f27f344 139 fb = 1;
j3 0:d2693f27f344 140 break;
j3 0:d2693f27f344 141
j3 0:d2693f27f344 142 case(ZONE_0):
j3 0:d2693f27f344 143 fb = 0;
j3 0:d2693f27f344 144 break;
j3 0:d2693f27f344 145
j3 0:d2693f27f344 146 case(ZONE_N1):
j3 0:d2693f27f344 147 fb = -1;
j3 0:d2693f27f344 148 break;
j3 0:d2693f27f344 149
j3 0:d2693f27f344 150 case(ZONE_N2):
j3 0:d2693f27f344 151 fb = -2;
j3 0:d2693f27f344 152 break;
j3 0:d2693f27f344 153
j3 0:d2693f27f344 154 case(ZONE_N3):
j3 0:d2693f27f344 155 fb = -3;
j3 0:d2693f27f344 156 break;
j3 0:d2693f27f344 157
j3 0:d2693f27f344 158 case(ZONE_N4):
j3 0:d2693f27f344 159 fb = -4;
j3 0:d2693f27f344 160 break;
j3 0:d2693f27f344 161
j3 0:d2693f27f344 162 case(ZONE_N5):
j3 0:d2693f27f344 163 fb = -5;
j3 0:d2693f27f344 164 break;
j3 0:d2693f27f344 165
j3 0:d2693f27f344 166 case(ZONE_N6):
j3 0:d2693f27f344 167 fb = -6;
j3 0:d2693f27f344 168 break;
j3 0:d2693f27f344 169
j3 0:d2693f27f344 170 case(ZONE_N7):
j3 0:d2693f27f344 171 fb = -7;
j3 0:d2693f27f344 172 break;
j3 0:d2693f27f344 173
j3 0:d2693f27f344 174 case(ZONE_LT0):
j3 0:d2693f27f344 175 fb = 8;
j3 0:d2693f27f344 176 break;
j3 0:d2693f27f344 177
j3 0:d2693f27f344 178 case(ZONE_LT1):
j3 0:d2693f27f344 179 fb = 8;
j3 0:d2693f27f344 180 break;
j3 0:d2693f27f344 181
j3 0:d2693f27f344 182 case(ZONE_LT2):
j3 0:d2693f27f344 183 fb = 8;
j3 0:d2693f27f344 184 break;
j3 0:d2693f27f344 185
j3 0:d2693f27f344 186 case(ZONE_RT0):
j3 0:d2693f27f344 187 fb = -8;
j3 0:d2693f27f344 188 break;
j3 0:d2693f27f344 189
j3 0:d2693f27f344 190 case(ZONE_RT1):
j3 0:d2693f27f344 191 fb = -8;
j3 0:d2693f27f344 192 break;
j3 0:d2693f27f344 193
j3 0:d2693f27f344 194 case(ZONE_RT2):
j3 0:d2693f27f344 195 fb = -8;
j3 0:d2693f27f344 196 break;
j3 0:d2693f27f344 197
j3 0:d2693f27f344 198 default:
j3 0:d2693f27f344 199 fb = fb;
j3 0:d2693f27f344 200 }
j3 0:d2693f27f344 201
j3 0:d2693f27f344 202 //get error signal
j3 0:d2693f27f344 203 current_error = SP-fb;
j3 0:d2693f27f344 204
j3 0:d2693f27f344 205 //get integral term, if statement helps w/wind-up
j3 0:d2693f27f344 206 if(current_error == 0)
j3 0:d2693f27f344 207 {
j3 0:d2693f27f344 208 integral = 0;
j3 0:d2693f27f344 209 }
j3 0:d2693f27f344 210 else if(((current_error < 0) && (previous_error > 0)) ||
j3 0:d2693f27f344 211 ((current_error > 0) && (previous_error < 0)))
j3 0:d2693f27f344 212 {
j3 0:d2693f27f344 213 integral = 0;
j3 0:d2693f27f344 214 }
j3 0:d2693f27f344 215 else
j3 0:d2693f27f344 216 {
j3 0:d2693f27f344 217 integral = (integral + current_error);
j3 0:d2693f27f344 218 }
j3 0:d2693f27f344 219
j3 0:d2693f27f344 220 //get derivative term
j3 0:d2693f27f344 221 derivative = (current_error - previous_error);
j3 0:d2693f27f344 222
j3 0:d2693f27f344 223 //save current error for next loop
j3 0:d2693f27f344 224 previous_error = current_error;
j3 0:d2693f27f344 225
j3 0:d2693f27f344 226 //get new duty cycle for right motor
j3 0:d2693f27f344 227 r_duty_cycle = ((KP*current_error) + (KI*integral) + (KD*derivative));
j3 0:d2693f27f344 228 if(r_duty_cycle > MAX_DUTY_CYCLE)
j3 0:d2693f27f344 229 {
j3 0:d2693f27f344 230 r_duty_cycle = MAX_DUTY_CYCLE;
j3 0:d2693f27f344 231 }
j3 0:d2693f27f344 232
j3 0:d2693f27f344 233 if(r_duty_cycle < MIN_DUTY_CYCLE)
j3 0:d2693f27f344 234 {
j3 0:d2693f27f344 235 r_duty_cycle = MIN_DUTY_CYCLE;
j3 0:d2693f27f344 236 }
j3 0:d2693f27f344 237
j3 0:d2693f27f344 238 //get new duty cycle for left motor
j3 0:d2693f27f344 239 l_duty_cycle = ((KP*current_error) + (KI*integral) + (KD*derivative));
j3 0:d2693f27f344 240 if(l_duty_cycle > MAX_DUTY_CYCLE)
j3 0:d2693f27f344 241 {
j3 0:d2693f27f344 242 l_duty_cycle = MAX_DUTY_CYCLE;
j3 0:d2693f27f344 243 }
j3 0:d2693f27f344 244
j3 0:d2693f27f344 245 if(l_duty_cycle < MIN_DUTY_CYCLE)
j3 0:d2693f27f344 246 {
j3 0:d2693f27f344 247 l_duty_cycle = MIN_DUTY_CYCLE;
j3 0:d2693f27f344 248 }
j3 0:d2693f27f344 249
j3 0:d2693f27f344 250 //ramp motors
j3 0:d2693f27f344 251 do
j3 0:d2693f27f344 252 {
j3 0:d2693f27f344 253 r_duty_cycle_old = ramp(r_duty_cycle, r_duty_cycle_old);
j3 0:d2693f27f344 254 motor_shield.set_pwm_duty_cycle(r_motor_driver, r_duty_cycle_old);
j3 0:d2693f27f344 255
j3 0:d2693f27f344 256 l_duty_cycle_old = ramp(l_duty_cycle, l_duty_cycle_old);
j3 0:d2693f27f344 257 motor_shield.set_pwm_duty_cycle(l_motor_driver, l_duty_cycle_old);
j3 0:d2693f27f344 258 }
j3 0:d2693f27f344 259 while((r_duty_cycle != r_duty_cycle_old) || (l_duty_cycle != l_duty_cycle_old));
j3 0:d2693f27f344 260 }
j3 0:d2693f27f344 261
j3 0:d2693f27f344 262 //shutdown
j3 0:d2693f27f344 263 motor_shield.set_operating_mode(l_motor_driver, Max14871_Shield::BRAKE);
j3 0:d2693f27f344 264 motor_shield.set_operating_mode(r_motor_driver, Max14871_Shield::BRAKE);
j3 0:d2693f27f344 265 }
j3 0:d2693f27f344 266 }
j3 0:d2693f27f344 267
j3 0:d2693f27f344 268
j3 0:d2693f27f344 269 float ramp(float val, float val_old)
j3 0:d2693f27f344 270 {
j3 0:d2693f27f344 271 if(val > val_old)
j3 0:d2693f27f344 272 {
j3 0:d2693f27f344 273 if((val - val_old) >= 0.1)
j3 0:d2693f27f344 274 {
j3 0:d2693f27f344 275 val_old += 0.1;
j3 0:d2693f27f344 276 }
j3 0:d2693f27f344 277 else
j3 0:d2693f27f344 278 {
j3 0:d2693f27f344 279 val_old = val;
j3 0:d2693f27f344 280 }
j3 0:d2693f27f344 281 }
j3 0:d2693f27f344 282 else if(val < val_old)
j3 0:d2693f27f344 283 {
j3 0:d2693f27f344 284 if((val_old - val) >= 0.1)
j3 0:d2693f27f344 285 {
j3 0:d2693f27f344 286 val_old -= 0.1;
j3 0:d2693f27f344 287 }
j3 0:d2693f27f344 288 else
j3 0:d2693f27f344 289 {
j3 0:d2693f27f344 290 val_old = val;
j3 0:d2693f27f344 291 }
j3 0:d2693f27f344 292 }
j3 0:d2693f27f344 293 else
j3 0:d2693f27f344 294 {
j3 0:d2693f27f344 295 val_old = val;
j3 0:d2693f27f344 296 }
j3 0:d2693f27f344 297
j3 0:d2693f27f344 298 return(val_old);
j3 0:d2693f27f344 299 }