mieki256's diary



2016/07/19(火) [n年前の日記]

#1 [raspberrypi] Raspberry Pi3でサーボモータを制御。その1

秋月電子から購入したマイクロサーボモータ、 _SG92R を、Raspberry Pi3 から制御したいなと。

サーボモータってのは…。この場合は、PWMで角度を指定して動かせるモータ、という認識でいいのだろうか。 _サーボモータ - Wikipedia を眺めるとゴイスなヤツからホビー用まで色々あるらしいけど。今回使うのはホビー用。

仕様をメモ。 :

とりあえず、SG92Rの仕様を秋月電子さんのサイトからコピペしてメモ。特に、PWMサイクル、制御パルスの仕様が重要。
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

マイクロサーボ SG92R: サーボ 秋月電子通商 電子部品 ネット通販 より


つまり、20ms間隔でPWMを流して…。0.5ms幅のパルスを送ると -90度に、2.4ms幅のパルスを送ると90度にモータが回転してくれる、のであろうと。

ピンコネクタでちょっと失敗。 :

サーボモータの端子をブレッドボードに差すために、 _細ピンヘッダ 1 x 20 も購入したのだけど。試してみたら長さが足りなかった…。もしかすると、ここは _両端ロングピンヘッダ なるものを購入すべきだったのだろうか…。

とりあえず、 _ブレッドボード用ジャンパーコード(オス - オス) をサーボモータ側の端子に差し込んでどうにか。

回路図。 :

こんな感じに。
servo_motor_02_bb.png

servo_motor_02_c.png
  • 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 として保存。
#!/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 使用時と違う結果になるのでは。試してみないと。

インストールは以下。
$ git clone git://github.com/richardghirst/PiBits.git
$ cd PiBits/ServoBlaster/user
$ make servod
$ sudo make install
servod てのが、コマンド名(?)らしい。

デーモンとして起動。あるいは、デーモンが起動中なら現在の状態を表示。
sudo servod

デーモンを終了。
sudo killall servod

ServoBlaster をインストールすると、サービスとして自動起動するように設定される。自動起動しないように設定する場合は以下。
sudo update-rc.d servoblaster remove

自動起動するように設定する場合は以下。
sudo update-rc.d servoblaster defaults

サーボ番号と、GPIO番号の対応は以下のようになってるらしい。コピペさせてもらってメモ。
サーボ番号01234567
GPIO番号4171821/2722232425
P1ピン番号?711121315161822

例えば、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/servoblaster
213より大きい値を指定すると異音がする…おそらく回りっぱなし…。本来なら 240 まで指定できそうだが…。

つまり、ServoBlaster + SG92R を使う際は、-90度 = 50, 0度 = 131, 90度 = 213 を指定する感じになりそう。

さておき。前述のPythonスクリプトで制御するとガクブルだったけど、ServoBlaster を使った場合は、ちゃんとピタリと止まってくれた。状況が改善した、ような気がする。

ServoBlasterが握るピンの数を変更。 :

ところで、このままだと ServoBlaster が複数のGPIOのピンを握り続けてしまって、他の実験がちょっとやりにくくなる。今回は GPIO 18番だけを使いたいわけで…。

ということで、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 として保存。
#!/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 でインストールできるんじゃないか、という気がするけど自信無し。

デーモンの起動と殺し方。
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/以下にあるのか、把握しておく。
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備忘録
pwmSetClockの値の設定についてだが、調べたところ以下の条件式が成立するらしい。

- 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周波数
ということは、50ms にしたいなら…。clock = 18750 / 50 = 375、なのかな。

以上です。

過去ログ表示

Prev - 2016/07 - Next
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project