Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PythonでRaspberry PiのGPIOを制御する

F907572635730576b6d609dc63ca4f52?s=47 kioto
November 13, 2019

PythonでRaspberry PiのGPIOを制御する

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

F907572635730576b6d609dc63ca4f52?s=128

kioto

November 13, 2019
Tweet

Transcript

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

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

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

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

  5. Agenda • GPIOとは • Input • スイッチON/OFF • Output •

    Lチカ • サーボモーター • サンプルプログラム • https://github.com/kioto/raspi_gpio_sample (この資料はRaspberry Pi 3B + Raspbian Stretchで動作確認)
  6. GPIOとは • General-Purpose Input/Output • ⽇本語で⾔うと「汎⽤⼊出⼒」 • 汎⽤じゃないI/O • SPI

    • I2C • UART
  7. Raspberry PiのI/O • GPIOは24系統 • UARTは1系統 • SPIは2系統 • GPIOとピン共⽤

    • I2Cは1系統 • GPIOとピン共⽤ • ピン配置の確認 • https://pinout.xyz
  8. デモのシステム構成 USB3 USB Analog Discovery 2 MacBook Pro Raspberry Pi

    4 プローブ I/O ブレッドボード
  9. Analog Discovery 2 • 「アナログ回路万能測定ツール」 • という名称で秋⽉電⼦で紹介されている • 千⽯電商、共⽴エレショップでも売ってる •

    オシロスコープ • アナログ波形を観測 • ロジックアナライザ • デジタル波形を観測 • 可変電圧DC電源 • etc…
  10. Input • GPIOでデジタル⼊⼒ • タクトスイッチ • 押すとON • 離すとOFF

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

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

  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
  14. 01_switch.py • パッケージはRpi.GPIOを使⽤ • ⼊⼒はGPIO 23番を使⽤ • setMode()でピン番号の指定⽅法を設定 • setup()

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

    通信が切れてもセッションは⽣きている • 使い⽅ • <PREFIX> c:セッション追加 • <PREFIX> d :デタッチ • tmux ls:セッション確認 • tmux a [-t セッション名]:アタッチ
  16. Pythonプログラムの実⾏ • 必ずsudoで実⾏すること • rootでないとGPIOデバイスにアクセスできないから $ sudo python3 01_switch.py

  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
  18. 01_switch_inter.py • パッケージはRpi.GPIOを使⽤ • ⼊⼒はGPIO 23番を使⽤ • setMode()でピン番号の指定⽅法を設定 • setup()で⼊⼒ピンとプルアップ設定

    • input()でピンの状態を取得 • add_event_detect() • ⽴ち上がりと⽴ち下がりを検出(BOTH) • 割り込み発⽣時に呼び出すコールバック関数設定
  19. SW⼊⼒検知プログラム • GUIを使った例 02_switch_inter_gui.py

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

  21. 配線図

  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
  23. 02_led.py • パッケージはRpi.GPIOを使⽤する • setMode()でピン番号の指定⽅法を設定 • setup()で出⼒ピン設定 • output()でピンの状態を設定 •

    cleanup()ですべてのピンを開放
  24. LEDの明るさを変えるには • 電圧を変える • 規格範囲内で電圧を変化させる • 電圧の制御回路が必要 • PWMを使⽤する •

    デジタル信号を周期的にON/OFFする • ソフトウェアで実現できる • ⾃分でsleepを呼び出して実装する • OSの割り込みを使う • Raspberry PiはハードウェアPWMを持っている
  25. PWMとは • Pulse With Modulation(パルス幅変調) • パルス幅をデジタルで変える • PWMの変調⽅法は⾊々あるけど、Raspberry Pi

    では周波数とduty⽐の2つだけ
  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
  27. ソフトウェアPWMを使⽤した プログラム • パッケージはRpi.GPIOを使⽤する • setMode()でピン番号の指定⽅法を設定 • setup()で出⼒ピン設定 • PWM()でPWMオブジェクトを⽣成

    • PWM.start()で初期duty⽐を設定 • PWM.ChangeDutyCycle ()でduty⽐を設定 • cleanup()ですべてのピンを開放
  28. ソフトウェアPWMの波形 (Rpi.GPIO) • 100Hz Duty⽐5% • 測定値:98.5Hz, パルス幅572us (duty⽐ 5.72%)

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

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

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

    5.17%)
  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%以上 • “-”は未サポート
  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
  36. Rpi.GPIO vs WiringPi ⽐較項⽬ RPi.GPIO WiringPi 使⽤感 ◦⼿軽に使える △設定が⾯倒 サンプルと資料

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

    sudoでの実⾏が不要 • ただし、 • 使う時はデーモンを⽴ち上げる必要がある • pipでインストールできない • ⽇本語のドキュメントが皆無 • からあげ(@karaage0703)さんが積極的に情報発信 されている • https://karaage.hatenadiary.jp/entry/2017/02/10/073000
  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
  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
  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
  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⽐測定はオシロの性能限界なので参考値
  42. リモートGPIO • Raspberry Piとネットワークで接続されている マシンから、Raspberry PiのGPIOにアクセスす るプログラムが書ける • 引数でホスト名指定 •

    デーモン起動時に、アクセス可能なホストを制 限できる • デフォルトで制限なし
  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
  44. DCモーター • プラモデルなどでよく使われる • 安価である • 電圧を変えると回転速度も変わる • ⾼速回転できる •

    低速の回転速度の調整が難しい マブチモーター FA-130RA
  45. DCモーターを電圧制御で動か す • マブチモーターFA-130 RAを使⽤する • Raspberry Piで直接電圧を制御できないので、 ここではAnalog Discovery

    2の直流電源を使う • モーターの規格は以下の通り https://product.mabuchi-motor.co.jp/detail.html?id=9
  46. DCモーターをPWM制御で動か す(動かさない) • Duty⽐を変えることにより、使⽤電⼒を変化さ せ、モーターの速度を制御する • 理論上、Duty⽐が50%だと使⽤電⼒も50%になるの で、回転速度もそれに伴う • モーターが必要とする電⼒が、ラズパイの

    GPIOで提供できる電流で⼗分とは思えないの で、今回は対象外とする • 普通、モータードライバ回路を⽤意する
  47. サーボモーター • 回転⾓度を指定して、その位置まで回る • 普通、何周もぐるぐる回るものでない • でも、何周もぐるぐる回るものもある(SG90-HV) • 産業⽤ロボットの関節や、ラジコンのステアリ ングなどで使われる

    • PWMで制御する TowerPro SG90
  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.
  49. サーボモーターを動かす

  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
  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
  52. お前、誰よ • 平原貴⾳ @takaneh • 三浦半島のフリーランスプログラマ • ⾞載組み込み系とかdjangoでwebサービスとか • 元Start

    Python Club名古屋⽀部スタッフ • 鎌倉Maker Lab⽴ち上げました
  53. • 鎌倉Tech Meetup #1 • 2019/12/7 (Sat) 9:00-12:00 • 鎌倉商⼯会議所101会議室(JR鎌倉駅徒歩5分)

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