Statistics
| Branch: | Tag: | Revision:

amiro-os / devices / DiWheelDrive / userthread.cpp @ 309980f0

History | View | Annotate | Download (36.847 KB)

1
#include "userthread.hpp"
2
#include "amiro/Constants.h"
3
#include "amiro_map.hpp"
4
#include "global.hpp"
5
#include "linefollow.hpp"
6

    
7
using namespace amiro;
8

    
9
extern Global global;
10

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

    
15

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

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

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

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

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

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

    
72
// ----------------------------------------------------------------
73

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

    
79
  }
80
    // chprintf((BaseSequentialStream*)&global.sercanmux1, "\n");
81

    
82
}
83

    
84

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

    
91
void UserThread::proxSectorSpeedCorrection(int (&rpmSpeed)[2], uint16_t (&proxVals)[8]){
92
  int i;
93
  uint16_t sProx[8];
94
  int32_t sPMax = 0;
95
  getProxySectorVals(proxVals, sProx);
96
  getMaxFrontSectorVal(sProx, sPMax);
97

    
98
  int32_t speedL = rpmSpeed[0] - (sPMax * pCtrl.pFactor);
99
  int32_t speedR = rpmSpeed[1] - (sPMax * pCtrl.pFactor);
100

    
101

    
102

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

    
116
  for(i=4; i<5; i++){
117
    if ((proxVals[i] > pCtrl.threshMid) && (proxVals[i+1] > pCtrl.threshLow)){
118
      rpmSpeed[0] = -5000000 ;
119
      rpmSpeed[1] = -5000000 ;
120
      // pCtrl.staticCont++;
121
      break;
122
    }
123
  }
124
  chargeAsLED();
125

    
126
  // 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]);
127

    
128

    
129
}
130
// -------------------------------------------------------------------
131

    
132

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

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

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

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

    
153
}
154

    
155

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

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

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

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

    
201
int UserThread::checkDockingSuccess(){
202
  // setRpmSpeed(stop);
203
  checkForMotion();
204
  int success = 0;
205
  // global.odometry.resetPosition();
206
  types::position start = global.startPos = global.odometry.getPosition();
207
  global.motorcontrol.setMotorEnable(false);
208
  this->sleep(1000);
209
  types::position stop_ = global.endPos = global.odometry.getPosition();
210

    
211
  // Amiro moved, docking was not successful
212
  // if ((start.x + stop_.x)  || (start.y + stop_.y)){
213
  if (abs(start.x - stop_.x) > 200 /* || (start.y + stop_.y) */){
214
    lightAllLeds(Color::RED);
215
    // Enable Motor again if docking was not successful
216
    global.motorcontrol.setMotorEnable(true);
217
    success = 0;
218
  }else{
219
    lightAllLeds(Color::GREEN);
220
    success = 1;
221
  }
222

    
223
  // this->sleep(500);
224
  lightAllLeds(Color::BLACK);
225
  return success;
226
}
227

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

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

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

    
250
void setAttributes(uint8_t (&map)[MAX_NODES][NODE_ATTRIBUTES],
251
                          uint8_t id, uint8_t l, uint8_t r, uint8_t att) {
252
  map[id][0] = l;
253
  map[id][1] = r;
254
  map[id][2] = att;
255
}
256

    
257
UserThread::UserThread() :
258
  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
259
{
260
}
261

    
262
UserThread::~UserThread()
263
{
264
}
265

    
266
msg_t
267
UserThread::main()
268
{
269
  /*
270
   * SETUP
271
   */
272
  // User thread state:
273

    
274
  for (uint8_t led = 0; led < 8; ++led) {
275
    global.robot.setLightColor(led, Color(Color::BLACK));
276
  }
277

    
278
  // State Variables
279
  ut_states prevState = ut_states::UT_IDLE;
280
  ut_states currentState = ut_states::UT_INACTIVE;
281
  ut_states newState = ut_states::UT_INACTIVE;
282

    
283

    
284
  running = false;
285
  LineFollowStrategy lStrategy = LineFollowStrategy::EDGE_RIGHT;
286
  LineFollow lf(&global);
287
  AmiroMap map(&global);
288
  /*
289
   * LOOP
290
   */
291
  while (!this->shouldTerminate())
292
  {
293
    /*
294
    * read accelerometer z-value
295
    */
296
    accel_z = global.lis331dlh.getAccelerationForce(LIS331DLH::AXIS_Z);
297

    
298
    if (accel_z < -900 /*-0.9g*/) {
299
      // Start line following when AMiRo is rotated
300
      if(currentState == ut_states::UT_INACTIVE){
301
        newState = ut_states::UT_FOLLOW_LINE;
302
      }else{
303
        newState = ut_states::UT_IDLE;
304
      }
305
      lightAllLeds(Color::GREEN);
306
      this->sleep(1000);
307
      lightAllLeds(Color::BLACK);
308

    
309
    // If message was received handle it here:
310
    } else if(global.msgReceived){
311
      global.msgReceived = false;
312
      // running = true;
313
      switch(global.lfStrategy){
314
      case msg_content::MSG_START:
315
        newState = ut_states::UT_CALIBRATION_CHECK;
316
        break;
317
      case msg_content::MSG_STOP:
318
        newState = ut_states::UT_IDLE;
319
        break;
320
      case msg_content::MSG_EDGE_RIGHT:
321
        // newState = ut_states::UT_FOLLOW_LINE;
322
        lStrategy = LineFollowStrategy::EDGE_RIGHT;
323
        break;
324
      case  msg_content::MSG_EDGE_LEFT:
325
        // newState = ut_states::UT_FOLLOW_LINE;
326
        lStrategy = LineFollowStrategy::EDGE_LEFT;
327
        break;
328
      case msg_content::MSG_FUZZY:
329
        // newState = ut_states::UT_FOLLOW_LINE;
330
        lStrategy = LineFollowStrategy::FUZZY;
331
        break;
332
      case msg_content::MSG_DOCK:
333
        newState = ut_states::UT_DETECT_STATION;
334
        break;
335
      case msg_content::MSG_UNDOCK:
336
        newState = ut_states::UT_RELEASE;
337
        break;
338
      case msg_content::MSG_CHARGE:
339
        newState = ut_states::UT_CHARGING;
340
        break;
341
      case msg_content::MSG_RESET_ODOMETRY:
342
        global.odometry.resetPosition();
343
        break;
344
      case msg_content::MSG_CALIBRATE_BLACK:
345
        proxCalib.calibrateBlack = true;
346
        // global.odometry.resetPosition();
347
        newState = ut_states::UT_CALIBRATION;
348
        break;
349
      case msg_content::MSG_CALIBRATE_WHITE:
350
        proxCalib.calibrateBlack = false;
351
        newState = ut_states::UT_CALIBRATION;
352
        break;
353
      case msg_content::MSG_TEST_MAP_STATE:
354
        if (AMIRO_MAP_AUTO_TRACKING){
355
          newState = ut_states::UT_TEST_MAP_AUTO_STATE;
356
        }else {
357
          newState = ut_states::UT_TEST_MAP_STATE;
358
        }
359
        break;
360
      case msg_content::MSG_SET_DIST_THRESH:
361

    
362

    
363
        break;
364
      case msg_content::MSG_GET_MAP_INFO:
365
        break;
366
      default:
367
        newState = ut_states::UT_IDLE;
368
        break;
369
      }
370
    }
371
    // newState = currentState;
372

    
373
    // Get sensor data
374
    uint16_t WL = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_LEFT].getProximityScaledWoOffset();
375
    uint16_t WR = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_RIGHT].getProximityScaledWoOffset();
376
    for(int i=0; i<8;i++){
377
      rProx[i] = global.robot.getProximityRingValue(i);
378
    }
379

    
380
    // Continously update devication values
381
    meanDeviation(rProx[0] & 0xFFF0, rProx[7] & 0xFFF0);
382
    // int FL = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset();
383
    // int FR = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
384
    switch(currentState){
385
      case ut_states::UT_INACTIVE:
386
        // Dummy state to deactivate every interaction
387
      break;
388
      // ---------------------------------------
389
      case ut_states::UT_CALIBRATION_CHECK:
390
        // global.robot.calibrate();
391
        if(global.linePID.BThresh >= global.linePID.WThresh){
392
          newState = ut_states::UT_CALIBRATION_ERROR;
393
        }else{
394
          newState = ut_states::UT_FOLLOW_LINE;
395
        }
396
      break;
397
      // ---------------------------------------
398
      case ut_states::UT_CALIBRATION:
399
        /* Calibrate the global thresholds for black or white.
400
            This values will be used by the line follow object
401
        */
402

    
403
        proxCalib.buf = 0;
404
        if(proxCalib.calibrateBlack){
405
          chprintf((BaseSequentialStream*)&global.sercanmux1, "Black Calibration, Place AMiRo on black Surface!\n");
406
          global.robot.calibrate();
407
        }
408
        for(int i=0; i <= proxCalib.meanWindow; i++){
409
          proxCalib.buf += global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset()
410
                          + global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
411
          this->sleep(CAN::UPDATE_PERIOD);
412
        }
413
        proxCalib.buf = proxCalib.buf / (2*proxCalib.meanWindow);
414

    
415
        if(proxCalib.calibrateBlack){
416
          global.linePID.BThresh = proxCalib.buf;
417
        }else  {
418
          global.linePID.WThresh  = proxCalib.buf;
419
        }
420
          chprintf((BaseSequentialStream*)&global.sercanmux1, "Black: %d, White: %d!\n", global.linePID.BThresh, global.linePID.WThresh);
421

    
422
        newState = ut_states::UT_IDLE;
423
      break;
424
      // ---------------------------------------
425
      case ut_states::UT_IDLE:
426
        global.motorcontrol.setMotorEnable(true);
427
        setRpmSpeed(stop);
428
        if(/* checkPinVoltage() && */ checkPinEnabled()){
429
          global.robot.requestCharging(0);
430
        }
431
        // pCtrl.pFactor = 0;
432
        pCtrl.staticCont = 0;
433
        utCount.whiteCount = 0;
434
        utCount.ringProxCount = 0;
435
        utCount.errorCount = 0;
436
        newState = ut_states::UT_INACTIVE;
437
      break;
438
      // ---------------------------------------
439
      case ut_states::UT_FOLLOW_LINE:
440
      // Set correct forward speed to every strategy
441
        if (global.forwardSpeed != global.rpmForward[0]){
442
          global.forwardSpeed = global.rpmForward[0];
443
        }
444

    
445
        if(lf.getStrategy() != lStrategy){
446
          lf.setStrategy(lStrategy);
447
        }
448

    
449
        if(lf.followLine(rpmSpeed)){
450
          utCount.whiteCount++;
451
          if(utCount.whiteCount >= WHITE_DETETION_TIMEOUT){
452
            setRpmSpeed(stop);
453
            utCount.whiteCount = 0;
454
            newState = ut_states::UT_WHITE_DETECTION_ERROR;
455
          }
456
        }else{
457
          utCount.whiteCount = 0;
458
        }
459

    
460
        preventCollision(rpmSpeed, rProx);
461
        // proxSectorSpeedCorrection(rpmSpeed, rProx);
462

    
463
        if(utCount.ringProxCount > RING_PROX_DETECTION_TIMEOUT){
464
          utCount.ringProxCount = 0;
465

    
466

    
467
          checkForMotion();
468
          // Check if only front sensors are active
469
          if (checkFrontalObject()) {
470
            // global.distcontrol.setTargetPosition(0, 2792526, ROTATION_DURATION);
471
            // // BaseThread::sleep(8000);
472
            // checkForMotion();
473
            this->utCount.whiteCount = 0;
474
            newState = ut_states::UT_TURN;
475
            // lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
476
          } else {
477
            newState = ut_states::UT_PROXY_DETECTION_ERROR;
478
          }
479
        }
480

    
481
        if (lf.getStrategy() == LineFollowStrategy::FUZZY){
482
          setRpmSpeedFuzzy(rpmSpeed);
483
        }else{
484

    
485
          setRpmSpeed(rpmSpeed);
486
        }
487

    
488
      break;
489
      // ---------------------------------------
490
    case ut_states::UT_TURN:{
491
        // Check the line strategy in order to continue driving on the right side
492
      int factor = SPEED_CONVERSION_FACTOR;
493
      int frontL = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset();
494
      int frontR = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
495
      int blackSensor = 0;
496
      if (lf.getStrategy() == LineFollowStrategy::EDGE_RIGHT) {
497
        factor = -factor;
498
        blackSensor = frontL;
499
      }else{
500
        blackSensor = frontR;
501
      }
502

    
503
      rpmSpeed[0] = factor * CHARGING_SPEED;
504
      rpmSpeed[1] = -factor * CHARGING_SPEED;
505
      setRpmSpeed(rpmSpeed);
506

    
507
      if ((blackSensor >= global.linePID.WThresh )){
508
        utCount.whiteCount = 1;
509
      }else {
510
        if((utCount.whiteCount == 1) && (blackSensor <= global.linePID.BThresh)){
511
          utCount.whiteCount = 0;
512
          newState = ut_states::UT_FOLLOW_LINE;
513
          setRpmSpeed(stop);
514
        }
515
      }
516
      break;
517
    }
518
      // ---------------------------------------
519
    case ut_states::UT_DETECT_STATION:
520

    
521
        if (global.forwardSpeed != DETECTION_SPEED){
522
          global.forwardSpeed = DETECTION_SPEED;
523
        }
524
        if(lf.getStrategy() != LineFollowStrategy::EDGE_RIGHT){
525
          lf.setStrategy(LineFollowStrategy::EDGE_RIGHT);
526
        }
527

    
528
        lf.followLine(rpmSpeed);
529
        setRpmSpeed(rpmSpeed);
530
        // // Detect marker before docking station
531
        // if ((WL+WR) < PROXY_WHEEL_THRESH){
532
        // Use proxy ring
533
        if ((rProx[3]+rProx[4]) > RING_PROX_FRONT_THRESH){
534

    
535
          setRpmSpeed(stop);
536
          checkForMotion();
537
          // 180° Rotation
538
          global.distcontrol.setTargetPosition(0, ROTATION_180, ROTATION_DURATION);
539
          // BaseThread::sleep(8000);
540
          checkForMotion();
541
          newState = ut_states::UT_CORRECT_POSITIONING;
542
        }
543
      break;
544
      // ---------------------------------------
545
    case ut_states::UT_CORRECT_POSITIONING:
546
        if (global.forwardSpeed != CHARGING_SPEED){
547
          global.forwardSpeed = CHARGING_SPEED;
548
        }
549
        if(lf.getStrategy() != LineFollowStrategy::EDGE_LEFT){
550
          lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
551
        }
552
        lf.followLine(rpmSpeed);
553
        setRpmSpeed(rpmSpeed);
554

    
555
        utCount.stateTime++;
556
        if (utCount.stateTime >= DOCKING_CORRECTION_TIMEOUT){
557
          utCount.stateTime = 0;
558
          newState = ut_states::UT_REVERSE;
559
          setRpmSpeed(stop);
560
          checkForMotion();
561
        }
562
      break;
563
      // ---------------------------------------
564
    case ut_states::UT_REVERSE:
565
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
566
          lf.setStrategy(LineFollowStrategy::REVERSE);
567
        }
568
        lf.followLine(rpmSpeed);
569
        setRpmSpeed(rpmSpeed);
570
        // utCount.stateTime++;
571

    
572
        // Docking is only successful if Deviation is in range and sensors are at their max values.
573
        if((rProx[0] >= PROX_MAX_VAL)
574
           && (rProx[7] >= PROX_MAX_VAL)
575
           && ((devCor.currentDeviation > -MAX_DEVIATION_FACTOR) && (devCor.currentDeviation < MAX_DEVIATION_FACTOR) )){
576
          // setRpmSpeed(stop);
577
          // checkForMotion();
578
          utCount.stateTime = 0;
579
          newState = ut_states::UT_PUSH_BACK;
580
        }else if ((devCor.currentDeviation <= -MAX_DEVIATION_FACTOR) && ((rProx[0] > DEVIATION_DIST_THRESH) || (rProx[7] > DEVIATION_DIST_THRESH))){
581
          // Case R
582
          utCount.stateTime = 0;
583
          setRpmSpeed(stop);
584
          devCor.RCase = true;
585
          lightAllLeds(Color::YELLOW);
586
          newState = ut_states::UT_DEVIATION_CORRECTION;
587
        }else if ((devCor.currentDeviation >= MAX_DEVIATION_FACTOR) && ((rProx[0] > DEVIATION_DIST_THRESH) || (rProx[7] > DEVIATION_DIST_THRESH))){
588
          // Case L
589
          utCount.stateTime = 0;
590
          setRpmSpeed(stop);
591
          devCor.RCase = false;
592
          lightAllLeds(Color::WHITE);
593
          newState = ut_states::UT_DEVIATION_CORRECTION;
594
        }else if (utCount.stateTime >= REVERSE_DOCKING_TIMEOUT){
595
          setRpmSpeed(stop);
596
          utCount.stateTime = 0;
597
          utCount.errorCount++;
598
          if (utCount.errorCount >= DOCKING_ERROR_THRESH){
599
            newState = ut_states::UT_DOCKING_ERROR;
600
          }else{
601
            newState = ut_states::UT_CORRECT_POSITIONING;
602
          }
603
        }
604

    
605
        // if((devCor.currentDeviation <= -10)){
606
        //   rpmSpeed[0] -= 2000000;
607
        // }else if(devCor.currentDeviation >= 10){
608
        //   rpmSpeed[1] -= 2000000;
609
        // }
610
        // setRpmSpeed(rpmSpeed);
611
      break;
612
      // ---------------------------------------
613
    case ut_states::UT_DEVIATION_CORRECTION:
614
        // if(lf.getStrategy() != LineFollowStrategy::REVERSE){
615
        //   lf.setStrategy(LineFollowStrategy::REVERSE);
616
        // }
617
        // lf.followLine(rpmSpeed);
618
        // setRpmSpeed(rpmSpeed);
619
        if(utCount.stateTime < DEVIATION_CORRECTION_DURATION / 2 ){
620
          if(devCor.RCase){
621
            rpmSpeed[0] = 0;
622
            rpmSpeed[1] = DEVIATION_CORRECTION_SPEED;
623
          }else {
624
            rpmSpeed[0] = DEVIATION_CORRECTION_SPEED;
625
            rpmSpeed[1] = 0;
626
          }
627
          setRpmSpeed(rpmSpeed);
628
        }else if (((utCount.stateTime >= DEVIATION_CORRECTION_DURATION / 2) && (utCount.stateTime < DEVIATION_CORRECTION_DURATION +10)) ){
629
          if(devCor.RCase){
630
            rpmSpeed[0] = DEVIATION_CORRECTION_SPEED;
631
            rpmSpeed[1] = 0;
632
          }else {
633
            rpmSpeed[0] = 0;
634
            rpmSpeed[1] = DEVIATION_CORRECTION_SPEED;
635
          }
636
          setRpmSpeed(rpmSpeed);
637
          if(((devCor.currentDeviation >= -5) && (devCor.currentDeviation <= 5))){
638
            utCount.stateTime = 0;
639
            newState = ut_states::UT_REVERSE;
640
            setRpmSpeed(stop);
641
          }
642
        }else{
643
          utCount.stateTime = 0;
644
          newState = ut_states::UT_REVERSE;
645
          setRpmSpeed(stop);
646
        }
647

    
648
        utCount.stateTime++;
649

    
650

    
651
        // if (utCount.stateTime > PUSH_BACK_TIMEOUT){
652
        //   utCount.stateTime = 0;
653
        //   newState = ut_states::UT_CHECK_POSITIONING;
654
        // }
655
      break;
656
      // ---------------------------------------
657
    case ut_states::UT_PUSH_BACK:
658
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
659
          lf.setStrategy(LineFollowStrategy::REVERSE);
660
        }
661
        lf.followLine(rpmSpeed);
662
        setRpmSpeed(rpmSpeed);
663

    
664
        utCount.stateTime++;
665
        if (utCount.stateTime > PUSH_BACK_TIMEOUT){
666
          utCount.stateTime = 0;
667
          newState = ut_states::UT_CHECK_POSITIONING;
668
        }
669
      break;
670
      // ---------------------------------------
671
    case ut_states::UT_CHECK_POSITIONING:
672
        setRpmSpeed(stop);
673
        checkForMotion();
674
        if(checkDockingSuccess()){
675
          newState = ut_states::UT_CHECK_VOLTAGE;
676
        }else{
677
          utCount.errorCount++;
678
          newState = ut_states::UT_CORRECT_POSITIONING;
679
          if (utCount.errorCount >= DOCKING_ERROR_THRESH){
680
              newState = ut_states::UT_DOCKING_ERROR;
681
            }
682
        }
683
      break;
684
      // ---------------------------------------
685
    case ut_states::UT_CHECK_VOLTAGE:
686
        if(!checkPinEnabled()){
687
          global.robot.requestCharging(1);
688
        } else {
689
          if(checkPinVoltage()){
690
            // Pins are under voltage -> correctly docked
691

    
692
            newState = ut_states::UT_CHARGING;
693
          }else{
694
            utCount.errorCount++;
695
            // No voltage on pins -> falsely docked
696
            // deactivate pins
697
            global.motorcontrol.setMotorEnable(true);
698
            global.robot.requestCharging(0);
699
            // TODO: Soft release when docking falsely
700
            if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
701
              newState = ut_states::UT_RELEASE_TO_CORRECT;
702
            } else {
703
              newState = ut_states::UT_RELEASE_TO_CORRECT; //ut_states::UT_CORRECT_POSITIONING;
704
            }
705

    
706
            if (utCount.errorCount > DOCKING_ERROR_THRESH){
707
              newState = ut_states::UT_DOCKING_ERROR;
708
            }
709
          }
710
        }
711
      break;
712
      // ---------------------------------------
713
    case ut_states::UT_RELEASE_TO_CORRECT:
714

    
715
        global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
716
        checkForMotion();
717
        // move 1cm forward
718
        global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
719
        checkForMotion();
720
        // rotate back
721
        global.distcontrol.setTargetPosition(0, -2*ROTATION_20, ROTATION_DURATION);
722
        checkForMotion();
723

    
724
        global.distcontrol.setTargetPosition(1500, 0, ROTATION_DURATION);
725
        checkForMotion();
726
        newState = ut_states::UT_CORRECT_POSITIONING;
727
      break;
728
      // ---------------------------------------
729
    case ut_states::UT_CHARGING:
730
        global.motorcontrol.setMotorEnable(false);
731
        utCount.errorCount = 0;
732
        // Formulate Request to enable charging
733
        if(/* checkPinVoltage() && */ !checkPinEnabled()){
734
          global.robot.requestCharging(1);
735
        }
736
        if(checkPinEnabled()){
737
          showChargingState();
738
        }
739
      break;
740
      // ---------------------------------------
741
    case ut_states::UT_RELEASE:
742

    
743
      if (global.forwardSpeed != DETECTION_SPEED){
744
          global.rpmForward[0] = DETECTION_SPEED;
745
        }
746
        if(/* checkPinVoltage() && */ checkPinEnabled()){
747
          global.robot.requestCharging(0);
748
        }else{
749
          global.motorcontrol.setMotorEnable(true);
750
          // TODO: Use controlled
751
          //Rotate -20° to free from magnet
752
          global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
753
          checkForMotion();
754
          // move 1cm forward
755
          global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
756
          checkForMotion();
757
          // rotate back
758
          // global.distcontrol.setTargetPosition(0, -ROTATION_20, ROTATION_DURATION);
759
          // checkForMotion();
760

    
761
          // global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
762
          // checkForMotion();
763
          lStrategy = LineFollowStrategy::EDGE_RIGHT;
764
          newState = ut_states::UT_FOLLOW_LINE;
765
            // whiteBuf = -100;
766
          // lf.followLine(rpmSpeed);
767
          // setRpmSpeed(rpmSpeed);
768
        }
769
        // lightAllLeds(Color::BLACK);
770
      break;
771
      // ---------------------------------------
772
    case ut_states::UT_DOCKING_ERROR:
773
      newState = ut_states::UT_RELEASE;
774
      break;
775
      // ---------------------------------------
776
    case ut_states::UT_REVERSE_TIMEOUT_ERROR:
777
      newState = ut_states::UT_IDLE;
778
      break;
779
      // ---------------------------------------
780
    case ut_states::UT_CALIBRATION_ERROR:
781
      newState = ut_states::UT_IDLE;
782
      break;
783
      // ---------------------------------------
784
    case ut_states::UT_WHITE_DETECTION_ERROR:
785
      newState = ut_states::UT_IDLE;
786
      break;
787
      // ---------------------------------------
788
    case ut_states::UT_PROXY_DETECTION_ERROR:
789
      newState = ut_states::UT_IDLE;
790
      break;
791
      // ---------------------------------------
792
    case ut_states::UT_NO_CHARGING_POWER_ERROR:
793
      newState = ut_states::UT_IDLE;
794
      break;
795
      // ---------------------------------------
796
    case ut_states::UT_UNKNOWN_STATE_ERROR:
797
        newState = ut_states::UT_IDLE;
798
      break;
799
      // ---------------------------------------
800
    case ut_states::UT_TEST_MAP_AUTO_STATE:
801
      chprintf((BaseSequentialStream *)&global.sercanmux1,
802
               "Start autotracking: \n");
803

    
804
      chprintf((BaseSequentialStream *)&global.sercanmux1,
805
               "NodeCount: %d\n", map.getNodeCount());
806
      for (int i=0; i<map.getNodeCount(); i++) {
807
        chprintf((BaseSequentialStream *)&global.sercanmux1,
808
                 "ID: %d, l: %d, r: %d \n", map.getNodeList()[i].id,
809
                 map.getNodeList()[i].left, map.getNodeList()[i].right);
810
      }
811
      newState = UT_IDLE;
812
      break;
813
    case ut_states::UT_TEST_MAP_STATE:{
814
      // Test suit for amiro map
815

    
816

    
817

    
818
      // AmiroMap map = AmiroMap(&global);
819

    
820
      // --------------------------------------------------
821

    
822
      global.tcase = 0;
823
      // Set basic valid map configuration
824
      setAttributes(global.testmap, 0, 1, 2, 1);
825
      setAttributes(global.testmap, 1, 2, 2, 0);
826
      setAttributes(global.testmap, 2, 1, 0, 0);
827
      setAttributes(global.testmap, 3, 0, 0, 0xff);
828
      chprintf((BaseSequentialStream *)&global.sercanmux1, "Init Case: %d, res: %d\n",global.tcase, map.initialize());
829
      global.testres[global.tcase] = map.get_state()->valid;
830

    
831
      global.tcase++; // 1
832
      // Test map fail if first node is flagged with end
833
      setAttributes(global.testmap, 0, 1, 2, 0xff);
834
      map.initialize();
835
      global.testres[global.tcase] = !map.get_state()->valid;
836

    
837
      global.tcase++; // 2
838
      // Test if node 2 is set as start node
839
      setAttributes(global.testmap, 0, 1, 2, 0);
840
      setAttributes(global.testmap, 2, 1, 0, 1);
841
      map.initialize();
842
      global.testres[global.tcase] = map.get_state()->current == 2;
843

    
844
      global.tcase++; // 3
845
      // Test if non reachable nodes will trigger invalid map
846
      setAttributes(global.testmap, 3, 0, 0, 0);
847
      setAttributes(global.testmap, 4, 0, 0, 0xff);
848
      map.initialize();
849
      global.testres[global.tcase] = !map.get_state()->valid;
850

    
851
      global.tcase++; // 4
852
      // Test Reinitialization
853
      setAttributes(global.testmap, 0, 1, 2, 1);
854
      setAttributes(global.testmap, 1, 2, 2, 0);
855
      setAttributes(global.testmap, 2, 1, 0, 0);
856
      setAttributes(global.testmap, 3, 0, 0, 0xff);
857
      map.initialize();
858
      global.testres[global.tcase] = map.get_state()->valid;
859

    
860
      global.odometry.resetPosition();
861
      uint8_t ret = 0;
862
      global.tcase++; // 5
863
      // Test update under normal linefollowing without fixpoint
864
      ret = map.update(20000, 20000, LineFollowStrategy::EDGE_RIGHT);
865
      chprintf((BaseSequentialStream *)&global.sercanmux1,
866
               "Update test %d: Ret %d, cur %d, nex %d\n", global.tcase, ret,
867
               map.get_state()->current, map.get_state()->next);
868
      // No case should be true because neither was a node visited nor
869
      // was a fixpoint detected.
870
      global.testres[global.tcase] = (ret == 0x4);
871

    
872

    
873
      global.odometry.setPosition(1.0, 0.0, 0.0);
874
      chprintf((BaseSequentialStream *)&global.sercanmux1, "Current Point: %d\n", global.odometry.getPosition().x);
875
      global.tcase++; // 6
876
      // Fixpoint on left side
877
      ret = map.update(0, 20000, LineFollowStrategy::EDGE_RIGHT);
878
      chprintf((BaseSequentialStream *)&global.sercanmux1,
879
               "Update test %d: Ret %d, cur %d, nex %d\n", global.tcase, ret,
880
               map.get_state()->current, map.get_state()->next);
881
      // No case should be true because neither was a node visited nor
882
      // was a fixpoint detected.
883
      // global.odometry
884
      global.testres[global.tcase] = (ret == 0x1)
885
        && (map.get_state()->strategy == 0x01)
886
        && (map.get_state()->dist == 0)
887
        && (map.get_state()->current == 2);
888

    
889

    
890
      global.odometry.setPosition(1.5, 0.0, 0.0);
891
      chprintf((BaseSequentialStream *)&global.sercanmux1,
892
               "Current Point: %d\n", global.odometry.getPosition().x);
893
      global.tcase++; // 7
894
      // Fixpoint on left side, no update should appear because fixpoint already
895
      // marked
896
      ret = map.update(0, 20000, LineFollowStrategy::EDGE_RIGHT);
897
      chprintf((BaseSequentialStream *)&global.sercanmux1,
898
               "Update test %d: Ret %d, cur %d, nex %d\n", global.tcase, ret,
899
               map.get_state()->current, map.get_state()->next);
900
      // No case should be true because neither was a node visited nor
901
      // was a fixpoint detected.
902
      global.testres[global.tcase] = (ret == 0x00)
903
        && (map.get_state()->strategy == 0x01);
904
        // && (map.get_state()->dist == 0);
905

    
906
      global.odometry.setPosition(1.2, 0.0, 0.0);
907
      global.tcase++; // 8
908
      // Fixpoint on left side, no update should appear because fixpoint already
909
      // marked
910
      ret = map.update(20000, 20000, LineFollowStrategy::EDGE_RIGHT);
911
      chprintf((BaseSequentialStream *)&global.sercanmux1,
912
               "Update test %d: Ret %d, cur %d, nex %d, dist %d, len %d\n", global.tcase, ret,
913
               map.get_state()->current, map.get_state()->next, map.get_state()->dist, map.get_state()->eLength);
914
      // No case should be true because neither was a node visited nor
915
      // was a fixpoint detected.
916
      global.testres[global.tcase] =
917
          (ret == 0x04) && (map.get_state()->strategy == 0x01)
918
        && (map.get_state()->dist == 0);
919

    
920
      global.odometry.setPosition(.5, 0.0, 0.0);
921
      chprintf((BaseSequentialStream *)&global.sercanmux1,
922
               "Current Point: %d\n", global.odometry.getPosition().x);
923
      global.tcase++; // 9
924
      // Fixpoint on left side, no update should appear because fixpoint already
925
      // marked
926
      ret = map.update(0, 20000, LineFollowStrategy::EDGE_RIGHT);
927
      chprintf((BaseSequentialStream *)&global.sercanmux1,
928
               "Update test %d: Ret %d, cur %d, nex %d, dist %d, len %d\n",
929
               global.tcase, ret, map.get_state()->current,
930
               map.get_state()->next, map.get_state()->dist,
931
               map.get_state()->eLength);
932
      // No case should be true because neither was a node visited nor
933
      // was a fixpoint detected.
934
      global.testres[global.tcase] =
935
        (ret == 9) &&
936
        (map.get_state()->strategy == 1) &&
937
        (map.get_state()->dist == 0) &&
938
        (map.get_state()->eLength == 50);
939

    
940
      global.odometry.setPosition(.75, 0.0, 0.0);
941
      chprintf((BaseSequentialStream *)&global.sercanmux1,
942
               "Current Point: %d\n", global.odometry.getPosition().x);
943
      global.tcase++; // 10
944
      // Fixpoint on left side, no update should appear because fixpoint already
945
      // marked
946
      ret = map.update(20000, 20000, LineFollowStrategy::EDGE_RIGHT);
947
      chprintf((BaseSequentialStream *)&global.sercanmux1,
948
               "Update test %d: Ret %d, cur %d, nex %d, dist %d, len %d\n",
949
               global.tcase, ret, map.get_state()->current,
950
               map.get_state()->next, map.get_state()->dist,
951
               map.get_state()->eLength);
952
      // No case should be true because neither was a node visited nor
953
      // was a fixpoint detected.
954
      global.testres[global.tcase] =
955
          (ret == 12) && (map.get_state()->strategy == 1) &&
956
          (map.get_state()->dist == 50) && (map.get_state()->eLength == 50);
957

    
958
      int failed = 0;
959
      int passed = 0;
960
      for (int i = 0; i <= global.tcase; i++) {
961
        if (global.testres[i]) {
962
          passed++;
963
          chprintf((BaseSequentialStream *)&global.sercanmux1,
964
                   "Test %d Passed!\n", i);
965
        } else {
966
          failed++;
967
          chprintf((BaseSequentialStream *)&global.sercanmux1,
968
                   "Test %d Failed\n", i);
969
        }
970
      }
971
      chprintf((BaseSequentialStream *)&global.sercanmux1,
972
               "Total: %d, Passed: %d, Failed: %d\n", global.tcase + 1, passed,
973
               failed);
974

    
975
      newState = ut_states::UT_IDLE;
976
      break;
977
    }
978
      // --------------------------------------------------
979
    default:
980
      newState = ut_states::UT_UNKNOWN_STATE_ERROR;
981
      break;
982
    }
983

    
984
    // In case a new state is set:
985
    // 1. Record the state transition
986
    if (AMIRO_MAP_AUTO_TRACKING) {
987
      // map.trackUpdate(WL, WR, lStrategy, currentState);
988
    }
989

    
990
    if (currentState != newState){
991

    
992
      global.stateTransitionCounter++;
993
      // Clear all state transitions to prevent overflow
994
      if (global.stateTransitionCounter >= 255) {
995
        global.stateTransitionCounter = 0;
996
        for (int i = 0; i < 24; i++) {
997
          global.stateTracker[i] = 0;
998
        }
999
}
1000
      // Transmit the new state over can
1001
      chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
1002
      global.robot.transmitState(newState);
1003

    
1004
      // Increase state count for specific state
1005
      // TODO: Improve with dictionary or other than switch case
1006
      if (newState == ut_states::UT_IDLE)
1007
        {global.stateTracker[ut_states::UT_IDLE] += 1;}
1008
      else if (newState == ut_states::UT_FOLLOW_LINE)
1009
        {global.stateTracker[ut_states::UT_FOLLOW_LINE] += 1;}
1010
      else if (newState == ut_states::UT_DETECT_STATION)
1011
        {global.stateTracker[ut_states::UT_DETECT_STATION] += 1;}
1012
      else if (newState == ut_states::UT_REVERSE)
1013
        {global.stateTracker[ut_states::UT_REVERSE] += 1;}
1014
      else if (newState == ut_states::UT_PUSH_BACK)
1015
        {global.stateTracker[ut_states::UT_PUSH_BACK] += 1;}
1016
      else if (newState == ut_states::UT_CHECK_POSITIONING)
1017
        {global.stateTracker[ut_states::UT_CHECK_POSITIONING] += 1;}
1018
      else if (newState == ut_states::UT_CHECK_VOLTAGE)
1019
        {global.stateTracker[ut_states::UT_CHECK_VOLTAGE] += 1;}
1020
      else if (newState == ut_states::UT_CHARGING)
1021
        {global.stateTracker[ut_states::UT_CHARGING] += 1;}
1022
      else if (newState == ut_states::UT_RELEASE)
1023
        {global.stateTracker[ut_states::UT_RELEASE] += 1;}
1024
      else if (newState == ut_states::UT_RELEASE_TO_CORRECT)
1025
        {global.stateTracker[ut_states::UT_RELEASE_TO_CORRECT] += 1;}
1026
      else if (newState == ut_states::UT_CORRECT_POSITIONING)
1027
        {global.stateTracker[ut_states::UT_CORRECT_POSITIONING] += 1;}
1028
      else if (newState == ut_states::UT_TURN)
1029
        {global.stateTracker[ut_states::UT_TURN] += 1;}
1030
      else if (newState == ut_states::UT_INACTIVE)
1031
        {global.stateTracker[ut_states::UT_INACTIVE] += 1;}
1032
      else if (newState == ut_states::UT_CALIBRATION)
1033
        {global.stateTracker[ut_states::UT_CALIBRATION] += 1;}
1034
      else if (newState == ut_states::UT_CALIBRATION_CHECK)
1035
        {global.stateTracker[ut_states::UT_CALIBRATION_CHECK] += 1;}
1036
      else if (newState == ut_states::UT_DEVIATION_CORRECTION)
1037
        {global.stateTracker[ut_states::UT_DEVIATION_CORRECTION] += 1;}
1038
      else if (newState == ut_states::UT_DOCKING_ERROR)
1039
        {global.stateTracker[16+(-ut_states::UT_DOCKING_ERROR)] += 1;}
1040
      else if (newState == ut_states::UT_REVERSE_TIMEOUT_ERROR)
1041
        {global.stateTracker[16+(-ut_states::UT_REVERSE_TIMEOUT_ERROR)] += 1;}
1042
      else if (newState == ut_states::UT_CALIBRATION_ERROR)
1043
        {global.stateTracker[16+(-ut_states::UT_CALIBRATION_ERROR)] += 1;}
1044
      else if (newState == ut_states::UT_WHITE_DETECTION_ERROR)
1045
        {global.stateTracker[16+(-ut_states::UT_WHITE_DETECTION_ERROR)] += 1;}
1046
      else if (newState == ut_states::UT_PROXY_DETECTION_ERROR)
1047
        {global.stateTracker[16+(-ut_states::UT_PROXY_DETECTION_ERROR)] += 1;}
1048
      else if (newState == ut_states::UT_NO_CHARGING_POWER_ERROR)
1049
        {global.stateTracker[16+(-ut_states::UT_NO_CHARGING_POWER_ERROR)] += 1;}
1050
      else if (newState == ut_states::UT_UNKNOWN_STATE_ERROR)
1051
        {global.stateTracker[16+(-ut_states::UT_UNKNOWN_STATE_ERROR)] += 1;}
1052
    }
1053

    
1054
    // Keep track of last state and set the new state for next iteration
1055
    prevState = currentState;
1056
    currentState = newState;
1057

    
1058
    this->sleep(CAN::UPDATE_PERIOD);
1059
  }
1060

    
1061
  return RDY_OK;
1062
}