The Whole Shebang
Congratulations, you’ve completed the calibration process! After calibration, the final program may seem long, but it’s really just a compilation of all the short programs we’ve just written and tested. Breaking maze navigation, or and any other robotic problem, down into small pieces and calibrating at each step helps ensure success. If you develop these habits now, it can save you tremendous amounts of time preparing for your next robotics project or contest entry.
The final code has some extra features to make navigation more reliable. For example, there’s a Turn_Check subroutine that prevents the Boe-Bot from misinterpreting %0111 or %1110 as a full 90° turn. It’s true that those QTI patterns do sometimes indicate a turn, but the same patterns can also indicate that the Boe-Bot has just drifted a little to the left or right of the line. The Turn_Check subroutine figures out whether the Boe-Bot is off course or on a turn by:
- Moving the Boe-Bot forward for 5 pulses
- Obtaining another QTI reading
- If the sensors still tell Boe-Bot to turn, it will, any other reading returns the program to the main routine for line adjustment
Another extra feature of the final code is that each SELECT…CASE statement in the main routine is sent to a subroutine. This is because we want the code to execute as quickly as possible. Each QTI reading is crucial to accurate maze navigation, so the faster the main routine executes, the more QTI readings we obtain. If we put every movement in the main routine, this severely slows down our code, which could cause missed readings in important areas, such as turns or T-intersections. That’s why the code in the main routine only checks the QTI states, and depending on the result, gets sent to the corresponding subroutine.
Before the code below will work on your Boe-Bot, it is essential for you to go through and update all the values you determined in this project’s calibration and testing steps. When running your Boe-Bot through the maze, you may find that some values need to be adjusted to account for unforeseen obstacles. That’s OK! Experiment with the code until your Boe-Bot can consistently navigate through your electrical tape maze.
' -----[ Title ]------------------------------------------------------------- ' FullMazeNavigation.bs2 ' Navigate your Boe-Bot through a "maze" made of electrical tape using the QTI ' Line Follower App Kit. ' IMPORTANT: This program has several operations that have to be tuned before ' it will work right! Follow the instructions above before running this ' program. ' {$STAMP BS2} ' Target device = BASIC Stamp 2 ' {$PBASIC 2.5} ' Language = PBASIC 2.5 ' -----[ Variables ]--------------------------------------------------------- rng VAR Byte ' Random number generator variable pulseCount VAR Byte ' FOR..NEXT loop counter for turning turnDecision VAR rng.BIT0 ' Bit 0 of random number generated AI VAR Bit ' "AI" remembers dead ends qtis VAR Nib ' QTI black/white states ' -----[ Initialization ]---------------------------------------------------- OUTB = %1111 ' Set OUTB bits to 1 AI = 0 ' Set AI variable to 0 FREQOUT 15, 1000, 2000 ' Battery Tester ' -----[ Main Routine ]------------------------------------------------------ DO ' Main DO...LOOP RANDOM rng ' Create a random number GOSUB Check_Qtis ' Get QTI states SELECT qtis CASE %0110 ' Mid Left and Right sensors detected, go forward GOSUB Forward CASE %1100 ' Far and Mid Left sensors detected = off track GOSUB BackOnTrack_TwoSensorsLeft CASE %0011 ' Far and Mid Right sensor detected = off track GOSUB BackOnTrack_TwoSensorsRight CASE %1110, %0111 ' Turn Detected GOSUB Turn_Check CASE %1111 ' All sensors detected = T-Intersection GOSUB T_Intersection CASE %0000 ' No track = dead end GOSUB Dead_End CASE %0001 ' Far Right sensor detected = off track GOSUB BackOnTrack_OneSensorRight CASE %1000 ' Far Left sensor detected = off track GOSUB BackOnTrack_OneSensorLeft CASE ELSE ' Any other combination, move forward until PULSOUT 13, 770 ' something else is detected. PULSOUT 12, 730 PAUSE 20 ENDSELECT LOOP ' -----[ Subroutines - Check_Qtis ]------------------------------------------ ' Checks the state of each QTI Sensor. 0 means white surface, 1 means black Check_Qtis: DIRB = %1111 ' P7..P4 -> output PAUSE 0 ' Delay = 230 us DIRB = %0000 ' P7..P4 -> input PAUSE 0 ' Delay = 230 us qtis = INB ' Store QTI outputs in INB RETURN ' -----[ Subroutines - Forward ]--------------------------------------------- ' Boe-Bot moves forward. Forward: PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 RETURN ' -----[ Subroutines - Turn_Check ]------------------------------------------ ' When three sensors are detected, this subroutine checks if there is actually ' a turn, or if the Boe-Bot got off track. Turn_Check: PULSOUT 13, 750 ' Stop moving PULSOUT 12, 750 FOR pulseCount = 0 TO 5 ' Move forward a bit PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 NEXT GOSUB Check_Qtis ' Check the new QTI states SELECT qtis CASE %1110 ' Left turn is detected GOSUB AI_Decision CASE %0111 ' Right turn is detected GOSUB Turn_Right CASE ELSE ' Boe-Bot was off track, RETURN ' return to main routine loop ENDSELECT RETURN ' -----[ Subroutines - AI_Decision ]----------------------------------------- ' When a left turn is detected, check if the Boe-Bot hit a dead end last. ' This will keep it from returning to Start. AI_Decision: IF (AI = 1) THEN ' If the AI variable is 1, Boe-Bot was in dead end AI = 0 ' Set AI variable to 0 GOSUB Ignore_Turn ' Ignore the turn that leads to Start ELSEIF (AI = 0) THEN ' If the AI variable is 0, Boe-Bot was not in GOSUB Turn_Left ' dead end, so it's OK to turn left. ENDIF RETURN ' -----[ Subroutines - Ignore_Turn ]----------------------------------------- ' AI variable was 1, so ignore the left turn by going forward for 50 pulses. Ignore_Turn: FOR pulseCount = 0 TO 50 PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 NEXT RETURN ' -----[ Subroutines - Turn_Left ]------------------------------------------- ' Boe-Bot executes a left turn. Turn_Left: FOR pulseCount = 0 TO 15 ' Go forward a bit so Boe-Bot stays on course PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 NEXT FOR pulseCount = 0 TO 17 ' Turn left, about 90-degrees PULSOUT 13, 650 PULSOUT 12, 650 PAUSE 20 NEXT RETURN ' -----[ Subroutines - Turn_Right ]------------------------------------------ ' Boe-Bot executes a right turn. Turn_Right: FOR pulseCount = 0 TO 15 ' Go forward a bit so Boe-Bot stays on course PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 NEXT FOR pulseCount = 0 TO 17 ' Turn right, about 90-degrees PULSOUT 13, 850 PULSOUT 12, 850 PAUSE 20 NEXT RETURN ' -----[ Subroutines - T_Intersection ]-------------------------------------- ' Boe-Bot makes a random turn when it comes to a T-Intersection T_Intersection: IF turnDecision = 0 THEN ' If Bit0 is 0 then turn right GOSUB Turn_Right ELSEIF turnDecision = 1 THEN ' If Bit0 is 1 then turn left GOSUB Turn_Left ENDIF RETURN ' -----[ Subroutines - Dead_End ]-------------------------------------------- ' Boe-Bot detects a dead end, backs up, and turns around to get back on track. Dead_End: DO GOSUB Check_Qtis PULSOUT 13, 730 PULSOUT 12, 770 PAUSE 20 LOOP UNTIL (qtis = %0111) IF (qtis = %0111) THEN PAUSE 20 FOR pulseCount = 0 TO 15 PULSOUT 13, 770 PULSOUT 12, 730 PAUSE 20 NEXT FOR pulseCount = 0 TO 17 PULSOUT 13, 850 PULSOUT 12, 850 PAUSE 20 NEXT ENDIF AI = 1 RETURN ' -----[ Subroutines - BackOnTrack_TwoSensorsLeft ]-------------------------- ' Boe-Bot is off track. Boe-Bot slowly rotates until the two middle sensors ' are detected, and then centers itself on the line. PULSOUT 13, 750 ' Stop PULSOUT 12, 750 DO GOSUB Check_Qtis ' Slowly rotate until the middle PULSOUT 13, 750 ' QTIs are back on the line PULSOUT 12, 740 PAUSE 20 LOOP UNTIL (qtis = %0110) IF (qtis = %0110) THEN ' When the middle QTIs are back FOR pulseCount = 1 TO 20 ' on the line, rotate left for PULSOUT 13, 750 ' 20 pulses and then rotate right PULSOUT 12, 730 ' for 10 pulses to center the Boe- PAUSE 20 ' Bot on the line. NEXT FOR pulseCount = 0 TO 10 PULSOUT 13, 770 PULSOUT 12, 750 PAUSE 20 NEXT ENDIF RETURN ' -----[ Subroutines - BackOnTrack_TwoSensorsRight ]------------------------- ' Boe-Bot is off track. Boe-Bot slowly rotates until the two middle sensors ' are detected, and then centers itself on the line. PULSOUT 13, 750 ' Stop PULSOUT 12, 750 DO GOSUB Check_Qtis ' Slowly rotate until the middle PULSOUT 13, 760 ' QTIs are back on the line PULSOUT 12, 750 PAUSE 20 LOOP UNTIL (qtis = %0110) IF (qtis = %0110) THEN ' When the middle QTIs are back FOR pulseCount = 1 TO 20 ' on the line, rotate right for PULSOUT 13, 770 ' 20 pulses and then rotate left PULSOUT 12, 750 ' for 10 pulses to center the Boe- PAUSE 20 ' Bot on the line. NEXT FOR pulseCount = 0 TO 10 PULSOUT 13, 750 PULSOUT 12, 730 PAUSE 20 NEXT ENDIF RETURN ' -----[ Subroutines - BackOnTrack_OneSensorLeft ]--------------------------- ' Boe-Bot is off track. Boe-Bot slowly rotates until the two middle sensors ' are detected, and then centers itself on the line. BackOnTrack_OneSensorLeft: PULSOUT 13, 750 ' Stop PULSOUT 12, 750 DO ' Slowly rotate until the middle GOSUB Check_Qtis ' QTIs are back on the line PULSOUT 13, 750 PULSOUT 12, 740 PAUSE 20 LOOP UNTIL (qtis = %0110) IF (qtis = %0110) THEN ' When the middle QTIs are back FOR pulseCount = 1 TO 20 ' on the line, rotate left for PULSOUT 13, 750 ' 20 pulses and then rotate right PULSOUT 12, 740 ' for 10 pulses to center the Boe- PAUSE 20 ' Bot on the line. NEXT FOR pulseCount = 0 TO 10 PULSOUT 13, 770 PULSOUT 12, 750 PAUSE 20 NEXT ENDIF RETURN ' -----[ Subroutines - BackOnTrack_OneSensorRight ]-------------------------- ' Boe-Bot is off track. Boe-Bot slowly rotates until the two middle sensors ' are detected, and then centers itself on the line. BackOnTrack_OneSensorRight: PULSOUT 13, 750 ' Stop PULSOUT 12, 750 DO GOSUB Check_Qtis ' Slowly rotate until the middle PULSOUT 13, 760 ' QTIs are back on the line PULSOUT 12, 750 PAUSE 20 LOOP UNTIL (qtis = %0110) IF (qtis = %0110) THEN ' When the middle QTIs are back FOR pulseCount = 1 TO 20 ' on the line, rotate right for PULSOUT 13, 760 ' 20 pulses and then rotate left PULSOUT 12, 750 ' for 10 pulses to center the Boe- PAUSE 20 ' Bot on the line. NEXT FOR pulseCount = 0 TO 10 PULSOUT 13, 750 PULSOUT 12, 730 PAUSE 20 NEXT ENDIF RETURN
Your Turn: Challenge Yourself and Friends!
Although this code was written specifically for the maze shown in Figure 2 (previous section), it can be adapted to a variety of other situations as well as expanded for more complex mazes. Challenge yourself by creating a random maze and see if you can program your Boe-Bot to get through it! You can also challenge your friends and see who can best navigate through mazes, or who can do it the fastest. As a final touch, try adding obstacles that can be detected by whiskers, infrared or light sensors, and try programming your Boe-Bot to navigate around these obstacles and get back on the maze.