jmichael

NV-DRD (Nearly) v2.0

Nov 13th, 2011
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.55 KB | None | 0 0
  1. /*
  2.  *  NV:DRD v1.2 by Jason Adams <[email protected]>
  3.  *
  4.  *  DONE:
  5.  *  + the bot now, every so often, spins around like a puppy for a few seconds and goes to sleep
  6.  *  + created a function that alternately fades and flashes the LEDs
  7.  *  + put blinking and backing-up in their own functions and added the ability to pass
  8.  *    parameters to them to change the number of blinks and the duration of backing-up each time
  9.  *  + created functions for turning left and right, with the ability to pass params (as ints)
  10.  *    to determine how long to turn
  11.  *  + implemented a way to detect that the bot is no longer moving forward and is therefore
  12.  *    likely stuck on something outside its field of view
  13.  *  + the bot takes a forward reading after turning but before moving again, to make sure there
  14.  *    is a fair amount of distance to travel. It then continues to look around and turn
  15.  *    until it detects enough room to move
  16.  *  + found the bug that causes the bot to see a nonexistent obsticle as soon as loop() starts
  17.  *
  18.  *  TODO:
  19.  *  - figure out the correct duration to turn in order to turn 90 degrees
  20.  *  - add a default value to each of the functions that take perameters
  21.  *  - find the max distance the sensor can return, convert it to cm, and add a test for that
  22.  *    reading to the logic that determines when the bot is stuck, so it doesn't interpret a large,
  23.  *    open room in which it can see to it's farthest ability for a length of time as being stuck
  24.  *
  25.  *  NEEDS TESTING:
  26.  *
  27.  */
  28.  
  29. char version[] = "NV:DRD v1.2";
  30.  
  31. #include <AFMotor.h>
  32. #include <Servo.h>
  33.  
  34. // create the motor objects
  35. AF_DCMotor motor1(1, MOTOR12_64KHZ); // create motor #1, 64KHz pwm
  36. AF_DCMotor motor2(2, MOTOR12_64KHZ); // create motor #2, 64KHz pwm
  37. Servo headTurner;                    // create servo object for turning the Ping))) sensor
  38.  
  39. // the calibrated servo motor positions for forward, left, and right.
  40. #define forward  99
  41. #define left     180
  42. #define right    20
  43.  
  44. // pin assignments
  45. #define servoPin          9     // servo motor on pin 9
  46. #define pingSensorPin     19    // Ping))) sensor on A5 (analog pins 0-5 can be used as digital pins 14-19)
  47. #define leftAntennaeLED   6
  48. #define rightAntennaeLED  5
  49.  
  50. // constantly changing variables
  51. long pingSensorReading, forwardReading, leftReading, rightReading;
  52. int directionToGo      = 0;     // 0 = forward, 1 = left, 2 = right
  53. int defaultBrightness  = 50;    // default LED brightness using analogWrite(). the scale is 0-255
  54. int minDistance        = 1500;  // the minimum distance to an object before the bot refuses to go forward anymore
  55. int sleepTimer         = 0;     // a counter to increment until the next time it's time to stop and "sleep"
  56. int logTimer           = 0;     // a counter to regulate the logging of forward Ping))) sensor readings
  57. int counterToConfusion = 0;     // a counter to trigger he "confused" LED animation after multiple failed
  58.                                 // attempts to turn to a direction that offers enough room to move forward
  59. boolean switchTurn     = false; // false = right, true = left - this bool is for alternating the direction
  60.                                 // the bot decides to turn when the right and left readings are the same.
  61.                                 // One time it'll go right, the next time left, etc.
  62. boolean firstTimeRun   = true;  // this gets flipped to false only once, after the Ping))) sensor has
  63.                                 // recorded distances (converted to cm) in all four of the ints below
  64. int forwardReading_CM = 0;
  65. int forwardReading_2 = 0;
  66. int forwardReading_3 = 0;
  67. int forwardReading_4 = 0;
  68.  
  69.  
  70. void setup() {
  71.   // initiate the LEDs
  72.   pinMode(leftAntennaeLED, OUTPUT);
  73.   pinMode(rightAntennaeLED, OUTPUT);
  74.  
  75.   // set up Serial library at 9600 bps
  76.   Serial.begin(9600);
  77.   Serial.println(version);
  78.  
  79.   // set the speeds to 200/255
  80.   motor1.setSpeed(255);
  81.   motor2.setSpeed(255);
  82.  
  83.   // attach the servo object to the pin the servo motor is on
  84.   headTurner.attach(servoPin);
  85.   delay(100);
  86.  
  87.   // turn Ping))) sensor forward, just to orient it for show immediately upon starting  
  88.   headTurner.write(forward);
  89.  
  90.   // turn antennae lights on
  91.   analogWrite(leftAntennaeLED, defaultBrightness);
  92.   analogWrite(rightAntennaeLED, defaultBrightness);
  93.  
  94.   // choose which direction to go
  95.   chooseDirection();
  96.  
  97.   // travel forward
  98.   goForward();
  99.  
  100.   delay(1000);
  101. }
  102.  
  103.  
  104. void loop() {
  105.   // see if we're nearing an object while moving forward
  106.   forwardReading = readPingSensor();
  107.   Serial.print("forward reading: ");
  108.   Serial.println(forwardReading);
  109.  
  110.   // increment the timer that helps decide when to next stop and go to sleep
  111.   sleepTimer++;
  112.  
  113.   // increment the timer that triggers storing of forwardReading values, to help determine we might be stuck
  114.   logTimer++;
  115.   if (logTimer == 5) {
  116.     forwardReading_4 = forwardReading_3;
  117.     forwardReading_3 = forwardReading_2;
  118.     forwardReading_2 = forwardReading_CM;
  119.     forwardReading_CM = (forwardReading * 0.03434);
  120.     logTimer = 0;
  121.     firstTimeRun = false;
  122.   }
  123.  
  124.   // see if we're no longer making forward progress, indicating we may be stuck
  125.   if (!firstTimeRun && forwardReading_CM == forwardReading_2 && forwardReading_2 == forwardReading_3 && forwardReading_3 == forwardReading_4) {
  126.     allStop(); // stop moving
  127.     blinkLEDs(2); // blink
  128.     goReverse(2500); // back up
  129.  
  130.     // choose the direction with the farthest distance to move
  131.     chooseDirection();
  132.  
  133.     // travel forward
  134.     goForward();
  135.    
  136.     // reset the logging variables so a full examination is required again to determine if we're stuck
  137.     forwardReading_4 = 0;
  138.     forwardReading_3 = 0;
  139.     forwardReading_2 = 0;
  140.  
  141.   // if we are nearing an object, stop moving...
  142.   } else if (forwardReading <= minDistance) {
  143.     allStop(); // stop moving
  144.     blinkLEDs(2); // blink
  145.     goReverse(400); // back up
  146.  
  147.     chooseDirection();        
  148.    
  149.     goForward(); // travel forward
  150.    
  151.   } else if (sleepTimer >= 900) {
  152.     // go to sleep every five minutes (900 seconds)
  153.     /* (I put this inside the 'else' in order to avoid the bot sleeping immediately after detecting that it's stuck or
  154.        too close to an object. It will catch the next time around that neither of the other two conditions are met) */
  155.     stopAndSleep(); // stop and sleep
  156.     sleepTimer = 0; // reset the sleep timer variable
  157.  
  158.     chooseDirection();
  159.    
  160.     goForward(); // travel forward    
  161.   }
  162.  
  163.   // wait 3/10 of a second so the Ping))) sensor gets polled 3x/sec when driving forward
  164.   delay(333);
  165. }
  166.  
  167.  
  168. /*
  169.   FUNCTIONS:
  170.     chooseDirection()              // Tested
  171.     stopAndSleep()                 // Tested
  172.     readPingSensor()               // Tested
  173.     alternatingLEDs(int)           // Tested
  174.     snoreLEDs(int)                 // Tested
  175.     blinkLEDs(int)                 // Tested
  176.     goForward()                    // Tested
  177.     goReverse(int)                 // Tested
  178.     turnLeft(int)                  // Tested
  179.     turnRight(int)                 // Tested
  180.     allStop()                      // Tested
  181. */
  182.  
  183.  
  184. void chooseDirection() {
  185.   // turn Ping))) sensor to look forward and then take a reading
  186.   headTurner.write(forward);
  187.   delay(500);
  188.   forwardReading = readPingSensor();
  189.   Serial.print("forward reading: ");
  190.   Serial.println(forwardReading);
  191.   delay(250);
  192.  
  193.   // turn Ping))) sensor to look left and then take a reading
  194.   headTurner.write(left);
  195.   delay(500);
  196.   leftReading = readPingSensor();
  197.   Serial.print("left reading: ");
  198.   Serial.println(leftReading);
  199.   delay(250);
  200.  
  201.   // turn Ping))) sensor to look right and then take a reading
  202.   headTurner.write(right);
  203.   delay(650);
  204.   rightReading = readPingSensor();
  205.   Serial.print("right reading: ");
  206.   Serial.println(rightReading);
  207.   delay(250);
  208.  
  209.   if (forwardReading <= minDistance && leftReading <= minDistance && rightReading <= minDistance) {
  210.  
  211.     if (leftReading > rightReading) {
  212.       turnLeft(450);
  213.     } else if (leftReading < rightReading) {
  214.       turnRight(450);
  215.     } else if (leftReading == rightReading) {
  216.       if (switchTurn == false) {
  217.         Serial.println("  right and left readings are the same; going right this time");
  218.         turnRight(450);
  219.       } else {
  220.         Serial.println("  right and left readings are the same; going left this time");
  221.         turnLeft(450);
  222.       }
  223.       switchTurn = !switchTurn;
  224.     }
  225.  
  226.     while (forwardReading <= minDistance && leftReading <= minDistance && rightReading <= minDistance ){
  227.      
  228.       counterToConfusion++;
  229.       if (counterToConfusion == 3) {
  230.         headTurner.write(forward);
  231.         delay(500);
  232.         alternatingLEDs(5);
  233.         counterToConfusion = 0;
  234.       }
  235.      
  236.       // turn Ping))) sensor to look forward and then take a reading
  237.       headTurner.write(forward);
  238.       delay(500);
  239.       forwardReading = readPingSensor();
  240.       Serial.print("*forward reading: ");
  241.       Serial.println(forwardReading);
  242.       delay(250);
  243.      
  244.       // turn Ping))) sensor to look left and then take a reading
  245.       headTurner.write(left);
  246.       delay(500);
  247.       leftReading = readPingSensor();
  248.       Serial.print("*left reading: ");
  249.       Serial.println(leftReading);
  250.       delay(250);
  251.        
  252.       // turn Ping))) sensor to look right and then take a reading
  253.       headTurner.write(right);
  254.       delay(650);
  255.       rightReading = readPingSensor();
  256.       Serial.print("*right reading: ");
  257.       Serial.println(rightReading);
  258.       delay(250);
  259.  
  260.       // compare the 'forward' and 'left' readings to see which direction offers more distance to travel
  261.       if (forwardReading >= leftReading) {
  262.         directionToGo = 0;
  263.         Serial.println("* determining i'd rather go forward than left");
  264.       } else {
  265.         directionToGo = 1;
  266.         Serial.println("* determining i'd rather go left than forward");
  267.       }
  268.  
  269.       // compare the 'right' reading to the winner of the previous comparison to see which direction we should go
  270.       if (directionToGo == 0 && rightReading > forwardReading) {
  271.         Serial.println("* determining i should go right instead of forward");
  272.         turnRight(450);
  273.         if (rightReading > minDistance) { break; }
  274.       } else if (directionToGo == 1 && rightReading > leftReading) {
  275.         Serial.println("* determining i should go right instead of left");
  276.         turnRight(450);
  277.         if (rightReading > minDistance) { break; }
  278.       } else if (directionToGo == 1 && rightReading < leftReading) {
  279.         Serial.println("* determining i should go left instead of right");
  280.         turnLeft(450);
  281.         if (leftReading > minDistance) { break; }
  282.       } else if (directionToGo == 1 && rightReading == leftReading) {
  283.         if (switchTurn == false) {
  284.           Serial.println("* right and left readings are the same; going right this time");
  285.           turnRight(450);
  286.         } else {
  287.           Serial.println("* right and left readings are the same; going left this time");
  288.           turnLeft(450);
  289.         }
  290.         switchTurn = !switchTurn;
  291.         if (leftReading > minDistance) { break; }
  292.       } else if (directionToGo == 0 && rightReading <= forwardReading && leftReading <= forwardReading) {
  293.         if (forwardReading > minDistance) {
  294.           break;
  295.         } else {
  296.           if (switchTurn == false) {
  297.             Serial.println("* forward reading was the largest, but i have to turn; going right this time");
  298.             turnRight(450);
  299.           } else {
  300.             Serial.println("* forward reading was the largest, but i have to turn; going left this time");
  301.             turnLeft(450);
  302.           }
  303.           switchTurn = !switchTurn;
  304.         }
  305.       }
  306.     }
  307.   } else {
  308.     // compare the 'forward' and 'left' readings to see which direction offers more distance to travel
  309.     if (forwardReading >= leftReading) {
  310.       directionToGo = 0;
  311.       Serial.println("  determining i'd rather go forward than left");
  312.     } else {
  313.       directionToGo = 1;
  314.       Serial.println("  determining i'd rather go left than forward");
  315.     }
  316.  
  317.     // compare the 'right' reading to the winner of the previous comparison to see which direction we should go
  318.     if (directionToGo == 0 && rightReading > forwardReading) {
  319.       Serial.println("  determining i should go right instead of forward");
  320.       turnRight(450);
  321.     } else if (directionToGo == 1 && rightReading > leftReading) {
  322.       Serial.println("  determining i should go right instead of left");
  323.       turnRight(450);
  324.     } else if (directionToGo == 1 && rightReading == leftReading) {
  325.       if (switchTurn == false) {
  326.         Serial.println("  right and left readings are the same; going right this time");
  327.         turnRight(450);
  328.       } else {
  329.         Serial.println("  right and left readings are the same; going left this time");
  330.         turnLeft(450);
  331.       }
  332.       switchTurn = !switchTurn;
  333.     }
  334.   }
  335.  
  336.   // look forward again in preparation for moving forward again
  337.   headTurner.write(forward);
  338. }
  339.          
  340.  
  341. void stopAndSleep() {
  342.   // announce over serial that it's time to sleep
  343.   Serial.println("getting sleepy. think i'll take a nap right here");
  344.  
  345.   // stop moving forward
  346.   allStop();
  347.   delay(750);
  348.  
  349.   // fade the antennae LEDs to indicate sleepiness
  350.   for(int fadeValue = defaultBrightness; fadeValue >= 0; fadeValue -= 1) {
  351.     analogWrite(leftAntennaeLED, fadeValue);
  352.     analogWrite(rightAntennaeLED, fadeValue);
  353.     delay(75);
  354.   }
  355.   delay(1000);
  356.  
  357.   // choose a direction, left or right, and spin in place like a puppy about to lay down
  358.   if (switchTurn == false){
  359.     turnRight(5000);
  360.   } else {
  361.     turnLeft(5000);
  362.   }
  363.  
  364.   // set this bool so the next time the bot will turn the other direction
  365.   switchTurn = !switchTurn;
  366.  
  367.   // orient the head forward
  368.   headTurner.write(forward);
  369.   delay(1000);
  370.  
  371.   snoreLEDs(10);
  372.  
  373.   // fade the LEDs back on quickly, like the bot is waking up
  374.   for(int fadeValue = 0 ; fadeValue <= defaultBrightness; fadeValue +=2) {
  375.     analogWrite(leftAntennaeLED, fadeValue);
  376.     analogWrite(rightAntennaeLED, fadeValue);
  377.     delay(20);
  378.   }
  379.   delay(1000);
  380.  
  381.   blinkLEDs(2);
  382.  
  383.   delay(500);
  384. }
  385.  
  386.  
  387. long readPingSensor() {
  388.   // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  389.   // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  390.   pinMode(pingSensorPin, OUTPUT);
  391.   digitalWrite(pingSensorPin, LOW);
  392.   delayMicroseconds(2);
  393.   digitalWrite(pingSensorPin, HIGH);
  394.   delayMicroseconds(5);
  395.   digitalWrite(pingSensorPin, LOW);
  396.  
  397.   // The same pin is used to read the signal from the PING))): a HIGH
  398.   // pulse whose duration is the time (in microseconds) from the sending
  399.   // of the ping to the reception of its echo off of an object.
  400.   pinMode(pingSensorPin, INPUT);
  401.   pingSensorReading = pulseIn(pingSensorPin, HIGH);
  402.  
  403.   return pingSensorReading;
  404. }
  405.  
  406.  
  407. void alternatingLEDs(int numFlashes) {
  408.   Serial.println("flashing my antennae lights");
  409.   for (int i = 0; i < numFlashes; i++) {
  410.     for(int fadeValue = 5; fadeValue <= 255; fadeValue +=5) {  // left brightening, right dimming
  411.       analogWrite(leftAntennaeLED, fadeValue);
  412.       analogWrite(rightAntennaeLED, 260 - fadeValue);
  413.       delay(10);
  414.     }
  415.     for(int fadeValue = 5; fadeValue <= 255; fadeValue +=5) {  // left dimming, right brightening
  416.       analogWrite(leftAntennaeLED, 260 - fadeValue);
  417.       analogWrite(rightAntennaeLED, fadeValue);
  418.       delay(10);
  419.     }
  420.   }
  421.   digitalWrite(leftAntennaeLED, LOW);
  422.   digitalWrite(rightAntennaeLED, LOW);
  423.   delay(200);
  424.   analogWrite(leftAntennaeLED, defaultBrightness);
  425.   analogWrite(rightAntennaeLED, defaultBrightness);
  426. }
  427.  
  428.  
  429. void snoreLEDs(int numSnores) {  // "sleep-breathe" the LEDs like a mac
  430.   for (int i = 0; i < numSnores; i++) {
  431.     for(int fadeValue = 0 ; fadeValue <= 15; fadeValue +=1) {  // on
  432.       analogWrite(leftAntennaeLED, fadeValue);
  433.       analogWrite(rightAntennaeLED, fadeValue);
  434.       delay(75);
  435.     }
  436.     for(int fadeValue = 15 ; fadeValue >= 0; fadeValue -=1) {  // off
  437.       analogWrite(leftAntennaeLED, fadeValue);
  438.       analogWrite(rightAntennaeLED, fadeValue);
  439.       delay(75);
  440.     }
  441.     delay(1500);
  442.   }
  443. }
  444.  
  445.  
  446. void blinkLEDs(int numBlinks) {
  447.   Serial.println("blinking");
  448.   for (int i = 0; i < numBlinks; i++) {
  449.     analogWrite(leftAntennaeLED, 0);
  450.     analogWrite(rightAntennaeLED, 0);
  451.     delay(100);
  452.     analogWrite(leftAntennaeLED, defaultBrightness);
  453.     analogWrite(rightAntennaeLED, defaultBrightness);
  454.     delay(100);
  455.   }
  456. }
  457.  
  458.  
  459. void goForward() {
  460.   Serial.println("driving forward");
  461.   motor1.run(FORWARD);
  462.   motor2.run(FORWARD);
  463. }
  464.  
  465.  
  466. void goReverse(int backUpDuration) {
  467.   Serial.println("backing up a little bit");
  468.   motor1.run(BACKWARD);
  469.   motor2.run(BACKWARD);
  470.   delay(backUpDuration);
  471.   motor1.run(RELEASE);
  472.   motor2.run(RELEASE);
  473.   delay(500);
  474. }
  475.  
  476.  
  477. void turnLeft(int turnDuration) {
  478.   headTurner.write(left);   // look left
  479.   delay(300);               // give servo (head) time to turn before beginning turning the bot's body
  480.   Serial.println("turning left");
  481.   // turn left
  482.   motor1.run(BACKWARD);
  483.   motor2.run(FORWARD);
  484.   delay(turnDuration);
  485.   motor1.run(RELEASE);
  486.   motor2.run(RELEASE);
  487.   delay(100);
  488. }
  489.  
  490.  
  491. void turnRight(int turnDuration) {
  492.   headTurner.write(right);   // look left
  493.   delay(300);                // give servo (head) time to turn before beginning turning the bot's body
  494.   Serial.println("turning right");
  495.   // turn right
  496.   motor1.run(FORWARD);
  497.   motor2.run(BACKWARD);
  498.   delay(turnDuration);
  499.   motor1.run(RELEASE);
  500.   motor2.run(RELEASE);
  501.   delay(100);
  502. }
  503.  
  504.  
  505. void allStop() {
  506.   Serial.println("ALL STOP!");  
  507.   motor1.run(RELEASE);
  508.   motor2.run(RELEASE);
  509.   delay(200);
  510. }
  511.  
Advertisement
Add Comment
Please, Sign In to add comment