Advertisement
Guest User

Untitled

a guest
May 18th, 2014
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.77 KB | None | 0 0
  1. * This code will solve a line maze constructed with a black line on a
  2. * white background, as long as there are no loops. It has two
  3. * phases: first, it learns the maze, with a "left hand on the wall"
  4. * strategy, and computes the most efficient path to the finish.
  5. * Second, it follows its most efficient solution.
  6. *
  7. * http://www.pololu.com/docs/0J21
  8. * http://www.pololu.com
  9. * http://forum.pololu.com
  10. *
  11. */
  12.  
  13. // The following libraries will be needed by this demo
  14. #include <Pololu3pi.h>
  15. #include <PololuQTRSensors.h>
  16. #include <OrangutanMotors.h>
  17. #include <OrangutanAnalog.h>
  18. #include <OrangutanLEDs.h>
  19. #include <OrangutanLCD.h>
  20. #include <OrangutanPushbuttons.h>
  21. #include <OrangutanBuzzer.h>
  22. #define SHORT_RANGE_SENSOR 0 // Uses digital Arduino Pin 1
  23. Pololu3pi robot;
  24. unsigned int sensors[5]; // an array to hold sensor values
  25.  
  26.  
  27. // This include file allows data to be stored in program space. The
  28. // ATmega168 has 16k of program space compared to 1k of RAM, so large
  29. // pieces of static data should be stored in program space.
  30. #include <avr/pgmspace.h>
  31.  
  32. // Introductory messages. The "PROGMEM" identifier causes the data to
  33. // go into program space.
  34. const char welcome_line1[] PROGMEM = " Pololu";
  35. const char welcome_line2[] PROGMEM = "3\xf7 Robot";
  36. const char demo_name_line1[] PROGMEM = "Maze";
  37. const char demo_name_line2[] PROGMEM = "solver";
  38.  
  39. // A couple of simple tunes, stored in program space.
  40. const char welcome[] PROGMEM = ">g32>>c32";
  41. const char go[] PROGMEM = "L16 cdegreg4";
  42.  
  43.  
  44. // Data for generating the characters used in load_custom_characters
  45. // and display_readings. By reading levels[] starting at various
  46. // offsets, we can generate all of the 7 extra characters needed for a
  47. // bargraph. This is also stored in program space.
  48. const char levels[] PROGMEM = {
  49. 0b00000,
  50. 0b00000,
  51. 0b00000,
  52. 0b00000,
  53. 0b00000,
  54. 0b00000,
  55. 0b00000,
  56. 0b11111,
  57. 0b11111,
  58. 0b11111,
  59. 0b11111,
  60. 0b11111,
  61. 0b11111,
  62. 0b11111
  63. };
  64.  
  65. // This function loads custom characters into the LCD. Up to 8
  66. // characters can be loaded; we use them for 7 levels of a bar graph.
  67. void load_custom_characters()
  68. {
  69. OrangutanLCD::loadCustomCharacter(levels + 0, 0); // no offset, e.g. one bar
  70. OrangutanLCD::loadCustomCharacter(levels + 1, 1); // two bars
  71. OrangutanLCD::loadCustomCharacter(levels + 2, 2); // etc...
  72. OrangutanLCD::loadCustomCharacter(levels + 3, 3);
  73. OrangutanLCD::loadCustomCharacter(levels + 4, 4);
  74. OrangutanLCD::loadCustomCharacter(levels + 5, 5);
  75. OrangutanLCD::loadCustomCharacter(levels + 6, 6);
  76. OrangutanLCD::clear(); // the LCD must be cleared for the characters to take effect
  77. }
  78.  
  79. // This function displays the sensor readings using a bar graph.
  80. void display_readings(const unsigned int *calibrated_values)
  81. {
  82. unsigned char i;
  83.  
  84. for (i=0;i<5;i++) {
  85. // Initialize the array of characters that we will use for the
  86. // graph. Using the space, an extra copy of the one-bar
  87. // character, and character 255 (a full black box), we get 10
  88. // characters in the array.
  89. const char display_characters[10] = {
  90. ' ', 0, 0, 1, 2, 3, 4, 5, 6, 255 };
  91.  
  92. // The variable c will have values from 0 to 9, since
  93. // calibrated values are in the range of 0 to 1000, and
  94. // 1000/101 is 9 with integer math.
  95. char c = display_characters[calibrated_values[i] / 101];
  96.  
  97. // Display the bar graph character.
  98. OrangutanLCD::print(c);
  99. }
  100. }
  101.  
  102. // Initializes the 3pi, displays a welcome message, calibrates, and
  103. // plays the initial music. This function is automatically called
  104. // by the Arduino framework at the start of program execution.
  105.  
  106.  
  107. void setup()
  108. {
  109. unsigned int counter; // used as a simple timer
  110.  
  111. pinMode(SHORT_RANGE_SENSOR,INPUT);
  112. // This must be called at the beginning of 3pi code, to set up the
  113. // sensors. We use a value of 2000 for the timeout, which
  114. // corresponds to 2000*0.4 us = 0.8 ms on our 20 MHz processor.
  115. robot.init(2000);
  116.  
  117. load_custom_characters(); // load the custom characters
  118.  
  119. // Play welcome music and display a message
  120. OrangutanLCD::printFromProgramSpace(welcome_line1);
  121. OrangutanLCD::gotoXY(0, 1);
  122. OrangutanLCD::printFromProgramSpace(welcome_line2);
  123. OrangutanBuzzer::playFromProgramSpace(welcome);
  124. delay(1000);
  125.  
  126. OrangutanLCD::clear();
  127. OrangutanLCD::printFromProgramSpace(demo_name_line1);
  128. OrangutanLCD::gotoXY(0, 1);
  129. OrangutanLCD::printFromProgramSpace(demo_name_line2);
  130. delay(1000);
  131.  
  132. // Display battery voltage and wait for button press
  133. while (!OrangutanPushbuttons::isPressed(BUTTON_B))
  134. {
  135. int bat = OrangutanAnalog::readBatteryMillivolts();
  136.  
  137. OrangutanLCD::clear();
  138. OrangutanLCD::print(bat);
  139. OrangutanLCD::print("mV");
  140. OrangutanLCD::gotoXY(0, 1);
  141. OrangutanLCD::print("Press B");
  142.  
  143. delay(100);
  144. }
  145.  
  146. // Always wait for the button to be released so that 3pi doesn't
  147. // start moving until your hand is away from it.
  148. OrangutanPushbuttons::waitForRelease(BUTTON_B);
  149. delay(1000);
  150.  
  151. // Auto-calibration: turn right and left while calibrating the
  152. // sensors.
  153. for (counter=0; counter<80; counter++)
  154. {
  155. if (counter < 20 || counter >= 60)
  156. OrangutanMotors::setSpeeds(40, -40);
  157. else
  158. OrangutanMotors::setSpeeds(-40, 40);
  159.  
  160. // This function records a set of sensor readings and keeps
  161. // track of the minimum and maximum values encountered. The
  162. // IR_EMITTERS_ON argument means that the IR LEDs will be
  163. // turned on during the reading, which is usually what you
  164. // want.
  165. robot.calibrateLineSensors(IR_EMITTERS_ON);
  166.  
  167. // Since our counter runs to 80, the total delay will be
  168. // 80*20 = 1600 ms.
  169. delay(20);
  170. }
  171. OrangutanMotors::setSpeeds(0, 0);
  172.  
  173. // Display calibrated values as a bar graph.
  174. while (!OrangutanPushbuttons::isPressed(BUTTON_B))
  175. {
  176. // Read the sensor values and get the position measurement.
  177. unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);
  178.  
  179. // Display the position measurement, which will go from 0
  180. // (when the leftmost sensor is over the line) to 4000 (when
  181. // the rightmost sensor is over the line) on the 3pi, along
  182. // with a bar graph of the sensor readings. This allows you
  183. // to make sure the robot is ready to go.
  184. OrangutanLCD::clear();
  185. OrangutanLCD::print(position);
  186. OrangutanLCD::gotoXY(0, 1);
  187. display_readings(sensors);
  188.  
  189. delay(100);
  190. }
  191. OrangutanPushbuttons::waitForRelease(BUTTON_B);
  192.  
  193. OrangutanLCD::clear();
  194.  
  195. OrangutanLCD::print("Go!");
  196.  
  197. // Play music and wait for it to finish before we start driving.
  198. OrangutanBuzzer::playFromProgramSpace(go);
  199. while(OrangutanBuzzer::isPlaying());
  200. }
  201.  
  202.  
  203. // This function, causes the 3pi to follow a segment of the maze until
  204. // it detects an intersection, a dead end, or the finish.
  205. void obstacleAvoidance(int step){
  206. // Add what you want the robot to do when it sees an obstacle
  207. if(step==1){
  208. OrangutanMotors::setSpeeds(50,-51);
  209. delay(300);
  210. OrangutanMotors::setSpeeds(50,51);
  211. delay(500);
  212. OrangutanMotors::setSpeeds(-50,51);
  213. delay(300);
  214. }
  215. if (step==2){
  216. OrangutanMotors::setSpeeds(50,51);
  217. delay(1799);
  218. OrangutanMotors::setSpeeds(-50,51);
  219. delay(300);
  220. OrangutanMotors::setSpeeds(50,51);
  221. delay(530);
  222. OrangutanMotors::setSpeeds(100,-101);
  223. delay(150);
  224. }
  225.  
  226.  
  227. }
  228. void follow_segment(){
  229.  
  230.  
  231. //Follow line until an intersection or dead end is detected
  232. while(1)
  233. {
  234.  
  235. //***************Put your line following code here*********************
  236. unsigned int position = robot.readLine(sensors, IR_EMITTERS_ON);
  237. if (position < 1600){
  238. OrangutanMotors::setSpeeds(17,71);
  239. }
  240. else if (position > 2400){
  241. OrangutanMotors::setSpeeds(70,17);
  242. }
  243. else
  244. {OrangutanMotors::setSpeeds(70,71);
  245. }
  246.  
  247.  
  248. /*if (digitalRead(SHORT_RANGE_SENSOR) == 0){
  249. while(digitalRead(SHORT_RANGE_SENSOR) == 0){
  250. obstacleAvoidance(1);
  251. }
  252. obstacleAvoidance(2);
  253. }
  254. */
  255.  
  256.  
  257. //*****************end of line following code**************************
  258.  
  259.  
  260. // Get the position of the line
  261.  
  262. // We use the inner three sensors (1, 2, and 3) for
  263. // determining whether there is a line straight ahead, and the
  264. // sensors 0 and 4 for detecting lines going to the left and
  265. // right.
  266.  
  267. if (sensors[1] < 100 && sensors[2] < 100 && sensors[3] < 100)
  268. {
  269. // There is no line visible ahead, and we didn't see any
  270. // intersection. Must be a dead end.
  271. return;
  272. }
  273. else if (sensors[0] > 100 || sensors[4] > 100)
  274. {
  275. // Found an intersection.
  276. return;
  277. }
  278. }//end while
  279.  
  280. }
  281.  
  282.  
  283.  
  284. // Code to perform various types of turns according to the parameter dir,
  285. // which should be 'L' (left), 'R' (right), 'S' (straight), or 'B' (back).
  286. // The delays here had to be calibrated for the 3pi's motors.
  287. void turn(unsigned char dir)
  288. {
  289. switch(dir)
  290. {
  291. case 'L':
  292. // Turn left.
  293. //***************Put your left turn code here*********************
  294.  
  295. OrangutanMotors::setSpeeds(-100,101);
  296. delay(145);
  297. OrangutanMotors::setSpeeds(0,0);
  298.  
  299.  
  300.  
  301.  
  302. //*****************end of left turn*** code**************************
  303.  
  304. break;
  305. case 'R':
  306. // Turn right.
  307. //***************Put your right turn code here*********************
  308.  
  309. OrangutanMotors::setSpeeds(100,-101);
  310. delay(145);
  311. OrangutanMotors::setSpeeds(0,0);
  312.  
  313.  
  314.  
  315.  
  316.  
  317. //*****************end of right turn code*****************************
  318. break;
  319. case 'B':
  320. // Turn around.
  321. //***************Put your turn back code here*********************
  322. OrangutanMotors::setSpeeds(-100,101);
  323. delay(280);
  324. OrangutanMotors::setSpeeds(0,0);
  325.  
  326.  
  327. //*****************end of turn back code*****************************
  328. break;
  329. case 'S':
  330. // Don't do anything!
  331. break;
  332. }
  333. }
  334.  
  335.  
  336. // The path variable will store the path that the robot has taken. It
  337. // is stored as an array of characters, each of which represents the
  338. // turn that should be made at one intersection in the sequence:
  339. // 'L' for left
  340. // 'R' for right
  341. // 'S' for straight (going straight through an intersection)
  342. // 'B' for back (U-turn)
  343. //
  344. // Whenever the robot makes a U-turn, the path can be simplified by
  345. // removing the dead end. The follow_next_turn() function checks for
  346. // this case every time it makes a turn, and it simplifies the path
  347. // appropriately.
  348. char path[100] = "";
  349. unsigned char path_length = 0; // the length of the path
  350.  
  351. // Displays the current path on the LCD, using two rows if necessary.
  352. void display_path()
  353. {
  354. // Set the last character of the path to a 0 so that the print()
  355. // function can find the end of the string. This is how strings
  356. // are normally terminated in C.
  357. path[path_length] = 0;
  358.  
  359. OrangutanLCD::clear();
  360. OrangutanLCD::print(path);
  361.  
  362. if (path_length > 8)
  363. {
  364. OrangutanLCD::gotoXY(0, 1);
  365. OrangutanLCD::print(path + 8);
  366. }
  367. }
  368.  
  369. // This function decides which way to turn during the learning phase of
  370. // maze solving. It uses the variables found_left, found_straight, and
  371. // found_right, which indicate whether there is an exit in each of the
  372. // three directions, applying the "left hand on the wall" strategy.
  373. unsigned char select_turn(unsigned char found_left, unsigned char found_straight, unsigned char found_right)
  374. {
  375. // Make a decision about how to turn. The following code
  376. // implements a left-hand-on-the-wall strategy, where we always
  377. // turn as far to the left as possible.
  378. if (found_left)
  379. {
  380. return 'L';
  381. }
  382. else if (found_straight)
  383. {
  384. return 'S';
  385. }
  386. else if (found_right)
  387. {
  388. return 'R';
  389. }
  390. else
  391. {
  392. return 'B';
  393. }
  394. }
  395.  
  396. // Path simplification. The strategy is that whenever we encounter a
  397. // sequence xBx, we can simplify it by cutting out the dead end. For
  398. // example, LBL -> S, because a single S bypasses the dead end
  399. // represented by LBL.
  400. void simplify_path()
  401. {
  402. // only simplify the path if the second-to-last turn was a 'B'
  403. if (path_length < 3 || path[path_length-2] != 'B')
  404. return;
  405.  
  406. int total_angle = 0;
  407. int i;
  408. for (i = 1; i <= 3; i++)
  409. {
  410. switch (path[path_length - i])
  411. {
  412. case 'R':
  413. total_angle += 90;
  414. break;
  415. case 'L':
  416. total_angle += 270;
  417. break;
  418. case 'B':
  419. total_angle += 180;
  420. break;
  421. }
  422. }
  423.  
  424. // Get the angle as a number between 0 and 360 degrees.
  425. total_angle = total_angle % 360;
  426.  
  427. // Replace all of those turns with a single one.
  428. switch (total_angle)
  429. {
  430. case 0:
  431. path[path_length - 3] = 'S';
  432. break;
  433. case 90:
  434. path[path_length - 3] = 'R';
  435. break;
  436. case 180:
  437. path[path_length - 3] = 'B';
  438. break;
  439. case 270:
  440. path[path_length - 3] = 'L';
  441. break;
  442. }
  443.  
  444. // The path is now two steps shorter.
  445. path_length -= 2;
  446. }
  447.  
  448. // This function comprises the body of the maze-solving program. It is called
  449. // repeatedly by the Arduino framework.
  450. void loop(){
  451.  
  452. while (1)
  453. {
  454.  
  455. // These variables record whether the robot has seen a line to the
  456. // left, straight ahead, and right, whil examining the current
  457. // intersection.
  458. unsigned char found_left = 0;
  459. unsigned char found_straight = 0;
  460. unsigned char found_right = 0;
  461.  
  462. //Define the Sensors Variable
  463. unsigned int sensors[5];
  464.  
  465. //************************************************
  466. //**********STEP 1: Follow a Segment *************
  467. //************************************************
  468.  
  469. //Follow a segment until we find a turn or an intersection
  470. follow_segment();
  471.  
  472.  
  473. // Drive straight a bit. This helps us in case we entered the
  474. // intersection at an angle.
  475. // Note that we are slowing down - this prevents the robot
  476. // from tipping forward too much.
  477. OrangutanMotors::setSpeeds(50, 50);
  478. delay(50);
  479.  
  480. //************************************************
  481. //*********STEP 2: Detecting a Turn***************
  482. //************************************************
  483.  
  484.  
  485. // Now read the sensors and check the intersection type.
  486. robot.readLine(sensors, IR_EMITTERS_ON);
  487.  
  488. //********Write in the conditions for the if statments below*******
  489. if (sensors[0]>100)
  490. found_left = 1;
  491.  
  492. else if (sensors[4]>100)
  493. found_right = 1;
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500. // Drive straight a bit more - this is enough to line up our
  501. // wheels with the intersection.
  502. OrangutanMotors::setSpeeds(40, 40);
  503. delay(100);
  504.  
  505. // Check for a straight exit.
  506. robot.readLine(sensors, IR_EMITTERS_ON);
  507.  
  508. //*********Write in the conditions for the if statments below********
  509.  
  510. if (sensors[1]>100||sensors[2]>100||sensors[3]>100)
  511. found_straight = 1;
  512.  
  513.  
  514. // Check for the ending spot.
  515. // If all three middle sensors are on dark black, we have
  516. // solved the maze.
  517.  
  518. //*********Write in the conditions for the if statments below********
  519.  
  520. if (sensors[0]>100 && sensors[1]>100 && sensors[2]>100 && sensors[3]>100 && sensors[4]>100)
  521. break;
  522.  
  523.  
  524.  
  525. //************************************************
  526. //************STEP 3: Take the Turn***************
  527. //************************************************
  528.  
  529. // Intersection identification is complete.
  530. // If the maze has been solved, we can follow the existing
  531. // path. Otherwise, we need to learn the solution.
  532. unsigned char dir = select_turn(found_left, found_straight, found_right);
  533.  
  534. // Make the turn indicated by the path.
  535. turn(dir);
  536.  
  537.  
  538. //****************END OF STEP 3*******************
  539. //************************************************
  540.  
  541. // Store the intersection in the path variable.
  542. path[path_length] = dir;
  543. path_length++;
  544.  
  545. // You should check to make sure that the path_length does not
  546. // exceed the bounds of the array. We'll ignore that in this
  547. // example.
  548.  
  549. // Simplify the learned path.
  550. simplify_path();
  551.  
  552.  
  553. // Display the path on the LCD.
  554. display_path();
  555. }
  556.  
  557. // Solved the maze!
  558.  
  559. // Now enter an infinite loop - we can re-run the maze as many
  560. // times as we want to.
  561. while (1)
  562. {
  563. // Beep to show that we solved the maze.
  564. OrangutanMotors::setSpeeds(0, 0);
  565. OrangutanBuzzer::play(">>a32");
  566.  
  567. // Wait for the user to press a button, while displaying
  568. // the solution.
  569. while (!OrangutanPushbuttons::isPressed(BUTTON_B))
  570. {
  571. if (millis() % 2000 < 1000)
  572. {
  573. OrangutanLCD::clear();
  574. OrangutanLCD::print("Solved!");
  575. OrangutanLCD::gotoXY(0, 1);
  576. OrangutanLCD::print("Press B");
  577. }
  578. else
  579. display_path();
  580. delay(30);
  581. }
  582. while (OrangutanPushbuttons::isPressed(BUTTON_B));
  583.  
  584. delay(1000);
  585.  
  586. // Re-run the maze. It's not necessary to identify the
  587. // intersections, so this loop is really simple.
  588. int i;
  589. for (i = 0; i < path_length; i++)
  590. {
  591. follow_segment();
  592.  
  593. // Drive straight while slowing down, as before.
  594. OrangutanMotors::setSpeeds(50, 50);
  595. delay(50);
  596. OrangutanMotors::setSpeeds(40, 40);
  597. delay(200);
  598.  
  599. // Make a turn according to the instruction stored in
  600. // path[i].
  601. turn(path[i]);
  602. }
  603.  
  604. // Follow the last segment up to the finish.
  605. follow_segment();
  606.  
  607. // Now we should be at the finish! Restart the loop.
  608. }
  609. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement