Raspberry Pi 2で遊ぶ:ボタン押したらコマンド実行なんて簡単だろうと思ったら結構大変だった

この記事は「Raspberry Pi記事まとめ」に集約しています。

「Raspberry Piで学ぶ電子工作」を読んで実践して、Arduinoが凄いのはA/D変換が組み込まれてるからセンサー類との親和性が高いんだなとか、RPiでセンサー付けるにはA/D変換噛まさないといけないから配線が多くなるなとかいろいろ分かってきました。
よく見る簡単事例でRPiに電源ボタンがないから付けようという記事をよくみかけるのですが、実際は電源オフボタンであり、電源の点いてないRPiにボタンで電源を入れるには別途電源管理ユニットが必要ってのも分かってきました。

で、本体の電源ボタンの実装が案外難しいなら、意外と需要ありそうな7インチ タッチスクリーンの電源オンオフなら簡単だろうと踏んでやってみたのですが・・・案外やることが多かったです。

一回ボタンを押すと数回実行してしまう

Raspberry Pi用 7インチ タッチスクリーンに電源ボタンはありません。また電源抜くとHDMIと違い再起動するまで映りません。
コマンドでオンオフできますが、いちいちターミナル叩かないといけないのが凄く面倒です。
RPiのGPIOを使ってボタンを押したら液晶の電源をオンオフできるようにすれば、ワンアクションで済むなと思ったのが経緯です。RPiは常時起動したいけど液晶は消しておきたいってときに使えます。

仕組みは簡単です。ボタン(タクトスイッチ)を押したら液晶のオンオフを切り替えるコマンドを走らせるだけといったものです。
使うGPIOは一番下の二つ(21,GND)だけです。
配線図
まずはタクトスイッチの挙動を確かめるために、以下のコードで実行してみました。ボタンを押すとファイルリストを出力するものです。
通常タクトスイッチを使うときは回路の間に抵抗を挟むプルアップ(プルダウン)抵抗を追加するのが定石らしいですが、下のコードではRPiが内部で持っているプルアップ抵抗を使うようにしたので、配線がシンプルになっています。

$ vi switchlcd.py

import RPi.GPIO as GPIO
from time import sleep
import subprocess

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)

cmd = "ls -al"

try:
    while True:
        if GPIO.input(21) == GPIO.LOW:
            subprocess.call(cmd, shell=True)
        sleep(0.01)

except KeyboardInterrupt:
    pass

GPIO.cleanup()

基本的に書籍に乗ってたコードを使っていますが、新しく使ったのは「subprocess.call」というところ。これは大雑把にいえばシェルを呼び出す関数で、よくある電源オフボタンの例でもこれが使われています。commands.getoutputという関数もありますが、将来廃止される予定らしいのでsubprocessの方を使っています。

このコードでも一応動作するのですが、一回タクトスイッチを押すと3〜5回くらいls -alが実行されてしまいます。
慎重にちょんっと押せば実行通りになりますが・・・このまま実装すると液晶のオンオフが瞬時に数回実行されるため、液晶を壊しかねません。

add_event_detectでノイズ対策

原因はタクトスイッチを押したときに発生するノイズ(チャタリング)なので、これを解消するコードを入れたのが以下。

$ vi switchlcd.py

import RPi.GPIO as GPIO
from time import sleep
import subprocess

def defSwitchLCD(channel):
    cmd = "ls -al"
    if channel == 21:
        subprocess.call(cmd, shell=True)

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(21, GPIO.RISING, callback=defSwitchLCD, bouncetime=200)

try:
    while True:
        sleep(0.01)

except KeyboardInterrupt:
    pass

GPIO.cleanup()

GPIO.add_event_detect関数が追加されています。GPIO.RISING、ボタンを押して上げるイベントが来たらユーザー定義関数defSwitchLCDを実行し、bouncetimeはイベント発生後200ミリ秒入力を受け付けない、という効果があります。この200ミリ秒というのがチャタリング対策のキモになります。

これで動くのが確認できたら、6行目を液晶用に変更します。

【6行目変更】
cmd = "echo $((`cat /sys/class/backlight/rpi_backlight/bl_power`==0)) > /sys/class/backlight/rpi_backlight/bl_power"

実行には管理者権限が必要なので、以下のコマンドで実行します。「&」はバックグラウンドで動作。止めるのはkillで。

$ sudo switchlcd.py &

実は液晶への出力が消えるだけで、タッチ機能は生きてます。

小さい基板と小さいタクトスイッチを用意すれば本格実装もできそうです。なんせ今はこんな絵面なので…

img_0219

タブレット端末らしく普通に押すと液晶が消え、長押しするとRPiの電源が落ちる、みたいな方法も取れるでしょう。まだドライバが対応してませんが、輝度調整ができるようになったらiPadみたいにふわっと液晶を消す、なんてのもできそう。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中