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円。モーター・ポンプなどの電池が消耗しやすい実験・工作におすすめです。

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

電池ボックス

電源に使用する乾電池用のボックスとスナップです。記事では単4を使っていますが、容量の大きい単3タイプをお勧めします。単3でも単4でも電圧は変わりません。

エネループ

使い捨ての乾電池もいいですが、エネループなら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のデータシート(一部抜粋)

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と簡単につなげて値段もお手軽、「ちょっと動く何かを作ってみたいな」「初めてモーターを触ってみたい」という方にピッタリなモーターです。

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

お知らせ

今月号のInterfaceは『仕事のChatGPT』!

今週号の日経Interfaceは「仕事のChatGPT」。
イントロとして、ChatGPTをはじめとした大規模言語モデル(LLM)の現在や、エンジニア向け生成AIの活用法。その後の内容で、ChatGPTを使ったPythonでゲームの作り方や生成AIを使ったシステムの製作例が学べます。

全ての内容はここでは紹介しきれないので、詳細は以下のAmazonページをご覧ください。

5月25日発売です。

CQ出版
¥1,430 (2024/04/25 12:53時点 | Amazon調べ)

質問・要望 大歓迎です

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

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

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

COMMENT

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

Index