見出し画像

Pythonライブラリ(GPIO操作): RPi.GPIO


1.概要

 Raspberry PiのGPIOピンを操作するためのライブラリである「RPi.GPIO」を紹介します。

1-1.GPIOとは

 GPIO (general-purpose input/output) ピンとは様々な用途に使用できるピンであり、ピンに下記のような機能を割り当てることが出来ます。

 Raspberry Piで使用できる機能としては下記があります。

  1. 電源供給:ファン等への電源供給

  2. GND(グランド):回路動作の基準となる電位

  3. シリアル通信:つのデータ伝送路を使い1ビットずつデータを送信する方式

  4. デジタル信号(Digital Output:DO):0/1の出力を出すことが可能

    • GPIOピンの出力電圧=3.3V

  5. アナログ出力(Analog Output:AO):最小値と最大値の情報を持った信号を電流や電圧で出力

1-2.コラム:DI/DO、AI/AOとは

 プラント業界において制御や監視システムで"DI/DO、AI/AO"という用語が使用され、特にPLC(Programmable Logic Controlle)やIPC(産業用PC)の利用には理解が必須となります。

 DI/DO, AI/AOの意味は下記の通りであり、信号のやり取りを意味します。

  • DI(Digital Input):デジタル信号(正確には接点)の入力

  • DO(Digital Output):デジタル信号(正確には接点)を入力

  • AI(Analog Input):アナログ信号を入力

  • AO(Analog Output):アナログ信号を出力

https://www.contec.com/jp/support/basic-knowledge/daq-control/analog-io/

 デジタル信号(DI/DO)というと”Ethernetやシリアル通信のような通信によるデータ”をイメージする人もいると思いますが、このDI/DOはシンプルな0/1の信号(計器用なら0Vと24Vの切り替え)を出力するものであり、つまりは”接点(電気の通り道)の開/閉”を制御しているものとなります。
 接点は大きく分けて無電圧接点有電圧接点があり、下記の通りです。

  • 無電圧接点:接点がONの状態になっても接点には電圧がかかっていない

    • 例としてスイッチやリレーがある

    • 電源は相手側の機器で用意するため、相手側の回路をオン・オフさせるだけの働きとなる

    • ドライ接点、DRY接点、乾接点とも呼ばれる

  • 有電圧接点:接点がONの状態になったときに、接点にも電圧が印加される

    • ウェット接点、WET接点、電圧接点ともとも呼ばれる

 アナログ信号(AI/AO)とは最小値と最大値を持つ情報を電圧や電流の大小でやり取りする信号であり、仕様としては下記があります。

  1. 電流信号:電流(mA)を用いたアナログ信号

    • DC4-20mA:データのMIN:4mA, MAX:20mAとして信号を電流で送付する方式。

      • ノイズの影響が小さい、伝送線抵抗の影響がない、1-5V信号に変換が用意(抵抗250Ωを設置), 2線伝送方式センサが可能などの特徴がある

      • 最小値が0mAでなく4mAのため、故障時(0mA)の判断が容易

  2. 電圧信号:電圧(V)を用いたアナログ信号

    • mAと比較して(電圧のため)複数機器に並列接続が可能

    • テスターによる測定が簡単

    • 電圧信号は電圧降下が生じるため長距離伝送には不向き

    • 種類としては「DC1-5V」、「DC0-5V」、「DC0-10V」などがある。

1-3.PicoのGPIOとの違い

 追って(別記事作成予定)

1-4.Raspberry Pi5との互換性

 下記記事より、Raspberry Pi5だと「RuntimeError: Cannot determine SOC peripheral base address」で動作しませんでした。

2.Raspberry PiのGPIO

2-1.GPIOの仕様

 Raspberry PiのGPIOの仕様は下記の通りです。

  1. 出力電圧:DC5VとDC3.3V (GNDピンも別で設置)

  2. GPIOの出力電圧:DC3.3V

  3. GPIOの最大電流:GPIOピン全体で50mA。個々は16mA

    • $${{抵抗値R = \frac{V}{I}R = \frac{3.3}{0.016}R = 206.25Ω}}$$

  4. GPIO2, GPIO3:固定されたプルアップ抵抗を保有

  5. 無い機能:Raspberry Pi本体には付属されていない機能

2-2.GPIOの配置

 Raspberry PiのGPIOの配置は下記の通りです。

https://www.raspberrypi-spy.co.uk/2012/06/simple-guide-to-the-rpi-gpio-header-and-pins/
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
https://qiita.com/Pumila/items/f362a3d68e57cd088713

2-3.GPIO操作ライブラリ一覧

 GPIOはマイコン/シングルボードから操作することが可能です。GPIOを操作するライブラリ一覧は下記の通りです。

  1. RPi.GPIO:GPIOピン操作では昔から人気が高く、GPIOピンの細かい部分まで制御が可能だが習得が難しい。

    • 公式より、本モジュールはPythonによるgarbage collectingのためリアルタイムや時間ズレの影響が大きいものには不向き

    • インストール方法」や「適用事例」なども公開している。

    • 現在の最新Ver.のリリース日が2022年2月7日であり更新されておらず、Wikiも2020-05-01以降で更新無し。

    • 公式より、現状ではSPI, I2C, 1-wireやシリアル通信機能はサポート無し

  2. gpiozeroRPi.GPIOとpigpiを基にして作られ、よりシンプルで直感的なAPIを提供

    • 公式Docsより、Raspberry Pi OSにはデフォルトでインストール済み

    • RPi.GPIOより高水準APIのため簡単に活用できる反面、細かい調整は苦手

  3. pigpio:-

  4. gpiolib:Linuxカーネル内部でGPIO(汎用入出力)を管理するためのフレームワーク

  5. libgpiod:Pythonライブラリではなく、Linuxカーネルで使用するGPIO

  6. WiringPi:C言語で書かれたライブラリだが、Python用もある。

    • 2019年8月に開発停止し、2023年10月時点で誰もメンテしてない

3.環境構築

3-1.ライブラリの確認

 最新のRaspberry Pi OSであればデフォルトでRPi.GPIOは入っていると思います。下記コマンドでエラーがでなければ追加の環境構築は不要です。
 もしMiniforgeのように仮想環境に入っている場合は仮想環境から出るか、ライブラリを追加します。

[Terminal]
python
import RPi.GPIO as GPIO

[OUT]

3-2.参考:エラー対応

 もしライブラリが無かった場合は下記でインストール可能です。 

[Terminal]
pip install RPi.GPIO

 なお本ライブラリはLinuxベースのRaspberry Pi OSで動作するよう設計されており、Windowsでは下記の通りエラー(sys/mman.h': No such file or directory)となります。

4.API:基本操作(ピン設定等)

 RPi.GPIOモジュールの基本操作を説明します。RPi.GPIOモジュールは事前にインポート済みとします。

[IN]
import RPi.GPIO as GPIO

 内容は公式Docsをベースとしました。なお記事がJuypterベースとモジュールベースが混ざっていますが、どちらでも対応可能です。

4-1.ピンのナンバリング:GPIO.setmode()

 RPi.GPIOではコードの初めに「GPIOピンの指定方法(ナンバリング)」を下記で設定できます。

[API]
GPIO.setmode(<方式>)

 Raspberry PiのGPIOには3種類(PIN, BCM, WiringPi)のナンバリング方式がありますが、RPi.GPIOのナンバリングは2種類となります。設定した方式は”GPIO.getmode()”で確認できます。

  1. BOARD numbering system:Raspberry Pi基板にある(物理的な)40個のピンに順番に割り振られた値を参照する方式

  2. BCM numbers:物理的な配置と関係なくGPIOピンに割り当たられた番号(BCMピン番号)を参照する方式

    • BCMはBroadcom SOC channelの略

    • 番号はBroadcom SOCのチャネル番号(Raspberry Pi上のチップ内のナンバー)を参照

    • ネット情報ではBCMピンでの設定が多い(理由は不明)

https://www.raspberrypi-spy.co.uk/2012/06/simple-guide-to-the-rpi-gpio-header-and-pins/

【Pythonコードの書き方】
 BOARDナンバリングシステムの設定は”GPIO.setmode(GPIO.BCM) ”です。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) 
mode = GPIO.getmode()
print(f"mode:{mode}")
[OUT]
mode:10

 BCMナンバーでの設定は”GPIO.setmode(GPIO.BCM) ”です。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)  #ピン設定:(Broadcom SOC channel)
mode = GPIO.getmode()
print(f"mode:{mode}")
[OUT]
mode:11

【参考:ピンナンバリングの設定切り替え】
 Jupyterなどで実行する場合は一度設定すると変更時にエラーとなります。この場合は再起動して設定を初期化する必要があります。 

4-2.GPIOピンの設定:GPIO.setup()

 使用したいGPIOピンに対して下記をGPIO.setup()で設定します。なおピン番号はすべてBCMで実施しました。

  1. チャネル:使用するピンの場所を番号で指定

    • 指定する番号は設定したBOARD/BCMに応じて設定

  2. I/O設定:Input(信号を取得)かOutput(信号を出力)するか設定

    • 入力:GPIO.IN、出力:GPIO.OUT

  3. initial(Option):ピンの初期状態を設定可能(DefaultはLOW)

    • 0/1でいうと、0:GPIO.LOW、1:GPIO.HIGH

  4. pull_up_down(Option):プルアップ抵抗/プルダウン抵抗の設定

    • GPIOピンをインプット(GPIO.IN)に指定する場合は設定推奨

    • GPIO.PUD_UP:プルアップ->デフォルトをHIGH(3.3V)に設定

    • GPIO.PUD_DOWN:プルダウン->デフォルトをLOW(0V)に設定

[API]
GPIO.setmode(<channel>, <I/O設定>, 
             initial=<Default>,
            pull_up_down=<抵抗の設定>)

 例としてInputをGPIO2, OUTPUTをGPIO3, 21で設定してみます。 設定は個別で設定する方法とリストでまとめて設定する方法があります。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #BCM mode
GPIO.setup(2, GPIO.OUT) #GPIO 2
GPIO.setup(5, GPIO.IN) #GPIO5ピンをINPUTで設定
[IN]
channels = [3, 21]
GPIO.setup(channels, GPIO.OUT) #GPIO3とGPIO21ピンをまとめてOUTPUTで設定

4-3.警告表示の無視:GPIO.setwarnings()

 Raspberry Piのスクリプトを複数立ち上げることが出来ますが、RPi.GPIOが複数の設定を検出するため下記のような警告を出します

[rpi_GPIO.py]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #BCM mode
GPIO.setup(2, GPIO.OUT) #GPIO 2
print(GPIO.getmode())
[Terminal]
python rpi_GPIO.py

[OUT]
/home/kiyo/Desktop/rpi_GPIO.py:4: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(2, GPIO.OUT) #GPIO 2

11

 警告を無視させる場合は"GPIO.setwarnings(False)"を設定します。これで警告を無視することが出来ます。

[rpi_GPIO.py]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #BCM mode
GPIO.setwarnings(False)
GPIO.setup(2, GPIO.OUT) #GPIO 2
print(GPIO.getmode())
[Terminal]
python rpi_GPIO.py

[OUT]
11

4-4.GPIOピン解放:GPIO.cleanup()

 GPIOピンの重複はエラーとなり、別スクリプトを実行すると警告も出るためプログラム終了時にGPIOの割り当てを開放するのがベターです。解放は"GPIO.cleanup()"で実施します。
 下記より、"GPIO.cleanup()"実行後はピンへの割り当てが消えます。

[test.py]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(2, GPIO.IN)
print(GPIO.input(2))

GPIO.cleanup()
print(GPIO.input(2))
[Terminal]
python test.py

[OUT]
1

Traceback (most recent call last):
  File "/home/kiyo/Desktop/tess.py", line 7, in <module>
    print(GPIO.input(2))
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

 下記の通りGPIO.cleanup(<ピン番号>)で個別に設定も可能です。

[test.py]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup([2,3], GPIO.IN)
print(GPIO.input(2), GPIO.input(3))

GPIO.cleanup(2)
print(GPIO.input(3))
print(GPIO.input(2))
[Terminal]
python test.py

[OUT]
1 1
1
Traceback (most recent call last):
  File "/home/kiyo/Desktop/tess.py", line 9, in <module>
    print(GPIO.input(2))
RuntimeError: You must setup() the GPIO channel first

4-5.RPiの情報取得:GPIO.RPI_INFO

 RPiの情報抽出は”GPIO.RPI_INFO”、Version情報は”GPIO.VERSION”を使用します。

[IN]
GPIO.RPI_INFO

GPIO.VERSION
[OUT]
{'P1_REVISION': 3,
 'REVISION': 'd03115',
 'TYPE': 'Pi 4 Model B',
 'MANUFACTURER': 'Sony UK',
 'PROCESSOR': 'BCM2711',
 'RAM': '8G'}

'0.7.1'

4-6.GPIOの機能確認:gpio_function()

 GPIOピンの機能を確認できる関数として”gpio_function()”があります。ただし私の環境では実行しても0, 1, -1しか出ませんでした。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.gpio_function(3)

[OUT]
0

5.API:Inputs(入力値)

 GPIOピンは供給される電圧の有無を検出可能です

5-1.入力値の確認:GPIO.input()

 GPIOピンの状態確認は”GPIO.input(<channel>)”を使用します。出力は”0 / GPIO.LOW / False”か”1 / GPIO.HIGH / True”です。
 結果として、OUTPUT(GPIO.OUT)は初期値0であることを確認できました。後述の通り、INPUT(GPIO.IN)は正しく設定しないと初期値が0になりません。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setwarnings(False) #警告を無効にする

#GPIOピンの設定
##個別設定
GPIO.setup(2, GPIO.IN) #GPIO2ピンをINPUTで設定
GPIO.setup(26, GPIO.IN)

##まとめて設定
channels = [3, 21]
GPIO.setup(channels, GPIO.OUT) #GPIO3とGPIO21ピンをまとめてOUTPUTで設定

state_PIN2 = GPIO.input(2) #GPIO2ピンの状態を取得
state_PIN26 = GPIO.input(26)
state_PIN3 = GPIO.input(3)
state_PIN21 = GPIO.input(21)
print(f'INPUT PIN2: {state_PIN2}, PIN26: {state_PIN26}, OUTPUT PIN3: {state_PIN3}, PIN21: {state_PIN21}')
[OUT]
INPUT PIN2: 1, PIN26: 1, OUTPUT PIN3: 0, PIN21: 0

5-2.GPIO.setup()による設定

 結論として、INPUT(GPIO.IN)の初期値は"GPIO.setup()"のpull_up_down引数を設定する必要があります。

 5-2-1.浮遊状態

 下図はINPUT(GPIO.IN)に設定したピン26を繰り返し実行しましたが、時間で数値が変わっています。
 これはGPIOピンが外部の電圧源やグラウンドに接続されていない(つまり何も接続していない)と、ピンは不定な状態となり小さな電磁干渉によってもHIGH(1)とLOW(0)の間を不規則に変動する可能性があります。これを浮いている状態(浮遊状態)と呼びます。
 問題点としてDI信号を0/1で取得したいのに値が変動することで誤検出/誤作動の恐れがある点です。対策として信号を安定化させる必要があります。

 5-2-2.プルアップ/プルダウン

 対策としてGPIOピンのデフォルトを所定値に固定する方法があり、0/1で下記の2種類があります。

  • プルアップ(Pull-Up):GPIOピンを高電圧レベル(3.3Vや5V)固定

    • ピンと電源(Vcc)の間に抵抗を接続することでプルアップを実装

    • 一般的には10kΩの抵抗を使用(小電流量と耐ノイズのバランス)

  • プルダウン(Pull-Down):GPIOピンを低電圧レベル(0VやGND)固定

    • ピンとGNDの間に抵抗を接続することでプルダウンを実装

    • 一般的には10kΩの抵抗を使用(小電流量と耐ノイズのバランス)

 Raspberry Piでは"GPIO.setup()"pull_up_down引数でプルアップ/プルダウンを設定できます。
 注意点として、(1次出典が見つけられなかったのですが)Raspberry Pi4では一部のピン(PIN:2~8と15)でしかプルアップができないとのことです。

5-3.プルアップ/プルダウンの動作確認

 接続状態を変えながら出力がどのようになるか確認しました。今回はGPIO4ピンを用いて実装しました。

【何も接続無し】
 GPIO4ピンには何も接続接続しない状態でGPIO.setup()をプルアップ/プルダウンに設定しました。結果として浮遊状態はなくなり下記となりました。

$$
\begin{array}{|c|c|c|} \hline \textbf{設定} & \textbf{状態} & \textbf{備考} \\ \hline \text{プルアップ} \\ (GPIO.PUD\_UP) & 1 & ピンを高電圧に保持 \\ \hline プルダウン \\ (GPIO.PUD\_DOWN) & 0 & ピンを低電圧に保持 \\ \hline \end{array}
$$

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) #プルダウン抵抗:回路が開いているときにLOW

print(GPIO.input(4))

[OUT]
0
[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP) #プルアップ抵抗:回路が開いているときにHIGH

print(GPIO.input(4))

[OUT]
1

【GPIOピンに電圧供給】
 DIでの使用を想定して、GPIO4ピンにDC3.3V電源を供給しました。結果は両方とも1となります。これは電源が常にGPIO4ピンに電圧をかけており、DIはHIGH(1)と判定しているためです。

$$
\begin{array}{|c|c|c|} \hline \textbf{設定} & \textbf{状態} & \textbf{備考} \\ \hline \text{プルアップ} \\ (GPIO.PUD\_UP) & 1\to1 & \\ \hline プルダウン \\ (GPIO.PUD\_DOWN) & 0\to1 &\\ \hline \end{array}
$$

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) #プルダウン抵抗:回路が開いているときにLOW

print(GPIO.input(4))

[OUT]
1
[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP) #プルアップ抵抗:回路が開いているときにHIGH

print(GPIO.input(4))

[OUT]
1

GPIOピンをGNDに接続
 次にGPIO4ピンをGNDに接続しました。結果として両者で出力はLOW(0)になりました。
 接点開(つまり何も接続していない状態)ではプルアップ抵抗によりGPIO4ピンには電圧がかかっておりHIGH(1)を示しましたが、接点閉(電気的接続がある状態)だと電流が流れるためピンに電圧がかからなくなり状態がLOW(0)に変わりました。
 これを使えば、ボタンやスイッチを押していない状態(接点開)で1、押した時(接点閉)で0の信号を出すこともでき、下記特徴があります。

  • 初期デフォルトの確認:電圧が無い(Low/0)だと正常/故障の判断が難しくなります。プルアップ(HIGH/1)だと初期状態を正確に認識できます。

  • ノイズ耐性:Lowと比較すると電磁干渉による状態への影響が小さくロバストになります。

  • 故障モード:故障時にピンの状態をHIGHに保持することで回路の断線やその他の故障発生時の対応がしやすくなります。

$$
\begin{array}{|c|c|c|} \hline \textbf{設定} & \textbf{状態} & \textbf{備考} \\ \hline \text{プルアップ} \\ (GPIO.PUD\_UP) & 1\to0 & \\ \hline プルダウン \\ (GPIO.PUD\_DOWN) & 0\to0 &\\ \hline \end{array}
$$

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) #プルダウン抵抗:回路が開いているときにLOW

print(GPIO.input(4))

[OUT]
0
[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP) #プルアップ抵抗:回路が開いているときにHIGH

print(GPIO.input(4))

[OUT]
0

5-4.コラム:GPIO2, GPIO3の内部抵抗

 GPIO2とGPIO3はRaspberry Pi内部に固定のプルアップ抵抗が含まれているため、ソフトウェアでは操作できません。

https://www.raspberrypi.org/app/uploads/2012/10/Raspberry-Pi-R2.0-Schematics-Issue2.2_027.pdf
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html

 下記の通り、GPIO.setup()でプルダウンに設定しても変化はなく警告が表示されました。

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(2, GPIO.IN)
GPIO.setup(3, GPIO.IN)
print(GPIO.input(2), GPIO.input(3))

GPIO.cleanup() #一旦クリア

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
GPIO.setup(2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
print(GPIO.input(2), GPIO.input(3))

[OUT]
1 1
1 1
/tmp/ipykernel_9912/2535750200.py:11: RuntimeWarning: A physical pull up resistor is 
                                      fitted on this channel!GPIO.setup(2, GPIO.IN, 
                                                        pull_up_down=GPIO.PUD_DOWN)

6.API:Outputs

 GPIOピンからDC3.3Vと0Vを操作してデバイスに電源や信号を供給可能です。

6-1.DOの状態:GPIO.LOW/GPIO.HIGH

 GPIOピンが出す信号0/1をGPIO.LOW/GPIO.HIGHで選択できます。この属性の出力は整数の0/1であり、次の"GPIO.output()"使用時に見た目が分かりやすいという特徴があります。

[IN]
import RPi.GPIO as GPIO

print(GPIO.LOW, type(GPIO.LOW))
print(GPIO.HIGH, type(GPIO.HIGH))

[OUT]
0 <class 'int'>
1 <class 'int'>

6-2.DOの設定:GPIO.output()

 信号の出力値(DO)設定はGPIO.output()を使用します。channelはBOARD/BCMのピン番号であり、stateは0/1(GPIO.LOW/GPIO.HIGH)で指定します。

[API]
GPIO.output(channel, state)

$$
\begin{array}{|c|c|c|} \hline \textbf{設定} & \textbf{状態} & \textbf{出力} \\
\hline GPIO.LOW& 接点OPEN & 0 (0V) \\
\hline GPIO.HIGH& 接点CLOSE & 1(3.3V)
\\ \hline \end{array}
$$

 GPIO.OUTのデフォルトは0であり、出力設定方法は下記があります。

  1. 個別設定:”GPIO.output(channel, state)”で1ピンずつ設定

  2. リストで一括設定:”GPIO.output(<ピン番号のList>, state)”で一括設定

  3. リスト+個別で設定:”GPIO.output(<ピン番号のList>, <出力のList>)”で調整して設定

[IN]
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel)
channels = [3, 4]
GPIO.setup(2, GPIO.OUT) #GPIO2
GPIO.setup(channels, GPIO.OUT) #GPIO3, 4
print(f'State(OUTPUT) PIN2: {GPIO.input(2)}, PIN3: {GPIO.input(3)}, PIN4: {GPIO.input(4)}')

GPIO.output(2, GPIO.LOW)
GPIO.output(channels, GPIO.HIGH)
print(f'State(OUTPUT) PIN2: {GPIO.input(2)}, PIN3: {GPIO.input(3)}, PIN4: {GPIO.input(4)}')

GPIO.output(channels, [0, 1])
print(f'State(OUTPUT) PIN2: {GPIO.input(2)}, PIN3: {GPIO.input(3)}, PIN4: {GPIO.input(4)}')
[OUT]
State(OUTPUT) PIN2: 0, PIN3: 0, PIN4: 0
State(OUTPUT) PIN2: 0, PIN3: 1, PIN4: 1
State(OUTPUT) PIN2: 0, PIN3: 0, PIN4: 1

6-3.参考:Lチカによる動作確認

 OUTPUTの動作が目視できるようにLEDを点灯させてみました。詳細は下記記事に記載しておりますので、抜粋の未記載しました。

 ブレッドボードを使用して「PIN(GPIO4)▶330Ω抵抗器▶LED▶GND」と繋ぎました。

 下記を実行するとHIGHでLEDが点灯し(電流が流れ)、LOWで消灯(電流が停止)していることが確認できます。また終了時はGPIO.cleanup()により消灯されることも確認できました。

[IN]
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel) 
GPIO.setup(4, GPIO.OUT) #GPIO2

try:
    while True:
        GPIO.output(4, GPIO.HIGH)
        print(f'HIGH({GPIO.input(4)})')
        time.sleep(1)
        GPIO.output(4, GPIO.LOW)
        print(f'LOW({GPIO.input(4)})')
        time.sleep(1)
except KeyboardInterrupt:
    print('finish') #Ctrl+Cで終了
finally:
    GPIO.cleanup() #終了時の処理

[OUT]

【コラム:プルアップ抵抗を持つGPOピンのGPIO.cleanup()】
  前述の通りGPIO2, 3ピンは内部プルアップを持ちます。よって、GPIO.cleanup()を実行してピンを初期化するとプルアップにより電圧がかかった状態になるため下記コードの終了時にはLEDは点灯します。

[IN]
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM) #ピン設定:(Broadcom SOC channel) 
GPIO.setup(2, GPIO.OUT) #GPIO2

try:
    while True:
        GPIO.output(2, GPIO.HIGH)
        print(f'HIGH({GPIO.input(2)})')
        time.sleep(1)
        GPIO.output(2, GPIO.LOW)
        print(f'LOW({GPIO.input(2)})')
        time.sleep(1)
except KeyboardInterrupt:
    print('finish') #Ctrl+Cで終了
finally:
    GPIO.cleanup() #終了時の処理

[OUT]

7.API:PWM

 Raspberry PiではBCM番号の”GPIO12, 13, 18, 19, 20, 21”でPWM(pulse-width modulation)を扱うこともできます。PWM詳細は下記記事をご確認ください。

https://qiita.com/Pumila/items/f362a3d68e57cd088713

7-1.PWMピンの設定:PWM()

 PWMをGPIOピンに割り当てるのは”GPIO.PWM()”を使用します。注意点などは下記の通りです。

  1. GPIO.PWM()の前にGPIO.setup(<番号>, GPIO.OUT)を実施しないとエラーとなる。

  2. frequencyは制御対象である機器の周波数[Hz]である。よって、制御する機器の仕様書を確認のこと

  3. GPIO.PWM()はインスタンス化できるため変数にしておく

  4. pwm.start(<初期値>)でデューティ比(0~100%)を初期化

[API]
GPIO.PWM(channel, frequency)
[IN]
import RPi.GPIO as GPIO

frequency = 50 # 設定周波数(Hz)

GPIO.setmode(GPIO.BCM) #GPIO番号で指定
GPIO.setup(18, GPIO.OUT) #GPIO18ピンを出力に設定
pwm = GPIO.PWM(18, frequency) #PWM出力に設定
pwm.start(0) #デューティ比0%で開始

pmw
[OUT]
<RPi.GPIO.PWM at 0x7fb30923f0>

【参考:GPIO.PWMのINPUT】
 
下図の通りデフォルトでも0であり、出力変更後も0でした。

7-2.周波数の変更:ChangeFrequency()

 周波数の変更は”pwm.ChangeFrequence()”を使用します。変更後の値確認はおそらくできません。

[IN]
pwm.ChangeFrequence(10) #周波数を変更

7-3.デューティ比の変更:ChangeDutyCycle()

 デューティ比の変更は”pwm.ChangeDutyCycle()”を使用します。変更後の値確認はおそらくできません。

[IN]
pwm.ChangeDutyCycle(50) #デューティ比を変更

7-4.停止:stop()

 PWM信号を停止するのは”pwm.stop()”を使用します。なお必要に応じて”GPIO.cleanup()”でピンの初期化を推奨します。

[IN]
pwm.stop() #PWM信号を停止
GPIO.cleanup() #GPIOピンの設定を初期化

8.参考:シリアル通信

 GPIOはシリアル通信(SPI, I2C, UART)の出力を出すことが出来ますが、RPi.GPIOはシリアル通信を直接制御する機能は提供していません。よってシリアル通信をする場合は別のライブラリを使用する必要があります。

  1. pySerial

  2. python-periphery

  3. smbus:I2C通信などに対応

    • 過去記事「温度センサー(ADT7410)」で実装済み

  4. Adafruit Python GPIO

    • 既に非推奨であり現在は「Adafruit_Blinka」が推奨

    • 過去記事「サーボモーター制御」で実装済み



参考資料

別添1.公式ドキュメント

別添2.技術ブログ

あとがき

 まずRaspberry Pi5で使用できなかったのが痛い。学習コストがもったいなかったのでシリアル通信ができて、Raspberry Pi5も含めて全部で使用できるライブラリを学習したい。

いいなと思ったら応援しよう!