Statistics
| Branch: | Tag: | Revision:

amiro-os / devices / DiWheelDrive / userthread.cpp @ d4c6efa9

History | View | Annotate | Download (27.617 KB)

1
// #include "userthread.hpp"
2
#include "global.hpp"
3
#include <cmath>
4
#include "linefollow.hpp" 
5
#include "userthread.hpp"
6
// #include <cmath>
7
// #include "global.hpp"
8
using namespace amiro;
9

    
10
extern Global global;
11

    
12
// a buffer for the z-value of the accelerometer
13
int16_t accel_z;
14
bool running = false;
15

    
16

    
17
/**
18
 * Set speed.
19
 * 
20
 * @param rpmSpeed speed for left and right wheel in rounds/min
21
 */
22
void UserThread::setRpmSpeedFuzzy(const int (&rpmSpeed)[2]) {
23
  global.motorcontrol.setTargetRPM(rpmSpeed[constants::DiWheelDrive::LEFT_WHEEL] * 1000000, rpmSpeed[constants::DiWheelDrive::RIGHT_WHEEL] * 1000000);
24
}
25

    
26
void UserThread::setRpmSpeed(const int (&rpmSpeed)[2]) {
27
  global.motorcontrol.setTargetRPM(rpmSpeed[constants::DiWheelDrive::LEFT_WHEEL], rpmSpeed[constants::DiWheelDrive::RIGHT_WHEEL]);
28
}
29

    
30
void UserThread::lightOneLed(Color color, int idx){
31
  global.robot.setLightColor(idx, Color(color));
32
}
33

    
34
void UserThread::lightAllLeds(Color color){
35
  int led = 0;
36
  for(led=0; led<8; led++){
37
        lightOneLed(color, led);
38
      }
39
}
40

    
41
void UserThread::showChargingState(){
42
  uint8_t numLeds = global.robot.getPowerStatus().state_of_charge / 12;
43
  Color color = Color::GREEN;
44
  if (numLeds <= 2){
45
    color = Color::RED;
46
  }else if(numLeds <= 6){
47
    color = Color::YELLOW;
48
  }
49
  for (int i=0; i<numLeds; i++){
50
    lightOneLed(color, i);
51
    this->sleep(300);
52
  }
53
  this->sleep(1000);
54
  lightAllLeds(Color::BLACK);
55
}
56

    
57
void UserThread::chargeAsLED(){
58
  uint8_t numLeds = global.robot.getPowerStatus().state_of_charge / 12;
59
  Color color = Color::GREEN;
60
  if (numLeds <= 2){
61
    color = Color::RED;
62
  }else if(numLeds <= 6){
63
    color = Color::YELLOW;
64
  }
65
  for (int i=0; i<numLeds; i++){
66
    lightOneLed(color, i);
67
    // this->sleep(300);
68
  }
69
  // this->sleep(1000);
70
  // lightAllLeds(Color::BLACK);
71
}
72

    
73
// ----------------------------------------------------------------
74

    
75
void UserThread::getProxySectorVals(uint16_t (&proxVals)[8], uint16_t (&sProx)[8]){
76
  for (int i=0; i<8; i++){
77
    sProx[i] = (proxVals[i] < proxVals[(i+1) % 8]) ? proxVals[i] : proxVals[(i+1) % 8];
78
    // chprintf((BaseSequentialStream*)&global.sercanmux1, "%d: %d, ", i, sProx[i]);
79
    
80
  }
81
    // chprintf((BaseSequentialStream*)&global.sercanmux1, "\n");
82

    
83
}
84

    
85

    
86
void UserThread::getMaxFrontSectorVal(uint16_t (&sProx)[8], int32_t &sPMax){
87
  for (int i=2; i<5; i++){
88
    sPMax = (sPMax < sProx[i]) ? sProx[i] : sPMax;
89
  }
90
}
91

    
92
void UserThread::proxSectorSpeedCorrection(int (&rpmSpeed)[2], uint16_t (&proxVals)[8]){
93
  int i;
94
  uint16_t sProx[8];
95
  int32_t sPMax = 0;
96
  getProxySectorVals(proxVals, sProx);
97
  getMaxFrontSectorVal(sProx, sPMax);
98
  
99
  int32_t speedL = rpmSpeed[0] - (sPMax * pCtrl.pFactor);
100
  int32_t speedR = rpmSpeed[1] - (sPMax * pCtrl.pFactor);
101

    
102

    
103

    
104
  if(sPMax > pCtrl.threshMid){
105
      rpmSpeed[0] = 0;
106
      rpmSpeed[1] = 0;
107
      pCtrl.staticCont++;
108
  }else if((speedL > 0) || (speedR > 0)){
109
    pCtrl.staticCont = 0;
110
    rpmSpeed[0] = speedL;
111
    rpmSpeed[1] = speedR;
112
  }else{
113
    rpmSpeed[0] = 4000000 + (rpmSpeed[0] - global.rpmForward[0] * 1000000);
114
    rpmSpeed[1] = 4000000 + (rpmSpeed[1] - global.rpmForward[0] * 1000000);
115
  }
116

    
117
  for(i=4; i<5; i++){
118
    if ((proxVals[i] > pCtrl.threshMid) && (proxVals[i+1] > pCtrl.threshLow)){
119
      rpmSpeed[0] = -5000000 ;
120
      rpmSpeed[1] = -5000000 ;
121
      // pCtrl.staticCont++;
122
      break;
123
    }
124
  }
125
  chargeAsLED();
126
    
127
  // chprintf((BaseSequentialStream*)&global.sercanmux1, "Max: %d factor: %d, Panel: %d SpeedL: %d SpeedR: %d ActualL: %d ActualR: %d\n",sPMax,  pCtrl.pFactor,  sPMax * pCtrl.pFactor, speedL, speedR, rpmSpeed[0], rpmSpeed[1]);
128

    
129

    
130
}
131
// -------------------------------------------------------------------
132

    
133

    
134
void UserThread::preventCollision( int (&rpmSpeed)[2], uint16_t (&proxVals)[8]) {
135

    
136
  if((proxVals[3] > pCtrl.threshLow) || (proxVals[4] > pCtrl.threshLow)){
137
      rpmSpeed[0] = rpmSpeed[0] / 2;
138
      rpmSpeed[1] = rpmSpeed[1] / 2;
139
  }
140

    
141
  if((proxVals[3] > pCtrl.threshMid) || (proxVals[4] > pCtrl.threshMid)){
142
      rpmSpeed[0] = rpmSpeed[0] / 3;
143
      rpmSpeed[1] = rpmSpeed[1] / 3;
144
  }
145

    
146
  if((proxVals[3] > pCtrl.threshHigh) || (proxVals[4] > pCtrl.threshHigh)){
147
      rpmSpeed[0] = 0;
148
      rpmSpeed[1] = 0;
149
      utCount.ringProxCount++;
150
  }else{
151
    utCount.ringProxCount = 0;
152
  }
153
  
154
}
155

    
156

    
157
/**
158
 * Blocks as long as the position changes.
159
 */
160
void UserThread::checkForMotion(){
161
  int motion = 1;
162
  int led = 0;
163
  types::position oldPos = global.odometry.getPosition();
164
  while(motion){
165
    this->sleep(500);
166
    types::position tmp = global.odometry.getPosition();
167
    motion = abs(oldPos.x - tmp.x)+ abs(oldPos.y - tmp.y)+abs(oldPos.z - tmp.z);
168
    oldPos = tmp;
169
      global.robot.setLightColor((led + 1) % 8, Color(Color::YELLOW));
170
      global.robot.setLightColor(led % 8, Color(Color::BLACK));
171
      led++;
172
  }
173
  lightAllLeds(Color::BLACK);
174
}
175

    
176
bool UserThread::checkFrontalObject(){
177
  uint32_t thresh = pCtrl.threshMid;
178
  uint32_t prox;
179
  for(int i=0; i<8; i++){
180
    prox = global.robot.getProximityRingValue(i);
181
    if((i == 3) || (i == 4)){
182
      if(prox < thresh){
183
        return false;
184
      }
185
    }else{
186
      if(prox > thresh){
187
        return false;
188
      }
189
    }
190
  }
191
  return true;
192
}
193

    
194
bool UserThread::checkPinVoltage(){
195
  return global.ltc4412.isPluggedIn(); 
196
}
197

    
198
bool UserThread::checkPinEnabled(){
199
  return global.ltc4412.isEnabled();
200
}
201

    
202
int UserThread::checkDockingSuccess(){
203
  // setRpmSpeed(stop);
204
  checkForMotion();
205
  int success = 0;
206
  // global.odometry.resetPosition();
207
  types::position start = global.startPos = global.odometry.getPosition();
208
  global.motorcontrol.setMotorEnable(false);
209
  this->sleep(1000);
210
  types::position stop_ = global.endPos = global.odometry.getPosition();
211
  
212
  // Amiro moved, docking was not successful
213
  // if ((start.x + stop_.x)  || (start.y + stop_.y)){
214
  if (abs(start.x - stop_.x) > 200 /* || (start.y + stop_.y) */){
215
    lightAllLeds(Color::RED);
216
    // Enable Motor again if docking was not successful
217
    global.motorcontrol.setMotorEnable(true);
218
    success = 0;
219
  }else{
220
    lightAllLeds(Color::GREEN);
221
    success = 1;
222
  }
223
  
224
  // this->sleep(500);
225
  lightAllLeds(Color::BLACK);
226
  return success;
227
}
228

    
229
int UserThread::getProxyRingSum(){
230
  int prox_sum = 0;
231
  for(int i=0; i<8;i++){
232
    prox_sum += global.robot.getProximityRingValue(i);;
233
  }
234
  return prox_sum;
235
}
236

    
237
int32_t UserThread::meanDeviation(uint16_t a, uint16_t b){
238
  int32_t diff = a - b;
239
  int32_t res = 0; 
240
  devCor.proxbuf[devCor.pCount] = (diff*100)/((a+b)/2);
241
  for (int i = 0; i< PROX_DEVIATION_MEAN_WINDOW; i++){
242
    res += devCor.proxbuf[i];
243
  }
244
  devCor.pCount++;
245
  devCor.pCount = devCor.pCount % PROX_DEVIATION_MEAN_WINDOW;
246

    
247
  devCor.currentDeviation =  res / PROX_DEVIATION_MEAN_WINDOW;
248
  return devCor.currentDeviation;
249
}
250

    
251

    
252
UserThread::UserThread() :
253
  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
254
{
255
}
256

    
257
UserThread::~UserThread()
258
{
259
}
260

    
261
msg_t
262
UserThread::main()
263
{
264
  /*
265
   * SETUP
266
   */
267
  // User thread state:
268

    
269
  for (uint8_t led = 0; led < 8; ++led) {
270
    global.robot.setLightColor(led, Color(Color::BLACK));
271
  }
272
  running = false;
273
  LineFollowStrategy lStrategy = LineFollowStrategy::EDGE_RIGHT;
274
  LineFollow lf(&global);
275
  /*
276
   * LOOP
277
   */
278
  while (!this->shouldTerminate())
279
  {
280
    /*
281
    * read accelerometer z-value
282
    */
283
    accel_z = global.lis331dlh.getAccelerationForce(LIS331DLH::AXIS_Z);
284
        
285
    if (accel_z < -900 /*-0.9g*/) { 
286
      // Start line following when AMiRo is rotated
287
      if(currentState == states::INACTIVE){
288
        newState = states::FOLLOW_LINE;
289
      }else{
290
        newState = states::IDLE;
291
      }
292
      lightAllLeds(Color::GREEN);
293
      this->sleep(1000);
294
      lightAllLeds(Color::BLACK);
295

    
296
    // If message was received handle it here:
297
    } else if(global.msgReceived){
298
      global.msgReceived = false;
299
      // running = true;
300
      switch(global.lfStrategy){
301
        case msg_content::MSG_START:
302
          newState = states::CALIBRATION_CHECK;
303
        break;
304
        case msg_content::MSG_STOP:
305
          newState = states::IDLE;
306
        break;
307
        case msg_content::MSG_EDGE_RIGHT:
308
          // newState = states::FOLLOW_LINE;
309
          lStrategy = LineFollowStrategy::EDGE_RIGHT;
310
        break;
311
        case  msg_content::MSG_EDGE_LEFT:
312
          // newState = states::FOLLOW_LINE;
313
          lStrategy = LineFollowStrategy::EDGE_LEFT;
314
        break;
315
        case msg_content::MSG_FUZZY:
316
          // newState = states::FOLLOW_LINE;
317
          lStrategy = LineFollowStrategy::FUZZY;
318
        break;
319
        case msg_content::MSG_DOCK:
320
          newState = states::DETECT_STATION;
321
        break;
322
        case msg_content::MSG_UNDOCK:
323
          newState = states::RELEASE;
324
        break;
325
        case msg_content::MSG_CHARGE:
326
          newState = states::CHARGING;
327
        break;
328
        case msg_content::MSG_RESET_ODOMETRY:
329
          global.odometry.resetPosition();
330
        break;
331
        case msg_content::MSG_CALIBRATE_BLACK:
332
          proxCalib.calibrateBlack = true;
333
          // global.odometry.resetPosition();
334
          newState = states::CALIBRATION;
335
        break;
336
        case msg_content::MSG_CALIBRATE_WHITE:
337
          proxCalib.calibrateBlack = false;
338
          newState = states::CALIBRATION;
339
        break;
340
        default:
341
          newState = states::IDLE;
342
        break;
343
      }
344
    }
345
    // newState = currentState;
346

    
347
    // Get sensor data 
348
    // uint16_t WL = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_LEFT].getProximityScaledWoOffset();
349
    // uint16_t WR = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_RIGHT].getProximityScaledWoOffset();
350
    for(int i=0; i<8;i++){
351
      rProx[i] = global.robot.getProximityRingValue(i);
352
    }
353

    
354
    // Continously update devication values
355
    meanDeviation(rProx[0] & 0xFFF0, rProx[7] & 0xFFF0);
356
    // int FL = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset();
357
    // int FR = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
358
    switch(currentState){
359
      case states::INACTIVE:
360
        // Dummy state to deactivate every interaction
361
      break;
362
      // ---------------------------------------
363
      case states::CALIBRATION_CHECK:
364
        // global.robot.calibrate();
365
        if(global.linePID.BThresh >= global.linePID.WThresh){
366
          newState = states::CALIBRATION_ERROR;
367
        }else{
368
          newState = states::FOLLOW_LINE;
369
        }
370
      break;
371
      // ---------------------------------------
372
      case states::CALIBRATION:
373
        /* Calibrate the global thresholds for black or white.
374
            This values will be used by the line follow object
375
        */
376

    
377
        proxCalib.buf = 0;
378
        if(proxCalib.calibrateBlack){
379
          chprintf((BaseSequentialStream*)&global.sercanmux1, "Black Calibration, Place AMiRo on black Surface!\n");
380
          global.robot.calibrate();
381
        }
382
        for(int i=0; i <= proxCalib.meanWindow; i++){
383
          proxCalib.buf += global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset() 
384
                          + global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset(); 
385
          this->sleep(CAN::UPDATE_PERIOD);
386
        }
387
        proxCalib.buf = proxCalib.buf / (2*proxCalib.meanWindow);
388
        
389
        if(proxCalib.calibrateBlack){
390
          global.linePID.BThresh = proxCalib.buf;
391
        }else  {
392
          global.linePID.WThresh  = proxCalib.buf;
393
        }
394
          chprintf((BaseSequentialStream*)&global.sercanmux1, "Black: %d, White: %d!\n", global.linePID.BThresh, global.linePID.WThresh);
395

    
396
        newState = states::IDLE;
397
      break;
398
      // ---------------------------------------
399
      case states::IDLE:
400
        global.motorcontrol.setMotorEnable(true);
401
        setRpmSpeed(stop);
402
        if(/* checkPinVoltage() && */ checkPinEnabled()){
403
          global.robot.requestCharging(0);
404
        }
405
        // pCtrl.pFactor = 0;
406
        pCtrl.staticCont = 0;
407
        utCount.whiteCount = 0;
408
        utCount.ringProxCount = 0;
409
        utCount.errorCount = 0;
410
        newState = states::INACTIVE;
411
      break;
412
      // ---------------------------------------
413
      case states::FOLLOW_LINE:
414
      // Set correct forward speed to every strategy
415
        if (global.forwardSpeed != global.rpmForward[0]){
416
          global.forwardSpeed = global.rpmForward[0];
417
        }
418
        
419
        if(lf.getStrategy() != lStrategy){
420
          lf.setStrategy(lStrategy);
421
        }
422

    
423
        if(lf.followLine(rpmSpeed)){
424
          utCount.whiteCount++;
425
          if(utCount.whiteCount >= WHITE_DETETION_TIMEOUT){
426
            setRpmSpeed(stop);
427
            utCount.whiteCount = 0;
428
            newState = states::WHITE_DETECTION_ERROR;
429
          }
430
        }else{
431
          utCount.whiteCount = 0;
432
        }
433

    
434
        preventCollision(rpmSpeed, rProx);
435
        // proxSectorSpeedCorrection(rpmSpeed, rProx);
436

    
437
        if(utCount.ringProxCount > RING_PROX_DETECTION_TIMEOUT){
438
          utCount.ringProxCount = 0;
439
          
440

    
441
          checkForMotion();
442
          // Check if only front sensors are active
443
          if (checkFrontalObject()) {
444
            // global.distcontrol.setTargetPosition(0, 2792526, ROTATION_DURATION);
445
            // // BaseThread::sleep(8000);
446
            // checkForMotion();
447
            this->utCount.whiteCount = 0;
448
            newState = states::TURN;
449
            // lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
450
          } else {
451
            newState = states::PROXY_DETECTION_ERROR;
452
          }
453
        }
454

    
455
        if (lf.getStrategy() == LineFollowStrategy::FUZZY){
456
          setRpmSpeedFuzzy(rpmSpeed);
457
        }else{
458

    
459
          setRpmSpeed(rpmSpeed);
460
        }
461
        
462
      break;
463
      // ---------------------------------------
464
    case states::TURN:{
465
        // Check the line strategy in order to continue driving on the right side
466
      int factor = SPEED_CONVERSION_FACTOR;
467
      int frontL = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset();
468
      int frontR = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
469
      if (lf.getStrategy() == LineFollowStrategy::EDGE_RIGHT) {
470
        factor = -factor;
471
      }
472
      
473
      rpmSpeed[0] = factor * CHARGING_SPEED;
474
      rpmSpeed[1] = -factor * CHARGING_SPEED;
475
      setRpmSpeed(rpmSpeed);
476
        
477
      if ((frontL > 2* pCtrl.threshHigh ) && (frontR > 2* pCtrl.threshHigh )){
478
        utCount.whiteCount = 1;
479
      }else{
480
        if(utCount.whiteCount){
481
          utCount.whiteCount = 0;
482
          newState = states::FOLLOW_LINE;
483
          setRpmSpeed(stop);
484
        }
485
      }
486
      break;
487
    }
488
      // ---------------------------------------
489
      case states::DETECT_STATION:
490
        
491
        if (global.forwardSpeed != DETECTION_SPEED){
492
          global.forwardSpeed = DETECTION_SPEED;
493
        }
494
        if(lf.getStrategy() != LineFollowStrategy::EDGE_RIGHT){
495
          lf.setStrategy(LineFollowStrategy::EDGE_RIGHT);
496
        }
497
        
498
        lf.followLine(rpmSpeed);
499
        setRpmSpeed(rpmSpeed);
500
        // // Detect marker before docking station
501
        // if ((WL+WR) < PROXY_WHEEL_THRESH){
502
        // Use proxy ring 
503
        if ((rProx[3]+rProx[4]) > RING_PROX_FRONT_THRESH){
504

    
505
          setRpmSpeed(stop);
506
          checkForMotion();
507
          // 180° Rotation 
508
          global.distcontrol.setTargetPosition(0, ROTATION_180, ROTATION_DURATION);
509
          // BaseThread::sleep(8000);
510
          checkForMotion();
511
          newState = states::CORRECT_POSITIONING;
512
        }
513
      break;
514
      // ---------------------------------------
515
      case states::CORRECT_POSITIONING:
516
        if (global.forwardSpeed != CHARGING_SPEED){
517
          global.forwardSpeed = CHARGING_SPEED;
518
        }
519
        if(lf.getStrategy() != LineFollowStrategy::EDGE_LEFT){
520
          lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
521
        }
522
        lf.followLine(rpmSpeed);
523
        setRpmSpeed(rpmSpeed);
524

    
525
        utCount.stateTime++;
526
        if (utCount.stateTime >= DOCKING_CORRECTION_TIMEOUT){
527
          utCount.stateTime = 0;
528
          newState = states::REVERSE;
529
          setRpmSpeed(stop);
530
          checkForMotion();
531
        }
532
      break;
533
      // ---------------------------------------
534
      case states::REVERSE:
535
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
536
          lf.setStrategy(LineFollowStrategy::REVERSE);
537
        }
538
        lf.followLine(rpmSpeed);
539
        setRpmSpeed(rpmSpeed);
540
        // utCount.stateTime++;
541

    
542
        // Docking is only successful if Deviation is in range and sensors are at their max values.
543
        if((rProx[0] >= PROX_MAX_VAL)
544
           && (rProx[7] >= PROX_MAX_VAL)
545
           && ((devCor.currentDeviation > -MAX_DEVIATION_FACTOR) && (devCor.currentDeviation < MAX_DEVIATION_FACTOR) )){
546
          // setRpmSpeed(stop);
547
          // checkForMotion();
548
          utCount.stateTime = 0;
549
          newState = states::PUSH_BACK;
550
        }else if ((devCor.currentDeviation <= -MAX_DEVIATION_FACTOR) && ((rProx[0] > DEVIATION_DIST_THRESH) || (rProx[7] > DEVIATION_DIST_THRESH))){
551
          // Case R 
552
          utCount.stateTime = 0;
553
          setRpmSpeed(stop);
554
          devCor.RCase = true;
555
          lightAllLeds(Color::YELLOW);
556
          newState = states::DEVIATION_CORRECTION;
557
        }else if ((devCor.currentDeviation >= MAX_DEVIATION_FACTOR) && ((rProx[0] > DEVIATION_DIST_THRESH) || (rProx[7] > DEVIATION_DIST_THRESH))){
558
          // Case L 
559
          utCount.stateTime = 0;
560
          setRpmSpeed(stop);
561
          devCor.RCase = false;
562
          lightAllLeds(Color::WHITE);
563
          newState = states::DEVIATION_CORRECTION;
564
        }else if (utCount.stateTime >= REVERSE_DOCKING_TIMEOUT){
565
          setRpmSpeed(stop);
566
          utCount.stateTime = 0;
567
          utCount.errorCount++;
568
          if (utCount.errorCount >= DOCKING_ERROR_THRESH){
569
            newState = states::DOCKING_ERROR;
570
          }else{
571
            newState = states::CORRECT_POSITIONING;
572
          }
573
        }
574

    
575
        // if((devCor.currentDeviation <= -10)){
576
        //   rpmSpeed[0] -= 2000000;
577
        // }else if(devCor.currentDeviation >= 10){
578
        //   rpmSpeed[1] -= 2000000;
579
        // }
580
        // setRpmSpeed(rpmSpeed);
581
      break;
582
      // ---------------------------------------
583
      case states::DEVIATION_CORRECTION:
584
        // if(lf.getStrategy() != LineFollowStrategy::REVERSE){
585
        //   lf.setStrategy(LineFollowStrategy::REVERSE);
586
        // }
587
        // lf.followLine(rpmSpeed);
588
        // setRpmSpeed(rpmSpeed);
589
        if(utCount.stateTime < DEVIATION_CORRECTION_DURATION / 2 ){
590
          if(devCor.RCase){
591
            rpmSpeed[0] = 0;
592
            rpmSpeed[1] = DEVIATION_CORRECTION_SPEED;
593
          }else {
594
            rpmSpeed[0] = DEVIATION_CORRECTION_SPEED;
595
            rpmSpeed[1] = 0;
596
          }
597
          setRpmSpeed(rpmSpeed);
598
        }else if (((utCount.stateTime >= DEVIATION_CORRECTION_DURATION / 2) && (utCount.stateTime < DEVIATION_CORRECTION_DURATION +10)) ){
599
          if(devCor.RCase){
600
            rpmSpeed[0] = DEVIATION_CORRECTION_SPEED;
601
            rpmSpeed[1] = 0;
602
          }else {
603
            rpmSpeed[0] = 0;
604
            rpmSpeed[1] = DEVIATION_CORRECTION_SPEED;
605
          }
606
          setRpmSpeed(rpmSpeed);
607
          if(((devCor.currentDeviation >= -5) && (devCor.currentDeviation <= 5))){
608
            utCount.stateTime = 0;
609
            newState = states::REVERSE;
610
            setRpmSpeed(stop);
611
          }
612
        }else{
613
          utCount.stateTime = 0;
614
          newState = states::REVERSE;
615
          setRpmSpeed(stop);
616
        }
617

    
618
        utCount.stateTime++;
619

    
620

    
621
        // if (utCount.stateTime > PUSH_BACK_TIMEOUT){
622
        //   utCount.stateTime = 0;
623
        //   newState = states::CHECK_POSITIONING;
624
        // }
625
      break;
626
      // ---------------------------------------
627
      case states::PUSH_BACK:
628
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
629
          lf.setStrategy(LineFollowStrategy::REVERSE);
630
        }
631
        lf.followLine(rpmSpeed);
632
        setRpmSpeed(rpmSpeed);
633

    
634
        utCount.stateTime++;
635
        if (utCount.stateTime > PUSH_BACK_TIMEOUT){
636
          utCount.stateTime = 0;
637
          newState = states::CHECK_POSITIONING;
638
        }
639
      break;
640
      // ---------------------------------------
641
      case states::CHECK_POSITIONING:
642
        setRpmSpeed(stop);
643
        checkForMotion();
644
        if(checkDockingSuccess()){
645
          newState = states::CHECK_VOLTAGE;
646
        }else{
647
          utCount.errorCount++;
648
          newState = states::CORRECT_POSITIONING;
649
          if (utCount.errorCount >= DOCKING_ERROR_THRESH){
650
              newState = states::DOCKING_ERROR;
651
            }
652
        }
653
      break;
654
      // ---------------------------------------
655
      case states::CHECK_VOLTAGE:
656
        if(!checkPinEnabled()){
657
          global.robot.requestCharging(1);
658
        } else {
659
          if(checkPinVoltage()){
660
            // Pins are under voltage -> correctly docked 
661
            
662
            newState = states::CHARGING;
663
          }else{
664
            utCount.errorCount++;
665
            // No voltage on pins -> falsely docked
666
            // deactivate pins
667
            global.motorcontrol.setMotorEnable(true);
668
            global.robot.requestCharging(0);
669
            // TODO: Soft release when docking falsely
670
            if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
671
              newState = states::RELEASE_TO_CORRECT;
672
            } else {
673
              newState = states::RELEASE_TO_CORRECT; //states::CORRECT_POSITIONING; 
674
            }
675

    
676
            if (utCount.errorCount > DOCKING_ERROR_THRESH){
677
              newState = states::DOCKING_ERROR;
678
            }
679
          }
680
        }
681
      break;
682
      // ---------------------------------------
683
      case states::RELEASE_TO_CORRECT:
684
        
685
        global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
686
        checkForMotion();
687
        // move 1cm forward
688
        global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
689
        checkForMotion();
690
        // rotate back
691
        global.distcontrol.setTargetPosition(0, -2*ROTATION_20, ROTATION_DURATION);
692
        checkForMotion();
693

    
694
        global.distcontrol.setTargetPosition(1500, 0, ROTATION_DURATION);
695
        checkForMotion();
696
        newState = states::CORRECT_POSITIONING;
697
      break;
698
      // ---------------------------------------
699
      case states::CHARGING:
700
        global.motorcontrol.setMotorEnable(false);
701
        utCount.errorCount = 0;
702
        // Formulate Request to enable charging
703
        if(/* checkPinVoltage() && */ !checkPinEnabled()){
704
          global.robot.requestCharging(1);
705
        }
706
        if(checkPinEnabled()){
707
          showChargingState();
708
        }
709
      break;
710
      // ---------------------------------------
711
      case states::RELEASE:
712
      if (global.forwardSpeed != DETECTION_SPEED){
713
          global.rpmForward[0] = DETECTION_SPEED;
714
        }
715
        if(/* checkPinVoltage() && */ checkPinEnabled()){
716
          global.robot.requestCharging(0);
717
        }else{
718
          global.motorcontrol.setMotorEnable(true);
719
          // TODO: Use controlled 
720
          //Rotate -20° to free from magnet
721
          global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
722
          checkForMotion();
723
          // move 1cm forward
724
          global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
725
          checkForMotion();
726
          // rotate back
727
          // global.distcontrol.setTargetPosition(0, -ROTATION_20, ROTATION_DURATION);
728
          // checkForMotion();
729

    
730
          // global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
731
          // checkForMotion();
732
          lStrategy = LineFollowStrategy::EDGE_RIGHT;
733
          newState = states::FOLLOW_LINE;
734
            // whiteBuf = -100;
735
          // lf.followLine(rpmSpeed);
736
          // setRpmSpeed(rpmSpeed);
737
        }
738
        // lightAllLeds(Color::BLACK);
739
      break;
740
      // ---------------------------------------
741
      case states::DOCKING_ERROR:
742
        newState = states::RELEASE;
743
      break;
744
      // ---------------------------------------
745
      case states::REVERSE_TIMEOUT_ERROR:
746
        newState = states::IDLE;
747
      break;
748
      // ---------------------------------------
749
      case states::CALIBRATION_ERROR:
750
        newState = states::IDLE;
751
      break;
752
      // ---------------------------------------
753
      case states::WHITE_DETECTION_ERROR:
754
        newState = states::IDLE;
755
      break;
756
      // ---------------------------------------
757
      case states::PROXY_DETECTION_ERROR:
758
        newState = states::IDLE;
759
      break;
760
      // ---------------------------------------
761
      case states::NO_CHARGING_POWER_ERROR:
762
        newState = states::IDLE;
763
      break;
764
      // ---------------------------------------
765
      case states::UNKNOWN_STATE_ERROR:
766
        newState = states::IDLE;
767
      break;
768
      // ---------------------------------------
769
      default:
770
        newState = states::UNKNOWN_STATE_ERROR;
771
      break;
772
      }
773
      if (currentState != newState){
774
        chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
775
        global.robot.transmitState(newState);
776
        if (newState == states::IDLE)
777
          {global.stateTracker[states::IDLE] += 1;}
778
        else if (newState == states::FOLLOW_LINE)
779
          {global.stateTracker[states::FOLLOW_LINE] += 1;}
780
        else if (newState == states::DETECT_STATION)
781
          {global.stateTracker[states::DETECT_STATION] += 1;}
782
        else if (newState == states::REVERSE)
783
          {global.stateTracker[states::REVERSE] += 1;}
784
        else if (newState == states::PUSH_BACK)
785
          {global.stateTracker[states::PUSH_BACK] += 1;}
786
        else if (newState == states::CHECK_POSITIONING)
787
          {global.stateTracker[states::CHECK_POSITIONING] += 1;}
788
        else if (newState == states::CHECK_VOLTAGE)
789
          {global.stateTracker[states::CHECK_VOLTAGE] += 1;}
790
        else if (newState == states::CHARGING)
791
          {global.stateTracker[states::CHARGING] += 1;}
792
        else if (newState == states::RELEASE)
793
          {global.stateTracker[states::RELEASE] += 1;}
794
        else if (newState == states::RELEASE_TO_CORRECT)
795
          {global.stateTracker[states::RELEASE_TO_CORRECT] += 1;}
796
        else if (newState == states::CORRECT_POSITIONING)
797
          {global.stateTracker[states::CORRECT_POSITIONING] += 1;}
798
        else if (newState == states::TURN)
799
          {global.stateTracker[states::TURN] += 1;}
800
        else if (newState == states::INACTIVE)
801
          {global.stateTracker[states::INACTIVE] += 1;}
802
        else if (newState == states::CALIBRATION)
803
          {global.stateTracker[states::CALIBRATION] += 1;}
804
        else if (newState == states::CALIBRATION_CHECK)
805
          {global.stateTracker[states::CALIBRATION_CHECK] += 1;}
806
        else if (newState == states::DEVIATION_CORRECTION)
807
          {global.stateTracker[states::DEVIATION_CORRECTION] += 1;}
808
        
809
        else if (newState == states::DOCKING_ERROR){global.stateTracker[16+(-states::DOCKING_ERROR)] += 1;}
810
        else if (newState == states::REVERSE_TIMEOUT_ERROR){global.stateTracker[16+(-states::REVERSE_TIMEOUT_ERROR)] += 1;}
811
        else if (newState == states::CALIBRATION_ERROR){global.stateTracker[16+(-states::CALIBRATION_ERROR)] += 1;}
812
        else if (newState == states::WHITE_DETECTION_ERROR){global.stateTracker[16+(-states::WHITE_DETECTION_ERROR)] += 1;}
813
        else if (newState == states::PROXY_DETECTION_ERROR){global.stateTracker[16+(-states::PROXY_DETECTION_ERROR)] += 1;}
814
        else if (newState == states::NO_CHARGING_POWER_ERROR){global.stateTracker[16+(-states::NO_CHARGING_POWER_ERROR)] += 1;}
815
        else if (newState == states::UNKNOWN_STATE_ERROR){global.stateTracker[16+(-states::UNKNOWN_STATE_ERROR)] += 1;}
816
      }
817
      prevState = currentState;
818
      currentState = newState;
819
      // if (utCount.stateCount > CAN_TRANSMIT_STATE_THRESH){
820
      //     utCount.stateCount = 0;
821
      //   // chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
822
      //   global.robot.transmitState(currentState);
823
      //   // global.robot.setOdometry(global.odometry.getPosition());
824
        
825
      // }else{
826
      //   utCount.stateCount++;
827
      // }
828
    this->sleep(CAN::UPDATE_PERIOD);
829
  }
830

    
831
  return RDY_OK;
832
}