概要
Raspberry Pi Pico 2W + MicroPython の PWM でサーボモーター(MG996R)を角度制御していると、「500〜2500usで0〜180度」というカタログ通りの前提で組んでも、実機では指定した角度からズレることがあります。実測で分度器を当ててキャリブレーションした方法と、途中でハマった2つの勘違いをまとめます。
つまずいたポイント1: sleep不足で「動いている途中」を最終角度と誤認していた
最初、set_angle(180) を実行すると「180度のはずが実機は120度くらいしか動いていない」ように見えて混乱しました。パルス幅を直接指定して数秒間静止させて確認するテストに切り替えたところ、同じ値でも実際は約190度動いていたことが判明します。
原因は MG996R の移動速度(0.17秒/60度程度)に対して time.sleep() が短すぎ、まだ回転している「移動途中」の角度を最終角度と誤認していた ことでした。確認用の待機時間は1〜3秒に伸ばす必要があります。
from machine import Pin, PWM
import time
servo = PWM(Pin(15))
servo.freq(50)
def set_pulse_us(us):
servo.duty_ns(int(us * 1000))
for us in (500, 1500, 2500):
print(f"パルス幅 {us}us に設定します。実機の角度を確認してください。")
set_pulse_us(us)
time.sleep(3) # ← ここが短いと「移動途中」を見てしまう
つまずいたポイント2: 公称180度のはずが実測198度、しかも上限/下限で余裕が非対称だった
分度器で実測すると、500〜2500us の範囲で実際には約198度動く個体でした。安価なクローン品ではこの手の個体差がよくあります。
さらに、サーボホーン(アーム)はスプライン(ギザギザの溝)構造のため任意の角度には物理的に取り付けられず、狙った0度の位置には固定できませんでした。これは物理的に付け直すのではなく、プログラム側にオフセットを持たせて吸収 します。
MIN_US, MAX_US = 500, 2340
HORN_OFFSET_DEG = 7 # ホーンの取り付けズレを補正するオフセット
def set_angle(angle):
corrected_angle = angle + HORN_OFFSET_DEG
pulse_width_us = MIN_US + (corrected_angle / 180) * (MAX_US - MIN_US)
servo.duty_ns(int(pulse_width_us * 1000))
補正の方向を決める際、逆方向(HORN_OFFSET_DEG = -7)も試したところストールしました。下限側を細かく調べると us=470 で唸り始める のに対し、上限側は us=2500 相当まで唸らずに動いており、上限には約18度分、下限にはわずか3度分の余裕しかない という非対称な結果でした。この結果から、余裕のある上限方向(+7)を補正に採用しています。個体差を疑うときは、片方向だけでなく上限・下限それぞれの限界を実測することをおすすめします。
完全なソースコードと手順はブログにまとめています
配線図、部品一覧、freq(50) の意味などPWM制御の基礎、簡易分度器を使った実測手順の写真、キャリブレーション後の実測確認値、タクトスイッチで角度を変える発展編への導線まで、以下の記事に書いています。
