A hobby servo is a small device that controls the position of flaps, rudders, and steering in many radio-controlled toy planes, boats, and cars. The Parallax Standard Servo is a hobby servo, and it’s also useful in many robotics and animatronics projects. Since it can both move to and hold a position, it is ideal for tasks like rotating a distance sensor or controlling the fingers in a robotic hand.
This tutorial will show you how to make a servo hold three different positions, and then guides you through creating smooth, continuous motion through small, evenly-timed changes in position.
(1) Parallax Standard Servo (#900-00005) [1]
(1) 3” Jumper Wire (#800-00016)
(1) Power supply. Options include:
A servo can draw more current than a USB port can supply, so you’ll need to plug an external power supply into the Activity Board’s 6 to 9 V power jack. Since the Parallax Standard Servo is rated for a 4 to 6 V supply, you may also need to move the Activity Board’s servo port power jumper settings to regulated 5V.
There are three pins to the immediate left of each pair of servo ports on the Propeller Activity Board (original or WX version). A small metal and plastic jumper can connect the middle pin to either the top or the bottom power pin. This is the power-select jumper for that pair of servo ports. When the jumper is over the bottom and middle pins, the pair ports' V+ pins receive 5 VDC through the board's voltage regulator. When the jumper is over the middle and top pins, the ports' V+ pins receive unregulated voltage directly from the power supply connected to the board.
It helps to make some sort of angle marker on the turning part of the servo (called its control horn) to know what position it is in. A jumper wire is handy for this.
If you haven't already installed the latest USB driver, SimpleIDE, or Learn folder, go to Propeller C - Set up SimpleIDE [2] and Propeller C - Start Simple [3].
The servo test code will move the servo to the three positions shown below (0°, 90°, and 180° ) with three seconds to move between and hold each position. While the program is running, the servo will resist any attempt to move it out of position. When the program finishes, the servo will stop resisting.
The servo_angle() function call takes two parameters: the pin the servo is connected to and the servo angle in tenths of a degree. For example, to make the servo connected to P16 turn to 90 degrees, the program uses servo_angle(16, 900). Keep in mind servo_angle() does not wait for the servo to get into position—it is necessary to include a pause for the servo to reach the desired position before setting a new angle.
/* Standard Servo Position.c Moves servo to 0, 90 and 180 degrees. Holds each position for 3 s. Connect servo to P16 port on Propeller Activity Board. */ #include "simpletools.h" // Include simpletools header #include "servo.h" // Include servo header int main() // main function { servo_angle(16, 0); // P16 servo to 0 degrees pause(3000); // ...for 3 seconds servo_angle(16, 900); // P16 servo to 90 degrees pause(3000); // ...for 3 seconds servo_angle(16, 1800); // P16 servo to 180 degrees pause(3000); // ...for 3 seconds servo_stop(); // Stop servo process }
Satellite dish image source: https://commons.wikimedia.org/wiki/File:Goldstone_DSN_antenna.jpg [4]
Servos aren’t just for hobbies. Much larger servos are used to precisely aim the position of huge satellite dishes towards extraterrestrial targets, like those in the Deep Space Network (above, left). Additionally, most robotic hands (like the one above that is preparing to make sign for number 7 in ASL, right, though it can't quite reach since the palm is not articulated.) are actuated by servos. Depending on how many independent degrees of freedom the hand has, it could use dozens of servos! The hand above is actuated using five standard servos.
Let’s use a feature called ramping to make the servo move to new positions gradually. Ramping “cushions” or “smooths-out” the servo’s responses to large or sudden changes in sensor measurements by limiting how much it can change position over a given amount of time. This servo control library's servo_setramp() function takes two parameters: the servo’s pin, and the speed at which the servo will change in tenths of a degree per 50th of a second.
Once servo_setramp() is called, every servo_angle() call that follows it will move at the rate set by servo_setramp. Without this command, the servo will always move to new positions at its maximum speed. In this example, the servo will move to its first two positions at full speed just like it did in the program above. Then servo_setramp(16, 8) will slow it down to .8° per 50th of a second as it moves to the last two positions.
In this example, the servo moved from 180 degrees back to 90 degrees more gradually because of servo_setramp(), but it still made it there and paused. What do you think would happen if you changed the rate to .5 degrees per 50th of a second? Would the servo make it to 180 degrees before turning back? Try it!
Imagine you’re the engineer in charge of animatronic devices at an amusement park. Let’s say one exhibit contains two servos for its face, and needs to display five expressions, one each thirty seconds. One way to do this would be by storing these expressions in two arrays (one for each servo).
If you haven’t worked with array variables before, check out the Array Variables [5] tutorial. Then, try the Index Array Variables [6] tutorial and pay close attention to how the code loops through an array using a for loop and then uses print() to display the values. Instead of displaying the values in the arrays with print(), you can send them to a servo with servo_angle().
Here is some code where we give print() p[i] as an input. Think about how you would change print() to servo_angle() so that it uses the indexed array value p[1] as the angle, and keep in mind you’ll need to increase the pause.
int p[] = {100, 200, 300, 500, 700, 1100}; // Initialize the array for(int i = 0; i < 6; i++) // Count i from 0 to 5 { pause(500); // 1/2 second pause print("p[%d] = %d\n", i, p[i]); // Display array element & value }
Add a P17 servo to your code. You can still test this code if you only have one servo. Run the code with the servo connected to P16 first, then turn off your board and switch the connection to P17. Run the test again to verify that if you had two servos, they would be working correctly and independently.
Links
[1] http://www.parallax.com/product/900-00005
[2] https://learn.parallax.com/propeller-c-set-simpleide
[3] https://learn.parallax.com/propeller-c-start-simple
[4] https://commons.wikimedia.org/wiki/File:Goldstone_DSN_antenna.jpg
[5] https://learn.parallax.com/propeller-c-start-simple/array-variables
[6] https://learn.parallax.com/propeller-c-start-simple/index-array-variables