Let's Make Robots!

Beware of Delays

Sensibilizes about the delay() function
  • Programming language:

Whenever you use delays in your robot code your microcontroller is going to do nothing but wait until the delay is passed.

Where on one hand this is a blessing it is on the other hand a curse. It is a blessing when you need to slow things down... but from my point of view this is mostly not nessesary. It is a curse when your system needs to be reactive but can't since there are several delays.

Reactiveness can make the difference between your robot falls down a stair or stops, crashes into a wall or avoids it, tracks an object or looses it, detects an important signal or misses it.

Many code examples you find work with delays. It is one of the most used function I guess. Missused function out of my perspective.

Basically I say that you almost never need a delay. And if you need one make shure you know what you do and what your robot does not do.

Read on to find out when to use the delay function and when not. Dive into the further readings if you want to learn more.

When do I need a delay?

You need a delay when you want to slow things down and give the robot a 20 to 50Hz frequency or if you have to fullfill a time constrainted contract between actor and sensor. That is i.e. with a infrared diode that emits light and the phototransistor reads light intensity a few microseconds after the emit. Same to the ultrasonic sender and resceiver.

Here time is one part of the mathematical calculation of transversal or longitudinal wave propagation speed. The time constraints are so strong that you can not leave it to some busy waiting or scheduling to wake you up after a while - you want an atomar block to wait before the whole system can continue.

Example with delay

long Ultrasonic::Timing()
{
  digitalWrite(Trig_pin, LOW);
  delayMicroseconds(2);
  digitalWrite(Trig_pin, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig_pin, LOW);
  duration = pulseIn(Echo_pin,HIGH);
  return duration;
}

When do I don't need a delay?

You don't need the delay function when working with motors and servos. Set the motor to forward and leave it in this setting until something changes. If your code is procedural and your thinking too then a delay might be the next logical step. But most of the time you try to be stateless when you actually should be stateful.

A motor forward is not only an event that exists on one moment in time and is forgotten afterwards. A motor forward event results into a stateful motor setting. A state in the physical world. Your motor turns and continues to turn unless you stop it. Since it continues to turn it is not nessesary to tell the motor to turn over and over again. It turns. And that is what you want: your robot moves forward.

Example without delay

void loop() {
  if(!isResceiveNewCommand()){
    return;
  }

  motorAction();

}

boolean isResceiveNewCommand(){
  command = readCommand(); /* read in the command data */
  if( command == commandMemento){
    return false; /* No new command arrived */
  }
  commandMemento = command; /* Take a memento of the command */
  return true;
}

void motorAction(){
  switch(command){
  case COMMAND_STOP:
    motor.run(RELEASE); 
    break;
  case COMMAND_FWD:
    motor.run(FORWARD);
    break;
  case COMMAND_BWD:
    motor.run(BACKWARD);
    break;
  }
}

But what if I need a delay? How can I stay reactive?

If your requirement is like "go ahead for five seconds and then turn around" do you want to say motor forward and then delay 5'000 millies? You rather use a timer to call your function after these five seconds, use a timestamp and a comparison to the current millies or do some form of busy waiting.

I know this is more difficult than simply calling the delay function. But the context is stronger than the concept. Keep that in mind. Reactiveness can make the difference between your robot succeed or fail.

A bit more complex code with reactiveness as a gain instead of simple code but a loss of reactiveness is acceptable.

Read on if you want to find out what delay variant matches best for your problem.

Further reading

http://arduino.cc/playground/Code/AvoidDelay
   "Using delay() has a (usually not intended) sideeffect - the Arduino does nothing for that while. To get two or more "actions" to run independent of each other, you can not use delay()."

http://arduino.cc/en/Reference/delay 
   "More knowledgeable programmers usually avoid the use of delay() for timing of events longer than 10's of milliseconds unless the Arduino sketch is very simple."

http://arduino.cc/playground/Code/Timer
   "The Arduino 'delay' function is both a blessing and a curse. Its great for showing beginners how to make an LED flash. But as soon as you get more complex and start slowing down your 'loop' function you will run into problems."

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Could you show an example with Arduino's HW interrupts?

I think it would be more complex, but more accurate...

It is really cool of you to offer this code for those robot creators, or engineers, who really don't like it when their bot sits there and waits for delays, or falls down the stairs.

Thank you for the comment. Keep in mind that this is sample code. Some details are not visible and some null-pointer check code is omitted. But if you fill up these missing pieces the code compiles and runs.

Depending on your sensors you might add a delay(20) to the end of the loop() function to give the robot a 50Hz frequency and the sonsors time to relieve.

Very interesting article and thank you for the follow up links because those were helpful as well.

Do you find multiple state machines as shown in your images to be overly complex for most simple robot projects or does that help in modeling different behavior instead of recoding the same actions over and over?

Which do you find more efficient, a straight C approach for your behavior modeling and state machines or C++/Objects with the associated overhead but ease of expanding and polymorpism?

Thanks!

Maus

Attention: this is off-topic and does not relate to the delay article.

Regarding your question about multiple state machines there is the following to say: if you decompose your problem into a physical and a logical part and define interfaces between them you can keep the physical part and only modify/extend/alternate the logical part.

The physical part translates realworld elements such as sensor readings into logical events. And it resceives actions from the logical part and translates them into physical actor commands.

In the logical part you can now start to teach the robot to give it the personality you like. As the teaching goes on each skill can be encapsulated to a certain extend. This is independent of the computation model you choose. Some use multiple finite state machines, others use procedures and other programmers use objects.

If you try to keep out of accidential complexity this teaching and the skills introduce the essential complexity of the robot's codified personality. We should all get along with that.

If the physical/logical distinction is designed into the robot's software you can now start to reuse. Reuse i.e. the object detection physical code in all your robots but make new logical behavior i.e. yellow drum machine, fhotibot, edward or barry hxt900. Or the other way around and keep logical behavior and use different drives i.e. tracks, wheels or legs. Now polymorphism comes into play if your language supports this and you can master complexity and variability with abstraction.

Regarding your performance question I can say: It depends...

Thanks for sharing. This is helpful.

Nice to read. Thanks. I guess this was no news for you. Or can one see your SCOUT+ standing around waiting for the delay to finish? I guess not :-)

Thanks, these were some useful tips. I'll keep this in mind next time I have to write some Arduino software.

Thank you for the comment. So your Butler-Bot will stay reactive and bring dinner now - not after the delay.

This delay topic is not only Arduino specific but applies to any microcontroller that offers this feature.