A hobby servo is normally used to hold the positions of radio controlled model airplane flaps, boat rudders, and car steering. A micro servo is one of the smallest versions of hobby servos. Hobby servos also come in continuous rotation versions which can be used to drive wheels of rolling robots, but the one in your kit is the standard variety that turns to and holds a position.
In this activity, you will:
The servo comes with several different shapes of “horns”. When the servo is built into a radio controlled model boat/airplane/car, screws and linkages connect a horn to the rudder, flap, or steering. Screws go through the mounting flanges to attach the servo’s case to the body or frame of the model plane/boat/car.
The servo is connected to supply voltage and a control signal through the plug and cable. The control signal, which the micro:bit will send, tells the servo what angle to point the horn. Last but not least, since the horn needs to stay connected to the servo’s output shaft, a screw holds the two together.
(1) Resistor - 220 Ω (red-red-brown-gold)
(1) Jumper wire - Red
(1) Jumper wire - Black
(1) Hobby micro servo
(1) Single horn
(1) Battery holder
We will not be using a screw to attach the horn to the output shaft in these activities. (If you end up using the servo to move a light load, use the screw that came with it to cinch the horn to the output shaft at that point. )
The servo has built-in motion limiters that allow it about a 200° range of motion. Follow these steps to mount the servo horn so that 200° of motion allows the horn to point from 190° to -10° (with 90° being the halfway point).
The first step to connecting the servo is to build a servo port. The port needs to connect to power, ground, and a micro:bit I/O pin so the servo can receive a control signal.
Next, you will connect the servo to the port. The servo’s three wires need to be connected as follows:
If you got the assembly instructions right, the servo_test_angles should make the servo horn point at 0°, 45°, 90°, and 180°. Don’t expect it to be precise, just reasonably close.
Example script: servo_test_angles
# servo_test_angles from microbit import * pin16.set_analog_period(20) while True: pin16.write_analog(26) # 25.6 -> 500 us -> 0 degrees sleep(4000) pin16.write_analog(51) # 51.2 -> 1000 us -> 45 degrees sleep(4000) pin16.write_analog(77) # 76.8 -> 1500 us -> 90 degrees sleep(4000) pin16.write_analog(128) # 128.0 -> 2500 us -> 180 degrees sleep(4000)
THE ANGLES WILL NOT BE PRECISE. If the horn points somewhere near each angle shown, that’ll be fine for now.
Let’s say you had to reduce the statement that positions the servo at 180° from pin16.write_analog(128) to pin16.write_analog(126). You could also try subtracting 2 from the other pin16.write_analog statements. For example, instead of 77, 51, and 26, you could try 75, 49, and 24.
Electrical and electronic parts typically have “manufacturing variations”. These are differences in the way an electrical or electronic part behaves. For example, the resistors in your kit all have gold bands, which means that they will be within 5% of the color coded value. Other resistors might have silver bands with 10%, or no band for 20%.
In the case of the hobby micro servo, one of them might measure a control signal from the micro:bit a little differently than another servo might. Even though the micro:bit, which has fairly precise timing, is sending the right signal, the servo might think the signal is “out of range”. When this happens, it holds the position of the most recent signal that was in-range.
If you are focusing on code to control the servo, pin16.set_analog_period(20) sets up the servo signal, and then pin16.write_analog(value) sets the servo’s position. For the servo, value has to be in the 26 to 128 range, and the resulting angle is in the 0° to 180° range.
Let’s take a closer look. The pin16.set_analog_period(20) statement tells the micro:bit to get ready to repeatedly set P16 high some fraction of 20 ms, and low for the rest of the time.
pin16.set_analog_period(20)
After that, a statement like pin16.write_analog(value) sets the pin high for value/1024ths of that 20 ms, and low the rest of the time. The signal that tells the servo what position to hold is like having a light that blinks at 50 Hz. Fifty LED blinks per second would be too fast for the human eye to discern, but a signal that would make a light blink that fast is what the servo needs for position information. Also, the on-times that actually tell the servo what direction to point are in the 0.5 ms to 2.5 ms range. It’s already impossible for the human eye to discern 50 blinks per second, but to tell the difference between on for 0.5 ms and on for 2.5 ms… Well, the LED would appear to be dim with 2.5 ms high times, and even dimmer with 0.5 ms high times.
The servo control signal the micro:bit script sends via P16 might not be easy for us to decipher, but it contains the position information the servo needs. Here are examples of the on/off signals plotted over time, and how they affect the servo’s position. As you will soon see, the results are not exactly the 0.5, 1.0, 1.5 and 2.5 ms values shown in the animation (See the mp4 here [2]).
Servo signal specifications assume the period of the signal is 20 ms, and then they equate an on-time to a servo position. For this micro-servo, an on time of 0.5 ms results in 0°, an on time of 1.5 ms results in 90°, and an on time of 2.5 ms results in an angle of 180°.
Remember from On-Off Signals [3] that a repeating on/off signal has a period T = tHIGH + tLOW. It also has a percent duty cycle of %DC = tHIGH / (tHIGH + tLOW).
The pin16.set_analog_period(20) call sets the period to 20 ms. That's T = tHIGH + tLOW = 20 ms.
The pin16.write_analog(value) sets the duty cycle as 1024ths of 20 ms. So, the signal high or on time works out to this:
tHIGH = value x 20 ms / 1024.
Example: What’s the actual high time from pin16.write_analog(26)?
Solution:
tHIGH = value x 20 ms / 1024
= 26 x 20 ms / 1024
≈ 0.508 ms
( close to 0.5 ms)
Example: What’s the actual high time from pin16.write_analog(51)?
Solution:
tHIGH = value x 20 ms / 1024
= 51 x 20 ms / 1024
≈ 0.996 ms
( close to 1.0 ms)
Keep in mind this high time is not just one pulse (blink). It is repeated 50 times per second. These repetitions continue while the servo is moving to its new position, and also to make the servo hold its position against opposing forces after it reaches its new position.
Tuning the angles takes three steps. First, make sure the horn is aligned as closely as possible to 0° when the script positions it there. Second, adjust the script to improve 0° alignment. Third, adjust the script to improve the accuracy of the other positions.
Two equations in two unknowns can be used to derive a formula for turning the servo to an angle of your choice. The final result needs to be y = mx + b, where x is the desired angle in degrees, and y is the argument for write_analog.
After solving for unknowns of m and b, we’ll have an equation that can be used in hand calculations, or in a script. You can also rearrange the terms in y = mx + b to x = (y - b) / m to solve for the angle if only the write_analog argument is known.
Since we want to be able to solve for the write_analog argument, let’s set y1 to 25.6 and y2 to 128.0. Then, x1 should be 0° and x2 should be 180°. The animation below shows how to solve for m and b. (See the .mp4 here.) [4]
With these formulas, you can calculate:
y = 0.5689x + 25.6 duty cycle if angle is known
x = (y - 25.6) / 0.5689 angle if duty cycle is known
Example: The angle we want is 30°, calculate the duty cycle..
y = m x + b
= 0.5689 x 30 + 25.6
= 17.067 + 25.6
= 42.667
≈ 43
Example: The duty cycle is 43, what’s the resulting angle?
x = (y - 25.6) / 0.5689
= (43-25.6) / 0.5689
= 17.4 / 0.5689
≈ 30.59
≈ 31
Keep in mind that 26...128 is 103 possible integer duty cycle values (including 26). There would have to be more than 180 or more possible integers to get closer to all possible servo degree angles. Other microcontrollers do have the ability to split this duty cycle range into many hundreds or even thousands of integer options.
You can control the servo’s position with the Serial terminal, entering integers in the 23...128 range to set the servo horn’s angle.
Example script: terminal_controlled_servo
# terminal_controlled_servo from microbit import * pin16.set_analog_period(20) print("Enter values in 26 to 128 range...") while True: text = input("Enter value >") y = int(text) if y < 129 and y > 25: pin16.write_analog(y) x = (y - 25.6) / 0.5699 print("servo degrees:", x)
Your challenge is to modify the script so that you can enter degree values in the 0 to 180 range, and it will correctly calculate and set the position.
Hints:
tHIGH = value x 20 ms / 1024 = 77 x 20 ms / 1024 ≈ 1.504 ms ( close to 1.5 ms)
1. Solution:
# servo_bounce_between_1 from microbit import * pin16.set_analog_period(20) while True: pin16.write_analog(26) # 0 degrees sleep(4000) pin16.write_analog(34) # 15 degrees sleep(4000)
2. Solution:
from microbit import * pin16.set_analog_period(20) print("Enter values in 51 to 102 range...") while True: text = input("Enter value >") y = int(text) if y < 103 and y > 50: pin16.write_analog(y) x = (y - 25.6) / 0.5699 print("servo degrees:", x)
3. Solution:
# terminal_controlled_servo_error from microbit import * pin16.set_analog_period(20) print("Enter values in 26 to 128 range...") while True: text = input("Enter value >") y = int(text) if y < 129 and y > 25: pin16.write_analog(y) x = (y - 25.6) / 0.5699 print("servo degrees:", x) else: print("Error, out of range")
Links
[1] https://python.microbit.org/v/2
[2] https://learn.parallax.com/sites/default/files/content/Python/servo/servo-connect-how-servo-sig-xfer-funct.mp4
[3] https://learn.parallax.com/tutorials/language/python/led-lights/connect-and-blink-light/signals
[4] https://learn.parallax.com/sites/default/files/content/Python/servo/derive-angle-to-write-analog-argument.mp4
[5] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk
[6] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk/scripts-print-terminal
[7] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk/input-messages
[8] https://learn.parallax.com/tutorials/robot/cyberbot/computer-microbit-talk/inputprint-applications