LinuxのPythonからlibgpiodを使ってGPIOを操作する

少し前の記事にまとめた通り、sysfs経由でのGPIO制御が非推奨となり、代わりにGPIOはキャラクタデバイス(/dev/gpiochip?)経由の方法が推奨されるようになった。

昨年の話だがOPi.GPIOというPythonライブラリを見つけて気に入っていたのに、残念だがこれも内部でsysfsインタフェースを利用してるため使わない方が良いという事に。

とはいえ、新しいlibgpiodを利用してPythonでGPIO制御する方法もそこそこ使いやすいことが分かった。方法をまとめる。

スポンサーリンク

ドキュメントやサンプルプログラムについて

新しい仕組みのためか、ドキュメントの整備が進んでおらず、現時点ではサンプルプログラムからコードの断片を拾って使うのが良さそうな印象。libgpiodを使ったPythonサンプルプログラムはlibgpiodのソースコードと一緒に配布されいる。

libgpiod/libgpiod.git - C library and tools for interacting with the linux GPIO character device

最新版のサンプルプログラムは下記リンクから直接取得出来るが、ライブラリのバージョンと合ってないとうまく動作しないので注意。

examples « python « bindings - libgpiod/libgpiod.git - C library and tools for interacting with the linux GPIO character device

Pythonモジュールのインストール

Buildrootの場合は、パッケージ選択でlibgpiod(BR2_PACKAGE_LIBGPIOD)をインストールすればOK。

Armbianの場合は、aptでpython3-libgpiodをインストールする。

sudo apt install python3-libgpiod

同じモジュール名でPyPIに登録されているgpiodはlibgpiodとは似て非なるもの。”pip install gpiod”とかやってしまうと以下で紹介するのとは別物がインストールされるので注意。

デバイスのパーミッション

gpiodはGPIOキャラクタデバイス(/dev/gpiochip?)を介してGPIOコントローラの操作を行うため、デバイスのパーミッションを適切に設定しておく必要がある。(以前の記事参照)

単体ピンを操作する

特定ピンに対応するオブジェクトの割当

まずは、対象ピンのGPIOコントローラに対応するChipオブジェクトを生成する。

import gpiod

chip = gpiod.Chip('gpiochip1', gpiod.Chip.OPEN_BY_NAME)

対象ピン番号を指定して、Lineオブジェクトを生成し変数に割当。

pa1 = chip.get_line(1)

あるいは、ピンにラベルが付けてある場合(前回記事を参照)は、ラベル名指定でピンに対応するLineオブジェクトを直接変数に割当て可能。

pa1 = chip.find_line('PA1')

type関数でpa1の型を確認。gpiod.Lineクラスのオブジェクトと分かる。

>>> type(pa1)
<class 'gpiod.Line'>

ピンの入出力を設定

Lineオブジェクトのメソッド呼び出しだけで簡単にピンの入出力を設定出来る。

  • 出力に設定したい時
pa1.request(consumer='foo', type=gpiod.LINE_REQ_DIR_OUT)
  • 入力に設定したい時
pa1.request(consumer='foo', type=gpiod.LINE_REQ_DIR_IN)

consumer引数で与える文字列は好きな文字列でOK。この文字列は、gpioinfoコマンドを実行した時の占有者を表す文字列として使用される。

$ gpioinfo gpiochip1
gpiochip1 - 224 lines:
        line   0:        "PA0"       unused  output  active-high 
        line   1:        "PA1"        "foo"  output  active-high [used]
        line   2:        "PA2"       unused  output  active-high
:
  • GPIOピンを開放したい時
pa1.release()

releaseメソッドを実行すると、gpioinfoコマンドで表示されていた”foo”の文字列がunusedに変わる。一度設定した入出力の方向変えたい時も、一旦releaseメソッドで開放してから行う。

値の読み書き

値の読み書きも、Lineオブジェクトのメソッド呼び出しだけでOK。

  • ピンに値を設定
pa1.set_value(value)
  • ピンの値を読み出し
value = pa1.get_value()

複数ピンをまとめて扱う

1つのオブジェクト変数から複数GPIOをまとめて扱うことも出来る。

Linesオブジェクトの生成

ピン番号のオフセットやラベルをリストで与えると、複数GPIOを一括操作出来るLinesオブジェクトを生成出来る。

  • ピン番号のオフセットをリストで与える方法
lines = chip.get_lines([0, 1, 2])
  • ラベルをリストで指定する方法(ピンにラベルが付いている場合)
lines = chip.find_lines(['PA0','PA1','PA2'])

ピンの入出力をまとめて設定

GPIOピンを単体で扱う時と同様requestメソッドで専有の宣言と入出力の設定を行い、releaseメソッドで開放する。

  • 複数ピンを全て入力に設定
lines.request(consumer='foo', type=gpiod.LINE_REQ_DIR_IN)  
  • 複数ピンを全て出力に設定
lines.request(consumer='foo', type=gpiod.LINE_REQ_DIR_OUT)  
  • 複数ピンを一括開放
lines.release()

値の読み書き

複数GPIOを一括で読み書き可能。

>>> lines.set_values([1,0,1])
>>> lines.get_values()
[1, 0, 1]

まとめ

libgpiodを使ったPythonによる新しいGPIO操作方法についてまとめた。従来のsysfs経由の物とは異なり、カーネルドライバを直接操作する形のため安心感があるし、APIもシンプルで分かりやすくなったと思う。

GPIOを操作するコードを新規開発する際は、特別な理由が無い限りgpiodを使って書く方が良いだろう。

コメント