Some time ago I wrote a sketch to control a servo with a potentiometer without using the delay function, you can find it here. This time I wanted to move or sweep a servo between 2 positions.
The Arduino IDE comes with a sweep example, you can find it under File -> Examples -> Servo -> Sweep. This sketch uses a for loop to sweep the servo. In the for loop there is a delay to wait for the servo to go to the position. I do not like the delay function because it stops all code running on the micro controller. You can not do anything else during that delay. This is not very ideal if you want the micro controller to do lots of other things, like reading the input of various sensors or doing things based on a “radio” like an nRF24L01 module connected to an Arduino. The delay function would make your code very unresponsive or downright slow. So I tried to find different ways of sweeping servos without using the delay function. I have come up with several solutions:
The Varspeedservo library:
I found this library on the Arduino forum. You can download it from there, but it has not been updated for Arduino 1.0 or later. But this is very easy, you just have to replace WProgram.h with Arduino.h in the VarSpeedServo.cpp file. This library lets you set a minimum and a maximum angle for each servo and also the speed at which the servo must move.
Example sketch:
// speed controlled Servo Sweep // see: http://arduino.cc/forum/index.php/topic,61586.0.html // // Michael Margolis 4 August 2011 // edited by http://www.bajdi.com #include <VarSpeedServo.h> VarSpeedServo MyServo; // servo objects int servoSpeeds = 30; // sweep speed, 1 is slowest, 255 fastest) int servoMinPosition = 0; // the minumum servo angle int servoMaxPosition = 180; // the maximum servo angle void setup() { MyServo.attach(9); MyServo.slowmove(servoMinPosition,servoSpeeds) ; // start sweeping from min position } void loop() { // sweep the servos if( MyServo.read() == servoMinPosition) { MyServo.slowmove(servoMaxPosition,servoSpeeds) ; } else if( MyServo.read() == servoMaxPosition) { MyServo.slowmove(servoMinPosition,servoSpeeds) ; } }
Using a switch case and the millis timer:
The next sketch will also sweep a servo but uses a switch case to accomplish this. This is handy if you also want to do things when a servo is at a certain position like reading a sensor input. That’s why the following sketch uses 6 cases. You could use only 2 cases if you just want to sweep from 0 to 180 degrees. Every case gets a certain amount of time, this time is calculated by using the millis function. I used this method to write the code for my hexapod.
/* http://www.bajdi.com Sweeping a servo with a switch case and without the delay function */ #include <Servo.h> Servo servo; unsigned long previousMillis; byte servoSweep = 0; void setup(){ servo.attach(9); } void loop(){ if (millis() >= previousMillis){ previousMillis = previousMillis+100; // each case gets 100ms servoSweep = servoSweep +1; if (servoSweep == 7){ servoSweep = 1; } } switch (servoSweep){ case 1: servo.write(0); break; case 2: servo.write(60); break; case 3: servo.write(120); break; case 4: servo.write(180); break; case 5: servo.write(120); break; case 6: servo.write(60); break; } // end of sweep }
Using if statements and the millis timer:
This sketch looks a lot like the sweep example that comes with the Arduino IDE. But instead of using a for loop I use if statements. These if statements are only run every 50 milliseconds by using the #define runEvery statement in the beginning of the sketch. I did not come up with this statement myself, I found it on the Arduino forums.
// http://www.bajdi.com // Sweeping a servo without the delay function. #include <Servo.h> Servo myservo; // create servo object to control a servo int pos = 90; // variable to store the servo position int direction = 0; #define runEvery(t) for (static typeof(t) _lasttime;(typeof(t))((typeof(t))millis() - _lasttime) > (t);_lasttime += (t)) void setup() { myservo.attach(9); // attaches the servo on pin 9 to the servo object myservo.write(pos); } void loop() { runEvery(50) //run every 50 milliseconds { if(pos < 180 && direction == 0) { pos = pos + 1; } if(pos > 0 && direction == 1) { pos = pos - 1; } } if (pos == 180 ) { direction = 1; } if (pos == 0 ) { direction = 0; } myservo.write(pos); }
These sketches only sweep servos but a lot of things can be programmed in the same way. I did not come up with these sketches in a short time. They are the result of many hours of testing code and lots of head scratching. I hope they can be useful for some of my readers 🙂
Hi, i got a question. I’m an artist and not quite handy in programming, even not Arduino. Mostly after looking for different codes on internet for days I probably manage to get the arduino done what I want it to do. Though right now I’m quite in a hurry to get my actual project done for a show.
What I want to do:
I send audio impulses in form of a square wave with just one peak to analog In (0) of the arduino. If the analog in reads a certain value, then something else has to happen. Tested that with a simple LED which lights up as soon as the value is bigger than the threshold, otherwise it’s off. But now I’d like to control a servo with it. The idea is as followed:
The servo’s startposition is always 0°.
case 1:
if analog value > or = threshold (only once within 500ms)
sweep servo from 0° to 180°
after reaching end position, hold it.
if the analog value > or = threshold (twice within 500ms)
sweep servo back from 180° to 0°
after reaching end position, hold it.
Could you help me with the code, how I would have to write it to achieve my aim? You would really help me big times. It’s driving me nuts. Really.
Hope to hear from you soon, thanks already
Greetings, Mathieu
You could program that with a switch case. Post your code on the Arduino forums. Lots of smart people there that can help you. I have enough trouble debugging my own code 🙂
Hi there,
Thanks for posting this info. I just imported the VarSpeedServo library and tried verifying your code, and got the following error:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In function ‘void handle_interrupts(timer16_Sequence_t, volatile uint16_t*, volatile uint16_t*)’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:91: error: ‘LOW’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:91: error: ‘digitalWrite’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:122: error: ‘HIGH’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:122: error: ‘digitalWrite’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:126: error: ‘clockCyclesPerMicrosecond’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: At global scope:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:266: error: ‘boolean’ does not name a type
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In constructor ‘VarSpeedServo::VarSpeedServo()’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:283: error: ‘clockCyclesPerMicrosecond’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘uint8_t VarSpeedServo::attach(int, int, int)’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:297: error: ‘OUTPUT’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:297: error: ‘pinMode’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:304: error: ‘isTimerActive’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘void VarSpeedServo::detach()’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:315: error: ‘isTimerActive’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘void VarSpeedServo::write(int)’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:326: error: ‘map’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘void VarSpeedServo::writeMicroseconds(int)’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:334: error: ‘byte’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:334: error: expected `;’ before ‘channel’
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:335: error: ‘channel’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:343: error: ‘clockCyclesPerMicrosecond’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘void VarSpeedServo::slowmove(int, uint8_t)’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:377: error: ‘map’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:380: error: ‘byte’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:380: error: expected `;’ before ‘channel’
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:381: error: ‘channel’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:388: error: ‘clockCyclesPerMicrosecond’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘int VarSpeedServo::read()’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:407: error: ‘map’ was not declared in this scope
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp: In member function ‘int VarSpeedServo::readMicroseconds()’:
/Users/aeggert/Documents/Arduino/libraries/VarSpeedServo/VarSpeedServo.cpp:414: error: ‘clockCyclesPerMicrosecond’ was not declared in this scope
Any ideas as to why it wouldn’t be working for me?
Thanks for your help!
Alicia
I just compiled this sketch in Arduino 1.0.5 and get no errors. My guess is you haven’t installed the library in the right folder? Take a look at this: http://arduino.cc/en/Guide/Libraries
Thanks for your reply. I figured it out – just had to replace WProgram.h with Arduino.h in the VarSpeedServo.cpp file (like you said in the beginning!). It works great now.
I recently adopted the VarSpeedServo.h library, and have updated it for Arduino 1.0 and added some new features, including allowing you to have a write() function block until the move is complete, and the ability to create and run sequences of moves asynchronously. I also added example code to the library.
Enjoy!
https://github.com/netlabtoolkit/VarSpeedServo
Hi, I have to control servo sweep with arduino
but, can I use a looping to make the servo on for 2 minute and off for 10 minute?
Thanks
Of course you can …
I need to move the servo randomly and slowly..do you any code block for that please ?
hi
we have made a pick and place robo using arduino.
we used varspeedservo library but as we used mg958 servo motors it aint working properly and we are unable decode why is this happening and where is the fault?
please let us know why is this happening.