Welcome to our first edition of the micro:bit peripherals in Python series. This is a new series designed to educate micro:bit users on different peripherals. We will explain the peripheral and its uses, describe how to use it with the micro:bit, and provide example Python code to operate it. We hope to make your adventures with Python and the micro:bit just a little bit more enjoyable.
Check out the 60-second demo video here: https://youtu.be/BuOEbXI3Sg4
This first installment is all about continuous rotation servo motors. There are two primary types of servo motors that can be used with the micro:bit: continuous rotation servos and positional rotation servos. We are going to cover positional rotation servos in our next article. For now, continuous rotation servos, you guessed it, can rotate continuously in either direction. These tiny motors can run on small DC power sources. They can provide all kinds of functionality from turning wheels to running pulleys and rotating objects.
All the examples provided below will be done using the FEETECH FS90R Continuous Rotation Servo but will work with nearly any standard RC continuous rotation servo.
SERVO INPUT LINES:
Continuous rotation servos are nearly all identical. They operate under some basic servo principles. Servos generally accept 3 input lines: power, ground, and signal.
The power line can accept a DC power source. You will want to check what voltage your peripheral is rated for before applying power. The FEETECH FS90R was designed to take either 5V or 3V power sources. The power line should be connected directly to the DC power source.
The ground line must be connected to the micro:bit ground. It is important that the two ground lines are connected so that the servo has a reference to use for the Signal line.
The signal line is connected to one of the Input / Output attachment points on the micro:bit. This signal line is where the magic happens when controlling a servo. This signal controls whether the servo is rotating, how fast it is rotating, and which direction it is turning.
THE SIGNAL:
To operate a servo we must send it a 50 Hertz (Hz) pulsed signal. This is a standard for nearly all DC servo motors. A pulsed signal looks like this:
50 Hz means one pulse happens 50 times every second. If you break it down another way, one pulse is sent every 1/50th of a second which equals 20 milliseconds (ms for short).
Continuous servo motors also operate with the following rules.
- If the pulse is high or “ON” for 1.0 ms during those 20 ms then the Servo will run at 100% speed in the clockwise direction
- If the pulse is high or “ON” for 1.5 ms during those 20 ms then the Servo is considered stopped
- If the pulse is high or “ON” for 2.0 ms during those 20 ms then the Servo will run at 100% speed in the counterclockwise direction
You can also set anything in between to get less than 100% speed. For example: setting the pulse high for 1.2 ms will run the servo at 60% speed in the clockwise direction. See the table below for more values.
Pulse High Time |
Percent Power |
Direction |
1.0 ms |
100% |
Clockwise |
1.1 ms |
80% |
Clockwise |
1.2 ms |
60% |
Clockwise |
1.3 ms |
40% |
Clockwise |
1.4 ms |
20% |
Clockwise |
1.5 ms |
0% |
Stopped |
1.6 ms |
20% |
Counterclockwise |
1.7 ms |
40% |
Counterclockwise |
1.8 ms |
60% |
Counterclockwise |
1.9 ms |
80% |
Counterclockwise |
2.0 ms |
100% |
Counterclockwise |
Now let’s see how that 1.2 ms setting would look in pulse form.
HOW THE MICRO:BIT OUTPUT WORKS:
In order to send this pulsed signal, we need to configure the micro:bit properly. Luckily for us, the micro:bit can send a Pulse-Width Modulation (PWM) signal. This signal is exactly what we want. So how do we configure it to work?
First, we need to set the length of one pulse to be 20 milliseconds. We do this by using the set_analog_period function on a pin. This function takes an input of milliseconds - PERFECT!! We would write the following in Python code:
pin0.set_analog_period(20)
Halfway there. The next step is to set the pulse to be on for 1.2 milliseconds. We do this by writing data out on the pin with the write_analog function on a pin. This function takes an input in the range of 0 to 1023. This sets the “duty cycle” of the periodic pulse. For example:
0 = the line is high or “ON” 0% of the time
511 = the line is high 50% of the time
1023 = the line is high 100% of the time
To use this function for our 1.2ms pulse example, we are going to have to convert 1.2 ms to a percentage of time the line is high. Since our period is 20ms, we can just use a ratio:
1.2 ms / 20 ms = 6%
Now we multiply the maximum input value (1023) by the percent of time the line needs to be high (6%) and we have our input value for the write_analog function:
Input value = 1023 * 6% = 61.38
So now we could write:
pin0.write_analog(61)
We could also write the following and let the micro:bit take care of this calculation for us:
pin0.write_analog(1023 * 1.2 / 20)
To recap. With just two short lines of code you can get your continuous servo motor running at 60% speed in the clockwise direction:
# Run servo clockwise at 60% speed
pin0.set_analog_period(20) # Send pulses at 50 Hz
pin0.write_analog(1023 * 1.2 / 20) # Each pulse is 1.2 ms
HOW TO RUN THE EXAMPLES:
When running any of the code samples below you should:
- Connect the servo as outlined in one of the diagrams below.
- Type one of the code examples below into CodeSpace: https://make.firialabs.com
- Run the example (do not press any buttons on the micro:bit yet)
- If your servo is turning when it should be stopped, you may need to adjust it.
- For the FS90R rotate the screw on the bottom of the servo with a screwdriver until it comes to a complete stop (and it stops making any noise)
- If your servo is turning when it should be stopped, you may need to adjust it.
SETTING UP THE DEVICE:
Shown below are two possible wiring options:
- Connect the micro:bit to USB / battery power and the servo to the micro:bit.
NOTE: Using the micro:bit to power the servo directly is simple, but beware that some servos require more power than the USB can deliver reliably in this way. Connecting an external battery pack to the micro:bit’s battery connector is recommended.
- Power the servo from its own 3 - 6V power supply, but connect all grounds together. For large, powerful servos this is required due to the power needs of the servo.
Note: In this configuration the battery pack shown is powering the servo, but not the micro:bit. Be very careful with the battery (+/-) polarity, or you could damage your micro:bit!
Python Code Examples:
CODE EXAMPLE 1: BARE MINIMUM CODE
This code demonstrates the fundamentals of controlling a servo, with the minimum amount of Python code necessary to do the work!
CODE EXAMPLE 2: AN EXAMPLE WITH FUNCTIONS
This code extends the first example with a function, to make it easier and clearer to control one or more servos in your main program.
CODE EXAMPLE 3: AN OBJECT-ORIENTED “CLASS” EXAMPLE
This code defines a Python class to encapsulate the servo functions. If you have multiple servos you can create instances of this class for each one based on the pin it's connected to.