今回は SG90 サーボモーター を使って、「角度を数値で指定して位置を決める」 モーター制御の基本を学びます。サーボモーターは 「0° から 180° まで自由な角度に止まるモーター」 で、ロボットアームの関節、ラジコンの舵、自動開閉ドアのレバーなど、「決まった位置に正確に動かしたい場面」 で大活躍する部品です。ラジコンサーボとも呼ばれ、SG90 は世界で最もよく使われる入門用サーボの一つです。
- SG90 サーボの 3 本線(VCC・GND・PWM 信号)の役割
- PWM 50Hz(周期 20ms) と パルス幅 500〜2400μs で角度が決まる仕組み
- 角度を 0°〜180° でリテラル指定する基本ブロック
- 角度に 変数や式 を差し込める
pico_servo_angle_val新ブロック - #05 の可変抵抗や #09 の超音波センサーと組み合わせた センサー連動制御
- Pico の 3.3V ピンでは電流不足。VBUS(5V) または外部電源 を使う注意
今回は PycoBlocks(MicroPythonモード) の 「モーター」カテゴリ にある「サーボ」 ブロックを使います。角度を 0〜180 の数字で指定するだけ でサーボが回転するシンプルなブロックで、内部では PWM(Pin(15), freq=50) を初期化し duty_u16 値をパルス幅に換算して送る処理が自動で行われます。

SG90 サーボの基礎:仕様と外観
SG90 は青いプラスチックボディに 白いプラスチックホーン(U字型・十字型・円盤型の付属品から選ぶ)が付いた、重さ約 9g・出力 1.8kg・cm の小型サーボです。3 本のリード線(茶=GND・赤=VCC・橙またはオレンジ=PWM 信号)が出ており、コネクタは 2.54mm ピッチの 3 ピンメス。ジャンパーワイヤー(オス→オス)でブレッドボードに繋ぐか、オス→メスのジャンパーで直接 Pico に繋ぎます。
| 項目 | SG90 仕様 | 備考 |
|---|---|---|
| 動作電圧 | 4.8〜6V(推奨 5V) | Pico の VBUS が便利 |
| 動作角度 | 約 180°(0°〜180°) | 個体差で 170〜200° 程度 |
| トルク | 1.8kg・cm(@4.8V) | 小型ロボット・小物制御に十分 |
| 速度 | 0.1秒/60° | 180° 動くのに約 0.3 秒 |
| 制御信号 | PWM 50Hz | 周期 20ms 固定 |
| パルス幅 | 500〜2400μs | 0°=500μs / 90°=1500μs / 180°=2400μs |
| 消費電流 | 動作時 100〜300mA、停動時 800mA | Pico の 3.3V では足りない |
| 重さ | 9g | ドローン・小型ロボに最適 |
| 価格 | 200〜500円 | 互換品も多数 |
PWM 50Hz の仕組み:パルス幅で角度を決める
サーボの角度は 「PWM 信号のパルス幅(HIGH の長さ)」 で決まります。サーボに送る信号は 「周期 20ms(50Hz)の中で短いパルスを出す」 形で、パルスの幅(HIGH の時間)を変える ことでサーボ内部の電子回路が「今この角度にいなさい」 と判断します。

# PWM 信号の波形イメージ(周期 20ms = 50Hz)
#
# HIGH ──┐ ┌─
# │ 幅 W μs │
# LOW └────────────────────────┘
# |← 20ms 周期 →|
#
# W = 500μs → 角度 0°
# W = 1500μs → 角度 90°(中央)
# W = 2400μs → 角度 180°
#
# Pico では PWM(Pin(15), freq=50) で周期 20ms (=1/50秒) を作る
# duty_u16 値(0〜65535)= W ÷ 20000 × 65535
# 500μs → duty_u16 ≈ 1638
# 1500μs → duty_u16 ≈ 4915
# 2400μs → duty_u16 ≈ 7864
PycoBlocks の 「サーボ」ブロック は、この計算を内部で自動的に行います。ユーザーは 「サーボ ピン GP15 を 90 度に回す」 と書くだけで、PWM(Pin(15), freq=50).duty_u16(1638 + 90 × 8192 // 180) という MicroPython コードが生成されます。数式の 1638 は 0° のパルス幅(500μs に相当する duty_u16)、8192 は 180° で増える分(2400 - 500 = 1900μs ≈ 6226 だが SG90 個体差に合わせ少し広め)です。
配線:3 本線をどう繋ぐか
SG90 の 3 本線をそれぞれ正しく繋ぎます。順番を間違えるとサーボが壊れることがあるので慎重に。
| SG90 のリード | 色(一般的) | Pico の繋ぎ先 | 役割 |
|---|---|---|---|
| VCC | 赤 | VBUS(5V) 推奨/3.3V は NG | サーボの電源 |
| GND | 茶 または 黒 | GND(どれか) | 共通グランド |
| PWM 信号 | 橙 または 黄 | GP15 など好きな PWM ピン | 角度指令 |
⚠️ 電源の重要な注意

ステップ1:サーボを 90° に動かしてみよう
まずは 1 回だけ角度を指定して動かす 基本コードです。「サーボ」ブロック の ピン GP15・角度 90 度 をひとつ置くだけ。実行ボタンを押すと、サーボのホーン(白い羽根)が 中央位置(90°)に瞬時に動いて止まるのが見えます。

from machine import PWM, Pin
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + 90 * 8192 // 180))
動作確認のコツ:サーボのホーンの初期位置はランダムなので、最初の 1 回目の実行で「ガッ」と中央に動く様子が見えます。2 回目以降は すでに 90° にいる ので動きません。角度を 0、45、135、180 などに変えて再実行 すると、その都度ホーンが該当位置にジャンプします。ホーンに鉛筆を貼り付けて 0/90/180 の位置を分度器で測ってみる と、実際の角度が指定値通りかを確認できます。
ステップ2:0° → 180° を行ったり来たりスイープしよう
サーボらしい動きを見るために、角度を 0° から 180° まで連続的に変えてみます。「変数 a を 0 から 180 まで 10 ずつ繰り返す」 ループの中で、新ブロック 「サーボ角度 a」(角度に変数を差し込めるバージョン)を呼び出します。0.05 秒ごとに 10° ずつ動かす と、ちょうどよい速さでホーンが扇形にスイープする様子が見られます。戻りは 180° → 0°(ステップ -10) のループでもう一度書き、forever でこれを繰り返します。

pico_servo_angle_val ブロックで、角度に変数や計算式を差し込めます。from machine import PWM, Pin
import utime
while True:
for a in range(0, 181, 10):
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + max(0, min(180, a)) * 8192 // 180))
utime.sleep(0.05)
for a in range(180, -1, -10):
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + max(0, min(180, a)) * 8192 // 180))
utime.sleep(0.05)
📝 新ブロック pico_servo_angle_val について
動作確認のコツ:「ジー、ジー」と低い駆動音 が聞こえながら、ホーンが扇のように左右に振れます。動きがカクついたり、途中で止まる 場合は電源不足のサインなので、Pico の VBUS から直接給電 しているか確認してください。スピードを速くしたい なら 0.05 を 0.02 に、ゆっくり動かしたい なら 0.1 に変えて感触を試しましょう。
演習課題
課題3-12-1:角度・パルス幅・duty_u16 の対応表を作ろう
サーボ制御は 「角度 → パルス幅 → duty_u16」 の 3 段階の変換が肝です。公式を整理して、いくつかの角度について計算してみましょう。
パルス幅の式(今回採用): W [μs] = 500 + 角度 × (2400 - 500) / 180 ≒ 500 + 角度 × 10.56
duty_u16 の式(Pico の PWM 50Hz): duty_u16 = W ÷ 20000 × 65535 = 1638 + 角度 × 8192 / 180
問1: 角度 0°、45°、90°、135°、180° のとき、それぞれの パルス幅 W [μs] と duty_u16 を求めよ。
問2: duty_u16 = 3000 のとき、サーボはおよそ何度を指すか。
問3: もし freq=100(100Hz、周期 10ms)に変えてしまうと、サーボはどうなるか予想せよ。
▶ 模範解答と解説を見る
# 問1: 角度 → パルス幅 → duty_u16
for a in [0, 45, 90, 135, 180]:
W = 500 + a * (2400 - 500) / 180
d = 1638 + a * 8192 // 180
print(f'{a}° : W={W:.0f}μs / duty_u16={d}')
# 0° : W=500μs / duty_u16=1638
# 45° : W=975μs / duty_u16=3686
# 90° : W=1450μs / duty_u16=5734(=1638+4096)
# 135° : W=1925μs / duty_u16=7782
# 180° : W=2400μs / duty_u16=9830(=1638+8192)
# 問2: duty_u16=3000 から角度を逆算
# d = 1638 + a × 8192/180
# a = (3000 - 1638) × 180 / 8192 ≈ 29.9°
# 問3: freq=100Hz に変えると周期は 10ms。
# パルス幅 500〜2400μs はそのままでも、サーボ側は
# 「20ms 周期の信号」を前提に作られているので、
# 動きが不安定になる、唸る、過熱する等の不具合が起きる。
# SG90 は freq=50(=20ms 周期)固定で使うのがルール。
解説: 解説:サーボ制御の 「3 段階変換」 を頭に入れておくと、別のサーボ(例:MG996R / DS3218 など)でパルス幅範囲が違うときも、「最小パルス幅と最大パルス幅をデータシートで確認 → 1638 と 8192 を置き換える」 という流れで対応できます。キャリブレーション:個体差で 0° のホーン位置がズレているサーボには、1638 を 1500 に下げるなどの調整が必要なことがあります(ピアノの調律のように)。SG90 の連続回転改造版(FS90R など)では 「角度」ではなく「速度と方向」 を duty_u16 で指定する仕様に変わります。
課題3-12-2:可変抵抗ノブでサーボの角度をコントロールしよう
#05 で使った可変抵抗ノブ(ADC:GP26)を回すと、サーボがそれに連動して動く ような直感的なコントローラを作ります。ADC 値(0〜65535)を 「× 180 ÷ 65535」 の式で 0〜180 に変換し、新ブロック 「サーボ角度」 に差し込みます。ロボットアームを手元のつまみで操作するイメージです。
配線追加:サーボ(GP15 + VBUS + GND)に加えて、可変抵抗ノブを3V3・GP26・GND(3 ピン)に繋ぎます。GP15(サーボ)と GP26(ADC)はぶつからない ので安心です。
▶ 模範解答と解説を見る
ブロックの組み合わせ例:

py_math_op を2回ネストして (pot × 180) ÷ 65535 を作っています。from machine import ADC, PWM, Pin
import utime
_adc26 = ADC(26)
while True:
pot = _adc26.read_u16()
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + max(0, min(180, pot * 180 / 65535)) * 8192 // 180))
utime.sleep(0.02)
解説: 動作確認のコツ:ノブを左いっぱい → サーボは 0° に、ノブを右いっぱい → サーボは 180° に、ノブを真ん中 → サーボは 90° に動きます。動きがガクガクする 場合は wait を 0.02 → 0.05 に伸ばすか、ADC 値のスムージング(移動平均:直前 5 回の平均を使う)を加えると滑らかになります。発展:
- 角度範囲を狭める:式を
pot × 90 / 65535 + 45にすると 45°〜135° の範囲のみ動かせる(限られたスペースで使うロボット関節向け) - 2 つのサーボを同時制御:可変抵抗を 2 個(GP26 と GP27)使って、X軸サーボと Y軸サーボを別々に動かせばパン・チルト雲台が作れる
- 逆向き連動:式を
180 - pot × 180 / 65535にすると、ノブを右に回すとサーボが左に動く逆連動になる

課題3-12-3:超音波センサーで自動開閉ゲートを作ろう
#09 で使った超音波センサー HC-SR04 と組み合わせて、「20cm 以内に物が近づいたらゲートを開ける」 自動ドアを作ります。距離が 20cm 未満ならサーボ 90°(ゲート開)、それ以上なら 0°(ゲート閉) という条件分岐。実際にレゴブロック等で ホーンの先に小さな板(ゲート) を付ければミニチュア自動ドアの完成です。
配線追加:サーボ(GP15 + VBUS + GND)に加えて、HC-SR04 を3V3・GP2(TRIG)・GP3(ECHO)・GND に繋ぎます。HC-SR04 の標準ピン GP14/GP15 はサーボ(GP15)とぶつかる ので、今回は HC-SR04 を GP2/GP3 に変更しています。HC-SR04 は 5V 動作が標準 ですが、Pico は 3.3V なので#09 で学んだ 3.3V 改造版(VCC=3V3) または 5V 給電+ECHO に分圧抵抗 のどちらかを選んでください。
▶ 模範解答と解説を見る
ブロックの組み合わせ例:

from machine import Pin, PWM, time_pulse_us
import utime
_trig = Pin(2, Pin.OUT)
_echo = Pin(3, Pin.IN)
while True:
_trig.value(0); utime.sleep_us(2)
_trig.value(1); utime.sleep_us(10); _trig.value(0)
_t = time_pulse_us(_echo, 1, 30000)
dist = _t / 58 if _t > 0 else -1
if dist < 20:
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + 90 * 8192 // 180))
else:
_sv = PWM(Pin(15), freq=50)
_sv.duty_u16(int(1638 + 0 * 8192 // 180))
utime.sleep(0.3)
解説: 動作確認のコツ:手を 20cm 以内に近づけるとサーボがガッと 90° に動いて、離すと元の 0° に戻る挙動を確認しましょう。0.3 秒の wait は HC-SR04 の測定間隔(最小 60ms) とサーボの動作時間(180° で約 0.3 秒) の両方を満たす値です。反応が遅い・チラチラする 場合は wait を 0.5 秒に伸ばしてみてください。発展:
- 段階的にゲートを開ける:
dist < 10 → 180°(全開)、dist < 20 → 90°(半開)、else → 0°(閉)の 3 段階制御で、近づくほど大きく開く賢いゲートに進化 - 距離→角度の連続マッピング:
angle = 180 - dist × 3(dist=0→180°、dist=60→0°)のように 距離に比例した角度に動かすと、リニアなジェスチャーセンサー風に - LCD で距離・角度を表示:#08 の I2C LCD を組み合わせて「距離 12 cm / 角度 90°」のような状態表示を加えると、デバッグも楽しい

まとめ
- SG90 サーボ は 3 本線(VCC・GND・PWM)で動く 0〜180° の小型角度制御モーター。
- 角度は PWM 50Hz(周期 20ms)のパルス幅(500〜2400μs) で決まる。Pico の duty_u16 値(1638〜9830) として PWM ブロックに渡される。
- 標準ブロック 「サーボ」 は角度をリテラル指定(0〜180)。今回追加した 「サーボ角度」(_val 版) は変数や計算式を差し込める。
- 電源は VBUS(5V)または外部電源 を使う。3.3V ピンでは電流不足 で Pico がリセットする。外部電源時は 共通グランド を忘れずに。
- 可変抵抗(#05)・超音波センサー(#09)と組み合わせれば、手回しコントローラ・自動開閉ドア・ロボットアーム など多彩な応用が可能。
- ピン衝突に注意:今回は HC-SR04 を GP2/GP3 に変更してサーボ GP15 と分けた。
📝 サーボの種類いろいろ
次の記事は #13「DC モーターを動かそう」。L298N モータードライバを使って、ラジコンカーや扇風機のようにグルグル回り続けるモーターを速度と方向の両方 でコントロールします。