Another way of writing a state machine in C

I was having a chat with RoboSumo team Frank the Tank (Eamos Fennell, Stephen Hanney, Karl Lawlor) on Friday and I noticed that they were using a state machine model in their PIC program, but that the structure of their C code was slightly different to what I used in the example that I published previously on this blog. Their way is functionally equivalent, but it struck me that some people might find it easier to understand than the way I wrote mine because each of their states is more self-contained in a short section of the C code, so I’ve decided to post another simple example using their structure.

The example I’m going to use is just a program to make a robot drive backwards and forwards across the Robosumo table, changing direction each time it meets the white perimeter.

I’ve added one subtle element that’s worth mentioning:

  • When the robot drives forward to the white perimeter, one of the two front sensors will detect white first.
  • The wheel on the other side (the one that hasn’t reached white yet) keeps turning until both colour sensors have detected white.
  • Once white is detected on both front sensors, the robot just goes into its reverse state and heads back across the table.

The idea of this is to roughly straighten up the robot relative to the edge of the table, so that it will end up driving back and forth across the centre of the table. If you’re using a web browser that supports SVG images (e.g. Firefox, Chrome), then click the image below to see an animation that will hopefully clarify what I mean:

There are four states in my state machine. The motor activity for each state and the conditions for each state transition are summarised in the following list:

  1. Drive Forwards: In this state, both motors move forwards. If the front left sensor detects white, change to state 2. If the front  right sensor detects white, change to state 3.
  2. Straighten up right side: In this sate, the left motor is stopped and the right motor continues moving forward. When the front right sensor detects white, change to state 4.
  3. Straighten up left side: In this state, the right motor is stopped and the left motor continues moving forward. When the front left sensor detects white, change to state 4.
  4. Reverse: In this state, both motors reverse. When either of the rear colour sensors detect white, change to state 1.

Here’s a state flow diagram showing the possible state transitions:

The code is shown below. I’m only going to show the main function here, which demonstrates the “Frank the Tank style” state machine. To form a complete program, just substitute this main function into my standard template program for the PIC18F4620.

int main()
{
	// Variable declarations
	int state = 1;
	int front_left_colour;
	int front_right_colour;
	int back_left_colour;
	int back_right_colour;

	// Configure the PIC
	setup();

	// The state machine is implemented in this while loop
	while(1)
	{
		// State 1: Drive forwards until white detected
		while(state == 1)
		{
			// Motors: both forward
			LATD = 0b00001010;

			// Read relevant sensors
			front_left_colour = read_analog_channel(0);
			front_right_colour = read_analog_channel(1);

			// Change state if necessary
			if (front_left_colour < 500) state = 2;
			if (front_right_colour < 500) state = 3;
		}

		// State 2: Left wheel stop, right wheel forward
		while(state == 2)
		{
			// Motors: left stop, right forward
			LATD = 0b00000010;

			// Read relevant sensors
			front_right_colour = read_analog_channel(1);

			// Change state if necessary
			if (front_right_colour < 500) state = 4;
		}

		// State 3: Left wheel forward, right wheel stop
		while(state == 3)
		{
			// Motors: left stop, right forward
			LATD = 0b00001000;

			// Read relevant sensors
			front_left_colour = read_analog_channel(0);

			// Change state if necessary
			if (front_left_colour < 500) state = 4;
		}

		// State 4: Reverse until white detected
		while(state == 4)
		{
			// Motors: both reverse
			LATD = 0b00000101;

			// Read relevant sensors
			back_left_colour = read_analog_channel(2);
			back_right_colour = read_analog_channel(3);

			// Change state if necessary
			if (back_left_colour < 500 || back_right_colour < 500)
				state = 1;
		}
	}

	return 0;
}

The basic difference between this structure and the one I used in my previous state machine example is that each state here is given its own while loop.

Advertisements
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s