I am trying to make an obstacle avoidance robot out of an old R/C car I have. currently my code has delay functions to ensure the car backs up all the way to clear the obstacle and so that it alternates between turning right and left. The problem is that the delay (as I'm sure you know) completely stops all other actions so in that time it isn't sensing for obstacles. I think you could use millis to fix this but I really don't know how it works. Could someone explain a good way to fix my problem?
Huntechr1:
I think you could use millis to fix this but I really don't know how it works
Then I think, with respect, it's time you stopped trying to progress until you do.
So here's my advice: take the BlinkwithOutDelay sketch and dissect it line by line until you fully understand what it's doing. It's too important a concept not to be comfortable with.
Once you have that clear in your mind, modify the sketch to use different times for on and off, then develop it to do that for more than one LED.
That's what I did when I was getting my mind round it.
I was writing the above while dmworking247 replied and you responded...
Huntechr1:
Even though I am looking at the example I'm still having trouble seeing how to fit it into my code
Forget the code for a moment (or as long as necessary) and write down in English the steps you would take if YOU the human stopped at a wall and then backed up for a stipulated time, while doing other stuff.
Huntechr1:
...my code has delay functions to ensure the car backs up all the way to clear the obstacle ...
This is a very common short-cut in early progtamming.
There is no 'ensuring' the car backs up happening here!
You are telling the car to back up, then going off to lunch...!
-- if you tell your dog not to eat the roast, then go out for an hour... what are the chances the roast will be there when you return?!,
Apart from delay() being a blight on well written .state aware' code, using this technique has no provision for a wheel slipping or other obstacle that might affect the distance travelled.
Read about closed loops, and consider sensing when the vehicle has moved to the desired position... yes, it's more difficult - but its also more accurate and reliable.
Huntechr1:
Ok, I guess I will have to spend some time tomorrow just trying to figure this out
Learning how to use millis in the Arduino environment was possibly the most useful and important part of all of it. There are several very well written examples - look at the 'Useful Links' thread at the top of this sub-forum's listing.
The trick is that in BlinkWithoutDelay one compares two times (a start time (called previousMillis) and the current time (conveniently called currentMillis)) and only does something if a certain duration has passed.
In combination with a state machine implementation, the below code that implements a non-blocking delay can be used.
/*
non blocking delay
returns false if delay in progress, else true
assumes a global variable currentMillis that is set to the current time
*/
bool doDelay(unsigned long duration)
{
// start time
static unsigned long starttime = 0;
// if delay not started
if(starttime == 0)
{
// set the start time of the delay
starttime = currentMillis;
}
// if delay has lapsed
if(currentMillis - starttime >= duration)
{
// reset start time for the next time that we need the delay function
starttime = 0;
// indicate that delay has lapsed
return true;
}
// indicate that delay in progress
return false;
}
Mostly posted in the hope that the comments help in understanding the above or understand BlinkWithoutDelay. currentMillis is a global variable.
Note that this is basically only useful for a statemachine. Example
// required global variables
int currentState = 0;
unsigned long currentMillis;
void setup()
{
}
void loop()
{
// get current time
currentMillis = millis();
// simple statemachine implementation
switch(currentState)
{
case 0:
// do something
...
...
// go to next state
currentState++;
break;
case 1:
// start delay / check if lapsed
if(deDelay(1000) == true)
{
// go to next state
currentstate++;
}
break;
case 2:
// do something else
...
...
// go back to first state (0)
currentState = 0;
break;
} // end_of_switch
}
bool doDelay(unsiged long duration)
{
// see previous code
...
...
}
unsigned int uS = sonar.ping();
int distance = sonar.ping_cm();
Serial.print("Ping: ");
Serial.print(uS / US_ROUNDTRIP_CM);
You didn't look closely enough at my reply in your other thread yesterday.
What's the point of doing 'sonar.ping()' immediately followed by 'sonar.ping_cm()'?
You follow it by converting the microseconds value from 'sonar.ping()' to cm anyway, in your 'Serial.print()'.
In the reply yesterday, I showed you how to print the return value of 'sonar.ping_cm()'.
All you really need is:-
int distance = sonar.ping_cm(); // Send ping and get distance in cm
Serial.print("Ping: ");
Serial.print(distance); // Print the distance
I noticed something else that you've overlooked, too. In the 'if' statements in the code you posted, you haven't made any allowance for what happens if the distance is exactly 20cm, only if it's larger or smaller than 20cm.
You've also doubled up on each of the 'if' statements, doing a different thing each time. Of course, the first of each will only happen for a split second before the second is executed.
These are your 4 conditional statements:-
(See the similarities?)
I realise that you're re-writing the code, but thought that I should point these things out anyway, so that you're aware.
Edit: Another quick note - I agree with JimboZA. Write things in order in English first, step-by-step, then write code to accomplish those steps. That's how I always write my programs.
JimboZA:
Forget the code for a moment (or as long as necessary) and write down in English the steps you would take if YOU the human stopped at a wall and then backed up for a stipulated time, while doing other stuff.