Hey all,
I've been working with the Arduino for quite some time now, and it bugged me that I didn't have a standardized way of developing state machines. So, I took some libraries originally written by a professor of mine, edited them somewhat, and ported to the Arduino.
I'd call this a beta revision of the code. I still need to deal with the timer overflowing; right now it'll break when that happens (after about an hour of runtime). There's also some trace/debug functionality that I need to include. However, it seems right now that everything works as intended.
For those who don't know, finite state machines are a way of organizing mechatronics projects in a logical manner and implementing cooperative multitasking. Once things get big enough, you have tons and tons of stuff going on; this allows you to break it down into pieces. For example, if you were making a robot, you might have a task to control the wheels, a task to read and filter sensor data, a task to control the gripper attachment, and a task to read data coming in over a radio signal.
You'd then break these tasks down into states. For the wheels, you could have a brake state, a "going forward" state, a reverse state, turn right, and turn left. For radio, however, you'd probably have a "waiting for data" state and a "read" state.
Then, you determine the conditions that cause your tasks to transition between states. For example, in the radio task you would transition to "reading data" when a check to the buffer shows that there's data there to be read, and you'd transition back when all the data has been dealt with.
Here are diagrams of a few tasks from a project I completed a few months back involving building an automated security camera system:
http://www.ecphrasis.org/task_logic.pdfhttp://www.ecphrasis.org/task_motor.pdfhttp://www.ecphrasis.org/task_sensor.pdf===============================
Implementing in code:
Here's where this library comes in. For each task you define, you need to make a new class by creating [taskname].h and [taskname].cpp as new tabs in the Arduino IDE. This class needs to inherit from the task class, and define a new run function like so
#include <Task.h>
class task_blink : public task
{
private:
int duration, outputPin;
unsigned int timer;
public:
// The constructor creates a new task object
task_blink(int pin, int theDuration);
// The run method is where the task actually performs its function
char run(char);
};
Also declare any variables you need (such as duration in this example).
Now, to define these methods:
#include "task_blink.h"
#include <Task.h>
#include "WProgram.h"
//States
const char OFF = 0;
const char ON = 1;
bool ledState = false;
task_blink::task_blink(int pin, int theDuration) : task(10,0){
duration = theDuration;
outputPin = pin;
timer = 0;
pinMode(outputPin,OUTPUT);
}
char task_blink::run(char state){
/*Serial.print("Running pin ");
Serial.print(outputPin, DEC);
Serial.print(" -> timer = ");
Serial.print(timer, DEC);
Serial.print(", duration = ");
Serial.println(duration, DEC);*/
switch(state){
case(OFF):
if(timer++ == duration){
timer = 0;
digitalWrite(outputPin, HIGH);
/*Serial.print("Turning on pin ");
Serial.println(outputPin, DEC);*/
return(ON);
}
return(OFF);
case(ON):
if(timer++ == duration){
timer = 0;
digitalWrite(outputPin, LOW);
/*Serial.print("Turning off pin ");
Serial.println(outputPin, DEC);*/
return(OFF);
}
return(ON);
default:
return(OFF);
};
}
Your constructor has to give two arguments to the superclass constructor defining how often you want the task to run: milliseconds and microseconds. In this example, we want the task to run every 10 milliseconds, so we passed (10,0). Keep in mind, you could also pass arguments from the constructor through to the superclass constructor.
Then, the run method. This method should contain a switch statement, with each case being a different state. The value you return is the case that will be run the next time the task is called. In this example, we sit in the OFF state until our timer hits our duration value. It then transitions to the ON state and stays there until timer hits duration again, before transitioning back.
Finally, in the main file:
#include "task_blink.h"
#include <Task.h>
task_blink pin0(0,9);
task_blink pin1(1,19);
task_blink pin2(2,29);
task_blink pin3(3,39);
task_blink pin4(4,49);
task_blink pin5(5,59);
task_blink pin6(6,69);
task_blink pin7(7,79);
void setup ()
{
Serial.begin(9600);
}
void loop ()
{
pin0.schedule();
pin1.schedule();
pin2.schedule();
pin3.schedule();
pin4.schedule();
pin5.schedule();
pin6.schedule();
pin7.schedule();
}
Just initialize the objects you need, and inside the loop simply call schedule() on everything.
The advantage to this approach is that it's completely non blocking, as long as your states and such don't take very long to run. You could run 40 led's, all blinking at different rates, by setting stuff up like this. It also makes it easy to precisely time stuff, as you know how often each of your tasks is going to be called. The library pulls timer data from the Arduino libraries, so as long as the board you're using is supported the timer will work correctly.
Anyhow, this is my beta revision of the library, and I figured I'd post it up here. Let me know if you have any questions/comments, and I'll keep updating this as I fix up the library more

Files can be found here; just drop into the libraries folder like always:
http://www.ecphrasis.org/Task.zip--John