Raspberry Pi : WiringPi-PythonでPWM

前回の
RaspberryPi : GPIOの制御方法にふれる
に続いて、実践的にPythonからモーター制御に欠かせないPWM制御について実装方法を学ぶ。

WiringPiライブラリのインストール

ライブラリとその他必要そうなものをインストールしておく。
WiringPiのインストールでは、コンパイルも実行されて大量のエラーが出力されて不安になるが、最後にSuccessfullyが出ればよさそう。
(ついでにRPI.GPIOもインストールしておく)

> sudo apt-get install python-dev
> sudo apt install python3-pip
> sudo pip3 install wiringpi rpi.gpio
:
Successfully installed wiringpi
Cleaning up...

WiringPiのAPIドキュメント

備忘録 wiringPi API

WiringPiを使ってGPIO18にPWMを設定する検証プログラムを作成し、波形を確認する。GPIO番号を指定したピンに対し、PWMに変更して周期[ms]、パルス幅[ms]を設定する。

#!/usr/bin/env python3
# coding: utf-8

# command args
# [1] pin number (GPIOn)
# [2] 周期 [ms]
# [3] パルス幅[ms]
# >python3 pi_servo.py 18 20 2

import sys
import wiringpi

args = sys.argv
argc = len( args )

if argc != 4 :
        print("error : invalid arguments")
        print("ex.) python3 pi_servo.py 18 20 2")
        quit()

pwm_pin = int( args[1] )
interval = float( args[2] )
pulse = float( args[3] )

"""
PWMは、以下の式で成り立つ

[PWM周波数] = 19.2MHz / [Clock] / [Range]
[Duty比] = [Duty] / [Range]

wiringpiでは、[Range] = 1024で固定し、[Clock]と[Duty]
の2つのパラメータでPWMを制御する

[Range] = 1024
[PWM周波数] = 18750 / [Clock]
[Duty比] = [Duty] / 1024
"""

range = 1024
duty_ratio = pulse / interval
hz = 1 / ( interval * 0.001 )
clock = int( 18750 / hz )
duty = int( duty_ratio * range )

print("pin = ", pwm_pin, " interval[ms] = ", interval, " pulse[ms] = ", pulse )
print("clock = ", clock, " duty=", duty, " duty_ratio=", duty_ratio )

# 初期設定
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode( pwm_pin, wiringpi.GPIO.PWM_OUTPUT )
wiringpi.pwmSetMode( wiringpi.GPIO.PWM_MODE_MS )

# ClockとDutyを設定してPWMを生成する
wiringpi.pwmSetClock( clock )
wiringpi.pwmWrite( pwm_pin, duty )

ところが、実行すると以下のメッセージが。。

> python3 pi_servo.py
clock =  375  duty= 102  duty_ratio= 0.1
Unable to determine hardware version. I see: Hardware   : BCM2835
,
 - expecting BCM2708 or BCM2709.
If this is a genuine Raspberry Pi then please report this
to projects@drogon.net. If this is not a Raspberry Pi then you
are on your own as wiringPi is designed to support the
Raspberry Pi ONLY.

どうも調べると、実行環境のカーネルが新しくてライブラリが対応してないようなことが記述されている。4.9系が云々と。

> uname -a
Linux raspi2 4.9.35-v7+ #1014 SMP Fri Jun 30 14:47:43 BST 2017 armv7l GNU/Linux

最近ダウンロードしたイメージなので、そういうことです。

e在京白堊会

に4.9に対応する方法がありました。
ほかはKernelをダウングレードする方法が大半。検討した結果ダウングレードの方が早そう。

4.4系のラストバージョンは、4.4.50以下のハッシュでカーネルのダウングレードを実施する。

> sudo rpi-update 52241088c1da59a359110d39c1875cda56496764
:
 *** Updating firmware
 *** Updating kernel modules
 *** depmod 4.4.50-v7+
 *** depmod 4.4.50+
 *** Updating VideoCore libraries
 *** Using HardFP libraries
 *** Updating SDK
 *** Running ldconfig
 *** Storing current firmware revision
 *** Deleting downloaded files
 *** Syncing changes to disk
 *** If no errors appeared, your firmware was successfully updated to 52241088c1da59a359110d39c1875cda56496764
 *** A reboot is needed to activate the new firmware
> sudo reboot

リブート後バージョンを確認

> uname -a
Linux raspi2 4.4.50-v7+ #970 SMP Mon Feb 20 19:18:29 GMT 2017 armv7l GNU/Linux

気を取り直して、プログラムが正常動作するか確認

> sudo python3 pi_servo.py 18 20 10
pin =  18  interval[ms] =  20.0  pulse[ms] =  10.0
clock =  375  duty= 512  duty_ratio= 0.5

> sudo python3 pi_servo.py 18 20 5
pin =  18  interval[ms] =  20.0  pulse[ms] =  5.0
clock =  375  duty= 256  duty_ratio= 0.25

> sudo python3 pi_servo.py 18 20 15
pin =  18  interval[ms] =  20.0  pulse[ms] =  15.0
clock =  375  duty= 768  duty_ratio= 0.75

サーボを取り付けて、実際に動かしてみる

使用したサーボはRB-50というミニサーボを利用。最大パルス幅を指定すると、反時計回りに回転し、最小パルス幅だとその逆に回転する。公称値よりも0.1~0.2ほど広く回転したが個体差があるので、個別に確認が必要。

> sudo python3 pi_servo.py 18 20 2.2
pin =  18  interval[ms] =  20.0  pulse[ms] =  2.2
clock =  375  duty= 112  duty_ratio= 0.11000000000000001

> sudo python3 pi_servo.py 18 20 1.3
pin =  18  interval[ms] =  20.0  pulse[ms] =  1.3
clock =  375  duty= 66  duty_ratio= 0.065

> sudo python3 pi_servo.py 18 20 0.5
pin =  18  interval[ms] =  20.0  pulse[ms] =  0.5
clock =  375  duty= 25  duty_ratio= 0.025