IT系夫婦がRaspberry Piをかじってみた。 ④イベント駆動編
こんにちは。カーチャンです。
小さなコンピュータ「Raspberry Pi(ラズベリーパイ、略してラズパイ)」を操作するシリーズ、
第4回は、タクトスイッチ(押しボタン)を使ったイベント制御を行います。
「ボタンが押された」などの出来事を「イベント」と呼び、イベントをきっかけに実行する実行形式を「イベント駆動(イベント・ドリブン)型プログラム」と呼びます。
そして、イベント発生により実行する処理を「コールバック関数」と呼びます。
イベントと処理(関数)を紐付ける方法を学びましょう。
こちらのサイトを参考にしました。
RPi.GPIO でボタンが押されたことを検出するには
GPIOエッジ検出コールバック関数 | TomoSoft
基本の回路とプログラム
参考にしたサイトに沿って、LEDとスイッチを繋ぎました。
プログラムは下記のように書いて実行します。
(ほぼコピペです。すみません。)
今回は、回数ではなく「ボタンを押す」というイベントを検知しなければなりません。
そのため、無限ループでイベントを検知するまで待機します。(27行目)
そのままだと処理が永遠に終わらないので、例外処理「try〜except〜finally」でキーボード入力の割り込み例外をキャッチして止まるようにしています。(25〜36行目)
スイッチは、回路を接続したり切断する部品です。
電気の性質として、接続・切断時に電圧が瞬間的に不安定になります。
OnでもOffでもない中間的な電圧がかかると、CPUが壊れることがあるのでGPIO端子には内部に抵抗が組み込まれていて電圧を安定させる機能があります。
規定の電圧に満たない時はOffにする抵抗を「プルダウン」と呼び、逆に規定の電圧以上になったらOffにする抵抗を「プルアップ抵抗」と呼びます。
19行目でGPIO端子のプルダウン抵抗の設定をOnにして、押した時(接続)に電流が流れ、離した時(切断)に切れるようにしています。
動かすとこんな風になります。
イベント駆動型にアップグレード
上記の場合、0.03秒ごとにスイッチの状態の検出とLEDへの出力が走ります。
常にスイッチの状態を監視し続けるため、あまりCPUに優しくない処理です。
イベント・ドリブン型にすると、「スイッチを押した・離した」というイベントは、OS側で処理します。
イベントを検知した時だけ処理が走るので、処理の負荷が低くなります。
ずーっと抱っこしていなきゃいけないタイプの赤ちゃんだと、まともに家事もできないけど、
泣いた時だけ駆け寄ればOKなタイプの赤ちゃんであれば、安全な場所に寝かせておいて簡単な家事ならできんことはないというイメージです。
その例え、子育てしてない人に伝わる?
9~13行目で定義している関数が、イベントが発生した時に実行する処理です。
32行目で、どんなイベントをキャッチするかの設定を行います。
今回は、押す時にOn、離した時にOffにしたいので、押した時と離した時の両方ともキャッチします。
35行目で、イベントをキャッチした時実行する関数を設定しています。
最後に、イベントの設定を削除して終了します。
応用
LEDを3つ繋げて、スイッチを押した回数によって点灯するLEDを変えると、「欽ちゃんの仮装大賞」風になります。
まとめ
最初の2つは、外から見た振る舞いはほとんど同じです。
実際の業務プログラミングでも、実装にあたっては何通りもの方法があり、
ハードウエア要件や、予算や納期、保守のしやすさ、他の機能との整合性などを考慮して、最適なロジックを選択しています……そのはずです……色々あることもありますが、トップが変なモノに感化されたりして横槍が入らない限りは、だいたいそんな感じです……
これを書いている時に、公式でもっと簡単に書けるライブラリ(プログラム部品セット)が公開されているのに気が付きました。ショック……
GPIO in Python - Raspberry Pi Documentation
ドキュメントが英語なので、英語できないカーチャンにはハードル高いですが、
LEDはLED、センサーはセンサーなどというように、よく使う電子素子単位でラップしてある感じなのかな?
イベント制御ができれば、今は亡きDashボタンのようなものを作れたりと、電子工作の幅がさらに広がります。
後は回路とプログラムの組み合わせ次第なので、何か家事・育児の助けになるものが作りたいです。