$30 off During Our Annual Pro Sale. View Details »

PythonでRaspberry PiのGPIOを制御する

kioto
November 13, 2019

PythonでRaspberry PiのGPIOを制御する

みんなのPython勉強会 #51 発表資料
https://startpython.connpass.com/event/150918/

kioto

November 13, 2019
Tweet

More Decks by kioto

Other Decks in Programming

Transcript

  1. PythonでRaspberry Piの
    GPIOを制御する
    2019/11/13
    平原貴⾳
    Start Python Club #51

    View Slide

  2. Motivation
    MMFS2019 : Mini MakerCon Tokyo 2019
    ⽇本の名カームブメントの⾃⽴と持続可能性を議論する。

    View Slide

  3. Motivation
    • できないことができるようにするのは喜びがあ
    る。しかし⾝の回りのものは「できることをや
    らないようにすむ」ようにしている。
    • できるようになる喜びを味わえるように

    View Slide

  4. Motivation
    • 「⾃分が得たものをほかの⼈に伝える」
    • 「⾃分が学んでいる姿を⼈に⾒せる」

    View Slide

  5. Agenda
    • GPIOとは
    • Input
    • スイッチON/OFF
    • Output
    • Lチカ
    • サーボモーター
    • サンプルプログラム
    • https://github.com/kioto/raspi_gpio_sample
    (この資料はRaspberry Pi 3B + Raspbian Stretchで動作確認)

    View Slide

  6. GPIOとは
    • General-Purpose Input/Output
    • ⽇本語で⾔うと「汎⽤⼊出⼒」
    • 汎⽤じゃないI/O
    • SPI
    • I2C
    • UART

    View Slide

  7. Raspberry PiのI/O
    • GPIOは24系統
    • UARTは1系統
    • SPIは2系統
    • GPIOとピン共⽤
    • I2Cは1系統
    • GPIOとピン共⽤
    • ピン配置の確認
    • https://pinout.xyz

    View Slide

  8. デモのシステム構成
    USB3
    USB
    Analog Discovery 2
    MacBook Pro
    Raspberry Pi 4
    プローブ
    I/O
    ブレッドボード

    View Slide

  9. Analog Discovery 2
    • 「アナログ回路万能測定ツール」
    • という名称で秋⽉電⼦で紹介されている
    • 千⽯電商、共⽴エレショップでも売ってる
    • オシロスコープ
    • アナログ波形を観測
    • ロジックアナライザ
    • デジタル波形を観測
    • 可変電圧DC電源
    • etc…

    View Slide

  10. Input
    • GPIOでデジタル⼊⼒
    • タクトスイッチ
    • 押すとON
    • 離すとOFF

    View Slide

  11. 実体配線図
    • こんな感じ

    View Slide

  12. Fritzing
    • 回路図エディタ
    • 実体配線図も描ける
    • 昔は無料だったけど今は有料?
    • http://fritzing.org

    View Slide

  13. SW⼊⼒検知プログラム
    5 import RPi.GPIO as GPIO
    6 import time
    7
    8 SWITCH_PORT = 23
    9
    10 GPIO.setmode(GPIO.BCM) # GPIO番号で指定
    11 GPIO.setup(SWITCH_PORT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    12
    13 state = False
    14 while True:
    15 current_state = GPIO.input(SWITCH_PORT)
    16 if current_state != state:
    17 if current_state:
    18 print('OFF')
    19 else:
    20 print('Pushed')
    21 state = current_state 01_switch.py

    View Slide

  14. 01_switch.py
    • パッケージはRpi.GPIOを使⽤
    • ⼊⼒はGPIO 23番を使⽤
    • setMode()でピン番号の指定⽅法を設定
    • setup()
    • ⼊⼒ピン設定
    • プルアップ(HighでON)設定
    • input()でピンの状態を取得
    • whileループで監視

    View Slide

  15. ターミナルマルチプレクサ
    • Raspbianにログインする時に使う便利なコマンド
    • 昔はscreenコマンド、今はtmux
    • 単⼀のウィンドウで複数のセッション
    • 制御端末からプロセスを切断できる
    • 通信が切れてもセッションは⽣きている
    • 使い⽅
    • c:セッション追加
    • d :デタッチ
    • tmux ls:セッション確認
    • tmux a [-t セッション名]:アタッチ

    View Slide

  16. Pythonプログラムの実⾏
    • 必ずsudoで実⾏すること
    • rootでないとGPIOデバイスにアクセスできないから
    $ sudo python3 01_switch.py

    View Slide

  17. SW⼊⼒検知プログラム
    • 割り込み制御のコード
    13 def cb_switch(ch):
    14 current_state = GPIO.input(ch)
    15 if current_state:
    16 print('OFF')
    17 else:
    18 print('Pushed')
    19
    20
    21 GPIO.add_event_detect(SWITCH_PORT, GPIO.BOTH, callback=cb_switch)
    22
    23 time.sleep(10) # なにか処理をしているものとする
    01_switch_inter.py

    View Slide

  18. 01_switch_inter.py
    • パッケージはRpi.GPIOを使⽤
    • ⼊⼒はGPIO 23番を使⽤
    • setMode()でピン番号の指定⽅法を設定
    • setup()で⼊⼒ピンとプルアップ設定
    • input()でピンの状態を取得
    • add_event_detect()
    • ⽴ち上がりと⽴ち下がりを検出(BOTH)
    • 割り込み発⽣時に呼び出すコールバック関数設定

    View Slide

  19. SW⼊⼒検知プログラム
    • GUIを使った例
    02_switch_inter_gui.py

    View Slide

  20. Output
    • GPIOでデジタル出⼒
    • Lチカ
    • GPIOがONになると点灯
    • GPIOがOFFになると消える

    View Slide

  21. 配線図

    View Slide

  22. LED点灯プログラム
    5 import RPi.GPIO as GPIO
    6 import time
    7
    8 LED_PORT = 18
    9
    10 GPIO.setmode(GPIO.BCM) # GPIO番号で指定
    11 GPIO.setup(LED_PORT, GPIO.OUT)
    12
    13 # LEDを5秒間点灯する
    14 GPIO.output(LED_PORT, True)
    15 time.sleep(5)
    16 GPIO.output(LED_PORT, False)
    17
    18 GPIO.cleanup()
    19
    20 print('done') 02_led.py

    View Slide

  23. 02_led.py
    • パッケージはRpi.GPIOを使⽤する
    • setMode()でピン番号の指定⽅法を設定
    • setup()で出⼒ピン設定
    • output()でピンの状態を設定
    • cleanup()ですべてのピンを開放

    View Slide

  24. LEDの明るさを変えるには
    • 電圧を変える
    • 規格範囲内で電圧を変化させる
    • 電圧の制御回路が必要
    • PWMを使⽤する
    • デジタル信号を周期的にON/OFFする
    • ソフトウェアで実現できる
    • ⾃分でsleepを呼び出して実装する
    • OSの割り込みを使う
    • Raspberry PiはハードウェアPWMを持っている

    View Slide

  25. PWMとは
    • Pulse With Modulation(パルス幅変調)
    • パルス幅をデジタルで変える
    • PWMの変調⽅法は⾊々あるけど、Raspberry Pi
    では周波数とduty⽐の2つだけ

    View Slide

  26. ソフトウェアPWMの例
    9 PWM_FREQUENCY = 500 # Hz
    10
    11 GPIO.setmode(GPIO.BCM) # GPIO番号で指定
    12 GPIO.setup(LED_PORT, GPIO.OUT)
    13
    14 # PWM
    15 pwm = GPIO.PWM(LED_PORT, PWM_FREQUENCY)
    16 pwm.start(0)
    17
    18 # LEDを2秒間点灯する
    19 for duty in (5, 20, 50, 80, 100):
    20 print(duty)
    21 pwm.ChangeDutyCycle(float(duty))
    22 time.sleep(2)
    23
    24 GPIO.cleanup()
    02_led_pwm.py

    View Slide

  27. ソフトウェアPWMを使⽤した
    プログラム
    • パッケージはRpi.GPIOを使⽤する
    • setMode()でピン番号の指定⽅法を設定
    • setup()で出⼒ピン設定
    • PWM()でPWMオブジェクトを⽣成
    • PWM.start()で初期duty⽐を設定
    • PWM.ChangeDutyCycle ()でduty⽐を設定
    • cleanup()ですべてのピンを開放

    View Slide

  28. ソフトウェアPWMの波形
    (Rpi.GPIO)
    • 100Hz Duty⽐5%
    • 測定値:98.5Hz, パルス幅572us (duty⽐ 5.72%)

    View Slide

  29. ソフトウェアPWMの波形
    (Rpi.GPIO)
    • 500Hz Duty⽐5%
    • 測定値:465Hz, パルス幅171us (duty⽐ 7.95%)

    View Slide

  30. ハードウェアPWMの例
    (WiringPi)
    5 import wiringpi
    7 LED_PORT = 18 # GPIO 18
    8 PWM_RANGE = 1024
    9 PWM_FREQUENCY = 500 # Hz
    10 CLOCK_BASE = int(18750 / PWM_FREQUENCY)
    13 wiringpi.wiringPiSetupGpio()
    14 wiringpi.pinMode(LED_PORT, wiringpi.GPIO.PWM_OUTPUT)
    15 wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS)
    16 wiringpi.pwmSetRange(PWM_RANGE)
    17 wiringpi.pwmSetClock(CLOCK_BASE)
    18
    19 # LEDを2秒間点灯する
    20 for duty_cycle in (5, 20, 50, 80, 100):
    22 wiringpi.pwmWrite(LED_PORT, int(PWM_RANGE * duty_cycle / 100))
    23 wiringpi.delay(2000)
    25
    26 wiringpi.pwmWrite(LED_PORT, 0)
    02_led_wiringpi_hardware_pwm.py

    View Slide

  31. ハードウェアPWMの波形
    • 500Hz Duty⽐5%
    • 測定値499Hz, パルス幅99.89us(duty⽐ 4.98%)

    View Slide

  32. ソフトウェアPWMの例
    (WiringPi)
    5 import wiringpi
    6
    7 LED_PORT = 18
    8 PWM_RANGE = 100
    9
    11 wiringpi.wiringPiSetupGpio()
    12 wiringpi.pinMode(LED_PORT, wiringpi.GPIO.PWM_OUTPUT)
    13 wiringpi.softPwmCreate(LED_PORT, 0, PWM_RANGE)
    14
    15 # LEDを2秒間点灯する
    16 for duty in (5, 20, 50, 80, 100):
    17 print(duty)
    18 wiringpi.softPwmWrite(LED_PORT, duty)
    19 wiringpi.delay(2000)
    20
    22 wiringpi.softPwmStop(LED_PORT)
    02_led_wiringpi_software_pwm.py

    View Slide

  33. ソフトウェアPWMの波形
    (WiringPi)
    • 100Hz Duty⽐ 5%(周波数は変更できない?)
    • 測定値:99.6Hz, パルス幅519us (duty⽐ 5.17%)

    View Slide

  34. PWM性能⽐較
    測定条件
    (周波数, duty⽐)
    Rpi.GPIO
    Software PWM
    WiringPi
    Software PWM
    WiringPi
    Hardware PWM
    100Hz, 5% 98.5Hz, 5.72% 99.6Hz, 5.17% 100Hz, 4.93%
    500Hz, 5% 465.0Hz, 7.95% - 499Hz, 4.98%
    1kHz, 5% 866.1Hz, 11.2% - 1.0kHz, 4.93%
    2kHz, 5% 1.56kHz, 14.0% - 2.1kHz, 4.9%
    5kHz, 5% 2.90kHz, 23.2% - 6.26kHz, 4.9%
    9.3kHz, 5% 3.94kHz, 30.4% - 9.37kHz, 5.0%
    9.4kHz, 5% 3.99kHz, 30.8% - (動作せず)
    • グレーの⽂字は誤差20%以上
    • “-”は未サポート

    View Slide

  35. Software PWM vs Hardware PWM
    ソフトウェアPWM ハードウェアPWM
    ソフトウェア割り込みで実装 ハードウェアで⽤意されたPWM
    GPIOのピン数だけ⽤意できる Raspberry Piでは2系統使える※
    周期が⻑いなら安定
    周期が短いと不安定
    ハードウェア性能の範囲で安定
    ※ https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

    View Slide

  36. Rpi.GPIO vs WiringPi
    ⽐較項⽬ RPi.GPIO WiringPi
    使⽤感 ○⼿軽に使える △設定が⾯倒
    サンプルと資料 ○⽇本語情報多い
    ○サンプル多数
    △⽇本語情報少ない
    ⼊⼒割り込み ○使⽤可 ×未サポート
    ソフトウェアPWM ○使⽤可 △100Hzのみ使⽤可
    ハードウェアPWM ×未サポート ○使⽤可

    View Slide

  37. PiGpioパッケージ
    • http://abyz.me.uk/rpi/pigpio/
    • ⼊⼒割り込みが使える
    • ハードウェアPWMが使える
    • リモートGPIOが使える
    • sudoでの実⾏が不要
    • ただし、
    • 使う時はデーモンを⽴ち上げる必要がある
    • pipでインストールできない
    • ⽇本語のドキュメントが皆無
    • からあげ(@karaage0703)さんが積極的に情報発信
    されている
    • https://karaage.hatenadiary.jp/entry/2017/02/10/073000

    View Slide

  38. PiGpioのインストールと設定
    • Raspberry Piから
    • raspi-configでRemote GPIOを有効にする
    • 5Interfacing Options -> P8 Remote GPIO
    • 以下のコマンドを実⾏
    • デーモンからGPIOにアクセスしている
    $ sudo apt-get update
    $ sudo apt-get install pigpio python-pigpio
    python3-pigpio
    # pigpiodを⾃動起動する
    $ sudo systemctl enable pigpiod

    View Slide

  39. PiGpioでソフトウェアPWM
    5 import time
    6 import pigpio
    7
    8 LED_PORT = 18
    9 PWM_FREQUENCY = 500 # Hz
    10 RANGE = 100
    11
    13 pi = pigpio.pi()
    14 pi.set_mode(LED_PORT, pigpio.OUTPUT)
    15 pi.set_PWM_frequency(LED_PORT, PWM_FREQUENCY)
    16 pi.set_PWM_range(LED_PORT, RANGE)
    17
    18 # LEDを2秒間点灯する
    19 for duty in (5, 20, 50, 80, 100):
    21 pi.set_PWM_dutycycle(LED_PORT, duty)
    22 time.sleep(2)
    23
    24 # ピンをINPUTモードにしておかないと、LEDが点灯し続けてしまう
    25 pi.set_mode(LED_PORT, pigpio.INPUT)
    26 pi.stop()
    02_led_pigpio_software_pwm.py

    View Slide

  40. PiGpioでハードウェアPWM
    5 import time
    6 import pigpio
    7
    8 LED_PORT = 18
    9 PWM_FREQUENCY = 500 # Hz
    10
    12 pi = pigpio.pi()
    13 pi.set_mode(LED_PORT, pigpio.OUTPUT)
    14
    16 for duty in (5, 20, 50, 80, 100):
    18 pi.hardware_PWM(LED_PORT, PWM_FREQUENCY, duty * 10000)
    19 time.sleep(2)
    20
    22 pi.set_mode(LED_PORT, pigpio.INPUT)
    23 pi.stop()
    02_led_pigpio_hardware_pwm.py

    View Slide

  41. PWM性能⽐較
    測定条件
    (周波数,
    duty⽐)
    Rpi.GPIO
    Software
    PWM
    WiringPi
    Hardware
    PWM
    PiGpio
    Software
    PWM
    PiGpio
    Hardware
    PWM
    100Hz, 5% 98.5Hz, 5.72% 100Hz, 4.93% 100Hz, 5.00% 100Hz, 5.04%
    500Hz, 5% 465Hz, 7.95% 499Hz, 4.98% 500Hz, 5.00% 501Hz, 4.93%
    1.0kHz, 5% 866Hz, 11.2% 1.0kHz, 4.93% 1.0kHz, 4.97% 1.0kHz, 4.98%
    2.0kHz, 5% - - 2.0kHz, 4.80% 2.0kHz, 5.00%
    9.3kHz, 5% 3.94kHz, 30.4% 9.37kHz, 5.0% 8.02kHz, 5.0% -
    9.4kHz, 5% 3.99kHz, 30.8% (動作せず) 8.00kHz, 3.65% -
    100kHz, 5% - - - 100kHz, 4.92%
    1MHz, 5% - - - (1MHz, 4.05%)
    • グレーの⽂字は誤差10%以上
    • “-”は未測定
    • 1MHz時のduty⽐測定はオシロの性能限界なので参考値

    View Slide

  42. リモートGPIO
    • Raspberry Piとネットワークで接続されている
    マシンから、Raspberry PiのGPIOにアクセスす
    るプログラムが書ける
    • 引数でホスト名指定
    • デーモン起動時に、アクセス可能なホストを制
    限できる
    • デフォルトで制限なし

    View Slide

  43. リモートGPIOの例
    4 import sys
    5 import time
    6 import pigpio
    7
    8 LED_PORT = 18
    9 HIGH = 1
    10 LOW = 0
    11
    12 def main(hostname):
    13 pi = pigpio.pi(hostname)
    14 pi.set_mode(LED_PORT, pigpio.OUTPUT)
    15
    17 pi.write(LED_PORT, HIGH)
    18 time.sleep(5)
    19 pi.write(LED_PORT, LOW)
    20
    remote/02_led_on_off.py

    View Slide

  44. DCモーター
    • プラモデルなどでよく使われる
    • 安価である
    • 電圧を変えると回転速度も変わる
    • ⾼速回転できる
    • 低速の回転速度の調整が難しい
    マブチモーター FA-130RA

    View Slide

  45. DCモーターを電圧制御で動か

    • マブチモーターFA-130 RAを使⽤する
    • Raspberry Piで直接電圧を制御できないので、
    ここではAnalog Discovery 2の直流電源を使う
    • モーターの規格は以下の通り
    https://product.mabuchi-motor.co.jp/detail.html?id=9

    View Slide

  46. DCモーターをPWM制御で動か
    す(動かさない)
    • Duty⽐を変えることにより、使⽤電⼒を変化さ
    せ、モーターの速度を制御する
    • 理論上、Duty⽐が50%だと使⽤電⼒も50%になるの
    で、回転速度もそれに伴う
    • モーターが必要とする電⼒が、ラズパイの
    GPIOで提供できる電流で⼗分とは思えないの
    で、今回は対象外とする
    • 普通、モータードライバ回路を⽤意する

    View Slide

  47. サーボモーター
    • 回転⾓度を指定して、その位置まで回る
    • 普通、何周もぐるぐる回るものでない
    • でも、何周もぐるぐる回るものもある(SG90-HV)
    • 産業⽤ロボットの関節や、ラジコンのステアリ
    ングなどで使われる
    • PWMで制御する
    TowerPro SG90

    View Slide

  48. サーボモーターを動かす
    • SG90を使⽤する
    • モーターの規格は以下の通り
    http://akizukidenshi.com/download/ds/towerpro/SG90_a.pdf
    Position "0" (1.45 ms pulse) is
    middle, "90" (~2.4 ms pulse)
    is all the way to the right,
    thele .
    "-90" (~ 0.5 ms pulse) is all
    the way left.

    View Slide

  49. サーボモーターを動かす

    View Slide

  50. サーボモーターを動かす
    4 import time
    5 import RPi.GPIO as GPIO
    6
    7 MOTOR_PORT = 19
    8 WAIT_TIME = 1.0
    9
    10 # SG90
    11 #
    12 # Position "0" (1.45 ms pulse) is middle,
    13 # "90" (~2.4 ms pulse) is all the way to the right,
    14 # "-90" (~ 0.5 ms pulse) is all the way left.
    15
    16 PWM_FREQUENCY = 50 # Hz
    17 PWM_CYCLE = 1/ PWM_FREQUENCY * 1000 # 20 ms
    18 DUTY_MIDDLE = 1.45 / PWM_CYCLE * 100 # duty %
    19 DUTY_PLUS_90 = 2.4 / PWM_CYCLE * 100 # duty %
    20 DUTY_MINUS_90 = 0.5 / PWM_CYCLE * 100 # duty %
    03_servo_software_pwm.py

    View Slide

  51. サーボモーターを動かす
    22 # Software PWM
    23 GPIO.setmode(GPIO.BCM)
    24 GPIO.setup(MOTOR_PORT, GPIO.OUT)
    25 pwm = GPIO.PWM(MOTOR_PORT, PWM_FREQUENCY)
    26 pwm.start(DUTY_MIDDLE)
    27 time.sleep(WAIT_TIME)
    28
    29 for i in range(3):
    30 for duty in [DUTY_MINUS_90,
    31 DUTY_MIDDLE,
    32 DUTY_PLUS_90,
    33 DUTY_MIDDLE,]:
    34 pwm.ChangeDutyCycle(duty)
    35 time.sleep(WAIT_TIME)
    03_servo_software_pwm.py

    View Slide

  52. お前、誰よ
    • 平原貴⾳ @takaneh
    • 三浦半島のフリーランスプログラマ
    • ⾞載組み込み系とかdjangoでwebサービスとか
    • 元Start Python Club名古屋⽀部スタッフ
    • 鎌倉Maker Lab⽴ち上げました

    View Slide

  53. • 鎌倉Tech Meetup #1
    • 2019/12/7 (Sat) 9:00-12:00
    • 鎌倉商⼯会議所101会議室(JR鎌倉駅徒歩5分)
    • 初⼼者歓迎
    • 興味のある⼈なら誰でも参加できます
    • 途中参加、途中退場OK
    • 鎌倉観光のついでにどうぞ
    • connpassで公開中
    • https://kamakurapython.connpass.com/event/154096/

    View Slide