3.16. 伺服馬達控制

業餘(RC)伺服馬達是一個裝在密封外殼內的小型減速馬達,內建閉迴路位置控制。外殼內有一個直流馬達、一組減速齒輪箱、一個連接到輸出軸的電位器,以及一塊小型驅動板,用來將電位器的讀數與來自外部的設定值進行比較。驅動板會以能縮小誤差的方向運轉馬達,並在位置吻合時停止。從相機這一側來看,這些都看不見——你只需告訴伺服馬達要轉到哪裡。

3.16.1. PWM 訊號

伺服馬達以固定 50 Hz 影格率的 PWM 訊號作為其設定值,其中 脈衝寬度 決定位置:

  • 1.0 ms 的脈衝會將軸驅動到其行程的一端。

  • 1.5 ms 的脈衝會將軸停在中央。

  • 2.0 ms 的脈衝會將軸驅動到行程的另一端。

介於其間的任何值則對應到中間位置。

三列方波波形垂直堆疊。 每一列顯示一個 50 Hz PWM 的 20 ms 週期, 在起始處有一道狹窄的高脈衝:最上列為 1.0 ms, 中間為 1.5 ms,最下列為 2.0 ms。

伺服馬達的 PWM 影格長 20 ms;脈衝寬度(1.0 -- 2.0 ms)決定位置。

不同於 LED 與馬達,伺服馬達並不會 平均 PWM。脈衝寬度本身就是指令:伺服馬達的內部邏輯會量測每個脈衝、據此設定其目標,並運轉馬達直到輸出吻合。以占空比比例表示的數值(在整個範圍內介於 5 % 與 10 % 之間)只是附帶結果——真正重要的是絕對脈衝寬度,這也是軟體所需控制的對象。

3.16.2. 接線

業餘伺服馬達使用三線接頭:

  • 電源(通常為紅色):伺服馬達自身的供電,通常為 4.8 V 到 6 V。請勿以相機的 3.3 V 電軌為伺服馬達供電——它無法供應堵轉電流,且該電軌會發生電壓驟降。

  • (通常為黑色或棕色):伺服馬達電源的回流路徑,接到相機的地,使訊號也有共同的參考點。

  • 訊號(通常為白色、黃色或橙色):來自相機 GPIO 的 PWM 線。

3.16.3. 程式碼

duty_u16() 也可以用,但它是以週期的比例來設定占空比——對於一個重要的是絕對脈衝寬度、而週期固定的訊號來說,這頗為彆扭。duty_ns() 則直接以奈秒為單位設定脈衝寬度:

from machine import PWM, Pin

servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000)  # centre

載波為 50 Hz(20 ms 週期);每個週期的高準位時間恰為 1500 µs。一個小型輔助函式可讓位置到脈衝的對應關係明確化:

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

在整個範圍內進行緩慢掃描:

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)

1.0 -- 2.0 ms 的範圍是標準值,但許多伺服馬達可接受更寬的範圍(常為 500 µs 到 2500 µs)以達到完整行程。伺服馬達的資料手冊會列出確切的脈衝寬度限制;超出該範圍的數值可能使馬達猛撞到其機械止點。

對於範圍非標準的伺服馬達,請將限制值提取為常數,並將對應關係參數化:

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)