$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. Agenda • GPIOとは • Input • スイッチON/OFF • Output •

    Lチカ • サーボモーター • サンプルプログラム • https://github.com/kioto/raspi_gpio_sample (この資料はRaspberry Pi 3B + Raspbian Stretchで動作確認)
  2. Raspberry PiのI/O • GPIOは24系統 • UARTは1系統 • SPIは2系統 • GPIOとピン共⽤

    • I2Cは1系統 • GPIOとピン共⽤ • ピン配置の確認 • https://pinout.xyz
  3. Analog Discovery 2 • 「アナログ回路万能測定ツール」 • という名称で秋⽉電⼦で紹介されている • 千⽯電商、共⽴エレショップでも売ってる •

    オシロスコープ • アナログ波形を観測 • ロジックアナライザ • デジタル波形を観測 • 可変電圧DC電源 • etc…
  4. 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
  5. 01_switch.py • パッケージはRpi.GPIOを使⽤ • ⼊⼒はGPIO 23番を使⽤ • setMode()でピン番号の指定⽅法を設定 • setup()

    • ⼊⼒ピン設定 • プルアップ(HighでON)設定 • input()でピンの状態を取得 • whileループで監視
  6. ターミナルマルチプレクサ • Raspbianにログインする時に使う便利なコマンド • 昔はscreenコマンド、今はtmux • 単⼀のウィンドウで複数のセッション • 制御端末からプロセスを切断できる •

    通信が切れてもセッションは⽣きている • 使い⽅ • <PREFIX> c:セッション追加 • <PREFIX> d :デタッチ • tmux ls:セッション確認 • tmux a [-t セッション名]:アタッチ
  7. 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
  8. 01_switch_inter.py • パッケージはRpi.GPIOを使⽤ • ⼊⼒はGPIO 23番を使⽤ • setMode()でピン番号の指定⽅法を設定 • setup()で⼊⼒ピンとプルアップ設定

    • input()でピンの状態を取得 • add_event_detect() • ⽴ち上がりと⽴ち下がりを検出(BOTH) • 割り込み発⽣時に呼び出すコールバック関数設定
  9. 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
  10. LEDの明るさを変えるには • 電圧を変える • 規格範囲内で電圧を変化させる • 電圧の制御回路が必要 • PWMを使⽤する •

    デジタル信号を周期的にON/OFFする • ソフトウェアで実現できる • ⾃分でsleepを呼び出して実装する • OSの割り込みを使う • Raspberry PiはハードウェアPWMを持っている
  11. ソフトウェア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
  12. ハードウェア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
  13. ソフトウェア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
  14. 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%以上 • “-”は未サポート
  15. Software PWM vs Hardware PWM ソフトウェアPWM ハードウェアPWM ソフトウェア割り込みで実装 ハードウェアで⽤意されたPWM GPIOのピン数だけ⽤意できる

    Raspberry Piでは2系統使える※ 周期が⻑いなら安定 周期が短いと不安定 ハードウェア性能の範囲で安定 ※ https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
  16. Rpi.GPIO vs WiringPi ⽐較項⽬ RPi.GPIO WiringPi 使⽤感 ◦⼿軽に使える △設定が⾯倒 サンプルと資料

    ◦⽇本語情報多い ◦サンプル多数 △⽇本語情報少ない ⼊⼒割り込み ◦使⽤可 ×未サポート ソフトウェアPWM ◦使⽤可 △100Hzのみ使⽤可 ハードウェアPWM ×未サポート ◦使⽤可
  17. PiGpioパッケージ • http://abyz.me.uk/rpi/pigpio/ • ⼊⼒割り込みが使える • ハードウェアPWMが使える • リモートGPIOが使える •

    sudoでの実⾏が不要 • ただし、 • 使う時はデーモンを⽴ち上げる必要がある • pipでインストールできない • ⽇本語のドキュメントが皆無 • からあげ(@karaage0703)さんが積極的に情報発信 されている • https://karaage.hatenadiary.jp/entry/2017/02/10/073000
  18. 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
  19. 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
  20. 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
  21. 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⽐測定はオシロの性能限界なので参考値
  22. リモート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
  23. DCモーターを電圧制御で動か す • マブチモーターFA-130 RAを使⽤する • Raspberry Piで直接電圧を制御できないので、 ここではAnalog Discovery

    2の直流電源を使う • モーターの規格は以下の通り https://product.mabuchi-motor.co.jp/detail.html?id=9
  24. サーボモーターを動かす • 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.
  25. サーボモーターを動かす 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
  26. サーボモーターを動かす 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
  27. • 鎌倉Tech Meetup #1 • 2019/12/7 (Sat) 9:00-12:00 • 鎌倉商⼯会議所101会議室(JR鎌倉駅徒歩5分)

    • 初⼼者歓迎 • 興味のある⼈なら誰でも参加できます • 途中参加、途中退場OK • 鎌倉観光のついでにどうぞ • connpassで公開中 • https://kamakurapython.connpass.com/event/154096/