so i've just started looking into arduino programming. Im trying to help my little brother with some programming for a school project but we've run into a dead end.
Basically the project requires you control a robot through an obstacle course. What sort of code would you need to run this?
Were using an IR sensor to measure distance (were only using the analog values so no need to convert it to physical distance) till the bot is close enough to a wall, then it turns right or left, and follows this procedure through a series of turns. Problem we have is, its a 2 wheeled bot, so i know how to make it stop and turn e.g. left by turning left motor off or reverse and right motor forwards, but then after that, how do you make it move both motors? I know it seems like a easy problem but i cant figure it out
here is my program code so far. Does it seem correct? Note that i have purposely left the sensor values (sensvalue) blank in the if statements. The intervals are also not correctly timed so ignore the actual value
// Define the sensor and motors as variables
int IRsensor = 0;
int leftmotor = 1;
int rightmotor = 2;
// This variable holds the state the system is in. It will start at 0 and count upwards for
// how every many state the system will have.
int state = 0;
//Create Flag Variable for State
int flag = 0;
// This long variable will hold the previous number of milli seconds that have ellapsed since
// the board was turned on. It is used for timing delays.
long previousMillis;
// This long variable will hold the current amount of ellapsed millis seconds since the board was turned on
long currentMillis;
// This variable will hold the desired delay time in millis seconds
long interval;
void setup()
{
Serial.begin(9600);
//Define the inputs and outputs
pinMode(IRsensor,INPUT);
pinMode(leftmotor,OUTPUT);
pinMode(rightmotor,OUTPUT);
}
void loop()
{
//Create variable 'val', and print sensor value into it
int sensval = analogRead(IRsensor);
// Update the current milli seconds. Millis() returns the number
// of milli seconds that have ellapsed sincethe board was turned on
currentMillis = millis();
//Define the variosu cases depending on IR sensor input
switch(state)
case 0: //wait two seconds before moving
previousMillis = currentMillis;
interval = 3000;
state = 1;
break;
case 1: // check if wait time has finished then move forwards.
if(currentMillis - previousMillis > interval){
Forwards(); // This function is defined at the bottom.
state = 2;
}
break;
case 2: // continue moving forward untill the 1st wall is close, then turn right
if(sensvalue < && state == 2){
RightTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 3000;
state = 3;
}
break;
case 3: //Keep moving after first turn
if(currentMillis - previousMillis > interval && state == 3){
Forwards(); // This function is defined at the bottom.
flag = 1
}
break;
case 4: // Keep moving forward till 2nd wall, then turn Right
if(sensvalue < && flag == 1){
RightTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 3000;
state = 4;
}
break;
case 5: //Keep moving after 2nd turn
if(currentMillis - previousMillis > interval && state == 4){
Forwards(); // This function is defined at the bottom.
flag = 2
}
break;
case 6: // Keep moving forward till 3rd wall, then turn Left
if(sensvalue < && flag == 2){
LeftTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 3000;
state = 5;
}
break;
case 7: //Keep moving after 3rd turn
if(currentMillis - previousMillis > interval && state == 5){
Forwards(); // This function is defined at the bottom.
flag = 2
}
break;
default: // if no cases match then default is executed.
//Do nothing
break;
}
}
// Motor control programs, depending on the case
void Forwards(){
digitalWrite(leftmotor,HIGH);
digitalWrite(rightMotor,HIGH);
}
void LeftTurn(){
digitalWrite(leftmotor,LOW);
digitalWrite(rightmotor,HIGH);
}
void RightTurn(){
digitalWrite(leftmotor,HIGH);
digitalWrite(rightmotor,LOW);
}
void Stop(){
digitalWrite(leftmotor,LOW);
digitalWrite(rightmotor,LOW);
}
Moderator edit: [code] ... [/code] tags added. (Nick Gammon)
my idea was to set a value to teh state variable, then use that as a condition for the next step. Im trying to get multiple conditions before each case is run e.g for case 2, it will only occur if the sensor value is below some value, and when state = 2, which is after case 1 has occured, thus forcing each step to happen in sequence.
Isnt the program run in a step structure, i.e. case 0, case 1, case 2, etc ? Im an undergrad in engineering so i've done some statement list programming on PLC's and i was trying to apply that to this.
kenny0987:
Isnt the program run in a step structure, i.e. case 0, case 1, case 2, etc ? Im an undergrad in engineering so i've done some statement list programming on PLC's and i was trying to apply that to this.
Not at all.
The switch (and cases) are like a lengthy "if". IF case 1 ELSE case 2 ELSE case 3 and so on. But the whole thing is done once.
kenny0987:
here is my program code so far. Does it seem correct?
Not according to the compiler, for which I have quite a bit of respect:
sketch_may30i.cpp: In function 'void loop()':
sketch_may30i:48: error: break statement not within loop or switch
sketch_may30i:51: error: case label '1' not within a switch statement
sketch_may30i:56: error: break statement not within loop or switch
sketch_may30i:60: error: case label '2' not within a switch statement
sketch_may30i:61: error: 'sensvalue' was not declared in this scope
sketch_may30i:67: error: break statement not within loop or switch
sketch_may30i:71: error: case label '3' not within a switch statement
sketch_may30i:75: error: expected `;' before '}' token
sketch_may30i:76: error: break statement not within loop or switch
sketch_may30i:78: error: case label '4' not within a switch statement
sketch_may30i:79: error: 'sensvalue' was not declared in this scope
sketch_may30i:85: error: break statement not within loop or switch
sketch_may30i:87: error: case label '5' not within a switch statement
sketch_may30i:91: error: expected `;' before '}' token
sketch_may30i:92: error: break statement not within loop or switch
sketch_may30i:94: error: case label '6' not within a switch statement
sketch_may30i:95: error: 'sensvalue' was not declared in this scope
sketch_may30i:101: error: break statement not within loop or switch
sketch_may30i:103: error: case label '7' not within a switch statement
sketch_may30i:107: error: expected `;' before '}' token
sketch_may30i:108: error: break statement not within loop or switch
sketch_may30i:110: error: case label not within a switch statement
sketch_may30i:112: error: break statement not within loop or switch
sketch_may30i:61: error: label 'state' used but not defined
sketch_may30i:79: error: label 'flag' used but not defined
sketch_may30i.cpp: At global scope:
sketch_may30i:117: error: expected declaration before '}' token
So then my program would run case 0, then halt? I thought it looped and ran whichever case had the conditions satisfied?
How would i be able to make it run those steps in sequence?
kenny0987:
So then my program would run case 0, then halt?
No, it likely ends up in state 3 as noted above.
I thought it looped and ran whichever case had the conditions satisfied?
It does loop and the switch statement runs whichever case matches your state variable.
How would i be able to make it run those steps in sequence?
You control it with the state variable - your code needs to set it to an appropriate value for the next iteration of loop. If you want it to run those steps in ascending order, each case needs to increment the state variable. Try searching the forums for state machine; there are a number of examples posted that illustrate this.
// Define the sensor and motors as variables
int IRsensor = 0;
int leftmotor = 1;
int rightmotor = 2;
// This variable holds the state the system is in. It will start at 0 and count upwards for
// how every many state the system will have.
int state = 0;
//Create Flag Variable for State
int flag = 0;
// This long variable will hold the previous number of milli seconds that have ellapsed since
// the board was turned on. It is used for timing delays.
long previousMillis;
// This long variable will hold the current amount of ellapsed millis seconds since the board was turned on
long currentMillis;
// This variable will hold the desired delay time in millis seconds
long interval;
void setup()
{
Serial.begin(9600);
//Define the inputs and outputs
pinMode(IRsensor,INPUT);
pinMode(leftmotor,OUTPUT);
pinMode(rightmotor,OUTPUT);
}
void loop()
{
//Create variable 'val', and print sensor value into it
int sensvalue = analogRead(IRsensor);
// Update the current milli seconds. Millis() returns the number
// of milli seconds that have ellapsed sincethe board was turned on
currentMillis = millis();
//Define the variosu cases depending on IR sensor input
switch(state){
case 0: //wait four seconds before moving
previousMillis = currentMillis;
interval = 4000;
state = 1;
break;
case 1: // check if 4 sec has finished then move forwards.
if(currentMillis - previousMillis > interval){
Forwards(); // This function is defined at the bottom.
state = 2;
}
break;
case 2: // continue moving forward untill the FIRST DEAD END is close, then turn right
if(sensvalue < 135 && state == 2){
RightTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 435;
state = 3;
}
break;
case 3: //Keep moving after first turn
if(currentMillis - previousMillis > interval && state == 3){
Forwards(); // This function is defined at the bottom.
flag = 1;
state = 4;
}
break;
case 4: // Keep moving forward till OBSTACLE, then turn Right
if(sensvalue < 135 && flag == 1){
RightTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 435;
state = 5;
}
break;
case 5: //Keep moving after 2nd turn
if(currentMillis - previousMillis > interval && state == 5){
Forwards(); // This function is defined at the bottom.
flag = 2;
state = 6;
}
break;
case 6: // Keep moving forward till DED END, then turn Left
if(sensvalue < 135 && flag == 2){
LeftTurn(); // This function is defined at the bottom.
previousMillis = currentMillis;
interval = 435;
state = 7;
}
break;
case 7: //Keep moving after DEAD END
if(currentMillis - previousMillis > interval && state == 7){
Forwards(); // This function is defined at the bottom.
flag = 3;
state = 8;
interval = 1500;
}
break;
case 8: //Turn 15 degrees Left
if(currentMillis - previousMillis > interval && flag == 8){
LeftTurn(); // This function is defined at the bottom.
flag = 4;
state = 9;
interval = 110;
}
break;
case 9: //Keep moving after Turning 15 Degrees for 5 seconds
if(currentMillis - previousMillis > interval && state == 9){
Forwards(); // This function is defined at the bottom.
flag = 5;
state = 10;
interval = 5000;
}
break;
case 10: //Stop after 5 seconds
if(currentMillis - previousMillis > interval && flag == 5){
Stop(); // This function is defined at the bottom.
flag = 6;
state = 11;
}
break;
default: // if no cases match then default is executed.
//Do nothing
break;
}
}
// Motor control programs, depending on the case
void Forwards(){
digitalWrite(leftmotor,HIGH);
digitalWrite(rightmotor,HIGH);
}
void LeftTurn(){
digitalWrite(leftmotor,LOW);
digitalWrite(rightmotor,HIGH);
}
void RightTurn(){
digitalWrite(leftmotor,HIGH);
digitalWrite(rightmotor,LOW);
}
void Stop(){
digitalWrite(leftmotor,LOW);
digitalWrite(rightmotor,LOW);
}
i dont quite follow. Correct me if im wrong, but you mean that, rather than have state = ... after each case, i simply delete each of these, then at the end of the switch statement, add in state ++ ?
Basically for this project, the bot is split into 2 parts. The first part, containing all the electronics, transports a ball though an path with obstacles till it gets to a bucket, whereby the bot drops the ball into the bucket. Within the bucket lies the 2nd part, purely mechanical, and is supposed to climb a certain length rope while holding onto the ball, then stop and hold it up there indefinitely.
kenny0987:
i dont quite follow. Correct me if im wrong, but you mean that, rather than have state = ... after each case, i simply delete each of these, then at the end of the switch statement, add in state ++ ?
Yes that was what I was getting at. Some state machines have all sorts of complex states (eg. state 5 leads to state 9 which leads to state 2 or 3). But in your case you seem to be going up one state at a time.
You still need to think of how to handle what to do when you reach your last state.
Doing an unconditional state++ after the switch statement isn't going to work for all cases. Consider case 9; there's a timing condition that must be satisfied before moving on to the next state. It is a slightly unusual application of a state machine though as there's no possibility of choosing a new path through your states at run time - you could simply write it sequentially (though I can see no reason to).
It sounds like the system will simply dead reckon its way round the maze and state 11 is a means to effectively end the program by using the default case. If so, presumably case 10 will have the ball drop code added.
If you haven't tested with the actual hardware yet, might I suggest that you do so soon? You will likely discover all sorts of minor issues that'll need work.