2016/07/19(火) [n年前の日記]
#1 [raspberrypi] Raspberry Pi3でサーボモータを制御。その1
秋月電子から購入したマイクロサーボモータ、
_SG92R
を、Raspberry Pi3 から制御したいなと。
サーボモータってのは…。この場合は、PWMで角度を指定して動かせるモータ、という認識でいいのだろうか。 _サーボモータ - Wikipedia を眺めるとゴイスなヤツからホビー用まで色々あるらしいけど。今回使うのはホビー用。
サーボモータってのは…。この場合は、PWMで角度を指定して動かせるモータ、という認識でいいのだろうか。 _サーボモータ - Wikipedia を眺めるとゴイスなヤツからホビー用まで色々あるらしいけど。今回使うのはホビー用。
◎ 仕様をメモ。 :
とりあえず、SG92Rの仕様を秋月電子さんのサイトからコピペしてメモ。特に、PWMサイクル、制御パルスの仕様が重要。
つまり、20ms間隔でPWMを流して…。0.5ms幅のパルスを送ると -90度に、2.4ms幅のパルスを送ると90度にモータが回転してくれる、のであろうと。
SG92R : メーカー : Tower Pro Pte Ltd
PWMサイクル : 20ms
制御パルス : 0.5ms〜2.4ms
制御角 : ±約90°(180°) 配線 : 茶 = GND、赤 = 電源[+]、橙 = 制御信号 [JRタイプ]
トルク : 2.5 kgf・cm
動作速度 : 0.1秒 / 60度
動作電圧 : 4.8V(〜6V)
温度範囲 : 0℃〜55℃
外形寸法 : 23 x 12.2 x 27mm
重量 : 9g
つまり、20ms間隔でPWMを流して…。0.5ms幅のパルスを送ると -90度に、2.4ms幅のパルスを送ると90度にモータが回転してくれる、のであろうと。
◎ ピンコネクタでちょっと失敗。 :
サーボモータの端子をブレッドボードに差すために、
_細ピンヘッダ 1 x 20
も購入したのだけど。試してみたら長さが足りなかった…。もしかすると、ここは
_両端ロングピンヘッダ
なるものを購入すべきだったのだろうか…。
とりあえず、 _ブレッドボード用ジャンパーコード(オス - オス) をサーボモータ側の端子に差し込んでどうにか。
とりあえず、 _ブレッドボード用ジャンパーコード(オス - オス) をサーボモータ側の端子に差し込んでどうにか。
◎ 回路図。 :
こんな感じに。
巷の解説記事を眺めてると、コンデンサや抵抗を入れる場合と入れない場合があるようで。
- Raspberry Pi3 の GPIO 18番を、サーボモータの制御信号に接続。GPIO 18番なら、PWMが使える場合が多いらしいので。
- サーボモータの電源は、単三電池 x 4 で確保。
- モータがノイズを出すらしいので、ノイズ対策としてモータの電源(VCC - GND)の間に 100uF のコンデンサを追加。コンデンサにはプラスマイナスがあるので注意。
巷の解説記事を眺めてると、コンデンサや抵抗を入れる場合と入れない場合があるようで。
- コンデンサをつけるとしても 0.1uF とか 100uF とか色々あって、どれが正しいのやら。
- Raspberry Pi3 の GPIOピンと、サーボモータの制御信号の間に、1KΩ程度の抵抗を入れる場合も。サーボモータが壊れた際に逆流しないように、という理由だとか。
◎ Pythonで動かしてみる。 :
とりあえず、LEDをPWMで光らせた時と同じやり方で ―― Python + RPi.GPIO を使う形で制御してみたり。servo_pwm.py として保存。
sudo python servo_pwm.py として実行。
動いた。
と思ったら、甘かった。指定角度で止まってくれたように一瞬見えたけど、なんだか「ジャジャッ…ジャッ…」と鳴きながら、ガクガクブルブルしている…。これじゃ使えない…。
Python + RPi.GPIO はPWM制御に関して精度がよろしくない、という話も見かけたけれど。ひょっとして、そのせいでガクブルしてしまうのだろうか…。それとも別の原因が…。
全然関係ないけど、サーボモータ上に乗せたのは _2012/05/15 に作ったペーパークラフト。机の中を探したらコレが見つかったので。
#!/usr/bin/python # -*- coding: utf-8 -*- import RPi.GPIO as GPIO import time PULSE_PIN = 18 TOTAL_MS = 20.0 MIN_MS = 0.5 MAX_MS = 2.4 MIN_DCV = (float(MIN_MS) / TOTAL_MS) * 100.0 - 0.7 MAX_DCV = (float(MAX_MS) / TOTAL_MS) * 100.0 - 0.5 def get_dc(ang): ang += 90 if ang < 0.0: ang = 0.0 if ang > 180.0: ang = 180.0 dc = MIN_DCV + ((MAX_DCV - MIN_DCV) * (float(ang) / 180.0)) return dc GPIO.setmode(GPIO.BCM) GPIO.setup(PULSE_PIN, GPIO.OUT) pwm = GPIO.PWM(PULSE_PIN, 50) pwm.start(get_dc(0)) try: for ang in [0, -90, 0, 90, 0, -90, -45, 0, 45, 90, 0]: dc = get_dc(ang) print "ang %f , dc %f" % (ang, dc) pwm.ChangeDutyCycle(dc) time.sleep(3) except KeyboardInterrupt: pass pwm.stop() GPIO.cleanup()
sudo python servo_pwm.py として実行。
動いた。
と思ったら、甘かった。指定角度で止まってくれたように一瞬見えたけど、なんだか「ジャジャッ…ジャッ…」と鳴きながら、ガクガクブルブルしている…。これじゃ使えない…。
Python + RPi.GPIO はPWM制御に関して精度がよろしくない、という話も見かけたけれど。ひょっとして、そのせいでガクブルしてしまうのだろうか…。それとも別の原因が…。
全然関係ないけど、サーボモータ上に乗せたのは _2012/05/15 に作ったペーパークラフト。机の中を探したらコレが見つかったので。
◎ ServoBlasterをインストールしてみた。 :
サーボモータを制御することに特化した、ServoBlaster なるものがあるそうで。デーモンとして動くことで、比較的正確なPWM制御が可能になっているらしい。
_Raspberry PI でサーボを動かす ・ Airwhite Memo
_Raspberry Pi でサーボモータ制御 - Qiita
_Raspberry-PiにおけるGPIO関係ツールのインストール方法
_[raspberry] GPIOの制御とservoblasterの併用時 | Gerolian
_Indoor airplane world
_raspberry Pi でサーボモータ制御 | Linux & Android Dialy
コレを使えば、RPi.GPIO 使用時と違う結果になるのでは。試してみないと。
インストールは以下。
デーモンとして起動。あるいは、デーモンが起動中なら現在の状態を表示。
デーモンを終了。
ServoBlaster をインストールすると、サービスとして自動起動するように設定される。自動起動しないように設定する場合は以下。
自動起動するように設定する場合は以下。
サーボ番号と、GPIO番号の対応は以下のようになってるらしい。コピペさせてもらってメモ。
例えば、GPIO 18番のdutyを、パーセント指定で変えたければ、以下のように打つ。
パーセントではなく、パルス幅(10マイクロ秒単位)で指定することも可能。
さて。手持ちの SG92R の場合、受け付けるパルス幅は、最小 0.5ms 〜 最大 2.4ms らしいので、以下が指定できるはずだけど。
試してみたところ、実際には指定できず…。以下の範囲でしか指定できなかった。
つまり、ServoBlaster + SG92R を使う際は、-90度 = 50, 0度 = 131, 90度 = 213 を指定する感じになりそう。
さておき。前述のPythonスクリプトで制御するとガクブルだったけど、ServoBlaster を使った場合は、ちゃんとピタリと止まってくれた。状況が改善した、ような気がする。
_Raspberry PI でサーボを動かす ・ Airwhite Memo
_Raspberry Pi でサーボモータ制御 - Qiita
_Raspberry-PiにおけるGPIO関係ツールのインストール方法
_[raspberry] GPIOの制御とservoblasterの併用時 | Gerolian
_Indoor airplane world
_raspberry Pi でサーボモータ制御 | Linux & Android Dialy
コレを使えば、RPi.GPIO 使用時と違う結果になるのでは。試してみないと。
インストールは以下。
$ git clone git://github.com/richardghirst/PiBits.git $ cd PiBits/ServoBlaster/user $ make servod $ sudo make installservod てのが、コマンド名(?)らしい。
デーモンとして起動。あるいは、デーモンが起動中なら現在の状態を表示。
sudo servod
デーモンを終了。
sudo killall servod
ServoBlaster をインストールすると、サービスとして自動起動するように設定される。自動起動しないように設定する場合は以下。
sudo update-rc.d servoblaster remove
自動起動するように設定する場合は以下。
sudo update-rc.d servoblaster defaults
サーボ番号と、GPIO番号の対応は以下のようになってるらしい。コピペさせてもらってメモ。
サーボ番号 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
GPIO番号 | 4 | 17 | 18 | 21/27 | 22 | 23 | 24 | 25 |
P1ピン番号? | 7 | 11 | 12 | 13 | 15 | 16 | 18 | 22 |
例えば、GPIO 18番のdutyを、パーセント指定で変えたければ、以下のように打つ。
echo 2=0% > /dev/servoblaster/dev/servoblaster に何かを書き込んでやることで指定できる、ということなんだろう…。
パーセントではなく、パルス幅(10マイクロ秒単位)で指定することも可能。
echo 2=120 > /dev/servoblaster
さて。手持ちの SG92R の場合、受け付けるパルス幅は、最小 0.5ms 〜 最大 2.4ms らしいので、以下が指定できるはずだけど。
echo 2=50 > /dev/servoblaster echo 2=240 > /dev/servoblaster
試してみたところ、実際には指定できず…。以下の範囲でしか指定できなかった。
echo 2=50 > /dev/servoblaster echo 2=213 > /dev/servoblaster213より大きい値を指定すると異音がする…おそらく回りっぱなし…。本来なら 240 まで指定できそうだが…。
つまり、ServoBlaster + SG92R を使う際は、-90度 = 50, 0度 = 131, 90度 = 213 を指定する感じになりそう。
さておき。前述のPythonスクリプトで制御するとガクブルだったけど、ServoBlaster を使った場合は、ちゃんとピタリと止まってくれた。状況が改善した、ような気がする。
◎ ServoBlasterが握るピンの数を変更。 :
ところで、このままだと ServoBlaster が複数のGPIOのピンを握り続けてしまって、他の実験がちょっとやりにくくなる。今回は GPIO 18番だけを使いたいわけで…。
ということで、GPIO 18番だけを利用しなさい、他は使わんでくれ、と指定する。P1ピン番号を使って指定するらしい。
再度 sudo servod を実行すると、元のピン設定に戻ってしまう模様。
それと、sudo servod 実行時に --idel-timeout=1000 をつけると、指定時間(ms)が過ぎたらアイドル状態になる、ような設定にできる、のかもしれないけど、このあたりよく分かってない。
ということで、GPIO 18番だけを利用しなさい、他は使わんでくれ、と指定する。P1ピン番号を使って指定するらしい。
sudo servod --p1pins=12ただし、コレを一度発行すると、ピン番号が入れ替わるので注意。デフォルトでは、
echo 2=50 > /dev/servoblaster echo 2=213 > /dev/servoblasterと指定したけど、1本だけ有効状態にすると、以下のような指定になる。
echo 0=50 > /dev/servoblaster echo 0=213 > /dev/servoblaster
再度 sudo servod を実行すると、元のピン設定に戻ってしまう模様。
それと、sudo servod 実行時に --idel-timeout=1000 をつけると、指定時間(ms)が過ぎたらアイドル状態になる、ような設定にできる、のかもしれないけど、このあたりよく分かってない。
◎ ServoBlasterを使ったPythonスクリプト。 :
ServoBlaster を使った場合の Pythonスクリプトを書いてみたり。servo_pwm2.py として保存。
sudo python servo_pwm2.py として実行。
こちらもガクブルしなかった。指定角度で、ちゃんと止まってるように見える。
#!/usr/bin/python # -*- coding: utf-8 -*- # # required servoblaster import subprocess import time START_V = 50 END_V = 213 CENTER_V = 131 def get_pulse(ang): ang += 90 if ang < 0.0: ang = 0.0 if ang > 180.0: ang = 180.0 v = float(END_V - START_V) * (ang / 180.0) + START_V return v try: cmd = "servod --p1pins=12 --idle-timeout=1000" subprocess.call(cmd, shell=True) for ang in [0, -90, 0, 90, 0, -45, 0, 45, 0]: pulse = get_pulse(ang) print "ang = %f , v = %f" % (ang, pulse) cmd = "echo 0=%d > /dev/servoblaster" % (pulse) subprocess.call(cmd, shell=True) time.sleep(3) except KeyboardInterrupt: pass要するに、bash上で手打ちしていたコマンドを、subprocess.call() を使って再現してるだけですが。
sudo python servo_pwm2.py として実行。
こちらもガクブルしなかった。指定角度で、ちゃんと止まってるように見える。
◎ pigpioを試用。 :
ServoBlaster はイイ感じにサーボモータを制御できるのだけど、コマンドを呼び出してる感がなんだか気になるわけで。
他の方法を探してみたところ、Python + RPi.GPIO ではなく、Python + RPIO ならサーボモータ専用のモジュールが既に用意されていたそうで。しかし、RPIOは随分前から開発停止状態。Pi3 や Pi2 に非対応なのだとか。残念。
ただ、RPIO関係を調べていたら、pigpio なるものがあると知り。ServoBlasterと同様にデーモンとして動く仕組みで、コマンドラインでも使えるし、Pythonから呼ぶためのモジュールも用意されているらしい。
ということで、pigpio を試用してみる。 Raspberry Pi3 の場合は、最初からインストールされてるっぽいが、入ってない時はおそらく sudo apt-get install pigpio でインストールできるんじゃないか、という気がするけど自信無し。
デーモンの起動と殺し方。
ひとまず、コマンドラインから使ってみる。pigs というコマンドを使って、GPIOに色々送れるっぽい。
GPIO 18番にサーボモータが繋がってるものとして、1.45ms のパルス幅を送る例。
パルス幅には、500 - 2500 の値を指定可能。つまり、0.5ms - 2.5ms の範囲で指定できる。
SERVO の記述は、s でも代替できる。以下は 0.5ms、2.4ms のパルス幅を送る例。
サーボモータ用のパルスを切る例。
詳細は _pigpio library を参照。
ところで、ServoBlaster を使った際は、最大値として 213 (2.13ms) までしか指定できなかったけど。pigpio (pigs) を使った場合は、2400 (2.4ms)まで指定できた。もしかするとPWMの精度に関して、ServoBlaster より pigpio のほうが高い、ということだろうか…。わからんけど。
他の方法を探してみたところ、Python + RPi.GPIO ではなく、Python + RPIO ならサーボモータ専用のモジュールが既に用意されていたそうで。しかし、RPIOは随分前から開発停止状態。Pi3 や Pi2 に非対応なのだとか。残念。
ただ、RPIO関係を調べていたら、pigpio なるものがあると知り。ServoBlasterと同様にデーモンとして動く仕組みで、コマンドラインでも使えるし、Pythonから呼ぶためのモジュールも用意されているらしい。
ということで、pigpio を試用してみる。 Raspberry Pi3 の場合は、最初からインストールされてるっぽいが、入ってない時はおそらく sudo apt-get install pigpio でインストールできるんじゃないか、という気がするけど自信無し。
デーモンの起動と殺し方。
sudo pigpiod sudo killall pigpiod
ひとまず、コマンドラインから使ってみる。pigs というコマンドを使って、GPIOに色々送れるっぽい。
GPIO 18番にサーボモータが繋がってるものとして、1.45ms のパルス幅を送る例。
pigs SERVO 18 1450オプション内容は、pigs SERVO GPIOピン番号 パルス幅(単位はマイクロ秒?)、だと思う。
パルス幅には、500 - 2500 の値を指定可能。つまり、0.5ms - 2.5ms の範囲で指定できる。
SERVO の記述は、s でも代替できる。以下は 0.5ms、2.4ms のパルス幅を送る例。
pigs s 18 500 pigs s 18 2400
サーボモータ用のパルスを切る例。
pigs s 18 0
詳細は _pigpio library を参照。
ところで、ServoBlaster を使った際は、最大値として 213 (2.13ms) までしか指定できなかったけど。pigpio (pigs) を使った場合は、2400 (2.4ms)まで指定できた。もしかするとPWMの精度に関して、ServoBlaster より pigpio のほうが高い、ということだろうか…。わからんけど。
◎ pigpioを自動起動。 :
Raspberry Pi3起動時に、pigpio が自動で起動するようにしたい。以下のページにやり方が色々載っていた。一つは crontab を使う方法。他には、サービスとして登録できるようにする方法。
_Raspberry Pi - View topic - PIGPIO daemon
とりあえず、サービスとして登録できるやり方を試してみたり。
最初に、pigpiod の場所を ―― /usr/local/bin/以下にあるのか、/usr/bin/以下にあるのか、把握しておく。
サービス起動用の雛形ファイルをコピー。
中身を編集
/etc/init.d/pigpiod の中身は、上記のサイトからコピペ。ただし、Pi3 などでは、
DAEMON=/usr/local/bin/$NAME
の行は、
DAEMON=/usr/bin/$NAME
になる。かもしれない。
サービスとして登録。
サービスの起動・終了ができるか確認してみる。
_Raspberry Pi - View topic - PIGPIO daemon
とりあえず、サービスとして登録できるやり方を試してみたり。
最初に、pigpiod の場所を ―― /usr/local/bin/以下にあるのか、/usr/bin/以下にあるのか、把握しておく。
which pigpiod
サービス起動用の雛形ファイルをコピー。
sudo cp /etc/init.d/skeleton /etc/init.d/pigpiod sudo chmod 755 /etc/init.d/pigpiod
中身を編集
sudo vi /etc/init.d/pigpiod
/etc/init.d/pigpiod の中身は、上記のサイトからコピペ。ただし、Pi3 などでは、
DAEMON=/usr/local/bin/$NAME
の行は、
DAEMON=/usr/bin/$NAME
になる。かもしれない。
サービスとして登録。
sudo update-rc.d pigpiod defaults sudo update-rc.d pigpiod enable
サービスの起動・終了ができるか確認してみる。
sudo service pigpiod start sudo service pigpiod status
sudo service pigpiod stop sudo service pigpiod status
◎ 参考ページ。 :
_サーボモーター(SG-90)を試す - Raspberry Pi 備忘録
_くたじんの鎌倉生活 RaspberryPiのPWM制御、周波数とデューティー比について
_Raspberrypi2 PWMでサーボモータを動かす | Myブーム & My備忘録
_くたじんの鎌倉生活 RaspberryPiのPWM制御、周波数とデューティー比について
_Raspberrypi2 PWMでサーボモータを動かす | Myブーム & My備忘録
pwmSetClockの値の設定についてだが、調べたところ以下の条件式が成立するらしい。ということは、50ms にしたいなら…。clock = 18750 / 50 = 375、なのかな。
- pwm周波数=raspiのPWMが持つベースクロック周波数/clock * range
- pwm周波数: 50Hz
- raspiのPWMが持つベースクロックの周波数: 19.2MHz
- range: 1024
- clock: pwmSetClockで設定する値
従ってclockを求める式は、clock = 19.2 x 10^6 / (pwm周波数 x 1024) となる。
故に、clock = 18750 / pwm周波数
[ ツッコむ ]
以上です。