はじめに
Jetson.GPIO Python library に付属している PWM のサンプルスクリプトがやっと動いたのでメモに残しておきます。まずは動画です。
他の 5 つのサンプルスクリプトは書籍「Jetson Nano超入門」で執筆させていただきました。
サンプルスクリプト
- simple_input.py
simple_input.pyはピン番号12(Raspberry Pi GPIO番号18)の入力値を読み取り、その値を画面に表示しま す。 - simple_out.py
simple_out.pyはピン番号12(Raspberry Pi GPIO番号18)の出力値を2秒ごとに変化させ、HIGHとLOW を交互に出力します。 - button_led.py
button_led.py はボタンの状態を読み取り、LED を点灯させます。ピン番号 18 と GND に接続されたボタン、ピ ン番号 18 と +3.3V に接続されたプルアップ抵抗、ピン番号 12 に接続された LED と電流制限抵抗が必要です。1 秒ごとにボタンの状態を読み取り、ボタンが押されている間は LED を点灯し続けます。 - button_event.py
button_event.py は、button_led.py と同様にボタンの状態を読み取り、LED を点灯させます。ピン番号 18 と GND に接続されたボタン、ボタンを +3.3V に接続するプルアップ抵抗、ピン番号 12 に接続された LED と電流制 限抵抗が必要です。button_led.py と機能は同じですが、CPU 使用量を減らすためにピン番号の入力値を継続的 にチェックする代わりにボタンを押すイベントにプログラムを変更しています。 - button_interrupt.py
button_interrupt.py は、ボタンの状態を読み取り、2 つの LED の点滅を制御します。ピン番号 18 と GND に接 続されたボタン、ピン番号 18 と +3.3V に接続されたプルアップ抵抗、ピン番号 12 に接続された 1 つ目の LED と 電流制限抵抗、ピン番号 13 に接続された 2 つ目の LED と電流制限抵抗が必要です。1 番目の LED が 2 秒ごとに遅 く点滅し、ボタンが押されると 2 番目の LED が 0.5 秒ごとに素早く連続して 5 回点滅します。
simple_pwm.py
ライブラリの README.md には「PWM チャンネルの使い方の詳細は simple_pwm.py を見ろ。」としか書かれておらず、他のサンプルスクリプトと比較して理解するのに苦労しました。
「Jetson.GPIO ライブラリは、ハードウェア PWM コントローラーが接続されたピンでのみ PWM をサポートします。 RPi.GPIO ライブラリとは異なり、Jetson.GPIO ライブラリはソフトウェアエミュレート PWM を実装していません。Jetson Nano は 2 つのハードウェア PWM チャンネルをサポートしています。システム pinmux は、ハードウェア PWM コントローラーを関連するピンに接続するように構成する必要があります。 pinmux が設定されていない場合、PWM 信号はピンに到達しません。Jetson.GPIO ライブラリは、これを実現するために pinmux 構成を動的に変更しません。 pinmux の構成方法の詳細については、L4T のドキュメントを読んでください。」
pinmux や L4T (=Linux for Tegra) ドキュメントなどハードルが高かったのですが、ようやく理解が追いついて無事に動かすことができました。
結論から先に言うと、正しく pinmux 設定さえできればサンプルスクリプトを動かすことができました。
JetPack 4.3 (r32.3.1) で追加された Jetson-IO tool を使用すると Pinmux の設定が容易になったことが大きかったです。
(参考)
JetPack 4.3 (r32.3.1) で追加された Jetson-IO tool を使用して Pinmux テーブルを設定してみた。
Jetson Nano の 2 つのハードウェア PWM を使用してみた。
サーボモーターを動かすためのスクリプトの修正
まず、付属しているサンプルスクリプトの内容を理解します。
- Jetson Nano の場合は PWM の出力に 33 ピンを使用します。
- PWM サイクル (周期) は 20 ms (50 Hz) を設定します。
- Duty 比 (パルス幅を周期で割った比率) は 25% を設定します。
import RPi.GPIO as GPIO
import time
output_pins = {
'JETSON_XAVIER': 18,
'JETSON_NANO': 33,
}
output_pin = output_pins.get(GPIO.model, None)
if output_pin is None:
raise Exception('PWM not supported on this board')
def main():
# Pin Setup:
# Board pin-numbering scheme
GPIO.setmode(GPIO.BOARD)
# set pin as an output pin with optional initial state of HIGH
GPIO.setup(output_pin, GPIO.OUT, initial=GPIO.HIGH)
p = GPIO.PWM(output_pin, 50)
p.start(25)
print("PWM running. Press CTRL+C to exit.")
try:
while True:
time.sleep(1)
finally:
p.stop()
GPIO.cleanup()
if __name__ == '__main__':
main()
2 つのサーボモーター (Geekservo 9g 360°サーボモーター) を使用するため、スクリプトを修正する必要があります。
- ピン設定
2 個 (32ピン、33ピン) へ変更 - PWM サイクル
20 ms (50 Hz) →変更なし - 制御パルス
0.5 ms 〜 2.4 ms →Duty 比を 2.5% (-90°方向へ回転) 〜 7.25%(0°=静止) 〜 12%(+90°方向へ回転) へ変更
(修正後のスクリプト)
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
output_pin1 = 32
output_pin2 = 33
def main():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(output_pin1, GPIO.OUT, initial=GPIO.HIGH)
p1 = GPIO.PWM(output_pin1, 50)
GPIO.setup(output_pin2, GPIO.OUT, initial=GPIO.HIGH)
p2 = GPIO.PWM(output_pin2, 50)
print("PWM running. Press CTRL+C to exit.")
try:
while True:
p1.start(2.5)
print("p1 start at 2.5%")
time.sleep(1)
p2.start(2.5)
print("p2 start at 2.5%")
time.sleep(1)
p1.start(7.25)
print("p1 start at 7.25%")
time.sleep(1)
p2.start(7.25)
print("p2 start at 7.25%")
time.sleep(1)
p1.start(12)
print("p1 start at 12%")
time.sleep(1)
p2.start(12)
print("p2 start at 12%")
time.sleep(1)
p1.start(7.25)
print("p1 start at 7.25%")
time.sleep(1)
p2.start(7.25)
print("p2 start at 7.25%")
time.sleep(1)
finally:
p1.stop()
p2.stop()
GPIO.cleanup()
if __name__ == '__main__':
main()
(実行結果)
$ python3 simple_pwm_servo.py
PWM running. Press CTRL+C to exit.
p1 start at 2.5%
p2 start at 2.5%
p1 start at 7.25%
p2 start at 7.25%
p1 start at 12%
p2 start at 12%
p1 start at 7.25%
p2 start at 7.25%
...