はじめに
前回、Donkey Car から PCA9685 を取っ払って、ESC・サーボをラズパイに直結するという記事を書きました。これはPWM出力にServoBlasterを利用するものでした。
ServoBlasterはapt
でインストールできず、なんだかアウェイ感が否めません(※個人の感想です)
その記事でも書きましたが、pigpioが使えそうです。こちらはapt
でインストールできるホーム感がうれしいところです。
ということで、pigpio を使ってまいります。
pigpio インストール
apt
でインストールできてホーム感がありますね(大事なことではないけど2回言ってみました)
sudo apt install python3-pigpio
sudo systemctl start pigpiod
manage.py 追記
(あとで仕切り直しで上書きしますが、参考までに)
elif cfg.DRIVE_TRAIN_TYPE == "SERVO_ESC_PIGPIO":
from donkeycar.parts.actuator import PiGPIO_PWM, PWMSteering, PWMThrottle
steering_controller = PiGPIO_PWM(cfg.STEERING_CHANNEL)
steering = PWMSteering(controller=steering_controller,
left_pulse=cfg.STEERING_LEFT_PWM*305,
right_pulse=cfg.STEERING_RIGHT_PWM*305)
throttle_controller = PiGPIO_PWM(cfg.THROTTLE_CHANNEL)
throttle = PWMThrottle(controller=throttle_controller,
max_pulse=cfg.THROTTLE_FORWARD_PWM*305,
zero_pulse=cfg.THROTTLE_STOPPED_PWM*305,
min_pulse=cfg.THROTTLE_REVERSE_PWM*305)
V.add(steering, inputs=['angle'])
V.add(throttle, inputs=['throttle'])
*305
は何をやっているかというと、PCA9685のときの設定値を流用するための係数です。
ServoBlasterで設定した4マイクロ秒ベースの値を使う場合は*300
にしましょう。
ラジコンの世界からやってきて、1マイクロ秒ベースで設定したい場合は*75
にしましょう。
なお、1は1/75/1000000[s]
です。
myconfig.py 修正
(あとで仕切り直しで上書きしますが、参考までに)
下記定数3つを修正します。
DRIVE_TRAIN_TYPE = "SERVO_ESC_PIGPIO"
STEERING_CHANNEL = 12 #pin number on the Raspberry Pi
THROTTLE_CHANNEL = 13 #pin number on the Raspberry Pi
今回は物理ピン番号でなく、GPIO番号のほうで指定します。ややこしや。
12と13を選んだのは、ハードウェアの制約でほぼそれしか選べないからです。
使えないピンを選ぶと manager.py
起動時に
pigpio.error: 'GPIO has no hardware PWM'
というエラーが出て実行出ません。
制約がきつすぎますね。ピンが隣り合っていないと、前回記事の「これをこうしてこうじゃ」の簡単な配線ができなくて微妙です。
仕切り直し
DonkeyCar の PiGPIO_PWM
クラスのソースを読んでみると、pigpioのhardware_PWM() を利用しています。これは2chしかないハードウェアPWMをそのまま使っていてモッタイナイです。
一方、pigpioには set_servo_pulsewidth() という関数もあるので、こちらを使いたいと思います。
ServoBlaster は PWMとDMAを組み合わせて、多チャンネルPWMを実現しています。詳しく調べていませんが、 pigpio のset_servo_pulsewidth() も同じ仕組みで動いていると思われます。
PiGPIO_SERVOクラス作成
クラスの内容は以下の通りとなります。
PWM周波数の設定をしていませんが、50Hzで動いているようです。これは特に変える必要はないでしょう。
class PiGPIO_SERVO():
def __init__(self, pin, pgio=None):
import pigpio
self.pin = pin
self.pgio = pgio or pigpio.pi()
self.pgio.set_mode(self.pin, pigpio.OUTPUT)
def __del__(self):
self.pgio.set_servo_pulsewidth(self.pin, 0)
self.pgio.stop()
def set_pulse(self, pulse):
self.pgio.set_servo_pulsewidth(self.pin, pulse)
def run(self, pulse):
self.set_pulse(pulse)
本来は ~/projects/donkeycar/donkeycar/parts/actuator.py
に追記するものと思いますが、書き換えるファイルが増えるとバージョンアップなどの際に面倒なことになるので manager.py
の適当なところに追記しちゃいましょう。
__del__
の中で self.pgio.set_servo_pulsewidth(self.pin, 0)
としているのは、非動作時にPWM出力を止めてサーボをお休みさせるためです。
manager.py修正
ふたたび manager.py
の編集です。
上の方で追記したところを下記のように書き換えます。
(PiGPIO_PWM
の利用は無かったことにします)
elif cfg.DRIVE_TRAIN_TYPE == "SERVO_ESC_PIGPIO":
from donkeycar.parts.actuator import PWMSteering, PWMThrottle
steering_controller = PiGPIO_SERVO(cfg.STEERING_CHANNEL)
steering = PWMSteering(controller=steering_controller,
left_pulse=cfg.STEERING_LEFT_PWM*4.069,
right_pulse=cfg.STEERING_RIGHT_PWM*4.069)
throttle_controller = PiGPIO_SERVO(cfg.THROTTLE_CHANNEL)
throttle = PWMThrottle(controller=throttle_controller,
max_pulse=cfg.THROTTLE_FORWARD_PWM*4.069,
zero_pulse=cfg.THROTTLE_STOPPED_PWM*4.069,
min_pulse=cfg.THROTTLE_REVERSE_PWM*4.069)
V.add(steering, inputs=['angle'])
V.add(throttle, inputs=['throttle'])
*4.069
は何をやっているかというと、PCA9685のときの設定値を流用するための係数です。
PiGPIO_SERVO
クラスの追加をマジメに actuator.py
に行った場合は、 import
に PiGPIO_SERVO
を追加しましょう。
myconfig.py 修正
下記定数3つを修正します。
DRIVE_TRAIN_TYPE = "SERVO_ESC_PIGPIO"
STEERING_CHANNEL = 17 #pin number on the Raspberry Pi
THROTTLE_CHANNEL = 27 #pin number on the Raspberry Pi
今回も物理ピン番号でなく、GPIO番号のほうで指定します。
前回の記事と同じピンを使うように設定してみました。
配線
配線は前回記事と同様です。
(同じにするためにわざわざ PiGPIO_SERVO
クラスを作成しました)
走行
あとはいつものように走行するだけです!
cd ~/mycar
python manage.py drive
(実は、「Webコントローラーから制御できてるな」という確認までしただけで、教師走行や自律走行は試しておりません。。。)
細かい話:PWM設定値
set_servo_pulsewidth()
はマイクロ秒で指定します。ラジコンの世界から来た人には分かりやすいです。値の指示はマイクロ秒単位でできますが、実際の精度はデフォルトだと5マイクロ秒らしいです。
精度を1マイクロ秒にもできるようですが、メカ側の精度がそんなにないと思うのでいじらなくてもいいんじゃないかと思います。
専用ハードウェアのPCA9685の場合で約4マイクロ秒精度ですし。
おまけ:キャリブレーション
pigs SERVO 17 1500
にて、手動でPWM出力できます。
一応説明しておくと、17がGPIO番号、1500が出力値です。
socket connect failed
というエラーが出る場合は、sudo raspi-config
で、Remote GPIO
を有効にしてください。(5 Interfacing Options
-> P8 Remote GPIO
にあります)
用事が済んだら
pigs SERVO 17 0
として出力を止めるとサーボ・バッテリーにやさしいと思います。
おわりに
環境整備ばかりしていて教師走行をしておりませんorz
CONFIG.SYS, AUTOEXEC.BATを延々いじっていた学生時代を思い出しますw