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.

Drie rijen blokgolfsporen verticaal gestapeld. Elke rij toont één periode van 20 ms van een 50 Hz PWM met een smalle hoge puls aan het begin: 1,0 ms in de bovenste rij, 1,5 ms in het midden, 2,0 ms in de onderste.

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)