How servo_test_angles Works
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).
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 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.
Try This
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.
- In the python.microbit.org, set the project name field and the line-1 comment to servo_test_angles_just_0_degrees.
- Remove all but the 0° position setting from the script by adding the three apostrophes '" shown on lines 10 and 17. The three apostrophes change everything between them into a block comment that the MicroPython runtime ignores.
- Make sure the script matches the one shown below, then click Save.
- Click Send to micro:bit.
- Pull the horn up and off the output shaft.
- In most cases, the horn’s and output shaft’s teeth will not align at exactly 0°, so find the closest of the two alignments.
- Update the project name field to servo_test_angles_tuning.
- Remove the lines with the three apostrophes.
- Adjust the 26 in pin16.write_analog(26) to improve alignment with 0°. To make the horn point further upward, increase the value above 26. To make it point further downward, decrease the value below 26. Repeat, update, and flash until you feel like it is as close as possible to 0°.
- Repeat for the other pin16.write_analog statements.
- After the servo positions have been tuned to your satisfaction, click Save.