Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (15.776 KB)

1
#include "userthread.hpp"
2
#include "global.hpp"
3
#include "linefollow.hpp" 
4

    
5
using namespace amiro;
6

    
7
extern Global global;
8

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

    
13

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

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

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

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

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

    
54
/**
55
 * Blocks as long as the position changes.
56
 */
57
void UserThread::checkForMotion(){
58
  int motion = 1;
59
  int led = 0;
60
  types::position oldPos = global.odometry.getPosition();
61
  while(motion){
62
    this->sleep(500);
63
    types::position tmp = global.odometry.getPosition();
64
    motion = abs(oldPos.x - tmp.x)+ abs(oldPos.y - tmp.y)+abs(oldPos.z - tmp.z);
65
    oldPos = tmp;
66
      global.robot.setLightColor((led + 1) % 8, Color(Color::YELLOW));
67
      global.robot.setLightColor(led % 8, Color(Color::BLACK));
68
      led++;
69
  }
70
}
71

    
72
bool UserThread::checkFrontalObject(){
73
  uint32_t thresh = 1000;
74
  uint32_t prox;
75
  for(int i=0; i<8; i++){
76
    prox = global.robot.getProximityRingValue(i);
77
    if((i == 3) || (i == 4)){
78
      if(prox < thresh){
79
        return false;
80
      }
81
    }else{
82
      if(prox > thresh){
83
        return false;
84
      }
85
    }
86
  }
87
  return true;
88
}
89

    
90
bool UserThread::checkPinVoltage(){
91
  return global.ltc4412.isPluggedIn(); 
92
}
93

    
94
bool UserThread::checkPinEnabled(){
95
  return global.ltc4412.isEnabled();
96
}
97

    
98
int UserThread::checkDockingSuccess(){
99
  // setRpmSpeed(stop);
100
  checkForMotion();
101
  int success = 0;
102
  global.odometry.resetPosition();
103
  types::position start = global.startPos = global.odometry.getPosition();
104
  global.motorcontrol.setMotorEnable(false);
105
  this->sleep(1000);
106
  types::position stop_ = global.endPos = global.odometry.getPosition();
107
  
108
  // Amiro moved, docking was not successful
109
  if ((start.x + stop_.x) || (start.y + stop_.y)){
110
    lightAllLeds(Color::RED);
111
    // Enable Motor again if docking was not successful
112
    global.motorcontrol.setMotorEnable(true);
113
    success = 0;
114
  }else{
115
    lightAllLeds(Color::GREEN);
116
    success = 1;
117
  }
118
  
119
  // this->sleep(500);
120
  lightAllLeds(Color::BLACK);
121
  return success;
122
}
123

    
124
int UserThread::getProxyRingSum(){
125
  int prox_sum = 0;
126
  for(int i=0; i<8;i++){
127
    prox_sum += global.robot.getProximityRingValue(i);;
128
  }
129
  return prox_sum;
130
}
131

    
132

    
133
UserThread::UserThread() :
134
  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
135
{
136
}
137

    
138
UserThread::~UserThread()
139
{
140
}
141

    
142
msg_t
143
UserThread::main()
144
{
145
  /*
146
   * SETUP
147
   */
148
  // User thread state:
149

    
150

    
151
  //  int whiteBuf = 0;
152
  //  int proxyBuf = 0;
153
  //  int reverseBuf = 0;
154
   int correctionStep = 0;
155
  //  int dist_count = 0;
156
  //  bool needDistance = false;
157

    
158
   uint16_t rProx[8]; // buffer for ring proxy values
159
  int rpmSpeed[2] = {0};
160
  int stop[2] = {0};
161
  int turn[2] = {5,-5};
162
  LineFollowStrategy lStrategy = LineFollowStrategy::EDGE_RIGHT;
163
  for (uint8_t led = 0; led < 8; ++led) {
164
    global.robot.setLightColor(led, Color(Color::BLACK));
165
  }
166
  running = false;
167
  LineFollow lf(&global);
168
  /*
169
   * LOOP
170
   */
171
  while (!this->shouldTerminate())
172
  {
173
    /*
174
    * read accelerometer z-value
175
    */
176
    accel_z = global.lis331dlh.getAccelerationForce(LIS331DLH::AXIS_Z);
177
        
178
    if (accel_z < -900 /*-0.9g*/) { 
179
      // Start line following when AMiRo is rotated
180
      if(utState == states::IDLE){
181
        newState = states::FOLLOW_LINE;
182
      }else{
183
        newState = states::IDLE;
184
      }
185
      lightAllLeds(Color::GREEN);
186
      this->sleep(1000);
187
      lightAllLeds(Color::BLACK);
188

    
189
    // If message was received handle it here:
190
    } else if(global.msgReceived){
191
      global.msgReceived = false;
192
      // running = true;
193
      switch(global.lfStrategy){
194
        case msg_content::START:
195
          newState = states::FOLLOW_LINE;
196
          break;
197
        case msg_content::STOP:
198
          newState = states::IDLE;
199
          break;
200
        case msg_content::EDGE_RIGHT:
201
          // newState = states::FOLLOW_LINE;
202
          lStrategy = LineFollowStrategy::EDGE_RIGHT;
203
          break;
204
        case  msg_content::EDGE_LEFT:
205
          // newState = states::FOLLOW_LINE;
206
          lStrategy = LineFollowStrategy::EDGE_LEFT;
207
          break;
208
        case msg_content::FUZZY:
209
          // newState = states::FOLLOW_LINE;
210
          lStrategy = LineFollowStrategy::FUZZY;
211
          break;
212
        case msg_content::DOCK:
213
          newState = states::DETECT_STATION;
214
          break;
215
        case msg_content::UNDOCK:
216
          newState = states::RELEASE;
217
          break;
218
        case msg_content::CHARGE:
219
          newState = states::CHARGING;
220
          break;
221
        default:
222
          newState = states::IDLE;
223
          break;
224
      }
225
    }
226
    // newState = utState;
227

    
228
    // Get sensor data 
229
    // uint16_t WL = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_LEFT].getProximityScaledWoOffset();
230
    // uint16_t WR = global.vcnl4020[constants::DiWheelDrive::PROX_WHEEL_RIGHT].getProximityScaledWoOffset();
231
    for(int i=0; i<8;i++){
232
      rProx[i] = global.robot.getProximityRingValue(i);
233
    }
234
    // int FL = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_LEFT].getProximityScaledWoOffset();
235
    // int FR = global.vcnl4020[constants::DiWheelDrive::PROX_FRONT_RIGHT].getProximityScaledWoOffset();
236
    switch(utState){
237
      case states::IDLE:
238
        global.motorcontrol.setMotorEnable(true);
239
        setRpmSpeed(stop);
240
        if(/* checkPinVoltage() && */ checkPinEnabled()){
241
          global.robot.requestCharging(0);
242
        }
243
        utCount.whiteCount = 0;
244
        utCount.proxyCount = 0;
245
        utCount.errorCount = 0;
246
        utCount.idleCount++;
247
        if (utCount.idleCount > 10){
248
          utCount.idleCount = 0;
249
        // chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
250
        global.robot.transmitState(utState);
251
      }
252
        break;
253
      // ---------------------------------------
254
      case states::FOLLOW_LINE:
255
      // Set correct forward speed to every strategy
256
        if (global.forwardSpeed != global.rpmForward[0]){
257
          global.forwardSpeed = global.rpmForward[0];
258
        }
259
        
260
        if(lf.getStrategy() != lStrategy){
261
          lf.setStrategy(lStrategy);
262
        }
263

    
264
        if(lf.followLine(rpmSpeed)){
265
          utCount.whiteCount++;
266
          if(utCount.whiteCount >= WHITE_COUNT_THRESH){
267
            rpmSpeed[0] = stop[0];
268
            rpmSpeed[1] = stop[1];
269
            newState = states::IDLE;
270
          }
271
        }else{
272
          utCount.whiteCount = 0;
273
          // setRpmSpeed(rpmSpeed);
274
        }
275

    
276
        if(getProxyRingSum() > PROXY_RING_THRESH){
277
          utCount.proxyCount++;
278
          if(utCount.proxyCount > WHITE_COUNT_THRESH){
279
            rpmSpeed[0] = stop[0];
280
            rpmSpeed[1] = stop[1];
281
            // newState = states::IDLE;
282
            if (continue_on_obstacle){
283
              newState = states::TURN;
284
              utCount.proxyCount = 0;
285
            }else{
286
              newState = states::IDLE;
287
            }
288
          }
289
        }else{
290
            utCount.proxyCount = 0;
291
        }
292

    
293
        if ((rProx[3] + rProx[4]) > RING_PROX_FRONT_THRESH){
294
          rpmSpeed[0] = stop[0];
295
          rpmSpeed[1] = stop[1];
296
        }
297

    
298
        if (lf.getStrategy() == LineFollowStrategy::FUZZY){
299
          setRpmSpeedFuzzy(rpmSpeed);
300
        }else{
301

    
302
          setRpmSpeed(rpmSpeed);
303
        }
304
        
305
        break;
306
      // ---------------------------------------
307
      case states::TURN:
308
        checkForMotion();
309
        // Check if only front sensors are active 
310
        if(checkFrontalObject()){
311
          global.distcontrol.setTargetPosition(0, ROTATION_180, ROTATION_DURATION);
312
          // BaseThread::sleep(8000);
313
          checkForMotion();
314
          newState = states::FOLLOW_LINE;
315
          lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
316
        }else{
317
          newState = states::IDLE;
318
        }
319
        break;
320
      // ---------------------------------------
321
      case states::DETECT_STATION:
322
        if (global.forwardSpeed != DETECTION_SPEED){
323
          global.forwardSpeed = DETECTION_SPEED;
324
        }
325
        if(lf.getStrategy() != LineFollowStrategy::EDGE_RIGHT){
326
          lf.setStrategy(LineFollowStrategy::EDGE_RIGHT);
327
        }
328

    
329
        lf.followLine(rpmSpeed);
330
        setRpmSpeed(rpmSpeed);
331
        // // Detect marker before docking station
332
        // if ((WL+WR) < PROXY_WHEEL_THRESH){
333
        // Use proxy ring 
334
        if ((rProx[3]+rProx[4]) > RING_PROX_FRONT_THRESH){
335

    
336
          setRpmSpeed(stop);
337
          checkForMotion();
338
          // 180° Rotation 
339
          global.distcontrol.setTargetPosition(0, ROTATION_180, ROTATION_DURATION);
340
          // BaseThread::sleep(8000);
341
          checkForMotion();
342
          newState = states::CORRECT_POSITIONING;
343
        }
344
        break;
345
      // ---------------------------------------
346
      case states::CORRECT_POSITIONING:
347
        if (global.forwardSpeed != CHARGING_SPEED){
348
          global.forwardSpeed = CHARGING_SPEED;
349
        }
350
        if(lf.getStrategy() != LineFollowStrategy::EDGE_LEFT){
351
          lf.promptStrategyChange(LineFollowStrategy::EDGE_LEFT);
352
        }
353
        lf.followLine(rpmSpeed);
354
        setRpmSpeed(rpmSpeed);
355

    
356
        utCount.stepCount++;
357
        if (utCount.stepCount >= MAX_CORRECTION_STEPS){
358
          utCount.stepCount = 0;
359
          newState = states::REVERSE;
360
          setRpmSpeed(stop);
361
          checkForMotion();
362
        }
363
        break;
364
      // ---------------------------------------
365
      case states::REVERSE:
366
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
367
          lf.setStrategy(LineFollowStrategy::REVERSE);
368
        }
369
        lf.followLine(rpmSpeed);
370
        setRpmSpeed(rpmSpeed);
371

    
372
        // if ((WL+WR) < PROXY_WHEEL_THRESH){
373
        // Is of those sensors at it max val means that the AMiRo cant drive back
374
        // so check if correctly positioned
375
        //definitely wrong positioned -> correct position directly without rotation
376
        // Both sensors are at a wall -> potential loading station dock and on magnet -> need to rotate
377
        // if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
378
        //   setRpmSpeed(stop);
379
        //   checkForMotion();
380
        //   newState = states::CHECK_POSITIONING;
381
        // } else 
382
        if((rProx[0] >= PROX_MAX_VAL) || (rProx[7] >= PROX_MAX_VAL)){
383
          // setRpmSpeed(stop);
384
          // checkForMotion();
385
          utCount.stepCount = 0;
386
          newState = states::PUSH_BACK;
387
        }
388
        break;
389
      // ---------------------------------------
390
      case states::PUSH_BACK:
391
        if(lf.getStrategy() != LineFollowStrategy::REVERSE){
392
          lf.setStrategy(LineFollowStrategy::REVERSE);
393
        }
394
        lf.followLine(rpmSpeed);
395
        setRpmSpeed(rpmSpeed);
396

    
397
        utCount.stepCount++;
398
        if (utCount.stepCount > PUSH_BACK_COUNT){
399
          newState = states::CHECK_POSITIONING;
400
        }
401
        break;
402
      // ---------------------------------------
403
      case states::CHECK_POSITIONING:
404
        setRpmSpeed(stop);
405
        checkForMotion();
406
        // if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
407
        if(checkDockingSuccess()){
408
          newState = states::CHECK_VOLTAGE;
409
        }else{
410
          utCount.errorCount++;
411
          newState = states::CORRECT_POSITIONING;
412
          if (utCount.errorCount > DOCKING_ERROR_THRESH){
413
              newState = states::ERROR;
414
            }
415
        }
416
        // }
417
        // else{
418
        //   newState = CORRECT_POSITIONING;
419
        // }
420
        break;
421
      // ---------------------------------------
422
      case states::CHECK_VOLTAGE:
423
        if(!checkPinEnabled()){
424
          global.robot.requestCharging(1);
425
        } else {
426
          if(checkPinVoltage()){
427
            // Pins are under voltage -> correctly docked 
428
            utCount.errorCount = 0;
429
            newState = states::CHARGING;
430
          }else{
431
            utCount.errorCount++;
432
            // No voltage on pins -> falsely docked
433
            // deactivate pins
434
            global.motorcontrol.setMotorEnable(true);
435
            global.robot.requestCharging(0);
436
            // TODO: Soft release when docking falsely
437
            if((rProx[0] >= PROX_MAX_VAL) && (rProx[7] >= PROX_MAX_VAL)){
438
              newState = states::RELEASE_TO_CORRECT;
439
            } else {
440
              newState = states::RELEASE_TO_CORRECT; //states::CORRECT_POSITIONING; 
441
            }
442

    
443
            if (utCount.errorCount > DOCKING_ERROR_THRESH){
444
              newState = states::ERROR;
445
            }
446
          }
447
        }
448
        break;
449
      // ---------------------------------------
450
      case states::RELEASE_TO_CORRECT:
451

    
452
        global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
453
        checkForMotion();
454
        // move 1cm forward
455
        global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
456
        checkForMotion();
457
        // rotate back
458
        global.distcontrol.setTargetPosition(0, -2*ROTATION_20, ROTATION_DURATION);
459
        checkForMotion();
460

    
461
        global.distcontrol.setTargetPosition(7000, 0, ROTATION_DURATION);
462
        checkForMotion();
463
        newState = states::CORRECT_POSITIONING;
464
        break;
465
      // ---------------------------------------
466
      case states::ERROR:
467
        utCount.errorCount = 0;
468
        // lStrategy = LineFollowStrategy::EDGE_RIGHT;
469
        newState = states::RELEASE;
470
        break;
471
      // ---------------------------------------
472
      case states::CHARGING:
473
        global.motorcontrol.setMotorEnable(false);
474
        // Formulate Request to enable charging
475
        if(/* checkPinVoltage() && */ !checkPinEnabled()){
476
          global.robot.requestCharging(1);
477
        }
478
        if(checkPinEnabled()){
479
          showChargingState();
480
        }
481
        break;
482
      
483
      // ---------------------------------------
484
      case states::RELEASE:
485
      if (global.forwardSpeed != DETECTION_SPEED){
486
          global.rpmForward[0] = DETECTION_SPEED;
487
        }
488
        if(/* checkPinVoltage() && */ checkPinEnabled()){
489
          global.robot.requestCharging(0);
490
        }else{
491
          global.motorcontrol.setMotorEnable(true);
492

    
493
          //Rotate -20° to free from magnet
494
          global.distcontrol.setTargetPosition(0, ROTATION_20, ROTATION_DURATION);
495
          checkForMotion();
496
          // move 1cm forward
497
          global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
498
          checkForMotion();
499
          // rotate back
500
          global.distcontrol.setTargetPosition(0, -ROTATION_20, ROTATION_DURATION);
501
          checkForMotion();
502

    
503
          // global.distcontrol.setTargetPosition(5000, 0, ROTATION_DURATION);
504
          // checkForMotion();
505
          lStrategy = LineFollowStrategy::EDGE_RIGHT;
506
          newState = states::FOLLOW_LINE;
507
            // whiteBuf = -100;
508
          // lf.followLine(rpmSpeed);
509
          // setRpmSpeed(rpmSpeed);
510
        }
511
        // lightAllLeds(Color::BLACK);
512
        break;
513
      
514
      default:
515
        break;
516
      }
517
      if (utState != newState){
518
        chprintf((BaseSequentialStream*)&global.sercanmux1, "Transmit state %d\n", newState);
519
        global.robot.transmitState(newState);
520
      }
521
      utState = newState;
522
    this->sleep(CAN::UPDATE_PERIOD);
523
  }
524

    
525
  return RDY_OK;
526
}