Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (27.622 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
  bool motion = true;
162
  int led = 0;
163
  types::position oldPos = global.odometry.getPosition();
164
  while(motion){
165
    this->sleep(200);
166
    types::position tmp = global.odometry.getPosition();
167
    motion = oldPos.x != tmp.x; //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
      int blackSensor = 0;
470
      if (lf.getStrategy() == LineFollowStrategy::EDGE_RIGHT) {
471
        factor = -factor;
472
        blackSensor = frontL;
473
      }else{
474
        blackSensor = frontR;
475
      }
476

    
477
      rpmSpeed[0] = factor * CHARGING_SPEED;
478
      rpmSpeed[1] = -factor * CHARGING_SPEED;
479
      setRpmSpeed(rpmSpeed);
480

    
481
      if ((blackSensor >= global.linePID.WThresh )){
482
        utCount.whiteCount = 1;
483
      }else {
484
        if((utCount.whiteCount == 1) && (blackSensor <= global.linePID.BThresh)){
485
          utCount.whiteCount = 0;
486
          newState = states::FOLLOW_LINE;
487
          setRpmSpeed(stop);
488
        }
489
      }
490
      break;
491
    }
492
      // ---------------------------------------
493
      case states::DETECT_STATION:
494

    
495
        if (global.forwardSpeed != DETECTION_SPEED){
496
          global.forwardSpeed = DETECTION_SPEED;
497
        }
498
        if(lf.getStrategy() != LineFollowStrategy::EDGE_RIGHT){
499
          lf.setStrategy(LineFollowStrategy::EDGE_RIGHT);
500
        }
501

    
502
        lf.followLine(rpmSpeed);
503
        setRpmSpeed(rpmSpeed);
504
        // // Detect marker before docking station
505
        // if ((WL+WR) < PROXY_WHEEL_THRESH){
506
        // Use proxy ring
507
        if ((rProx[3]+rProx[4]) > RING_PROX_FRONT_THRESH){
508

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

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

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

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

    
622
        utCount.stateTime++;
623

    
624

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

    
638
        utCount.stateTime++;
639
        if (utCount.stateTime > PUSH_BACK_TIMEOUT){
640
          utCount.stateTime = 0;
641
          newState = states::CHECK_POSITIONING;
642
        }
643
      break;
644
      // ---------------------------------------
645
      case states::CHECK_POSITIONING:
646
        setRpmSpeed(stop);
647
        checkForMotion();
648
        if(checkDockingSuccess()){
649
          newState = states::CHECK_VOLTAGE;
650
        }else{
651
          utCount.errorCount++;
652
          newState = states::CORRECT_POSITIONING;
653
          if (utCount.errorCount >= DOCKING_ERROR_THRESH){
654
              newState = states::DOCKING_ERROR;
655
            }
656
        }
657
      break;
658
      // ---------------------------------------
659
      case states::CHECK_VOLTAGE:
660
        if(!checkPinEnabled()){
661
          global.robot.requestCharging(1);
662
        } else {
663
          if(checkPinVoltage()){
664
            // Pins are under voltage -> correctly docked
665

    
666
            newState = states::CHARGING;
667
          }else{
668
            utCount.errorCount++;
669
            // No voltage on pins -> falsely docked
670
            // deactivate pins
671
            global.motorcontrol.setMotorEnable(true);
672
            global.robot.requestCharging(0);
673
            // TODO: Soft release when docking falsely
674
            if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
675
              newState = states::RELEASE_TO_CORRECT;
676
            } else {
677
              newState = states::RELEASE_TO_CORRECT; //states::CORRECT_POSITIONING;
678
            }
679

    
680
            if (utCount.errorCount > DOCKING_ERROR_THRESH){
681
              newState = states::DOCKING_ERROR;
682
            }
683
          }
684
        }
685
      break;
686
      // ---------------------------------------
687
      case states::RELEASE_TO_CORRECT:
688

    
689
        global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
690
        checkForMotion();
691
        // move 1cm forward
692
        global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
693
        checkForMotion();
694
        // rotate back
695
        global.distcontrol.setTargetPosition(0, -2*ROTATION_20, ROTATION_DURATION);
696
        checkForMotion();
697

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

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

    
813
        else if (newState == states::DOCKING_ERROR){global.stateTracker[16+(-states::DOCKING_ERROR)] += 1;}
814
        else if (newState == states::REVERSE_TIMEOUT_ERROR){global.stateTracker[16+(-states::REVERSE_TIMEOUT_ERROR)] += 1;}
815
        else if (newState == states::CALIBRATION_ERROR){global.stateTracker[16+(-states::CALIBRATION_ERROR)] += 1;}
816
        else if (newState == states::WHITE_DETECTION_ERROR){global.stateTracker[16+(-states::WHITE_DETECTION_ERROR)] += 1;}
817
        else if (newState == states::PROXY_DETECTION_ERROR){global.stateTracker[16+(-states::PROXY_DETECTION_ERROR)] += 1;}
818
        else if (newState == states::NO_CHARGING_POWER_ERROR){global.stateTracker[16+(-states::NO_CHARGING_POWER_ERROR)] += 1;}
819
        else if (newState == states::UNKNOWN_STATE_ERROR){global.stateTracker[16+(-states::UNKNOWN_STATE_ERROR)] += 1;}
820
      }
821
      prevState = currentState;
822
      currentState = newState;
823
      // if (utCount.stateCount > CAN_TRANSMIT_STATE_THRESH){
824
      //     utCount.stateCount = 0;
825
      //   // chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
826
      //   global.robot.transmitState(currentState);
827
      //   // global.robot.setOdometry(global.odometry.getPosition());
828

    
829
      // }else{
830
      //   utCount.stateCount++;
831
      // }
832
    this->sleep(CAN::UPDATE_PERIOD);
833
  }
834

    
835
  return RDY_OK;
836
}