2025年8月12日火曜日

サーボモーターを動かしてみよう(SG90制御入門)

 回は**ラジコンサーボ(RCサーボ)**を動かしてみます。

ロボットを作るときや、センサーと組み合わせて何かを動かしたいときなど、RCサーボはとてもよく使われる部品です。小さなモーターにギアや制御回路が内蔵されていて、指定した角度まで正確に動かせるのが特徴です。

そこで今回は、代表的なサーボモーター「SG90」を使って、サーボを動かす基本的な仕組みや制御方法を学んでいきましょう。

🌀 そもそも「PWM」ってなに?

**PWM(Pulse Width Modulation:パルス幅変調)**とは、
デジタル信号(ONかOFFだけ)を工夫して「出力の強さ」や「角度」を調整する方法です。

  • サーボモーターは 50Hz の PWM信号(1秒間に50回)で角度を決めます。

  • 「ONにしている時間(パルス幅)」を変えると、サーボの角度が変わります。

パルス幅(ON時間)おおよその角度
約0.5ms(ミリ秒)左端(0度)
約1.5ms真ん中(90度)
約2.5ms右端(180度)

💡 PWMの周期は「20ms(=1秒 ÷ 50Hz)」で、
その中の 0.5〜2.5ms の間だけピンをONにします。

回路


SG90の線接続先(Pico)説明
赤(VCC)5V(VSYSや外部5V)電源(強い電流)
茶(GND)GNDマイナス(共通)
橙(PWM)GP16(ピン21)PWM信号(制御)


✅ サーボ SG90 を動かす MicroPython コード

# ---------------------------------------------------------------
# Raspberry Pi Pico (W) で SG90 サーボを動かす簡易コンソールツール
#
#   コマンド        動作
#   ──────────────  ────────────────────────────────────────────
#     l  … 左端まで回転(ステップ指定でゆっくり移動も可)
#     r  … 右端まで回転(ステップ指定でゆっくり移動も可)
#     m  … 真ん中(90°付近)へ移動
#     t  … センター → 右端 → 左端 → センター(デモ)
#     q  … 終了(PWM を停止してリセット)
#
# ▸ 配線例
#   SG90 赤(VCC)  : 5 V (Pico の VSYS か外部 5 V)   ★電流に余裕のある電源推奨
#   SG90 茶(GND)  : GND
#   SG90 橙(PWM)  : GP16  ← 本スクリプトで制御するピン
#
# ▸ 制御のしくみ
#   - サーボは 50 Hz (周期 20 ms) の PWM で動く
#   - パルス幅 0.5 ms ≒ -90°、1.5 ms ≒ 0°、2.5 ms ≒ +90°
#   - Pico の PWM は duty_ns() で“パルス幅(ナノ秒)”を直接指定できる
# ---------------------------------------------------------------
from machine import Pin, PWM
import time
import sys

# ─────────────────────────────────────────────
# 1. サーボ用 PWM 設定(GP16, 50 Hz)
# ─────────────────────────────────────────────
SERVO_PIN = 16
servo = PWM(Pin(SERVO_PIN))
servo.freq(50)                      # 50 Hz = 周期 20 ms

# パルス幅の最小・最大値(ナノ秒)
MIN_NS = 500_000    # 0.5 ms  ≒ -90°
MID_NS = 1_500_000  # 1.5 ms  ≒    0°
MAX_NS = 2_500_000  # 2.5 ms  ≒ +90°

def write_ns(pulse_ns):
    """指定したパルス幅(ns)でサーボを駆動"""
    servo.duty_ns(int(pulse_ns))

def move_steps(start_ns, end_ns, steps=10, delay=0.5):
    """start → end へ分割ステップでゆっくり移動"""
    step_ns = (end_ns - start_ns) / steps
    for i in range(steps):
        write_ns(start_ns + step_ns * (i + 1))
        time.sleep(delay)

def menu():
    print("\n==== SG90 Servo Control (Pico W) ====")
    print("l = 左へ      r = 右へ")
    print("m = 中央へ    t = デモ")
    print("q = 終了")
    print("───────────────────────────────────")

# 電源 ON 直後は中央へ
write_ns(MID_NS)
menu()

try:
    while True:
        cmd = input("Command > ").strip().lower()

        # ------ デモ動作 ------
        if cmd == "t":
            print("センター → 右 → 左 → センター")
            write_ns(MID_NS); time.sleep(1)
            write_ns(MAX_NS); time.sleep(1)
            write_ns(MIN_NS); time.sleep(1)
            write_ns(MID_NS)

        # ------ 右へ(+90°) ------
        elif cmd == "r":
            steps = int(input("ステップ数(1-10, Enter): ") or 10)
            steps = max(1, min(steps, 10))
            print(f"{steps} ステップで右端へ")
            move_steps(MIN_NS, MAX_NS, steps)

        # ------ 左へ(-90°) ------
        elif cmd == "l":
            steps = int(input("ステップ数(1-10, Enter): ") or 10)
            steps = max(1, min(steps, 10))
            print(f"{steps} ステップで左端へ")
            move_steps(MAX_NS, MIN_NS, steps)

        # ------ 中央へ ------
        elif cmd == "m":
            print("中央へ移動")
            write_ns(MID_NS)

        # ------ 終了 ------
        elif cmd == "q":
            print("プログラムを終了します")
            break

        # ------ 無効コマンド ------
        else:
            print("⚠ そのコマンドは無効です")
            menu()

finally:
    # 終了時に PWM を停止し出力を 0
    servo.deinit()
    print("PWM 停止、終了しました")


使いかた(Thonny 上で)

  1. Pico W にこのファイルを保存して実行(▶ボタン)

  2. Thonny のシェルに表示されるメニューに従い、l / r / m / t / q を入力

  3. サーボが指示通りに動くことを確認します

電源に注意
USB の 5 V でも動きますが、ピーク電流が足りないと位置が不安定になります。安定しない場合は VSYS(5 V) ピンや外部 5 V を使用してください。 

"ステップ数(1-10, Enter): " というプロンプトに書かれている

  “1-10” は、ユーザーが入力できる数値の範囲(1 〜 10 の整数) を示しています。 

なぜ 1〜10 なの?

  • 細かく刻み過ぎない:ステップ数が大きすぎると動きが遅く、面倒になります。

  • 粗すぎない:逆に 1〜2 しか選べないと動きがガクッと変わって雑になります。

  • 直感的に扱いやすい:10 段階評価は人がイメージしやすいので、初心者にも分かりやすい設定です。

📌 なぜ PWM でサーボが動くの?

サーボモーターには中に制御回路が入っており、
PWM信号を「このパルス幅は何度だな」と判断して内部モーターをその角度に保ちます。


🧠 このプログラムの処理の流れ(わかりやすく)

1. 初期設定

servo = PWM(Pin(16))  # GP16ピンでPWMを開始

servo.freq(50)        # 周波数はサーボ用に50Hz

2. 角度ごとのパルス幅(ナノ秒)を定義

MIN_NS = 500_000     # 0.5ms → 左端

MID_NS = 1_500_000   # 1.5ms → 真ん中

MAX_NS = 2_500_000   # 2.5ms → 右端

→ 数字は「ナノ秒」なので、1ms = 1,000,000ns

3. サーボを動かす関数

def write_ns(pulse_ns):

    servo.duty_ns(int(pulse_ns))

→ この関数を使って、サーボを「どの角度にするか」を決めます。

🔁 move_steps() 関数

def move_steps(start_ns, end_ns, steps=10, delay=0.5):

・「いきなり動く」のではなく、ステップ(分割)してゆっくり動かす仕組みです。

・たとえば、0度 → 180度 を10ステップに分けて動かすことで、スムーズになります。


0 件のコメント:

コメントを投稿

Google Spread Sheetの利用

  以前に ESP32 で作っていたものを、Raspberry Pi Pico W + MicroPythonで再現してみました。 1.Googleスプレッドシートの設定 1.Google Drive → 右クリック → Google スプレッドシート 2.作成して共有をクリック