This is the first draft of this Tutorial and all comments are welcome. After about a week or so I will produce an updated version taking account of comments where appropriate.
I would particularly welcome comments about how to make the code more obvious for a newbie or about improvements to clarify my explanation.
Introduction
In Several Things at a Time I showed how to write a program so that it appears that the Arduino is doing things simultaneously. Actually it can only do one thing at a time but because it is very fast by human standards it can give the impression that multiple things are happening at once.
There is another sort of programming problem in which the various tasks depend on previous actions having been completed. For example the warehouse door must be opened before the forklift can drive in to pick up a load. In some projects the different tasks may take a known length of time and a program could be written to do different things at different time intervals. But in many real world situations there is no predictable duration for an action. For example on one occasion the forklift driver may spend a few minutes chatting with a colleague before exiting the warehouse so a door closure based on a timer would not be suitable.
The usual way to deal with this sort of problem is with the concept that has the rather grand name of "State Machine". Don't worry, this is not a complicated programming idiom that will require 2 or 3 weeks of careful study. All that's involved is the use of one or more variables to keep track of the state of the system, or different parts of the system.
Applying a State Machine to the problem
For my example program I will use the variable doorState to keep track of the door and forkliftState to keep track of the forklift. (I use a servo to represent the door and flashing LEDs to represent the forklift moving and the load being picked up and a push-button switch to start things off).
The doorState can take any one of these values
LOCKED,
UNLOCKED,
OPENING,
OPEN,
CLOSING,
The idea is that the forklift can't move unless the doorState is OPEN and the door cannot operate unless the forklift is STOPPED. That way the forklift should never hit the door and the door should never hit the forklift.
The values for forkliftState will be
STOPPED,
ENTERING,
LOADING,
READY_TO_LEAVE,
LEAVING,
In the program I have represented these states using ENUMs. If you are not familiar with them I have written a few words of explanation at the bottom of Reply #XX.
The general idea of a State Machine is that the program moves from one state to the next as different things happen. For example when the door is locked a push on the START button will change the state to UNLOCKED. That almost clears the path for the door to open but the program must also check to ensure that the forklift is STOPPED. Assuming it is the state will change to OPENING and that will allow the servo to operate. When the servo has reached the end of its sweep doorState will change to OPEN.
All this time the forklift will have been waiting but it cannot start moving until the doorState is OPEN. (For simplicity I am just assuming the forklift takes a set time to enter or leave the warehouse. In a real situation the location of the forklift might be detected by a beam-break sensor at the warehouse door)
When applying the State Machine concept to a problem it is important to appreciate that what happens at any one time depends only on the value in the state variable. For example the START button does not directly make the door move, it only changes the value of doorState from LOCKED to UNLOCKED. Separating the inputs from the outputs in this way means that the checkButton() function could be replaced by (for example) a function that gets a start message from the Arduino Serial Monitor without any changes being needed in other parts of the program. The subsequent actions neither know nor care how doorState comes to have the value UNLOCKED.
It is probably also worth pointing out how the use of state variables allows each function to be very short. That makes debugging much easier and allows for easy testing of the functions separate from one another if necessary.


