NVIDIA Jetson TX2のGPIOでざっくり遊んでみた話(Jetson.GPIO)

# 背景
最近Jetson nanoが発売され、巷ではJetsonブームが起きている（らしい）。
どうやらラズパイ感覚でJetsonのGPIOが使えるらしいから、ちょっと触ってみようと思う。

# 注意点
やっていることは、ほとんどこのサイトの中にある内容である。
だから、既にGPIOでゴニョゴニョ手を動かしている人は今すぐブラウザバックだ！

- NVIDIA/jetson.GPIO
https://github.com/NVIDIA/jetson-gpio

---

# つかったもの
最後の一個は、ぶっちゃけ検証にはいらない。
けど、GPIOから出力する信号（PWM、UARTとか）を見るときには結構重宝する。

- Jetson TX2(Jetpack4.2) 1台
- LED1個
- 抵抗２個（自分は300 Ωのカーボン抵抗をつかった）
- メスーオスのジャンパ４本
- オスーオスのジャンパ１本
- ダクトスイッチ1個
- ブレッドボード1個
- Analog Discovery ２(メルカリで22 k円で買ったｗ)

---

# インストール方法
Jetson本体のセットアップとpython3(pip3含む)のインストールが完了していることを仮定して、手順を説明する。
ここで述べる内容はGPIOを使えるようにするための手順である。
(注意:本操作はJetson側で実施する。)

1. [このサイト（Jetson.GPIO本家のリポジトリ）](https://github.com/NVIDIA/jetson-gpio)で*Clone or Download*をクリックし、*Download ZIP*からZipファイルを取得する。
2. *sudo mkdir /opt/nvidia*を実行する（既にフォルダが存在してる場合は不要）。
3. *sudo unzip <保存したZipファイルのパス> -d /opt/nvidia/*を実行する。その後、*/opt/nvidia*に*jetson-gpio*フォルダが作成されていることを確認する。
4. *sudo pip3 install Jetson.GPIO*でpython3用のモジュールをインストールする。
5. 以下のコマンドを入力する（GPIOの操作に関する権限の設定とデバイスファイル関係）。

```console:command
sudo groupadd -f -r gpio
sudo usermod -a -G gpio <ユーザー名>
sudo cp /opt/nvidia/jetson-gpio/etc/99-gpio.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm trigger
```

---

# GPIOをつかってみる
インストールが完了したことを確認するために、早速GPIOを使ってみる。
ブレッドボード上にこんな感じで結線する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/d4bab2d1-2014-b325-49c7-907f71c7163e.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/86ad01b0-afb3-377e-67d3-aecdaf9b1373.png" width=50%>

GPIOはJ21▲というマークのあるピンを1番目として数える。左→右→左下→...という順に
GPIOのナンバリングをカウントアップする。

配線が終わったら、Jetson側で好きなエディタで以下のプログラムを書く。

```python:testLED.py
import Jetson.GPIO as GPIO
import time

# 使用するGPIOピン。ピン番号は以下のjetsonhackのサイトを参考にしたよ                                                                                                                                        
led_pin = 12
button_pin = 13

# LEDの状態を保持するよ。                                                                                                                                                                                   
prev_value = None

# pin番号の指定方法を設定。この場合だと以下サイトの◎のピン番号で指定するよ                                                                                                                                  
# https://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout/                                                                                                                                          
GPIO.setmode(GPIO.BOARD)

# 出力に使うピンと入力に使うピンを設定する。                                                                                                                                                                
GPIO.setup(led_pin, GPIO.OUT)
GPIO.setup(button_pin, GPIO.IN)

# 最初はLEDを消灯させるよ                                                                                                                                                                                   
GPIO.output(led_pin, GPIO.LOW)

print("LED点滅開始！CTRL+Cで中止するよ！")

try:
    while True:
        # ボタン入力の状態(GPIO.HIGH/GPIO.LOW)を取得するよ                                                                                                                                                  
        cur_value = GPIO.input(button_pin)

        # 過去のボタン入力と今のボタン入力が違う場合に処理に入るよ                                                                                                                                          
        if(cur_value != prev_value):
            # LEDの出力を反転させるよ                                                                                                                                                                       
            GPIO.output(led_pin, not cur_value)
            # 反転後のLED出力を保存するよ                                                                                                                                                                   
            prev_value = cur_value
            print("pin:{} output:{}".format(led_pin, cur_value))

        # 無限ループで怒られないように10 msだけ待機するよ。                                                                                                                                                 
        time.sleep(0.01)

except KeyboardInterrupt:
    pass

finally:
    # LEDとボタンで使っていたGPIOを開放するよ。                                                                                                                                                             
    GPIO.cleanup()
    print("終了します")
```
プログラムを実行してボタンをおすと、押している間だけLEDが光り、離すとLEDが消灯することが確認できるはず。また、標準出力にピン出力に関する情報が表示されると思う。
飽きたら*Ctrl+C*で終了する。

このプログラムが実行できれば、おそらく環境構築に問題は無いハズ。。。

---

# PWMを簡単に作ってみた話（余談）
Raspberry Piと同じノリでPWMを使おうとしたらエラーが出た。かなしい。
多分ADC/DACが無いから作らなかったというところだろうか？（あるいは見落としているだけ？
<img width="80%" alt="スクリーンショット 2019-05-03 22.58.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/00e3d5e7-d415-e0ee-c024-00807b57b4e3.png">

仕方がない。自分でつくろう。そんなわけで以下のコードである。

```python:testPWM.py
import Jetson.GPIO as GPIO
import time

# PWMもどき                                                                                                                                                                                                 
# Jetson.GPIOにはまだPWMが無いっぽい(´・ω・｀)                                                                                                                                                              
def PWM(pin,duty,ms):
    low_duty = 100-duty
    GPIO.output(pin, GPIO.HIGH)
    time.sleep(ms*(duty/100))
    GPIO.output(pin,GPIO.LOW)
    time.sleep(ms*(low_duty/100))

# 使用するGPIOピン。ピン番号は以下のjetsonhackのサイトを参考にしたよ                                                                                                                                        
pwm_pin = 12
button_pin = 13

# pin番号の指定方法を設定。この場合だと以下サイトの◎のピン番号で指定するよ                                                                                                                                  
# https://www.jetsonhacks.com/nvidia-jetson-tx2-j21-header-pinout/                                                                                                                                          
GPIO.setmode(GPIO.BOARD)

# 出力に使うピンと入力に使うピンを設定する。                                                                                                                                                                
GPIO.setup(pwm_pin, GPIO.OUT)
GPIO.setup(button_pin,GPIO.IN)

# 最初はLEDを消灯させるよ                                                                                                                                                                                   
duty = 0

print("LED点滅開始！CTRL+Cで中止するよ！")

try:
    while True:
        # ボタン入力の状態(GPIO.HIGH/GPIO.LOW)を取得するよ                                                                                                                                                  
        value = GPIO.input(button_pin)

        # Duty比をかえてみるよ                                                                                                                                                                              
        if(value):
            duty = 100
        else:
            duty = 10
        # 1kHz(0.001ms)の疑似PWMを作った。                                                                                                                                                                  
        PWM(pwm_pin,duty,0.001)

except KeyboardInterrupt:
    pass

finally:
    # LEDとボタンで使っていたGPIOを開放するよ。                                                                                                                                                             
    GPIO.cleanup()
    print("終了します")
```
LEDで光らせて確認してみたのもあるけれども、せっかくだから
Analog Discovery２で確認してみた。してみたかったんだ。

<img width="1222" alt="スクリーンショット 2019-05-03 23.25.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/ceaecb49-eb59-b197-ab02-c610215f81c9.png">

オーバーシュートちょっと大きい気がするけど、PWMっぽいしいいや（おい
PWMができれば、サーボモータとかそのあたりは普通に使えそう。

---

# まとめ
- Jetson.GPIOはラズパイっぽくつかえる。（ただし、PWMやADCなどは無い？）
- Jetson.GPIOはHigh/Lowの入力/出力のみ。
- 当たり前な話だけど、おなじみの方法でPWMは作れる。

---

# 余談（真似してはいけないこと）
*GPIO.setup(hoge_pin, GPIO.OUT)*したピンに電圧を印加すると、JetsonTX2が落ちる。
その時には、一度電源ジャックを抜き差しして、再度電源を入れてあげると復旧する。
（保護回路が動いたのかな。良い子は真似してはいけない）