8.d. The Main Loop(s)

The strategy of our program is expressed in the file maze-solve.c. Most importantly, we want to keep track of the path that we have followed, so we define an array storing up to 100; these will be the same characters used in the turn() function. We also need to keep track of the current path length so that we know where to put the characters in the array.

char path[100] = "";
unsigned char path_length = 0; // the length of the path

Our “main loop” is found in the function maze_solve(), which is called after calibration, from main.c. This function actually includes two main loops – a first one that handles solving the maze, and a second that replays the solution for the fastest possible time. In fact, the second loop is actually a loop within a loop, since we want to be able to replay the solution many times. Here’s an outline of the code:

// This function is called once, from main.c.
void maze_solve()
{
while(1)
{
// FIRST MAIN LOOP BODY
// (when we find the goal, we use break; to get out of this)
}

// Now enter an infinite loop - we can re-run the maze as many
// times as we want to.
while(1)
{
// Beep to show that we finished the maze.
// Wait for the user to press a button...

int i;
for(i=0;i<path_length;i++)
{
// SECOND MAIN LOOP BODY
}

// Follow the last segment up to the finish.
follow_segment();

// Now we should be at the finish!  Restart the loop.
}
}	

The first main loop needs to drive down a segment of the course, decide how to turn, and record the turn in the path variable. To pass the correct arguments to select_turn(), we need to carefully examine the intersection as we cross it. Note that there is a special exception for finding the end of the maze. The following code works pretty well, at least at the slow speeds that we’re using:

		// FIRST MAIN LOOP BODY
follow_segment();

// Drive straight a bit.  This helps us in case we entered the
// intersection at an angle.
// Note that we are slowing down - this prevents the robot
// from tipping forward too much.
set_motors(50,50);
delay_ms(50);

// These variables record whether the robot has seen a line to the
// left, straight ahead, and right, whil examining the current
// intersection.
unsigned char found_left=0;
unsigned char found_straight=0;
unsigned char found_right=0;

// Now read the sensors and check the intersection type.
unsigned int sensors[5];

// Check for left and right exits.
if(sensors[0] > 100)
found_left = 1;
if(sensors[4] > 100)
found_right = 1;

// Drive straight a bit more - this is enough to line up our
// wheels with the intersection.
set_motors(40,40);
delay_ms(200);

// Check for a straight exit.
if(sensors[1] > 200 || sensors[2] > 200 || sensors[3] > 200)
found_straight = 1;

// Check for the ending spot.
// If all three middle sensors are on dark black, we have
// solved the maze.
if(sensors[1] > 600 && sensors[2] > 600 && sensors[3] > 600)
break;

// Intersection identification is complete.
// If the maze has been solved, we can follow the existing
// path.  Otherwise, we need to learn the solution.
unsigned char dir = select_turn(found_left, found_straight, found_right);

// Make the turn indicated by the path.
turn(dir);

// Store the intersection in the path variable.
path[path_length] = dir;
path_length ++;

// You should check to make sure that the path_length does not
// exceed the bounds of the array.  We'll ignore that in this
// example.

// Simplify the learned path.
simplify_path();

// Display the path on the LCD.
display_path();

We’ll discuss the call to simplify_path() in the next section. Before that, let’s take a look at the second main loop, which is very simple. All we do is drive to the next intersection and turn according to our records. After doing the last recorded turn, the robot will be one segment away from the finish, which explains the final follow_segment() call in the outline of maze_solve() above.

			// SECOND MAIN LOOP BODY
follow_segment();

// Drive straight while slowing down, as before.
set_motors(50,50);
delay_ms(50);
set_motors(40,40);
delay_ms(200);

// Make a turn according to the instruction stored in
// path[i].
turn(path[i]);