Strandbeest Remote
A strandbeest controlled with infrared as well as an ultraound device.
Components and supplies
Breadboard (generic)
Ultrasonic Sensor - HC-SR04 (Generic)
Dual H-Bridge motor drivers L298
IR Transceiver (Generic)
Arduino Uno Leonardo prototyping shield
Arduino UNO
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
Code
IrRemote code
arduino
1#include <IRremote.h> 2#include <NewPing.h> // to avoid compiling errors in combination with the use of the IRremote library, you should set the '#define TIMER_ENABLED' in this header file to false; 3 // this was for a while a major headache. Eventually the author, Tim Eckel, provided the answer in of the arduino forums. Thanks, M8! 4 5// Finite State Machine implementation using a switch statment used by the infrared remote control 6#define IRForward 2 7#define IRForwardAvoid 12 // 26? = FR 8#define IRRight 6 9#define IRRightAvoid 16 //64? = RL 10#define IRBack 8 11#define IRLeft 4 12#define IRLeftAvoid 14 // 46? = LR 13#define IRStop 5 14#define IRStopAvoid 15 //58? = SB 15 16 // secundary transition states 17 // StateID can be calculated by (10*currentDirection+targetDirection) 18 // the mnemonic is tin the same way a simple combination of current- and target direction 19 20#define FS 25 // IRForward -> IRSTOP 21#define BS 85 // IRBack -> IRStop 22#define LS 45 // Left -> Stop 23#define RS 65 // Right -> Stop 24#define SF 52 // IRStop -> IRForward 25#define SB 58 // IRStop -> IRBack 26#define SL 54 // Stop -> Left 27#define SR 56 // Stop -> Right 28#define FR 26 // etc. 29#define FB 28 30#define FL 24 31#define RF 62 32#define BF 82 33#define LF 42 34#define BL 84 35#define BR 86 36#define LB 48 37#define RB 68 38#define RL 64 39#define LR 46 40 41// used by single motors 42#define ForwardStop 25 43#define BackwardStop 25 44#define StopForward 52 45#define StopBackward 58 46 47//pindefines 48 49//motor A, in my case the left one 50#define Ena 10 //Enable, and speed control 51#define a1 8 // turning direction HIGH or LOW or LOW. HIGH HIGH is nonsense. LOW LOW makes the motor stop. 52#define a2 7 // turning direction LOW or HIGH or LOW 53 54#define Enb 9 //Enable, and speed control 55#define b1 4 56#define b2 6 57// A word to the wise. Do not use arduino ports 3 and 11 in situations where PFM on multiple devices, even if only a LED is necessary. 58// It won't work. Hence the curious use of the enable ports 59 60#define LEDpin 14 // A0 Infrarood 61#define TrigPin 16 // A1 ultrasound 62#define EchoPin 15 // A2 ultrasound 63#define redLED 5 // redLED must be PFM enabled ... 64#define greenLED 12 // green LED on/off only 65#define BAUDRATE 9600 // debugging 66 67//constants 68const int safeDistance=15; 69const unsigned int maxDistance = 200; 70const unsigned int DCMaxSpeed = 255; 71const unsigned int DCMinSpeed = 32; 72const int SpeedStep = 4; 73 74const long Button_DEC_code[21] = 75 { 76 16753245, 16736925, 16769565, 77 16720605, 16712445, 16761405, 78 //vol-,vol+,eq 79 16769055, 16754775, 16748655, 80 //0,100+,200+ 81 16738455, 16750695, 16756815, 82 // the number buttons 83 16724175, 16718055, 16743045, 84 16716015, 16726215, 16734885, 85 16728765, 16730805, 16732845 86 }; 87const unsigned long ff_code[21] = // unknown IR device 88 { 89 3810010651,5316027,4001918335, 90 1386468383,3622325019,553536955, 91 4034314555,2747854299,3855596927, 92 3238126971,2538093563,4039382595, 93 2534850111,1033561079,1635910171, 94 2351064443,1217346747,71952287, 95 851901943,465573243,1053031451 96 }; 97 98 99// global variables 100 101int IRstate=IRStop; 102int changeState=0; 103boolean watchit=false; // obstruction detected 104boolean USaan=false; 105unsigned int currentDCSpeed = 168; 106unsigned int lastDCSpeed=currentDCSpeed; 107int tempDirection=0; 108 109int currentDirection = -1; 110int targetDirection = -1; 111 112// initialise infrared 113const int RECV_PIN = LEDpin; 114IRrecv irrecv(RECV_PIN); 115decode_results results; 116const int nobuttons=21; 117unsigned long buttonPressed=0; 118 119// initialise ultrasound 120 121NewPing sonar(TrigPin, EchoPin, maxDistance); 122 123void setup() { 124 // put your setup code here, to run once: 125 pinMode(LEDpin,INPUT); 126 Serial.begin(BAUDRATE); 127 irrecv.enableIRIn(); // Start the receiver 128 // start motor A 129 pinMode(Ena,OUTPUT); 130 pinMode(a1,OUTPUT); 131 pinMode(a2,OUTPUT); 132 analogWrite(Ena,currentDCSpeed); // necessary for some reason 133 // start motor B 134 pinMode(Enb,OUTPUT); 135 pinMode(b1,OUTPUT); 136 pinMode(b2,OUTPUT); 137 analogWrite(Enb,currentDCSpeed); 138 139 moveDirection(IRStop); // Vehicle.direction = DirectionForward 140 141 pinMode(redLED, OUTPUT); // red LED 142 pinMode(greenLED, OUTPUT); // green LED 143} 144 145void loop() { 146 147 if (!safe2Proceed()){ // also controls red LED 148 watchit=true; // we must take some action to avoid obstruction 149 } 150 else{ 151 watchit=false; 152 } 153 154 buttonPressed=getRemoteSignal(); 155 if(buttonPressed>0){ 156 157 switch(buttonPressed) // -1 = unknown. I included the other codes in comment, just in case. If these dont work. find out yourself. 158 { 159 case 16716015://case 2351064443: // '4' = turn left 160 targetDirection=IRLeft; 161 break; 162 case 16718055: // case 1033561079: // '2' = straight on 163 targetDirection=IRForward; 164 break; 165 case 16734885: // 71952287: // '6' = turn right 166 targetDirection=IRRight; 167 break; 168 case 16730805: // 465573243: // '8' = backwards 169 targetDirection=IRBack; 170 break; 171 case 16726215: // 1217346747: // '5' = stop 172 targetDirection=IRStop; 173 break; 174 175 case 16769055: //4034314555: // '-' = slow down 176 decreaseSpeed(); 177 break; 178 case 16754775: //2747854299: // '+' = speed up 179 increaseSpeed(); 180 break; 181 } 182 183 changeState=10*currentDirection + targetDirection; // check this out! 184 changeDirection(changeState); // gradualy change speed of the motors, in ordor to not to stress te motor-connections withe the frame. 185 // if you are sure your connection is very firm, you can skip the changeDirection procedure. 186 187 moveDirection(targetDirection); 188 currentDirection=targetDirection; 189 } 190 191 buttonPressed=0; 192 moveDirection(currentDirection); 193 194} // loop 195 196boolean safe2Proceed(){ 197 if (USaan){ 198 unsigned int distance=sonar.convert_cm(sonar.ping_median(5)); // to get a reliable value. Default this will use a Timer interrupt, wich may be conflicting with either other libraries 199 // or the default Arduino code. If you have a compiler, or rather, linking errors containing 'vect_7', 200 // set the USE_TIMER directive in newping.h to false. 201 // Thank you, Tim Eckel, the author of this library. 202 if (distance==0){ 203 digitalWrite(greenLED,LOW); // you could change this command with assembler code, much faster. I.E. : "PORTB &= ~(1 << 4);" But I doubt you will ever notice the speed change. 204 // Code size will change to decrease the amount, however. Same goes for other digitalWrite or digitalRead procedures. 205 return true; 206 } 207 else{ 208 digitalWrite(greenLED,HIGH); // "PORTB |= (1 << 4);" 209 signalLed(distance); 210 return (distance>safeDistance); 211 } 212 } 213} 214 215void signalLed(int dist){ 216 int index=0; 217 if(dist<=48){ 218 index = ((dist-48)/-4); // linear equatation based on desired result graph. Check it out yourself. 219 analogWrite(redLED,23*index);// glowing to bright red scaled to 0..253. Index ranging between 0 and 11 220 } 221 else{ 222 digitalWrite(redLED,LOW);// Led off 223 } 224} 225 226void changeDirection(int state){ 227 int speed=currentDCSpeed; 228 switch (state){ 229 case FS: 230 while (speed>=DCMinSpeed){ 231 speed-=SpeedStep; 232 delay(10); 233 moveOn(speed); 234 } 235 break; 236 case SF: 237 speed=DCMinSpeed; 238 while (speed<=currentDCSpeed){ 239 speed+=SpeedStep; 240 delay(10); 241 moveOn(speed); 242 } 243 break; 244 case BS: 245 while (speed>=DCMinSpeed){ 246 speed-=SpeedStep; 247 delay(10); 248 moveBack(speed); 249 } 250 break; 251 case SB: 252 speed=DCMinSpeed; 253 while (speed<=currentDCSpeed){ 254 speed+=SpeedStep; 255 delay(10); 256 moveBack(speed); 257 } 258 break; 259 case LS: 260 while (speed>=DCMinSpeed){ 261 speed-=SpeedStep; 262 delay(10); 263 moveLeft(speed); 264 } 265 break; 266 case SL: 267 speed=DCMinSpeed; 268 while (speed<=currentDCSpeed){ 269 speed+=SpeedStep; 270 delay(10); 271 moveLeft(speed); 272 } 273 break; 274 case RS: 275 while (speed>=DCMinSpeed){ 276 speed-=SpeedStep; 277 delay(10); 278 moveRight(speed); 279 } 280 break; 281 case SR: 282 speed=DCMinSpeed; 283 while (speed<=currentDCSpeed){ 284 speed+=SpeedStep; 285 delay(10); 286 moveRight(speed); 287 } 288 break; 289 case FR: 290 motorAChange(FS); 291 motorAChange(SB); 292 break; 293 case FB: 294 while (speed>DCMinSpeed){ 295 speed-=SpeedStep; 296 delay(10); 297 moveOn(speed); 298 } 299 while (speed<currentDCSpeed){ 300 speed+=SpeedStep; 301 delay(10); 302 moveBack(speed); 303 } 304 break; 305 case FL: 306 motorBChange(FS); 307 motorBChange(SB); 308 break; 309 case RF: 310 motorAChange(BS); 311 motorAChange(SF); 312 break; 313 case BF: 314 while (speed>DCMinSpeed){ 315 speed-=SpeedStep; 316 delay(10); 317 moveBack(speed); 318 } 319 while (speed<currentDCSpeed){ 320 speed+=SpeedStep; 321 delay(10); 322 moveOn(speed); 323 } 324 break; 325 case LF: 326 motorBChange(BS); 327 motorBChange(SF); 328 break; 329 case BL: 330 motorAChange(BS); 331 motorAChange(SF); 332 break; 333 case BR: 334 motorBChange(BS); 335 motorBChange(SF); 336 break; 337 case LB: 338 motorBChange(LS); 339 motorBChange(SB); 340 break; 341 case RB: 342 motorAChange(RS); 343 motorAChange(SB); 344 break; 345 case RL: 346 while (speed>DCMinSpeed){ 347 speed-=SpeedStep; 348 delay(10); 349 moveRight(speed); 350 } 351 while (speed<currentDCSpeed){ 352 speed+=SpeedStep; 353 delay(10); 354 moveLeft(speed); 355 } 356 break; 357 case LR: 358 while (speed>DCMinSpeed){ 359 speed-=SpeedStep; 360 delay(10); 361 moveLeft(speed); 362 } 363 while (speed<currentDCSpeed){ 364 speed+=SpeedStep; 365 delay(10); 366 moveRight(speed); 367 } 368 break; 369 } 370} 371 372void moveDirection(int dir){ // Implementation of the FSM controlling your direction according to the IRdevice. 373 // I use a 'switch' structure, which is fast and can be readily understood. 374 // in parallel the results of the US device (watchit) ar taken in consideration. 375 switch (dir) { // target state 376 case IRForward: // straight on 377 USaan=true; 378 if (watchit){ 379 changeDirection(FR); 380 currentDirection = IRForwardAvoid; 381 } 382 else{ 383 currentDirection=IRForward; 384 moveOn(currentDCSpeed); 385 } 386 break; 387 case IRForwardAvoid: 388 if (!watchit){ 389 changeDirection(RF); 390 currentDirection = IRForward; 391 moveOn(currentDCSpeed); 392 } 393 else { 394 currentDirection= IRForwardAvoid; 395 moveRight(currentDCSpeed); 396 } 397 break; 398 case IRBack: 399 USaan=false; 400 digitalWrite(greenLED,LOW); 401 currentDirection=IRBack; 402 moveBack(currentDCSpeed); 403 break; 404 case IRLeft: 405 USaan=true; 406 if(watchit){ 407 changeDirection(LF); 408 currentDirection=IRLeftAvoid; 409 } 410 else{ 411 currentDirection=IRLeft; 412 moveLeft(currentDCSpeed); 413 } 414 break; 415 case IRLeftAvoid: 416 if (!watchit){ 417 currentDirection=IRLeft; 418 moveLeft(currentDCSpeed); 419 } 420 else{ 421 currentDirection=IRLeftAvoid; 422 moveOn(currentDCSpeed); 423 } 424 break; 425 case IRRight: 426 USaan=true; 427 if(watchit){ 428 changeDirection(RL); 429 currentDirection=IRRightAvoid; 430 } 431 else{ 432 currentDirection=IRRight; 433 moveRight(currentDCSpeed); 434 } 435 break; 436 case IRRightAvoid: 437 if(!watchit){ 438 currentDirection=IRRight; 439 changeDirection(LR); 440 moveRight(currentDCSpeed); 441 } 442 else{ 443 currentDirection=IRRightAvoid; 444 moveLeft(currentDCSpeed); 445 } 446 break; 447 case IRStop: 448 USaan=true; 449 if(watchit){ 450 changeDirection(SB); 451 currentDirection=IRStopAvoid; 452 } 453 else{ 454 currentDirection=IRStop; 455 moveNot(currentDCSpeed); 456 } 457 break; 458 case IRStopAvoid: 459 if(!watchit){ 460 changeDirection(BS); 461 currentDirection=IRStop; 462 moveNot(currentDCSpeed); 463 } 464 else{ 465 currentDirection=IRStopAvoid; 466 moveBack(currentDCSpeed); 467 } 468 break; 469 } 470 } 471void decreaseSpeed(){ 472 if (currentDCSpeed>(SpeedStep-1)){ 473 currentDCSpeed -=SpeedStep; 474 } 475} 476void increaseSpeed(){ 477 if (currentDCSpeed<DCMaxSpeed-SpeedStep){ 478 currentDCSpeed +=SpeedStep; 479 } 480} 481 482void moveOn(int speed){ // currentspeed 483 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); // the digitalWrite functions can be replaced by register calls, Faster and take up less memory. 484 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); // But again I doubt if it is noticable in speed. It will in program size. 485} 486 487void moveBack(int speed){ 488 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); // the Arduino softwae is a bit of a hog on memory space. 489 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); // I don't know enough of the analogWrite procedure to give any advice, except from, DON'T tinker with it. 490} 491 492void moveLeft(int speed){ 493 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); // because it relies heavily on the scarce Timer resources of the Arduino Uno. 494 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 495} 496 497void moveRight(int speed){ 498 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 499 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 500} 501 502void moveNot(int speed){ 503 digitalWrite(a1,LOW); digitalWrite(a2,LOW); 504 digitalWrite(b1,LOW); digitalWrite(b2,LOW); 505} 506 507void motorAChange(int mode){ 508 int speed=currentDCSpeed; 509 switch(mode){ 510 case ForwardStop: 511 while (speed >DCMinSpeed){ 512 speed-=SpeedStep; 513 delay(10); 514 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); 515 } 516 break; 517 case BackwardStop: 518 while (speed > DCMinSpeed){ 519 speed-=SpeedStep; 520 delay(10); 521 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 522 } 523 break; 524 case StopForward: 525 speed=DCMinSpeed; 526 while (speed < currentDCSpeed){ 527 speed+=SpeedStep; 528 delay(10); 529 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); 530 } 531 break; 532 case StopBackward: 533 speed=DCMinSpeed; 534 delay(10); 535 while (speed < currentDCSpeed){ 536 speed+=SpeedStep; 537 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 538 } 539 break; 540 } 541} 542void motorBChange(int mode){ 543int speed=currentDCSpeed; 544 switch(mode){ 545 case ForwardStop: 546 while (speed >DCMinSpeed){ 547 speed-=SpeedStep; 548 delay(10); 549 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 550 } 551 break; 552 case BackwardStop: 553 while (speed > DCMinSpeed){ 554 speed-=SpeedStep; 555 delay(10); 556 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 557 } 558 break; 559 case StopForward: 560 speed=DCMinSpeed; 561 while (speed < currentDCSpeed){ 562 speed+=SpeedStep; 563 delay(10); 564 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 565 } 566 break; 567 case StopBackward: 568 speed=DCMinSpeed; 569 while (speed < currentDCSpeed){ 570 speed+=SpeedStep; 571 delay(10); 572 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 573 } 574 break; 575 } 576} 577 578unsigned long getRemoteSignal(void){ // This is copied from the example. IF you have another kind of IR device test and debug. use plenty of Serial.print... 579 // Hopefully you will only need different values in your lookup table. See the library documentation 580 // I think it would be a bad idea to transform all this into an Interrupt Service Routine. Takes too much performance time... 581 unsigned long retval=0; 582 if (irrecv.decode(&results)){ 583 int teller =0; // originally global 584 boolean notfound = true; // originally global 585 if (results.decode_type == -1) // due to initialy very confusing errors/faults, I discovered the type -1 resluted in consistent button values. 586 // I do both now, one of them does the job ... 587 { 588 while (teller< nobuttons && notfound) 589 { 590 unsigned long button=results.value; 591 if (button==ff_code[teller]) 592 { 593 retval=button; 594 notfound = false; 595 } 596 teller++; 597 } 598 } 599 if (results.decode_type == 3) // DEC??? 600 { 601 while (teller< nobuttons && notfound) 602 { 603 unsigned long button=results.value; 604 if (button==Button_DEC_code[teller]) 605 { 606 retval=button; 607 notfound = false; 608 } 609 teller++; 610 } 611 } 612 if (notfound) 613 { 614 String button=String(results.value, HEX); 615 if (button.substring(0,6)!="ffffff") 616 { 617 button.toUpperCase(); 618 } 619 } 620 irrecv.resume(); // Receive the next value 621 } 622 return retval; 623} 624 625
IrRemote code
arduino
1#include <IRremote.h> 2#include <NewPing.h> // to avoid compiling errors in combination with the use of the IRremote library, you should set the '#define TIMER_ENABLED' in this header file to false; 3 // this was for a while a major headache. Eventually the author, Tim Eckel, provided the answer in of the arduino forums. Thanks, M8! 4 5// Finite State Machine implementation using a switch statment used by the infrared remote control 6#define IRForward 2 7#define IRForwardAvoid 12 // 26? = FR 8#define IRRight 6 9#define IRRightAvoid 16 //64? = RL 10#define IRBack 8 11#define IRLeft 4 12#define IRLeftAvoid 14 // 46? = LR 13#define IRStop 5 14#define IRStopAvoid 15 //58? = SB 15 16 // secundary transition states 17 // StateID can be calculated by (10*currentDirection+targetDirection) 18 // the mnemonic is tin the same way a simple combination of current- and target direction 19 20#define FS 25 // IRForward -> IRSTOP 21#define BS 85 // IRBack -> IRStop 22#define LS 45 // Left -> Stop 23#define RS 65 // Right -> Stop 24#define SF 52 // IRStop -> IRForward 25#define SB 58 // IRStop -> IRBack 26#define SL 54 // Stop -> Left 27#define SR 56 // Stop -> Right 28#define FR 26 // etc. 29#define FB 28 30#define FL 24 31#define RF 62 32#define BF 82 33#define LF 42 34#define BL 84 35#define BR 86 36#define LB 48 37#define RB 68 38#define RL 64 39#define LR 46 40 41// used by single motors 42#define ForwardStop 25 43#define BackwardStop 25 44#define StopForward 52 45#define StopBackward 58 46 47//pindefines 48 49//motor A, in my case the left one 50#define Ena 10 //Enable, and speed control 51#define a1 8 // turning direction HIGH or LOW or LOW. HIGH HIGH is nonsense. LOW LOW makes the motor stop. 52#define a2 7 // turning direction LOW or HIGH or LOW 53 54#define Enb 9 //Enable, and speed control 55#define b1 4 56#define b2 6 57// A word to the wise. Do not use arduino ports 3 and 11 in situations where PFM on multiple devices, even if only a LED is necessary. 58// It won't work. Hence the curious use of the enable ports 59 60#define LEDpin 14 // A0 Infrarood 61#define TrigPin 16 // A1 ultrasound 62#define EchoPin 15 // A2 ultrasound 63#define redLED 5 // redLED must be PFM enabled ... 64#define greenLED 12 // green LED on/off only 65#define BAUDRATE 9600 // debugging 66 67//constants 68const int safeDistance=15; 69const unsigned int maxDistance = 200; 70const unsigned int DCMaxSpeed = 255; 71const unsigned int DCMinSpeed = 32; 72const int SpeedStep = 4; 73 74const long Button_DEC_code[21] = 75 { 76 16753245, 16736925, 16769565, 77 16720605, 16712445, 16761405, 78 //vol-,vol+,eq 79 16769055, 16754775, 16748655, 80 //0,100+,200+ 81 16738455, 16750695, 16756815, 82 // the number buttons 83 16724175, 16718055, 16743045, 84 16716015, 16726215, 16734885, 85 16728765, 16730805, 16732845 86 }; 87const unsigned long ff_code[21] = // unknown IR device 88 { 89 3810010651,5316027,4001918335, 90 1386468383,3622325019,553536955, 91 4034314555,2747854299,3855596927, 92 3238126971,2538093563,4039382595, 93 2534850111,1033561079,1635910171, 94 2351064443,1217346747,71952287, 95 851901943,465573243,1053031451 96 }; 97 98 99// global variables 100 101int IRstate=IRStop; 102int changeState=0; 103boolean watchit=false; // obstruction detected 104boolean USaan=false; 105unsigned int currentDCSpeed = 168; 106unsigned int lastDCSpeed=currentDCSpeed; 107int tempDirection=0; 108 109int currentDirection = -1; 110int targetDirection = -1; 111 112// initialise infrared 113const int RECV_PIN = LEDpin; 114IRrecv irrecv(RECV_PIN); 115decode_results results; 116const int nobuttons=21; 117unsigned long buttonPressed=0; 118 119// initialise ultrasound 120 121NewPing sonar(TrigPin, EchoPin, maxDistance); 122 123void setup() { 124 // put your setup code here, to run once: 125 pinMode(LEDpin,INPUT); 126 Serial.begin(BAUDRATE); 127 irrecv.enableIRIn(); // Start the receiver 128 // start motor A 129 pinMode(Ena,OUTPUT); 130 pinMode(a1,OUTPUT); 131 pinMode(a2,OUTPUT); 132 analogWrite(Ena,currentDCSpeed); // necessary for some reason 133 // start motor B 134 pinMode(Enb,OUTPUT); 135 pinMode(b1,OUTPUT); 136 pinMode(b2,OUTPUT); 137 analogWrite(Enb,currentDCSpeed); 138 139 moveDirection(IRStop); // Vehicle.direction = DirectionForward 140 141 pinMode(redLED, OUTPUT); // red LED 142 pinMode(greenLED, OUTPUT); // green LED 143} 144 145void loop() { 146 147 if (!safe2Proceed()){ // also controls red LED 148 watchit=true; // we must take some action to avoid obstruction 149 } 150 else{ 151 watchit=false; 152 } 153 154 buttonPressed=getRemoteSignal(); 155 if(buttonPressed>0){ 156 157 switch(buttonPressed) // -1 = unknown. I included the other codes in comment, just in case. If these dont work. find out yourself. 158 { 159 case 16716015://case 2351064443: // '4' = turn left 160 targetDirection=IRLeft; 161 break; 162 case 16718055: // case 1033561079: // '2' = straight on 163 targetDirection=IRForward; 164 break; 165 case 16734885: // 71952287: // '6' = turn right 166 targetDirection=IRRight; 167 break; 168 case 16730805: // 465573243: // '8' = backwards 169 targetDirection=IRBack; 170 break; 171 case 16726215: // 1217346747: // '5' = stop 172 targetDirection=IRStop; 173 break; 174 175 case 16769055: //4034314555: // '-' = slow down 176 decreaseSpeed(); 177 break; 178 case 16754775: //2747854299: // '+' = speed up 179 increaseSpeed(); 180 break; 181 } 182 183 changeState=10*currentDirection + targetDirection; // check this out! 184 changeDirection(changeState); // gradualy change speed of the motors, in ordor to not to stress te motor-connections withe the frame. 185 // if you are sure your connection is very firm, you can skip the changeDirection procedure. 186 187 moveDirection(targetDirection); 188 currentDirection=targetDirection; 189 } 190 191 buttonPressed=0; 192 moveDirection(currentDirection); 193 194} // loop 195 196boolean safe2Proceed(){ 197 if (USaan){ 198 unsigned int distance=sonar.convert_cm(sonar.ping_median(5)); // to get a reliable value. Default this will use a Timer interrupt, wich may be conflicting with either other libraries 199 // or the default Arduino code. If you have a compiler, or rather, linking errors containing 'vect_7', 200 // set the USE_TIMER directive in newping.h to false. 201 // Thank you, Tim Eckel, the author of this library. 202 if (distance==0){ 203 digitalWrite(greenLED,LOW); // you could change this command with assembler code, much faster. I.E. : "PORTB &= ~(1 << 4);" But I doubt you will ever notice the speed change. 204 // Code size will change to decrease the amount, however. Same goes for other digitalWrite or digitalRead procedures. 205 return true; 206 } 207 else{ 208 digitalWrite(greenLED,HIGH); // "PORTB |= (1 << 4);" 209 signalLed(distance); 210 return (distance>safeDistance); 211 } 212 } 213} 214 215void signalLed(int dist){ 216 int index=0; 217 if(dist<=48){ 218 index = ((dist-48)/-4); // linear equatation based on desired result graph. Check it out yourself. 219 analogWrite(redLED,23*index);// glowing to bright red scaled to 0..253. Index ranging between 0 and 11 220 } 221 else{ 222 digitalWrite(redLED,LOW);// Led off 223 } 224} 225 226void changeDirection(int state){ 227 int speed=currentDCSpeed; 228 switch (state){ 229 case FS: 230 while (speed>=DCMinSpeed){ 231 speed-=SpeedStep; 232 delay(10); 233 moveOn(speed); 234 } 235 break; 236 case SF: 237 speed=DCMinSpeed; 238 while (speed<=currentDCSpeed){ 239 speed+=SpeedStep; 240 delay(10); 241 moveOn(speed); 242 } 243 break; 244 case BS: 245 while (speed>=DCMinSpeed){ 246 speed-=SpeedStep; 247 delay(10); 248 moveBack(speed); 249 } 250 break; 251 case SB: 252 speed=DCMinSpeed; 253 while (speed<=currentDCSpeed){ 254 speed+=SpeedStep; 255 delay(10); 256 moveBack(speed); 257 } 258 break; 259 case LS: 260 while (speed>=DCMinSpeed){ 261 speed-=SpeedStep; 262 delay(10); 263 moveLeft(speed); 264 } 265 break; 266 case SL: 267 speed=DCMinSpeed; 268 while (speed<=currentDCSpeed){ 269 speed+=SpeedStep; 270 delay(10); 271 moveLeft(speed); 272 } 273 break; 274 case RS: 275 while (speed>=DCMinSpeed){ 276 speed-=SpeedStep; 277 delay(10); 278 moveRight(speed); 279 } 280 break; 281 case SR: 282 speed=DCMinSpeed; 283 while (speed<=currentDCSpeed){ 284 speed+=SpeedStep; 285 delay(10); 286 moveRight(speed); 287 } 288 break; 289 case FR: 290 motorAChange(FS); 291 motorAChange(SB); 292 break; 293 case FB: 294 while (speed>DCMinSpeed){ 295 speed-=SpeedStep; 296 delay(10); 297 moveOn(speed); 298 } 299 while (speed<currentDCSpeed){ 300 speed+=SpeedStep; 301 delay(10); 302 moveBack(speed); 303 } 304 break; 305 case FL: 306 motorBChange(FS); 307 motorBChange(SB); 308 break; 309 case RF: 310 motorAChange(BS); 311 motorAChange(SF); 312 break; 313 case BF: 314 while (speed>DCMinSpeed){ 315 speed-=SpeedStep; 316 delay(10); 317 moveBack(speed); 318 } 319 while (speed<currentDCSpeed){ 320 speed+=SpeedStep; 321 delay(10); 322 moveOn(speed); 323 } 324 break; 325 case LF: 326 motorBChange(BS); 327 motorBChange(SF); 328 break; 329 case BL: 330 motorAChange(BS); 331 motorAChange(SF); 332 break; 333 case BR: 334 motorBChange(BS); 335 motorBChange(SF); 336 break; 337 case LB: 338 motorBChange(LS); 339 motorBChange(SB); 340 break; 341 case RB: 342 motorAChange(RS); 343 motorAChange(SB); 344 break; 345 case RL: 346 while (speed>DCMinSpeed){ 347 speed-=SpeedStep; 348 delay(10); 349 moveRight(speed); 350 } 351 while (speed<currentDCSpeed){ 352 speed+=SpeedStep; 353 delay(10); 354 moveLeft(speed); 355 } 356 break; 357 case LR: 358 while (speed>DCMinSpeed){ 359 speed-=SpeedStep; 360 delay(10); 361 moveLeft(speed); 362 } 363 while (speed<currentDCSpeed){ 364 speed+=SpeedStep; 365 delay(10); 366 moveRight(speed); 367 } 368 break; 369 } 370} 371 372void moveDirection(int dir){ // Implementation of the FSM controlling your direction according to the IRdevice. 373 // I use a 'switch' structure, which is fast and can be readily understood. 374 // in parallel the results of the US device (watchit) ar taken in consideration. 375 switch (dir) { // target state 376 case IRForward: // straight on 377 USaan=true; 378 if (watchit){ 379 changeDirection(FR); 380 currentDirection = IRForwardAvoid; 381 } 382 else{ 383 currentDirection=IRForward; 384 moveOn(currentDCSpeed); 385 } 386 break; 387 case IRForwardAvoid: 388 if (!watchit){ 389 changeDirection(RF); 390 currentDirection = IRForward; 391 moveOn(currentDCSpeed); 392 } 393 else { 394 currentDirection= IRForwardAvoid; 395 moveRight(currentDCSpeed); 396 } 397 break; 398 case IRBack: 399 USaan=false; 400 digitalWrite(greenLED,LOW); 401 currentDirection=IRBack; 402 moveBack(currentDCSpeed); 403 break; 404 case IRLeft: 405 USaan=true; 406 if(watchit){ 407 changeDirection(LF); 408 currentDirection=IRLeftAvoid; 409 } 410 else{ 411 currentDirection=IRLeft; 412 moveLeft(currentDCSpeed); 413 } 414 break; 415 case IRLeftAvoid: 416 if (!watchit){ 417 currentDirection=IRLeft; 418 moveLeft(currentDCSpeed); 419 } 420 else{ 421 currentDirection=IRLeftAvoid; 422 moveOn(currentDCSpeed); 423 } 424 break; 425 case IRRight: 426 USaan=true; 427 if(watchit){ 428 changeDirection(RL); 429 currentDirection=IRRightAvoid; 430 } 431 else{ 432 currentDirection=IRRight; 433 moveRight(currentDCSpeed); 434 } 435 break; 436 case IRRightAvoid: 437 if(!watchit){ 438 currentDirection=IRRight; 439 changeDirection(LR); 440 moveRight(currentDCSpeed); 441 } 442 else{ 443 currentDirection=IRRightAvoid; 444 moveLeft(currentDCSpeed); 445 } 446 break; 447 case IRStop: 448 USaan=true; 449 if(watchit){ 450 changeDirection(SB); 451 currentDirection=IRStopAvoid; 452 } 453 else{ 454 currentDirection=IRStop; 455 moveNot(currentDCSpeed); 456 } 457 break; 458 case IRStopAvoid: 459 if(!watchit){ 460 changeDirection(BS); 461 currentDirection=IRStop; 462 moveNot(currentDCSpeed); 463 } 464 else{ 465 currentDirection=IRStopAvoid; 466 moveBack(currentDCSpeed); 467 } 468 break; 469 } 470 } 471void decreaseSpeed(){ 472 if (currentDCSpeed>(SpeedStep-1)){ 473 currentDCSpeed -=SpeedStep; 474 } 475} 476void increaseSpeed(){ 477 if (currentDCSpeed<DCMaxSpeed-SpeedStep){ 478 currentDCSpeed +=SpeedStep; 479 } 480} 481 482void moveOn(int speed){ // currentspeed 483 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); // the digitalWrite functions can be replaced by register calls, Faster and take up less memory. 484 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); // But again I doubt if it is noticable in speed. It will in program size. 485} 486 487void moveBack(int speed){ 488 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); // the Arduino softwae is a bit of a hog on memory space. 489 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); // I don't know enough of the analogWrite procedure to give any advice, except from, DON'T tinker with it. 490} 491 492void moveLeft(int speed){ 493 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); // because it relies heavily on the scarce Timer resources of the Arduino Uno. 494 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 495} 496 497void moveRight(int speed){ 498 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 499 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 500} 501 502void moveNot(int speed){ 503 digitalWrite(a1,LOW); digitalWrite(a2,LOW); 504 digitalWrite(b1,LOW); digitalWrite(b2,LOW); 505} 506 507void motorAChange(int mode){ 508 int speed=currentDCSpeed; 509 switch(mode){ 510 case ForwardStop: 511 while (speed >DCMinSpeed){ 512 speed-=SpeedStep; 513 delay(10); 514 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); 515 } 516 break; 517 case BackwardStop: 518 while (speed > DCMinSpeed){ 519 speed-=SpeedStep; 520 delay(10); 521 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 522 } 523 break; 524 case StopForward: 525 speed=DCMinSpeed; 526 while (speed < currentDCSpeed){ 527 speed+=SpeedStep; 528 delay(10); 529 digitalWrite(a1,LOW); digitalWrite(a2,HIGH); analogWrite(Ena,speed); 530 } 531 break; 532 case StopBackward: 533 speed=DCMinSpeed; 534 delay(10); 535 while (speed < currentDCSpeed){ 536 speed+=SpeedStep; 537 digitalWrite(a1,HIGH); digitalWrite(a2,LOW); analogWrite(Ena,speed); 538 } 539 break; 540 } 541} 542void motorBChange(int mode){ 543int speed=currentDCSpeed; 544 switch(mode){ 545 case ForwardStop: 546 while (speed >DCMinSpeed){ 547 speed-=SpeedStep; 548 delay(10); 549 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 550 } 551 break; 552 case BackwardStop: 553 while (speed > DCMinSpeed){ 554 speed-=SpeedStep; 555 delay(10); 556 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 557 } 558 break; 559 case StopForward: 560 speed=DCMinSpeed; 561 while (speed < currentDCSpeed){ 562 speed+=SpeedStep; 563 delay(10); 564 digitalWrite(b1,LOW); digitalWrite(b2,HIGH); analogWrite(Enb,speed); 565 } 566 break; 567 case StopBackward: 568 speed=DCMinSpeed; 569 while (speed < currentDCSpeed){ 570 speed+=SpeedStep; 571 delay(10); 572 digitalWrite(b1,HIGH); digitalWrite(b2,LOW); analogWrite(Enb,speed); 573 } 574 break; 575 } 576} 577 578unsigned long getRemoteSignal(void){ // This is copied from the example. IF you have another kind of IR device test and debug. use plenty of Serial.print... 579 // Hopefully you will only need different values in your lookup table. See the library documentation 580 // I think it would be a bad idea to transform all this into an Interrupt Service Routine. Takes too much performance time... 581 unsigned long retval=0; 582 if (irrecv.decode(&results)){ 583 int teller =0; // originally global 584 boolean notfound = true; // originally global 585 if (results.decode_type == -1) // due to initialy very confusing errors/faults, I discovered the type -1 resluted in consistent button values. 586 // I do both now, one of them does the job ... 587 { 588 while (teller< nobuttons && notfound) 589 { 590 unsigned long button=results.value; 591 if (button==ff_code[teller]) 592 { 593 retval=button; 594 notfound = false; 595 } 596 teller++; 597 } 598 } 599 if (results.decode_type == 3) // DEC??? 600 { 601 while (teller< nobuttons && notfound) 602 { 603 unsigned long button=results.value; 604 if (button==Button_DEC_code[teller]) 605 { 606 retval=button; 607 notfound = false; 608 } 609 teller++; 610 } 611 } 612 if (notfound) 613 { 614 String button=String(results.value, HEX); 615 if (button.substring(0,6)!="ffffff") 616 { 617 button.toUpperCase(); 618 } 619 } 620 irrecv.resume(); // Receive the next value 621 } 622 return retval; 623} 624 625
Downloadable files
mini breadboard. on the right the IR sensor. The yellow wire goes into A01
mini breadboard. on the right the IR sensor. The yellow wire goes into A01
motor board. left motor and right motor are self explaining. diver wires: at the bottom.
the leftmost orange wire is VIN: 9v. the rightmost orange feeds the Arduino with 5V. The blue one is ground Just above them the controller wire between Arduino and this board. inner ones for the polarty, outer ones for the speed control.
motor board. left motor and right motor are self explaining. diver wires: at the bottom.
mini breadboard. on the right the IR sensor. The yellow wire goes into A01
mini breadboard. on the right the IR sensor. The yellow wire goes into A01
Comments
Only logged in users can leave comments