投稿日: May 29, 2019 6:29:9 AM
RPi2とかRPi3とかは割と普通にPCとしての運用が可能ですのでChromiumブラウザーでネットブラウズしたりもします。
ある程度は大丈夫なんですが夢中になって調べものとかしてるとメモリをやたら食うウェブページとか踏んでしまってOSごとフリーズしちゃうなんてことも。
そこでRPiらしく電子工作の力でどうにかしようと考えました(というかずっと考えてたけど腰重くてうごけなかった)
まず、Chromiumのプロセス一覧を取得するには
ps -aux | grep chromium
ps -aux でユーザのプロセス一覧が出てきます。で、コマンドにchromiumって含まれるものに絞り込んでるわけです。
「|」はパイプって言います、Linuxでは超よくつかうやつで、プロセスの結果をさらに別のプロセスに投げるバトンリレーみたいな役割してます。ちょーーー重要です。覚えておきましょうね!
で、これでいいです。いいんですがpsコマンド自体のプロセスとか、これをシェルスクリプトにしたときはbashのプロセスとかも含まれちゃいます。
出てくる情報をじーっと見てみます。
pi 19440 3.4 5.7 330456 54412 ? Sl 14:14 0:07 /usr/lib/chromium-browser/chromium-browser-v7
ほしいのは2番目赤い部分。で、何やらの区切り文字でそれぞれの要素は区切られているんだけどもその11番目にある/usr/lib/chromiumほにゃららって部分、これが実行してるコマンド名になるので、ここにchuromiumって含まれてるやつが kill したいヤツってことになります。
2番目と11番目の要素だけ拾って表示してみるにはこんな感じ。
ps -aux | grep chromium | awk '{print $2,$11}'
結果はこんな感じ。
4547 /usr/lib/chromium-browser/chromium-browser-v7
4568 /usr/lib/chromium-browser/chromium-browser-v7
4570 /usr/lib/chromium-browser/chromium-browser-v7
4600 /usr/lib/chromium-browser/chromium-browser-v7
4661 /usr/lib/chromium-browser/chromium-browser-v7
4822 /usr/lib/chromium-browser/chromium-browser-v7
17376 /usr/lib/chromium-browser/chromium-browser-v7
19123 /usr/lib/chromium-browser/chromium-browser-v7
19254 /usr/lib/chromium-browser/chromium-browser-v7
19440 /usr/lib/chromium-browser/chromium-browser-v7
19623 grep
一番最後に余計なプロセスも含まれてるのがわかります。これはこのリストを表示する為に実行したまさに今実行したコマンドによるものですねー。
それ以外は kill したいヤツらってことです。なんでこんなに動いてるのか。ブラウザは奥が深い。
次も簡単、こんどはこの結果にchromiumって含まれるものに絞り込みます。
ps -aux | grep chromium | awk '{print $2,$11}' | grep chromium
こうね。
で、プロセスID、コマンドと2つの情報が出ているのだけどもほしいのはプロセスIDだけ。
そこでまたawkを使って1番目に絞り込むと。
ps -aux | grep chromium | awk '{print $2,$11}' | grep chromium | awk '{print $1}'
4568
4570
4600
4661
4822
17376
19123
19254
19440
kill したいプロセス一覧が出来ました。
ではどうやってkillコマンドにこれを渡せば良いのか。
ps -aux | grep chromium | awk '{print $2,$11}' | grep chromium | awk '{print "kill ",$1}' | sh
kill プロセスID と表示したものをシェルにパイプすればオッケー! なんだ普通じゃん。
あとはシェルスクリプトとして実行できるように #!/bin/bashを追加して killchromium.sh とか保存して、chmod +x killchromium.sh で。これで実行可能になりましたー。
#!ほにゃって書くのはシバンって言うんだよ。
Chromiumが起動してるときに試しに
./killchromium.sh
と実行してやるとすぱっとChromiumが終了します。
pkillじゃなくてkillですからね。○ネーーッ! くらいの勢いです。
良いんですそういう為のものですから。
ではこれを実行するには
これを使いたいケースというのは、もはや操作不能になってる状況下で。です。
つまり普通にコマンド叩いて実行とかはできない場合がおおいはずです。
ただ操作不能なだけで数回くらいならコマンドを実行する猶予があることが多い印象です。(そのあと固まっちゃうのでワンライナーで実行しないとおおよそどうにもならななくなる)
しかし、RPiにはGPIOがあるのでGPIOを監視してコマンドを起動してやれば、操作不能な状況からChromiumをkillして通常作業に戻れる可能性があるってことです。
さて、GPIOをどうやって監視しましょうか。
というところで宿題にしてTwitterにその旨ポストして寝て起きたら答えを教えてもらってました。
なんという素晴らしい時代なんだ。本当にありがとう。
PythonのRPi.GPIOモジュールにはGPIOを監視、コールバックするためのメソッドがありますのでこれをつかうということです。
RPi.GPIOはRaspbian stretchのfull版にはもともとインストールされているようです。
それ以外のバージョンでもし使えないようならインストール方法を調べてみてください。
まずGPIOの設定からね。ひとまずREPLでお試しです。
Python3にて。
>>> import RPi.GPIO as g
>>> g.setmode(g.BCM)
>>> g.setup(4,g.IN, pull_up_down=g.PUD_UP)
GPIO 4を INPUT、PULLUPとして動作させます。
できてるのかなーってことで。
>>> g.input(4)
1
あっさり動いてますねー。
RPi初期の頃はGPIO使うにはそこそこ大変だったような記憶があるんだけど。
まあ、さておいて。
HIGH → LOW を FALLING
LOW → HIGH を RISING
どっちからどっちに変化した場合も反応させたい場合は BOTH
こんな感じでピンを監視します。
GPIO 4は何もしてなければ通常 1 が返ってきます。 PULLUPなので何もしなければ常にHIGHです。
ここをGNDに繋いだ時にLOW、つまり 0 になります。
つまり、今回の場合 HIGH → LOW を検出したいので FALLING を使えばいいということですネ。
>>> g.add_event_detect(4, g.FALLING)
これで監視開始です。
でも、監視してるだけです。
状況に適合した際に何かアクションするにはコールバックしなければなりません。
お試しに GPIO 4 が LOW になったら HELLO GPIO4 と表示させるようにしてみます。
>>> def hello( p ):
... print("HELLO GPIO4")
...
>>> g.add_event_callback(4 hello)
特にループ処理とかなしで大丈夫。
GPIO 4と GNDをちょこっと触れさせるとドバーっと「HELLO GPIO4」と表示されますね。
とりあえず実験は成功のようですがいっぱい表示されるのはなんなんだ。です。
これはチャタリングといって電子回路の永遠のテーマでもあり・・・ってほどではないですが厄介ものです。
これを回避するように修正します。
>>> import time
>>> t = time.time()
>>> def hello(p):
... global t
... if time.time() > (t + 1):
... print("HELLO GPIO4")
... t = time.time()
前回イベントが起きたときから1秒経過していないならコールバックルーチンでの処理は素通りするというような処理です。
単純にtime.sleepで処理を待機させるとイベントが蓄積されて待ち時間経過後にコールバックが発生するため。
以上をまとめるとこうなります。
#!/usr/bin/python3
import RPi.GPIO as g
import time
t = time.time()
def hello(p):
global t
if time.time() > (t + 1):
print("HELLO GPIO4")
t = time.time()
g.setmode(g.BCM)
g.setup(4,g.IN, pull_up_down=g.PUD_UP)
g.add_event_detect(4, g.FALLING)
g.add_event_callback(4, hello)
while True:
time.sleep(1)
最後の while は、Pythonスクリプトが終了してしまうのを防ぐもので。単純にループしながら1秒待ってるもので、実質何もしてませんが必要というものです。
では、合体させよう。
これで 「KILL CHROMIUM ボタン」を作るためのプログラム部品は揃いました。
で、合体ですが。
気力が尽きたので次回にもちこし。