Navigate the Maze
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.