This article is based on Ethan's teaching on state machine.
Serial is used for communication between the Arduino board and a computer or other devices. This posts a big challenge as the data transfer may be interrupted or even lost due to electrical noise and other hardware problems.
Is there any way to handle this situation? The answer is State Machine.
A state machine is an abstract machine that can be in exactly one of the few pre-defined states at any given time. The state machine can change from one state to another in response to some inputs.
In simpler terms, a state machine will read a series of inputs. When it reads an input, it will switch to a different state. Each state specifies which state to switch to for a given input, and what other actions to take.
For our serial communication practice, a state machine is a key component to ensure that the receiving part gets the correct data. Thus we can define the following 3 states:
- Init - This is the default state before the program reads in serial data.
- Normal - Reading regular bytes
- Escaped - Reading the escape byte
Figure 1. Three States in Our State Machine
There is a type of data that comes prior to the first complete data frame. We call it junk data. Junk data has no value and will be ignored by the program.
Figure 2. Junk Data
The state machine will keep track of the data received. So even the transfer is interrupted the receiving part still knows what to do when the next byte comes in 10 minutes later. While waiting for the next data the Arduino can perform other tasks so it doesn't waste time on waiting. Using a state machine is highly recommended for your RCJ robots.
Figure 3. State Machine Flow Chart
Figure 4. Serial Communication Flow Chart for Line Following
To better understand how the state machine works in our serial communication programming, let's look at some examples with the following assumptions:
- FLAG byte: 0xaa
- ESCAPE byte: 0xab
- Before the input data gets sent out, any byte after the Escape byte will be converted to a different number using Bitwise Exclusive OR (^).
Example 1 - What are the outputs after the following data frame is received:
[0x11, 0x1, 0x2, 0x10, 0x21, 0x11]
Example 2 - In this example, there is some data prior to the first flag (delimiter byte). It can be treated as junk. So what would be the outputs if the data below is received:
[0x1, 0x2, 0x11, 0x1, 0x10, 0x21, 0x11]
The following function expresses the relations between input, output and the changing state:
fn(in, state) => out, state
In a situation that multiple data frames are sent out in a row, we can use one flag byte between two frames.
It's also possible that the ending flag of a data frame never comes. Most likely something goes wrong on the sender side, for example, the sender dies due to technical issues. In this case, the receiver can time out the data. More specifically, if the receiver detects that it takes too long to get the next byte, even though the ending flag is not here yet, the receiver can simple drop the communication.
Now as we get better understanding of the state machine in our program, we will do some implementation in the next article.
About the author
Coach Cindy - BananaBots head coach
Cindy has years of experience in IT and project management. As the lead supervisor of BananaBots, she hopes that, one day, the younger generation will show their true power through their efforts and persistence.
More posts by Coach Cindy