3.16. Servobesturing¶
Een hobby- (RC-)servo is een kleine vertraagde motor in een afgesloten behuizing met ingebouwde positiebesturing met gesloten lus. In de behuizing zit een DC-motor, een reductietandwielkast, een potentiometer die met de uitgangsas is verbonden, en een klein driverbord dat de uitlezing van de pot vergelijkt met een setpoint dat van buitenaf binnenkomt. De driver laat de motor draaien in de richting die de fout verkleint, en stopt wanneer de positie overeenkomt. Vanaf de kant van de camera is niets daarvan zichtbaar – je vertelt de servo gewoon waar hij heen moet.
3.16.1. Het PWM-signaal¶
Een servo neemt zijn setpoint als een PWM-signaal met een vaste frame rate van 50 Hz, waarbij de pulsbreedte de positie selecteert:
Een puls van 1,0 ms stuurt de as naar het ene uiteinde van zijn slag.
Een puls van 1,5 ms parkeert de as in het midden.
Een puls van 2,0 ms stuurt de as naar het andere uiteinde.
Alles daartussenin wordt afgebeeld op een tussenliggende positie.
Het PWM-frame van de servo is 20 ms lang; de pulsbreedte (1,0 – 2,0 ms) selecteert de positie.¶
Anders dan LED’s en motoren middelt de servo de PWM niet. De pulsbreedte zelf is het commando: de interne logica van de servo meet elke puls, stelt zijn doel dienovereenkomstig in, en laat de motor draaien totdat de uitgang overeenkomt. De duty cycle als fractie (tussen 5 % en 10 % over het volledige bereik) is bijkomstig – het is de absolute pulsbreedte die ertoe doet, en dat is wat software moet besturen.
3.16.2. Bedrading¶
Hobbyservo’s gebruiken een driedraads connector:
Voeding (meestal rood): de eigen voeding van de servo, doorgaans 4,8 V tot 6 V. Voed de servo niet vanaf de 3,3 V-rail van de camera – die kan de blokkeerstroom niet leveren, en de rail zal inzakken.
Massa (meestal zwart of bruin): het retourpad voor de voeding van de servo, verbonden met de massa van de camera zodat het signaal ook een gedeelde referentie heeft.
Signaal (meestal wit, geel of oranje): de PWM-lijn van de GPIO van de camera.
3.16.3. Code¶
duty_u16() zou werken, maar stelt de duty in als een fractie van de periode – onhandig voor een signaal waarbij de absolute pulsbreedte ertoe doet en de periode vast is. duty_ns() stelt de pulsbreedte rechtstreeks in nanoseconden in:
from machine import PWM, Pin
servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000) # centre
De drager is 50 Hz (periode van 20 ms); de hoge tijd in elke cyclus is precies 1500 µs. Een kleine helper maakt de afbeelding van positie naar puls expliciet:
def set_position(angle):
# angle: 0..180 degrees mapped to 1.0..2.0 ms
pulse_us = 1000 + (angle * 1000) // 180
servo.duty_ns(pulse_us * 1000)
set_position(0) # full one way
set_position(90) # centre
set_position(180) # full the other way
Een langzame sweep over het bereik:
import time
for angle in range(0, 181, 5):
set_position(angle)
time.sleep_ms(20)
for angle in range(180, -1, -5):
set_position(angle)
time.sleep_ms(20)
Het bereik van 1,0 – 2,0 ms is de standaard, maar veel servo’s accepteren een breder bereik (vaak 500 µs tot 2500 µs) voor de volledige slag. Het datasheet van de servo vermeldt de exacte pulsbreedtegrenzen; getallen buiten dat bereik kunnen de motor tegen zijn mechanische aanslagen rammen.
Voor een servo met een niet-standaard bereik haal je de grenzen in constanten en parametriseer je de afbeelding:
PULSE_MIN_US = 500 # full one way (from the data sheet)
PULSE_MAX_US = 2500 # full the other way
def set_position(angle):
span_us = PULSE_MAX_US - PULSE_MIN_US
pulse_us = PULSE_MIN_US + (angle * span_us) // 180
servo.duty_ns(pulse_us * 1000)