Raspberry Pi PR

【Python】RaspberryPiでサーボモーター SG90を使う方法【RPi.GPIO】

記事内に商品プロモーションを含む場合があります

はじめに

RaspberryPiで、サーボモータ(ラジコンサーボ)を使う方法について質問をいただいたので、電子工作でよく使われる「SG90」使う方法を解説します。

プログラム言語は「Python」ライブラリは「RPi.GPIO」を使います。

カンパチさんご質問ありがとうございます。

環境

この記事で使用する環境は以下の通りです。

環境 備考
RaspberryPi 4 Model B Pi3でもOKです。
OS RaspberryPi OS (bullseye) 64bit版です
言語 Python 3.9.2
ライブラリ RPi.GPIO

RaspberryPi2や3も使用できます。ピン配置は同じなので、記事と同じように接続してください。

サーボモーター(ラジコンサーボ) SG90

SG90と付属品の画像
SG90 単三電池は比較用です。

今回の記事で使用するサーボーモーター(ラジコンサーボ)「SG90」です。

ラジコンサーボは、モータ・ギアボックス・制御基板などが1つのケースにまとめられたモーターで、±90度など、ある特定の範囲を動かすことに特化しています。

ラジコンカーのステアリング・ラジコン飛行機の翼の操作・ホビーロボットの関節軸などによく使われており、「電源・GND・PWM信号」の3本だけで動かすことができます。

SG90の電源は4.8Vですが、PWM信号は3.3Vでも反応してくれるので、RaspberryPiシリーズでも簡単に使うことができます。

項目 スペック
電圧 4.8V
動作範囲 180度(±90度)
トルク 1.8kgf・cm
付属品 サーボホーン3種
サーボ固定ねじ×2、ホーン固定ねじ×1

RaspberryPiとの接続

RaspberryPi4・SG90・充電池(エネループ)を以下のようにつなぎます。

RaspberryPi本体の5Vピンをつないでも動きますが、電流が不足しそうなので、エネループをサーボ用の電源に使っています。

なお、別電源を使う際は、RaspberryPiと電源のGNDをつないで使用してください、GNDの共通化を行わないと、動作が不安定になったり、動かないことがあります。

(間違って単4の電池ケースを購入したので単4を使っていますが、単3でもOKです)

RaspberryPi4とSG90を接続する方法を解説した画像
RaspberryPiとの接続方法

ピン番号 RaspberryPi側 サーボモータ
33 GPIO13(PWM1) PWM
39 GND GND (電池と共通化します)
電池+ 電源
電池 − GND (電池と共通化します)

ピンアサイン

RaspberryPi 公式のGitHubより引用

使用する部品

RaspberryPi 4 (4GBモデル)

やっと価格が適正値に戻ってきました。国内代理店であるスイッチサイエンスさんやKSYさんでも在庫が復活しているようなので、そちらで購入するのもありです。

サーボモータ(ラジコンサーボ) SG90

冒頭でも紹介した、RaspberryPiシリーズで使えるサーボモータ(ラジコンサーボ)です。 人気のため、コピー品も多いようです。私は以下の正規販売元のページから購入しました。

¥820 (2023/08/25 06:08時点 | Amazon調べ)

ブレッドボード

サンハヤト性のブレッドボードです。少々堅めの指し心地ですが、などの品質も高く、おすすめの一品です。

電池ボックス

電源に使う電池用ボックスです。スイッチ付きで何かあってもすぐに電源を切れるので、安心して工作することができます。

記事では単4を使っていますが、容量の大きい単3タイプをお勧めします。単3でも単4でも電圧は変わりません。

電池ボックス(単4)

記事で使っている単4を3本使うタイプはこちらで購入しています。

ジャンプワイヤ (オス-メス タイプ)

RaspberryPiで使う場合は、以下のオスーメスタイプがおすすめです。

エネループ

使い捨ての乾電池もいいですが、エネループなら4本充電時の電気代が約1円。モーター・ポンプなどの電池が消耗しやすい実験・工作におすすめです。

※ はじめて使う方は充電器とのセットがおすすめです

プログラム概要

今回のプログラムの概要は以下の通りです。

  • PWMの設定をする。
  • サーボモータを動かす。

実行結果

後述するプログラムの実行結果です。サーボモータが「-90度」「0度」「+90度」の順で、3回動作します。

プログラムを実行して、サーボを-90度に動かしたときの画像
-90度
プログラムを実行して、サーボを0度に動かしたときの画像
0度
プログラムを実行して、サーボを+90度に動かしたときの画像
90度

全体コード

全体コードは以下の通りです。詳細な内容は後述する「コードのポイント」で解説します。

# RPi.GPIOのライブラリを「GPIO」という名前で使います
import RPi.GPIO as GPIO
import time

# サーボが動作可能な範囲です
ANGLE_RANGE = 180
# サーボに指定するPWMの時間の範囲です
TIME_RANGE  = 1.9
# サーボに指定できる最小の時間です
MIN_TIME    = 0.5
# サーボのPWMの周期時間です
CYCLE_TIME  = 20.0

# GPIOのピン番号指定を「BCM」に設定します
GPIO.setmode(GPIO.BCM)

# 設定を確認。BCMの場合は「11」が返ります
mode = GPIO.getmode()
print(mode)

# PWMに使うピンに名前をつけます
PWM = 13

# PWMに使うピンを「Out」に設定します
GPIO.setup(PWM,GPIO.OUT)

def moveServo(pwm,angle ):

    # 入力角度のチェックです。±90以外はエラーにします
    if  angle < -90  or angle > 90 :
        return False

    # 指定角度を、0~180の表現に変えます
    angle = angle + 90

    # 指定角度を、全体(180度)中の割合に変換します
    percent =  angle  / ANGLE_RANGE

    # 割合を時間の範囲に適応して、指定角度を動かす時間を計算します
    addTime = TIME_RANGE * percent

    # 時間範囲は0.5から始まるので0.5に指定角度の時間を足します
    time = MIN_TIME + addTime

    # 指定角度の時間を、20msecの周期中の割合(%)に変換します
    ratio = ( time / CYCLE_TIME ) * 100

    # 動作実行します
    pwm.ChangeDutyCycle(ratio)

    return True

# PWMのピンと周波数を設定します。
# 周波数は、SG90の仕様の50Hz(20msec)に設定します
pwm = GPIO.PWM(PWM,50)

# PWMを開始します
pwm.start(0)

# 同じ動作を3回繰り返します
for i in range(3):

    # -90度に動作
    moveServo(pwm, -90)
    time.sleep(2)

    # 0度に動作
    moveServo(pwm, 0)
    time.sleep(2)

    # +90度
    moveServo(pwm, 90)
    time.sleep(2)

# GPIOの設定を解除します
GPIO.cleanup(PWM)

コードのポイント

周期の設定

PWMのピンと周波数を設定します。

秋月電子さんで公開されている「SG90のデータシート」に「50Hz」と記載されているため、PWMの周波数を50Hz(1周期20msec)に設定します。

# PWMのピンと周波数を設定します。
# 周波数は、SG90の仕様の50Hz(20msec)に設定します
pwm = GPIO.PWM(PWM,50)

# PWMを開始します
pwm.start(0)

SG90のデータシートの抜粋
SG90のデータシート(抜粋)

Duty比の作成

サーボ角度はPWMのDuty比を変えることで指定できます。角度の変更は何度も実行する処理のため、関数にまとめてメイン処理側のコードが簡潔にしています。

処理内容は以下の通りです。

① 角度を割合に変換

計算を楽にするため、「SG90」が動作できる範囲である±90度を、90度ずらして、0~180度の範囲(表現)に変換します。

0度に指定する例: 0 + 90 = 90度

次に、変換後の入力角度を、SG90の動作範囲(180度)で割り、入力角度が動作範囲対してどの程度の割合であるかを計算します。

0度に指定する例: 90 ÷ 180 = 0.5

角度を0~180に変換するイメージ
角度(表現)変更のイメージ

def moveServo(pwm,angle ):

    # 入力角度のチェックです。±90以外はエラーにします
    if  angle < -90  or angle > 90 :
        return False

    # 指定角度を、0~180の表現に変えます
    angle = angle + 90

    # 指定角度を、全体(180度)中の割合に変換します
    percent =  angle  / ANGLE_RANGE

② 角度から時間に変換

前述した「入力角度の割合」を使って、PWMのDuty(どれだけの時間、信号をONにすればいいか?)を計算します。

データシートを見ると、ON時間と動作角度は以下のように対応しています。

  • 0.5msec ON -90度
  • 2.4msec ON +90度

上記の範囲は1.9msecなので、ON時間の幅「1.9msec」に、上で計算した角度の割合を当てはめることで、入力角度を動かすためのON時間を計算することができます。

0度に指定する例: 1.9 × 0.5 = 0.95

角度の割合を時間に適応するイメージ
角度の割合から時間を計算するイメージ

ここで、ON時間は0.5msecから始まっているため、割合で計算した値に0.5を追加します。

0度に指定する例: 0.95 + 0.5 = 1.45

時間が0.5始まりなので、ON時間に0.5をするイメージ
0.5から始まるイメージ
    # 割合を時間の範囲に適応して、指定角度を動かす時間を計算します
    addTime = TIME_RANGE * percent

    # 時間範囲は0.5から始まるので0.5に指定角度の時間を足します
    time = MIN_TIME + addTime

③ Duty比に変換

前述までの計算で指定角度を動かす場合の、ON時間(1.9msec)が計算できました。

しかし、PWMを設定するChangeDutyCycle関数は、初期化時に指定した1周期(20msec)の内、何秒ONにするかを、「割合」を「パーセント」で指定する必要があるため、ON時間を割合に変換します。

0度に指定する例: 1.45 ÷ 20 = 0.0725

0度に指定する例: 0.0725 × 100 = 7.25

    # 指定角度の時間を、20msecの周期中の割合(%)に変換します
    ratio = ( time / CYCLE_TIME ) * 100

    # 動作実行します
    pwm.ChangeDutyCycle(ratio)

    return True

まとめ

RaspberryPi(ラズパイ) でサーボモータ(ラジコンサーボ)を使う方法を解説しました

SG90はRaspberryPiと簡単につなげて値段もお手軽、「ちょっと動く何かを作ってみたいな」「初めてモーターを触ってみたい」という方にピッタリなモーターです。

動く工作も簡単に作れるので、興味を持ったかたはぜひ遊んでみてください。参考になればうれしいです。

お知らせ

ラズパイマガジン春号が発売されました

ラズパイマガジン春号が発売されました!今回は、日本での発売間近の「RaspberryPi 5」の徹底レビュー。「ラズパイ5、ちょっと気になるな〜」という方はこの本で細かいところまで確かめてみるものもいいんじゃないでしょうか。
話題のChatGPTを使って作品作りを効率化する方法も紹介されています。

質問・要望 大歓迎です

「こんな解説記事作って」「こんなことがしたいけど、〇〇で困ってる」など、コメント欄で教えてください。 質問・要望に、中の人ができる限り対応します。

使えたよ・設定できたよの一言コメントも大歓迎。気軽に足跡を残してみてください。記事を紹介したい方はブログ、SNSにバシバシ貼ってもらってOKです。

ABOUT ME
えす
現役のソフトウェアエンジニアです。 C++ C# Python を使ってます。10年ちょい設計/開発部門にいましたが、今はQAエンジニアっぽいことをしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

Index