Normally, to control a servo with any other micro-controller you would have to cycle a digital output port between high to low for 1 to 2ms depending on the angle you want to set the servo (usually between 0-180 degrees). Depending on the rotational speed of the servo, you would have to determine how long the servo needs to get into position and plan your program accordingly. Sounds like a lot of overhead just to control one little piece of hardware. Thankfully, the Arduino once again has a set of built in functions to take care of most of this for you. You will still need to do a few calculations or trial and error, however, to figure out the delay time.
I visited my local hobby shop, HobbyTown USA, and picked up a standard servo, the HS-322HD. If you're not using the servo for anything important, like in an RC airplane for instance, there's no need to spend more than ten bucks or so on a servo. The HS-322HD would be considered about a medium sized servo and has the following specs.
Picked it up for $9.99 at my local HobbyTown USA |
- Speed: 0.15sec/60 degrees
- Torque: 51oz.in (who uses kg and cm anyways?)
- Resin Bushings
- Karbonite Gears, for an extra dollar over the HS-311, they are supposed to be four times stronger than standard resin gears... why not?
Enough chit-chat, let's get this guy spinning.
There are a few things you need to include before you start coding in order to initialize your servo. The first thing is to add the servo library at the begining of your code: #include <Servo.h>. Then, right below your #define statement you need to create a servo object with a Servo myservo statement. You can set the servo object's name to anything you want, you just need to make sure you are consistent at all instances of the object. It's a good idea to also create a variable to keep track of the position of your servo, i.e. the int pos in the code below. Lastly, in your setup() function you need to assign a digital output pin to your servo object via myservo.attach(#). This would be the Arduino pin that you have plugged the servo's yellow data wire into.
Now that our servo is all set-up, we can start coding. Fun!
The servo's position is controlled with the myservo.write(#) function. You can set the servo's angle from 0 to 180 degrees with this write function. Depending on the distance the servo needs to rotate, you might have to include a delay statement to make sure the servo has enough time to set to the correct position, otherwise the servo may try to move faster than it is able to and overheat. Included in the Arduino IDE are example sketches of how to use a servo, File>Examples>Servo.
Expanding upon the Sweep example code by BARRAGAN, I wrote a program that incorporates the IR sensor from the last blag post.
// 5/30/2011
// http://arduinomega.blogspot.com
// Arduino Mega 2560
//This sketch is used to control a Sharp Long Range IR Sensor mounted on a servo.
//The servo sweeps between 0 to 180 degrees while the IR sensor looks for objects.
//If the IR sensor detects an object within 10 inches of the servo, the servo
//stops moving and the angle of the servo is printed to the Serial Monitor. The
//servo waits until the object is no longer within 10 inches. Once the object has
//passed, the servo goes back to sweeping the area, checking for objects.
#include <Servo.h>
#define sensorIR 15
Servo myservo; // Creates a servo object
int pos = 0; // Variable to store the servos angle
volatile float inches;
void setup()
{
myservo.attach(53); // Assigns data pin to your servo object, must be digital port
Serial.begin(9600);
}
void loop()
{
search();
}
//This function sweeps the servo searching the area for an object within range
void search()
{
for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
sensorPrint(analogRead(sensorIR));
if (inches < 10) follow();
}
for(pos = 180; pos>=1; pos -= 1) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
sensorPrint(analogRead(sensorIR));
if (inches < 10) follow();
}
}
//This function determines the distance from the servo and prints it to the SMonitor
void sensorPrint(float sensorValue)
{
inches = 4192.936 * pow(sensorValue,-0.935) - 3.937; //algorithm from last post
//cm = 10650.08 * pow(sensorValue,-0.935) - 10; //if you use cm instead of in
Serial.print("Inches: ");
Serial.println(inches);
}
//This function only determines the distance from the servo without printing
void noPrint(float sensorValue)
{
inches = 4192.936 * pow(sensorValue,-0.935) - 3.937; //algorithm from last post
//cm = 10650.08 * pow(sensorValue,-0.935) - 10; //if you use cm instead of in
}
//This function keeps the servo locked on the object until it moves out of range
void follow()
{
while (inches < 10)
{
noPrint(analogRead(sensorIR)); //we want to find the distance but not print it
Serial.print("Angle: "); //Current angle of the servo between 0 to 180
Serial.println(pos);
}
}
This is what the program above will be controlling |
It's an IR sensor hot glued to a servo, hot dog! |
By attaching the Sharp Long Range IR sensor from the last blag post to our servo, I created a makeshift proximity detector. The servo sweeps from 0 to 180 degrees while the IR sensor checks for any objects that are within 10 inches of the servo. If an object moves within 10 inches of the servo and is in the IR sensor's line of sight, the servo will stop moving and the angle of the servo is printed to the Serial Monitor. The IR sensor will continue to check the distance of the object and wait until it is no longer within 10 inches of the servo. Once the object has passed, or unfortunately gets closer than 4 inches from the servo... damn blind spot, the servo resumes sweeping the area.
That's some fancy servo action right there I tell you what!
If the servo and IR sensor were mounted to a robot, you could use this code to make sure that your robot doesn't bump into any objects or walls. Once the robot detects that an object is too close, you could have it back up and turn. If you wanted to be even cooler, you could have it sweep the servo one more time after it detects an object and use the IR sensor to determine how far it needs to back up and which way it should turn. By using the IR sensor to see which direction has a further average distance, 0 to 90 degrees vs. 90 to 180 degrees i.e. left vs. right, you can prevent the robot from wasting time backing up and turning into the same wall. Don't always have your robot just blindly back-up and turn right whenever it bumps into something or it may get stuck and freak out. Your robot is only going to be as smart, or stupid, as you program it to be.