みつきんのメモ

組み込みエンジニアです。Interface誌で「My オリジナルLinuxの作り方」連載中

ラズベリーパイ3の(ソフトウェア)PWMで回転サーボを動かす

はじめに

秋月電子でも入手可能な回転サーボ FS90R を入手したので動かしてみる。

環境はwarrior(Yocto 2.7)でmeta-raspberrypiを使用する。

環境構築

ここの「環境構築」を参照。

local.confに下記の内容を追加する。

IMAGE_INSTALL_append = " rpi-gpio"

core-image-baseを作成する。

$ bitbake core-image-base

ddやEtcherなどでマイクロSDに書き込む。

配線

FS90R側の信号は次のようになる。

信号
オレンジ Signal(PWM)
+(V)
-(GND)

駆動電圧は最低4.8Vなので、5V入れてやれば動く。 制御用の電圧は3.3Vでも問題ない様子。

ラズベリーパイの5VのピンはUSBからの電流を分配しているだけっぽいので、 手っ取り早くやるなら、+のところはラズベリーパイの5Vに接続してしまっても問題ないと思う。 ただし、本体の電源そのものなので、サーボを回すと高頻度で次のように電源低下を検出ようになる。

[ 1747.351869] Under-voltage detected! (0x00050005) 

それが気になる場合は、別系統で電源を引っ張ってきてモーターに入れると良い。

筆者は、USB-シリアル変換ケーブルのPCのUSBから出ている5Vをモーターに入れた。 (ラズベリーパイにコンセントの電源をひっぱているので、普段この5Vは余っている)

プログラム

PWMを制御したいので手っ取り早くpythonで書く。GPIOの制御にはRPi.GPIOを使用する。 RPi.GPIOはソフトウェアでPWMをシミュレートすることができ、普通のGPIOピンでもPWMすることができる。

ただし、ハードウェアPWMと比べると制度が低いので、正確なパルス幅が必要な場合は注意が必要となる。

Duty比

パルス幅のレンジは700〜2300usで、1500usで停止。これを境に小さいと時計回り、大きいと半時計回りとなる。

動作 パルス幅(us)
停止 1500
時計回り 1500未満
半時計回り 1501以上

RPi.GPIOのPWMではベースとなる周波数とDuty比でパルス幅を指定する。

例えば50Hzの場合、1回の振幅に20msかかるので、1500usのパルス幅を指定したい場合次のように計算する。

1500us = 1500us/(20ms*1000)*100 = 7.5%

停止させておくために設定するDutyは7.5%ということになる。

次のプログラムは制御信号にGPIO21を使用して次の動作を行う。

  • 2秒間停止
  • 2秒間時計回りで回転
  • 2秒間半時計回りで回転
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

gp_out = 21
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(7.5)
time.sleep(2)
servo.ChangeDutyCycle(5)
time.sleep(2)
servo.ChangeDutyCycle(10)
time.sleep(2)
servo.stop()
GPIO.cleanup() 

しかし、実際に動かしてみるとピッタリと停止しないことがわかる。 これは先述の通りソフトウェアPWMでありパルス幅が正確ではないことが原因とななる。

なので、7.5の時点でどちらに回転しているかを見て値を微調整する。 筆者の環境では7.1でピッタリと停止した。

まとめ

サーボの電源は本体と別系統が無難。

ソフトウェアPWMでも、値を微調整すれば回転サーボの制御は可能。 ただし正確に制御したい場合はハードウェアPWMのほうが確実。