-
Notifications
You must be signed in to change notification settings - Fork 2
/
main_v_5
445 lines (408 loc) · 12.5 KB
/
main_v_5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
#include "mbed.h"
#include "QEI.h"
#define RECEIVER_THRESHOLD 0.1 //not used atm
#define ENC_PER_REV 360
#define SAMPLES 20
#define MAX_SPEED 0.2f
float defaultSpeed = MAX_SPEED * 0.75f;
////MODIFICATIONS FROM MAIN_REVISED.CPP////
// 1. added/revised turning and stopping code (not tested)
// 2. removed unused code
// 3. minor cleanup
/////////////TO DO/////////////////
// 1. (Optional) Tune encoder so that it goes straight with IR enabled
// 2. Check if dt in D_controller needs 10^(-6) multiplier because us.
// 3. Tune all K values
// 4. Tune stopping
// 5. Naming conventions becoming ambiguous again (thresholds in IR setup is actually BASELINEs)
///////////////////////////////////
///////////////////////
// Function Declarations
///////////////////////
void turn(bool left);
float P_Controller(float error, float Kp);
float I_Controller(float error, float Ki, float& integrator, float decayFactor);
float D_Controller(float error, float Kd, float& prevError );
void update_enc();
void systick_forward();
void systick_forward_default(float error, float correction_factor, float Kp, float Kd, float Ki, float& integrator, float decayFactor, float& prevError, Timer& timer);
void update_IR();
void systick_forward_enc();
void forward(int n);
void forward_until_wall();
void setup_IR(float& cL, float& cR);
bool detect_wall();
bool detect_missing_wall();
void stop();
void setup_enc();
///////////////////////
// flags
///////////////////////
bool missing_left_wall = false, missing_right_wall = false;
int wall_state = 0; // 1 for missing no walls, 2 for missing left wall,
// 3 for missing right wall, 4 for missing both walls
///////////////////////
// K Values
///////////////////////
float Kp_enc = 6,
Ki_enc = 2,
Kd_enc = 20,
Kp_IR = 0.5f,
Ki_IR = 0,
Kd_IR = 15;
///////////////////////
// Speed Variables
///////////////////////
float LSpeed = defaultSpeed,
RSpeed = defaultSpeed;
////////////////////////
// PID miscellanies
////////////////////////
float integrator_enc = 0; // I_Controller() variables
float integrator_IR = 0;
float decayFactor_enc = 2; // I_Controller() variable
float decayFactor_IR = 2;
float prevError_enc = 0; // D_Controller() variable
float prevError_IR = 0;
float correction_factor_enc = 1/(36000*(LSpeed+RSpeed));
float correction_factor_IR = 1;
//////////////////////
// Pin definitions
/////////////////////
DigitalOut LED_left(PB_7);
DigitalOut LED_frontLeft(PB_0);
DigitalOut LED_frontRight(PC_11);
DigitalOut LED_right(PC_10);
AnalogIn REC_left(PC_0);
AnalogIn REC_frontLeft(PC_1);
AnalogIn REC_frontRight(PA_4);
AnalogIn REC_right(PA_0);
PinName mLencA = PA_15,
mLencB = PB_3,
mRencA = PA_1,
mRencB = PC_4,
usbTX = PA_2,
usbRX = PA_3,
mLB = PC_7,
mLF = PB_10,
mRF = PA_7,
mRB = PB_6;
PwmOut MLF(mLF),
MRF(mRF),
MLB(mLB),
MRB(mRB);
/////////////////////////
// Encoder Variables
/////////////////////////
int enc_leftD, enc_rightD,
enc_left, enc_right,
enc_left_prev, enc_right_prev; // enc_leftD = encoder value difference of left motor
/////////////////////////
// IR Variables/Used in PID
/////////////////////////
float
IR_leftD, IR_rightD,
IR_left, IR_right,
IR_left_prev,
IR_right_prev; // IR_leftD = IR value difference of left motor
////////////////////////
// REC Setup Variables
////////////////////////
float
REC_threshold, // not used atm, for hardcoding/testing
REC_left_baseline = 0,
REC_right_baseline = 0,
REC_front_threshold = 0;
////////////////////////
// IR Values/Readings
////////////////////////
float
REC_val_left,
REC_val_right,
REC_val_frontLeft,
REC_val_frontRight; // IR readings
///////////////////////
// Timer/Serial
///////////////////////
Ticker Systicker;
Timer timer_enc, timer_IR;
Serial pc(usbTX, usbRX);
///////////////////////
// Motor init
///////////////////////
QEI wheelL(mLencA, mLencB, NC, 624, QEI::X4_ENCODING);
QEI wheelR(mRencA, mRencB, NC, 624, QEI::X4_ENCODING);
//////////////////////
// FUNCTIONS
//////////////////////
// Turn immediately to direction dir (pos right, left neg)
void turn(bool left){
int left_pulse = -wheelL.getPulses();
int right_pulse = wheelR.getPulses();
while(abs(-wheelL.getPulses()-left_pulse) + abs(wheelR.getPulses()-right_pulse) <= 365){
//turn right
if (!left){
MLF.write(defaultSpeed); //-Kp_turn*diff);
MLB.write(0);
MRB.write(defaultSpeed); //-Kp_turn*diff);
MRF.write(0);
}
//turn left
else{
MLB.write(defaultSpeed); //-Kp_turn*diff);
MLF.write(0);
MRF.write(defaultSpeed); //-Kp_turn*diff);
MRB.write(0);
}
//diff = wheelR.getPulses() - wheelL.getPulses();
//pc.printf("diff: %d\n", diff); //to debug and determine proper Kp
}
MLB.write(0);
MLF.write(0);
MRB.write(0);
MRF.write(0);
wait(0.1f);
}
float P_Controller(float error, float Kp)
{
float correction = Kp*error; // Calculate Correction
return correction;
}
float I_Controller(float error, float Ki, float& integrator, float decayFactor)
{
integrator += error; // Add error to running total
float correction = Ki*integrator; // Calculate Correction
integrator /= decayFactor; // Need to make sure running total
// doesn't grow too large
return correction;
}
float D_Controller(float error, float Kd, float& prevError, Timer& timer)
{
float dError = error - prevError; // Get change in error
int dt = timer.read_us(); // Get change in time, may not be
timer.reset(); // Reset Time for next cycle
prevError = error; // Update previous error
float correction = Kd*dError/dt; // Calculate Correction
return correction;
}
//This is to update encoder values even when the rat is not moving.
//Previously this update function and forward function was one.
void update_enc()
{
//update EL and ER
enc_left = -wheelL.getPulses();
enc_right = wheelR.getPulses();
//find difference from prev values
enc_leftD = enc_left - enc_left_prev;
enc_rightD = enc_right - enc_right_prev;
//update EL_prev and ER_prev
enc_left_prev = enc_left;
enc_right_prev = enc_right;
}
//This is to update IR values even when the rat is not moving.
//Previously this update function and forward function was one.
void update_IR()
{
//update left and right IR
IR_left = REC_left.read();
REC_val_frontRight = REC_frontRight.read();
REC_val_frontLeft = REC_frontLeft.read();
IR_right = REC_right.read();
//find difference compared to calibrated/setup threshold
IR_leftD = IR_left - REC_left_baseline;
IR_rightD = IR_right - REC_right_baseline;
}
void systick_forward_enc()
{
//find error (can optimize later)
//NOTE: ELD and ERD are both positive if spinning forward.
int error = enc_rightD - enc_leftD;
//find correction
float speedDiff = MAX_SPEED* correction_factor_enc * (P_Controller(error, Kp_enc) + I_Controller(error,Ki_enc,integrator_enc,decayFactor_enc) + D_Controller(error, Kd_enc, prevError_enc, timer_enc));
//update speeds
if (RSpeed > MAX_SPEED)
RSpeed = MAX_SPEED;
if (LSpeed > MAX_SPEED)
LSpeed = MAX_SPEED;
if (LSpeed < 0)
LSpeed = 0;
if (RSpeed < 0)
RSpeed = 0;
LSpeed = LSpeed + speedDiff;
RSpeed = RSpeed - speedDiff; // right wheel runs little faster than left
}
void systick_forward_default(float error, float correction_factor, float Kp, float Kd, float Ki, float& integrator, float decayFactor, float& prevError, Timer& timer)
{
//NOTE: Multiplied by MAX_SPEED because the speed can only be in range 0 - MAX_SPEED, whereas
//IR values are from 0 - 1.
float speedDiff = MAX_SPEED * correction_factor * (P_Controller(error, Kp) + I_Controller(error,Ki,integrator,decayFactor) + D_Controller(error, Kd, prevError, timer));
//update speeds
LSpeed = defaultSpeed + speedDiff;
RSpeed = defaultSpeed - speedDiff;
if (RSpeed > MAX_SPEED)
RSpeed = MAX_SPEED;
if (LSpeed > MAX_SPEED)
LSpeed = MAX_SPEED;
if (LSpeed < 0)
LSpeed = 0;
if (RSpeed < 0)
RSpeed = 0;
}
void systick_forward()
{
//update IR variables
update_IR();
update_enc();
if (!detect_missing_wall())
{
if(wall_state != 1)
{
wall_state = 1;
integrator_IR = 0;
prevError_IR = 0;
timer_IR.reset();
}
systick_forward_default(IR_rightD - IR_leftD, correction_factor_IR, Kp_IR, Kd_IR, Ki_IR, integrator_IR, decayFactor_IR, prevError_IR, timer_IR);
}
else if(missing_left_wall)
{
if(wall_state != 2)
{
wall_state = 2;
integrator_IR = 0;
prevError_IR = 0;
timer_IR.reset();
}
systick_forward_default(IR_rightD, correction_factor_IR, Kp_IR, Kd_IR, Ki_IR, integrator_IR, decayFactor_IR, prevError_IR, timer_IR);
}
else if(missing_right_wall)
{
if(wall_state != 3)
{
wall_state = 3;
integrator_IR = 0;
prevError_IR = 0;
timer_IR.reset();
}
systick_forward_default(IR_leftD, correction_factor_IR, Kp_IR, Kd_IR, Ki_IR, integrator_IR, decayFactor_IR, prevError_IR, timer_IR);
}
else // missing both walls
{
//update encoder variables
if(wall_state != 4)
{
wall_state = 4;
integrator_enc = 0;
prevError_enc = 0;
timer_enc.reset();
}
systick_forward_enc();
}
}
void forward(int n)
{
MLF.write(LSpeed);
MLB.write(0);
MRF.write(RSpeed);
MRB.write(0);
wait(n*0.001);
}
void setup_IR(float& cL, float& cR)
{
LED_left = 1;
LED_frontRight = 1;
LED_frontLeft = 1;
LED_right = 1;
wait(2);
float TcR = 0;
float TcL = 0;
float TcFR = 0;
float TcFL = 0;
for(int i= 0; i < SAMPLES; i++)
{
TcR += REC_right.read();
TcL += REC_left.read();
TcFR += REC_frontRight.read();
TcFL += REC_frontLeft.read();
}
TcR /= SAMPLES;
TcL /= SAMPLES;
TcFR /= SAMPLES;
TcFL /= SAMPLES;
cR = TcR;
cL = TcL;
REC_front_threshold = TcFR + TcFL;
timer_IR.start();
}
bool detect_wall(){
float reading = REC_val_frontLeft + REC_val_frontRight;
return (reading >= REC_front_threshold * 0.95f);
}
//0 is false; 1 is true
bool detect_missing_wall(){
missing_left_wall = (REC_val_left <= REC_left_baseline * .7f);
missing_right_wall = (REC_val_right <= REC_right_baseline * .7f);
return (missing_left_wall || missing_right_wall);
}
void stop()
{
Timer temp;
temp.start();
int baseline = temp.read_ms();
int stop_time = 10;
while (temp.read_ms() - baseline < stop_time){
MLB.write(0.5f);
MLF.write(0);
MRB.write(0.5f);
MRF.write(0);
}
MLB.write(0);
MRB.write(0);
temp.stop();
}
void setup_enc()
{
enc_left_prev = -wheelL.getPulses();
enc_right_prev = wheelR.getPulses();
timer_enc.start();
}
int main()
{
// general setup
setup_IR(REC_left_baseline, REC_right_baseline);
setup_enc();
bool previous_forward = false; // forward or not
turn(true);
turn(true);
Systicker.attach(&systick_forward,0.01f);
wait(1);
// int left_pulse = -wheelL.getPulses();
// int right_pulse = wheelR.getPulses();
// while(-wheelL.getPulses()-left_pulse < 180 && wheelR.getPulses()-right_pulse < 180)
// { pc.printf("%d\t%d\n", -wheelL.getPulses()-left_pulse, wheelR.getPulses()-right_pulse); }
while(1){
//move
/* if (detect_wall()){
previous_forward = false;
Systicker.attach(NULL,0.01f);
stop();
if(!missing_left_wall && !missing_right_wall)
{
turn(true); turn(true);
}
else
turn(missing_left_wall); // will turn left if true.
}
else{*/
if(!previous_forward)
{
previous_forward = true;
timer_IR.reset();
Systicker.attach(&systick_forward,0.01f);
}
forward(1);
// }
}
timer_enc.stop();
timer_IR.stop();
}