The classic “hello world” of the Arduino world includes something like:
void loop() { digitalWrite(ledPin, HIGH); // sets the LED on delay(1000); // waits for a second digitalWrite(ledPin, LOW); // sets the LED off delay(1000); // waits for a second }
Simple sample code for robotic vehicles may include something similar, such as
//Move Forward for 10 seconds advance (255,255); delay(10000);
where the advance function is previously defined. This approach, using delay(), works fine until you want your robot to do something else while moving, like check sensors for obstacles, or see if a button was pushed to turn it off, or updating its position based on sensor input. The problem of course, is that while the delay is running, the cpu does nothing (although it will process interrupts). So clearly using delay() for this purpose is not a good idea.
Rather than having your code sit idle at a point in the loop function, spinning its figurative wheels, you want the software to continue looping through the main loop, but stopping when a set time is reached. One approach is to use a timer interrupt. Have your code continue through the loop, but set an interrupt service routine that sets a flag, signifying the time has elapsed and it’s time to stop doing what you were doing (e.g., moving forward) and do something else. An introduction to timers and interrupts can be found on the Let’s Make Robots site, and you should also check the Arudino reference page on interrupts . If you’d like to keep things simpler, there are Arduino libraries for using timer interrupts as well.
An alternative approach is to use the metro library. The metro library provides an alternative to using timer interrupts. Because it does not use interrupts, the code in your loop will need to check to see if the timer has expired or not. The sample code below works on my robot that uses an Arduino-compatible Romeo controller and RP5 chassis. It was based on the example provided by DFRobot but adds a) using switch 1 on the Romeo board as a start/stop switch and b) instead of using delay(), it uses the Metro library.
The key section of the code is the nextMovement function. It’s called every time the main loop executes. A timer called movementMetro was already initialized as part of the setup. This nextMovement function checks if the timer has gone off, and if it has, changes the movement case to the next in line and resets the value for the appropriate time. One tricky part is that the timer value is for the NEXT movement, not the one in the movement just completed.
void nextMovement (int next,unsigned long wait) // Set case and delay for next movement { if (movementMetro.check() == 1) { movement = next; movementMetro.interval(wait); } }
Here’s the full, working code. When run, you need to push button 1 once the code is loaded. The robot then moves forward, turns, move forward, reverses, turns, and reverses again, with pauses between each movement. You can stop and restart the cycle by using switch 1.
#include <Metro.h> // Setup movement timer using the Metro library Metro movementMetro = Metro(4000); // Buttons vars const int key_S1_5 = 7; int state = false; // Off if 0, On if 1 int buttons_check(){ // This function checks button 1 and returns // 0 if no button pressed, 1 if pressed // Priorities: S1, S2, S3, S4, S5 int w = analogRead(key_S1_5); #define vS2 130 if ( w < vS2/2 ){ return 1; } return 0; }//End buttons_check() // Set up for running motors int E1 = 5; // digital output pin sending PWM power to the motor int E2 = 6; // digital output pin sending PWM power to the motor int M1 = 4; // controls is motor moves forward or backwards int M2 = 7; // controls is motor moves forward or backwards void forward(byte a,byte b) //Move forward { analogWrite(E1,a); digitalWrite(M1,HIGH); analogWrite(E2,b); digitalWrite(M2,HIGH); } void stop(void) //Stop { digitalWrite(E1,LOW); digitalWrite(E2,LOW); } void backward (byte a,byte b) //Move backward { analogWrite (E1,a); digitalWrite(M1,LOW); analogWrite (E2,b); digitalWrite(M2,LOW); } void Left (byte a,byte b) //Turn left { analogWrite (E1,a); digitalWrite(M1,LOW); analogWrite (E2,b); digitalWrite(M2,HIGH); } void Right (byte a,byte b) //Turn right { analogWrite (E1,a); digitalWrite(M1,HIGH); analogWrite (E2,b); digitalWrite(M2,LOW); } int movement = 1; // movement controls which movement (forward, turn, etc.) void nextMovement (int next,unsigned long wait) // Set case and delay for next movement { if (movementMetro.check() == 1) { movement = next; movementMetro.interval(wait); } } void setup(){ for(int i=4;i<=7;i++) pinMode(i, OUTPUT); Serial.begin(9600); }// End setup void loop(){ // This section checks button 1, which functions as stop/start switch, initially stopped int button = buttons_check(); if ( button == 1 ) { // Button 1 has been pressed state = !state; } Serial.println(state); // Whenstopped after running, reset to original start mode if (state == false) { stop(); //Stop movement = 1; movementMetro.interval(4000); } else { Serial.println(movement); // Each case sets movement command, signals next movement, and resets timer for duration OF NEXT MOVEMENT switch (movement) { case 1: forward(255,255); //Forward at full speed nextMovement(2, 5000); break; case 2: stop(); //Stop nextMovement(3, 650); break; case 3: Right(255,255); //Right at full speed nextMovement(4, 5000); break; case 4: stop(); //Stop nextMovement(5, 4000); break; case 5: forward(255,255); //Forward at full speed nextMovement(6, 5000); break; case 6: stop(); //Stop nextMovement(7, 4000); break; case 7: backward(255,255); //backward at full speed nextMovement(8, 5000); break; case 8: stop(); //Stop nextMovement(9, 650); break; case 9: Left(255,255); //Left at full speed nextMovement(10, 5000); break; case 10: stop(); //Stop nextMovement(11, 4000); break; case 11: backward(255,255); //backward at full speed nextMovement(12, 5000); break; case 12: stop(); //Stop nextMovement(1, 4000); break; } } }// End loop
Nothing fancy, but it was my start on getting my project underway and moving beyond using delay().
Look like a good approach! I used something much less sophisticated for my AVC robot last year; just read a millisecond timer, checked the modulus and ran one piece of code every 20ms and another piece every 100ms. 🙂 Coincidentally, uchobby just posted an article on this very topic, a different take on it, I guess. http://www.uchobby.com/index.php/2012/01/21/replacing-delay-in-arduino-sketches-istime-to-the-rescue/ Take it easy –Michael