hi,
I'm new to arduino programming.
I've got a schoolproject about a state machine. The function of the machine is explained in the pictures.
The problem is that the states don't work. It looks like the loop is passing the states.
#include <Servo.h>
Servo servojq;
int incomingByte = 0;
int incomingByteCheck = 0;
int outgoingByte = 0;
int delayvalue = 1000;
int ledpin = 13;
int button = 2;
int potpin = 0;
int val;
int F;
int S;
int R;
int B;
int W;
const int Rest = 10;
const int Step = 11;
const int Stepwait = 12;
const int Follow = 13;
const int Blink = 14;
const int Switch = 15;
void setup()
{
Serial.begin(9600);
pinMode (ledpin, OUTPUT);
pinMode (button, INPUT);
servojq.attach(3);
}
void loop()
{
int button_state = digitalRead(button);
static int state = Rest;
switch (state)
{
case Rest:
if (digitalRead(Serial.read()) == S) {
state = Step;
}
if (digitalRead(Serial.read()) == B) {
state = Blink;
}
break;
case Step:
servojq.write(30);
delay(1000);
servojq.write(60);
delay(1000);
servojq.write(30);
state = Stepwait;
break;
case Stepwait:
if (digitalRead (Serial.read()) == F) {
state = Follow;
}
if (digitalRead(Serial.read()) == R) {
state = Rest;
}
break;
case Follow:
val = analogRead(potpin);
val = map(val, 0, 1023, 0, 180);
servojq.write(val);
delay(10);
if (digitalRead (Serial.read()) == S) {
state = Step;
}
else {
state = Follow;
}
break;
case Blink:
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
if (digitalRead (Serial.read()) == R) {
state = Rest;
}
if (digitalRead (Serial.read()) == W) {
state = Switch;
}
else {
state = Blink;
}
break;
case Switch:
if (button_state == HIGH) {
digitalWrite(ledpin, HIGH);
delayvalue = (1000);
}
else
{ digitalWrite(ledpin, LOW);
}
if (digitalRead (Serial.read()) == R) {
state = Rest;
}
else {
state = Switch;
}
break;
}
}
The syntax for digitalRead is digitalRead(pin) What does Serial.read return? Is it a pin number?
I think that you need to study up on how serial communication works. Here is a post that covers receiving and parsing serial data.
AWOL:
OK, to answer my own question, F,S, R, B, W all have the value zero, aka LOW.
How much Arduino programming experience do you have?
I have no experience in aruidno programming...
I've read a lot information but it's something really new for me.
I can do a little bit of matlab, thats all.
Funnily enough, while I was out for a long walk yesterday, I was thinking through the steps in coding a state machine of about this complexity and OP's example landed at the right moment for me as a weekend exercise.
I think of particular importance is that the blink and step states need to employ delay()-less, millis()-based thinking so as to catch the next incoming command in real time.
I've got some decent Arduino experience and done a fair bit of programming over the years (but I'm not a Programmer with a capital-P by any means) and found this a reasonably complex project.
I'm keen to hear from OP as to what teaching has actually been provided for this project.
OK to help progress a bit and may be serve as food for thoughts for other starters looking at this thread, here is an empty code structure that would help you get started from the right foot with the loop()
reading the Serial input to capture a new command
handling state changes based on the new command when they are legit
handling timing related activities
there are many ways to skin a cat, so this is not supposed to be THE ultimate solution
and Of course I left many many functions voluntarily empty for you to fill in. won't do your job either
// SERVO RELATED
#include <Servo.h>
Servo servojq; // WHAT A STUPID NAME...
const byte servoPin = 3;
const int restAngle = 30;
int stepAngle;
const int delayServo = 5; // ms for servo to avoid mechanical strain
const unsigned long stepperTickPeriod = 250; // ms between two consecutive steps
// LED RELATED
const byte ledPin = 13;
unsigned long lastBlinkTime;
const unsigned long blinkPeriod = 1000ul;
// BUTTONS RELATED
const byte buttonPin = 2;
const byte potentionmeterPin = A0;
enum {REST, STEP, FOLLOW, BLINK, SWITCH} state;
// -----------------------------------------
// SUPPORT STATE FUNCTIONS
// -----------------------------------------
void setRestState()
{
state = REST;
if (stepAngle != restAngle) {
stepAngle = restAngle;
servojq.write(restAngle);
delay(delayServo);
Serial.print(F("Set Rest Angle = ")); Serial.println(stepAngle);
}
digitalWrite(ledPin, LOW);
}
void tickStepState()
{
static unsigned long lastTickStepTime = 0;
// handle the case when comming from FOLLOW stage where we can be anywhere
if (stepAngle > 60) {
}
if (millis() - lastTickStepTime >= stepperTickPeriod) {
// Progress the Servo based on incrementing stepAngle but not going over 60
lastTickStepTime = millis();
}
}
void tickBkinkState()
{
if (millis() - lastBlinkTime >= blinkPeriod) {
// toggle LED
lastBlinkTime = millis();
}
}
void tickFollowState()
{
int newAngle;
// DEFINE newAngle based on mapping analogRead(potentionmeterPin) to an angle between 0° and 180°
if (newAngle != stepAngle) {
// SET SERVO TO NEW ANGLE ONLY IF DIFFERENT FORM CURRENT ONE
}
}
void tickSwitchSate()
{
// SET LED TO MATCH BUTTON POSITION
}
// -----------------------------------------
// STANDARD SKETCH FUNCTIONS
// -----------------------------------------
void setup()
{
Serial.begin(115200);
pinMode (ledPin, OUTPUT);
pinMode (buttonPin, INPUT);
servojq.attach(servoPin);
setRestState();
}
void loop()
{
char serialCommand;
static boolean newCommand = false;
if (Serial.available()) {
serialCommand = Serial.read();
newCommand = true;
}
if (newCommand) { // handle state change if correct command
switch (serialCommand) {
case 'F':
if (state == STEP) {
state = FOLLOW;
Serial.println(F("state = FOLLOW"));
}
break;
case 'S':
if ((state == REST) || (state == FOLLOW)) {
state = STEP;
Serial.println(F("state = STEP"));
}
break;
case 'R':
if (true) { // I THINK YOU GET THE IDEA, DEFINE THE CORRECT TEST, not just true
setRestState();
Serial.println(F("state = REST"));
}
break;
case 'B':
if (true) { // I THINK YOU GET THE IDEA, DEFINE THE CORRECT TEST, not just true
state = BLINK;
Serial.println(F("state = BLINK"));
}
break;
case 'W':
if (true) { // I THINK YOU GET THE IDEA, DEFINE THE CORRECT TEST, not just true
state = SWITCH ;
Serial.println(F("state = SWITCH"));
}
break;
}
}
// handle ticks for various stages requiring time related activity
switch (state) {
case STEP:
tickStepState();
break;
case FOLLOW:
tickFollowState();
break;
case BLINK:
tickBkinkState();
break;
case SWITCH:
tickSwitchSate();
break;
}
}
I just typed that in so there might be mistakes of course. Don't even know if this is compiling
@manor_royal : Don't know if this will make any sense or helps. But when I do a state machine it typically follows the model of two functions.
In the loop() function is a switch of all the states I can be waiting in, along with what I'm waiting for. Kind of a pass through waiting room. You run in to your state, see if anything needs changing and run out.
Then there is a function setState(newState) that is called when the loop() sees a change and its time to change states. setState(newState) has another switch with all the states, but each one has the steps to get to the newState passed in.
The loop has the bubbles & setState() is the connections on the graph.
I find when I use this model, everything gets really easy to deal with and typically it works. Very handy in machine control.
jimLee: @manor_royal : Don't know if this will make any sense or helps.
Yep that's pretty much what I did thanks.
In loop() I have 2x functions, manageStates() and getCommand(). getCommand() reads the serial input and kicks out if it's illegal (illegal overall that is, like a Z or a Q), then manageStates() is a switch...case where each enum'd state is a case that does its thing (blink a led, move a servo etc) on entry and over time until it's time to exit with a cleanup() on receipt of a valid incoming command (valid that is, for the state, given the allowable paths).
Blinking and servo sweeping is all delay()-less so that the incoming serial isn't missed or held up.
jimLee:
The loop has the bubbles & setState() is the connections on the graph.
I find when I use this model, everything gets really easy to deal with and typically it works. Very handy in machine control.
-jim lee
Maybe I'm misunderstanding you but the loop has the conditions to leave each state. For example after 100ms in this_state, go to that_state, if emergency-stop pressed in this_state, go to stop_state. Those are the connections in the diagram.
setState() seems more like it's setting the outputs correctly for each state. It starts the millisecond timer or whatever. That seems to me more like the description written inside each bubble.
MorganS:
Maybe I'm misunderstanding you but the loop has the conditions to leave each state. For example after 100ms in this_state, go to that_state, if emergency-stop pressed in this_state, go to stop_state. Those are the connections in the diagram.
setState() seems more like it's setting the outputs correctly for each state. It starts the millisecond timer or whatever. That seems to me more like the description written inside each bubble.
Well I did'n't read the text in the bubbles. I just glanced at the pictures. I saw the bubbles as little places to wait for things to change and the lines as making changes. From state(bubble) to state(bubble).
jimLee:
Well I did'n't read the text in the bubbles. I just glanced at the pictures. I saw the bubbles as little places to wait for things to change and the lines as making changes. From state(bubble) to state(bubble).