« RaspberryPiのライブカメラをストリーム画面で操作する | トップページ | RasPiライブカメラの回路図、CGIソースの公開とその他の工作 »

2013年10月12日 (土)

もう一台のRaspberryPiをSAMBAサーバーにする

 RaspberryPi(以下Raspi)とUSBカメラで、お家(うち)ライブカメラを作るプロジェクトは、5ヶ月近くかかったが、めでたくウェブでライブ画像を見ながら遠隔地からカメラを上下左右に振れるところまで来た。

 留守中の猫の監視用なのだが、今はまだカメラ可動部やRaspiが裸で、このままカメラを動かせば、すぐに猫の襲撃を受けることは必至である。何らかの対策なしに運用には入れない。といって、すぐに気の利いた解決策も思いつかない。

 そういえば、ライブカメラのRaspiを含めた全体の回路図や、AVRのソースコード、RaspiのapacheのCGIやHTMLファイルの公開はまだしていない。隠すつもりは全くない。たださぼっているだけで、この先の自分のためにもまとめておきたいのだが、何かこう気が抜けてしまって、どうも重い腰が上がらない。

S_pa126094 そんなこともあって、ライブカメラのプロジェクトは少しお休みし、工作机のまわりを片付けたり、半かけになっている他の工作を再開したりして気力が戻るのを待つことにした。

SAMBAサーバーを羊羹(ようかん)の紙箱に入れる(10/2/2013)
 がた老AVR研究所は、Raspiを2台持っている。1台はライブカメラ用で、もう1台は、この間動かしたSAMBAサーバー(Windows用のリモートサーバー)にするつもりでいる(2013/5/12「機嫌の悪いRaspberryPi基板を飼いならす」)。 家族が独立し、家の中に共用サーバーをたてる強い必然性はなくなったのだが、所長一人でも、1Fの居間と地下のオーディオルーム兼工作室にそれぞれあるPC間のデータ交換の需要は見込める。

 それに、RaspiとPCの間でデータ共有ができるのが大きい。Raspiでの開発のソースコード入力は、Raspiの環境でやるより、PCで作ってからRaspiに送る方が効率が良いからである。

S_pa126086 Raspiはコネクターが基板4方に発散しており、そのままでは接続したケーブルが机の上のスペースを無駄にとって始末が悪い。SAMBAサーバーとして運用するには、いずれ本格的なケースに入れる必要がある。あれこれ考えているが、これもうまいアイデアが浮かばない。そのうち思いついて何かの整理用に残してあった紙箱に一式を放り込んでみた。

 これが意外とうまく行ったのである。ケーブルが周りと干渉することもなく、移動させるのにも気を使わない。この箱は、羊羹で有名なとらやの紙箱で結構しっかりしている。Raspiは最初、送られてきたピンクのケースに穴を開けて入れていたのだが、放熱を考慮して、ケースからとりだした。

S_pa126096 USBハブや、2.5インチHDDなどから出るUSBケーブルは、アマゾンから短いケーブルや、軸を換えられる3Dコネクターを取り寄せたので、箱の中もきれいに納まった。それより机の上が見違えるほどすっきりした。このままでも良いような気がしてきた。

 SAMBAサーバーは購入直後、動くことを確認しているが、もういちどテストする。順調に立ち上がった。このサーバーの消費電力は、HDD(2.5")を入れても10W以下なので、常時ONでも問題ない。しかし留守中や、夜中でも動かしておくのには抵抗がある。

 作業が終わったら電源を切るようにしたいのだが、Linuxをいきなり止めるのは、危険である。といって、電源を切るだけのために、コンソールを立ち上げてコマンドを打ち込むのも芸がない。何とかならないかと考えるうち良いアイデアが湧いた。

 Raspiの特長であるGPIOのどれかのPINにスイッチをつけ、その入力で、shutdownコマンドを出すプログラムを作って、デーモンにしておけば良い。sambaサーバーの立ち上げは、ハブの電源をONするだけで勝手に立ち上がるし、終了はボタン一押しで決まる(誤動作をさけるためにボタン長押しが良いだろう)。

S_pa126091  本当の電源断は、これでは出来ないが、shutdownしたあとのRaspiは、生きている時と違って、発熱量がごく僅かなので放っておいても資源の無駄遣いにならない。よし、これは面白そうだ。やってみよう。

 目の前に目新しい目標ができて、俄然やる気が出てきた。すぐにウェブを前に、色々情報を調べ始める。いっそのこと、サーバーの電源も自動的に入り切り出来るようにならないだろうか。SSRを使うか。いろいろと妄想がふくらむ。

スイッチひとつでRaspiを安全に停止させる方法を実装する(10/3/2013)
 RaspiのGPIOの入力データは、wiringPiライブラリに、digitalRead( )という関数が用意されて簡単に読むことが出来る。しかし、普通の8ビットマイコンのように、ループで待ち続けてはファイルサーバーとしての仕事に差し障る。

 ここは当然、スイッチ割り込みでプログラムが起動するようにしないといけない。サーバーの仕事より、こちらの方がCPUを喰ってしまう本末転倒のようなことは、所長の職人魂が許さない。

 しかし、wiringPiは割り込みをサポートしているのだろうか。まずはウェブで、「wiringPi 割り込み」で検索する。大丈夫。ちゃんとwiringPiでも割り込みをサポートしていた。ただしV2からだ。あわててインストールしたwiringPiを確かめる。よし、2.13だ。

 ウェブには既に、いくつかのサイトで割り込みを使ったソースプログラムが紹介されており、wiringPiのサンプルプログラムにも割り込みを使ったプログラムがある。心配なさそうだ。   

 さらに、ウェブを読み込む。ふむ、割り込みを扱う関数は2種類ある。ひとつは、割り込みが来るまで、ひたすら待ち、望みの割り込みが来たら次のステップに行く、waitForInterrupt(割り込みピン、タイムアウト時間)というのがある。

 もうひとつは、wiringPiISR(割り込みピン, 割り込みタイプ, 割り込み先関数エントリー)という関数だ。呼ばれる関数のエントリーを指定しておき、割り込みが起きた時、この関数へジャンプして、その処理が終わると元のプロセスに戻る。一般的なマルチプロセスのサポートである。

 今度の用途は、複雑な処理をするわけではなく、所定のピンにつけられたスイッチがONされるのをひたすら待ち、待ちが解消されたらsystemコマンドで、shutdown を出すという至極簡単なロジックである。

 waitForInterruptの方が簡単そうだったが、ちょうど、wiringPiISRを利用したソースリストを見つけたので、とりあえず、これをまるまる利用させてもらって組むことにする。以下のソースのような感じ。

#include < wiringpi.h >
void send_shut(void) {
   system("sudo shutdown -h now" );   //ピンがグランドになるとシャットダウン
} 

int main(void){
   int setup = 0;
   int GPIO_PIN = 24;
   
   setup = wiringPiSetupSys();    //初期化(正しくはwiringPiSetupGpio)
   piMode(GPIO_PIN, input);       //入力ピンに設定
   pullUpDnControl(GPIO_PIN, PUD_UP);    //プルアップ
   while(setup != -1){                   //ひたすら待つ。
       wiringPiISR( GPIO_PIN, INT_EDGE_FALLING, send_shut ); 
       sleep(10000);
   }
   return 0;
}

sleep(10000)というのが少し気に入らないが、簡単なプログラムなのでwiringPi関数が所定の機能どおり動けば、すぐ動くだろう。あとはgccの環境セットアップとライブラリの確認である。

Raspberryで、はじめてgccを使ってコンパイルする(10/5/2013)
 gccの環境は問題なかった。このRaspiのディストリビューション(Raspbian)にはgccがインストール済みであった。恥ずかしながら、実は、所長はgccをコンソールから使うのは、20年近く前からのLinuxの経験を含めて全くの始めてである。

 ウェブで勉強する。何か至極簡単そうだ。あっという間にHello World出力のプログラムが動くようなことが書いてある。あの鬼のように長いパラメーターを入れたmakeのコンパイルの時と同じコマンドとは思えない簡単さだ。

 言われるままに前記のソースコードを、コンソールから簡易エディターnanoで入力し、以下のgccコマンドを入れる。

gcc -v send_shut.c -lwiringPi.h

たったのこれだけである。-vを入れたお陰で、makeのときに御馴染みのメッセージが沢山出て一瞬でコンパイルは終わった。最初、ヘッダーファイルが見つからないと怒られたが、wiringPiをインストールしたときに、./buildを忘れていたことがわかり、再度実行して、表記どおりのコマンドでコンパイルが通った。

Gcc_compile  始め、実行ファイルができてないと騒いだのは秘密(パラメーターなしだと、a.outが実行ファイルなんですよね)として、./a.outでとりあえず実行させてみる。いきなりsysytemコマンドでshutdownさせるのではテストが続かないので、これをコメントにし、printfで適当なメッセージを出力させる。

 出た。プログラムが開始したことを示すメッセージが出た。へー、簡単にプログラムが動くんだ。妙なところで感心する。スイッチを押してみる。当然のように反応なし。そうだよな、そう甘くはない。

 さて、デバッグである。wiringPiには、いくつかのGPIOをチェックするコマンドが用意されている。これを使ってひとつづつ、wiringPiの関数がそのとおり動いているかチェックしていった。コンパイルはあっという間に終わるので、ひとつづつでも手間はかからない。

 piModeでピンが入力モードになったのは、gpio readallで確かめられた。次は、プルアップさせるpullUpDnControl(GPIO_PIN, PUD_UP)である。うーむ、上手く動いていない。スイッチは、ピンをショートする形でプログラムは立下りを調べているので、これでは割り込みは起きない。テスターで測っても、Highになっていない。

 ピンを間違えていないか。RaspiのGPIOピンのアサインはえらく複雑で、少なくとも3種類のピン番号の系列があり、しかも初期化によって同じピンで番号が違ってしまう。何度も確認する。しかし間違っていない。

ピンがプルアップされない理由がわかった(10/6/2013)
 思わぬところで暗礁に乗り上げた。24番PINがプルアップされない。余程、強制的に、プルアップ抵抗を外付けしてしまおうと思ったが、せっかくの機能が動いていないと言うのは気分が悪い。何か情報がないか、ウェブを調べる。

 しかし、めぼしい情報は得られない。仕方がないので、別の関数waitForInterruptを使って割り込みを待つプログラムにしてみた。wiringPiの公式サンプルプログラムwfi.cを参考にする(ただし、このwfi.cは、別スレッドを新たに立てる複雑なプログラムでそのままは使えない)。

 このソースコードを参考に、ピンの初期化を、system("gpio edge 24 falling"); というwiringPiのコマンドで代用して動かしてみる。ついでにプルアップを、sysytem("gpio -g mode 24 up")でごまかす。 S_pa126092

 これで見事に、スイッチ入力が有効になった。スイッチを押すたびに、コンソールにメッセージが出る。良いぞ。ただ、チャタリングがひどいので、wiringPiに標準でついてくるms単位のウエイト関数delay( ms )を使って判断を遅らす。これでチャタリングも止まった。

 しかし、動いたことは動いたのだが、問題が残った。system関数で、gpioコマンドを出す方法は、ピン番号がコマンド列にキャラクターで入っているので、決め打ちしかできない。他は変数なのに美しくない。sprintfでコマンド文字列を変数から作る方法もあるが、この程度のプログラムではおおごとだ。

 何かもっと上手い方法はないか、さらに探す。だいたいどうして前のpullUpDnControl( )が動かないのか。本家のウェブスペックを読むうち、遂にその謎が解決した。このスペックは邦訳がでていて、ちょっと意味の取れないところがあったので原文を読んでいて発見した。

 GPIOの初期化に3つも種類があるので、その差を調べていたら、今、こちらで使っている初期化関数、wiringPiSetupSys( )は、pullUpDnControl( )をサポートしていないことがわかった。

 pullUpDnContro( )の説明には、Sys modeでは動かないと書いてあるのだが、このSys modeが理解できなくて、初期化のwiringPiSetupSysのsysに結びつかなかったのである。

要するに、pullUpDnControlを使うには、/sys/class/gpioという仮想ファイルを初期化するwiringPiSetupSysではなく、管理者権限のあるユーザーしか使えないwiringPiSetupGpioで初期化する必要があるということだ。

 なーんだ。そうだったのか。あわてて初期化をwiringPiSetupGpioの方に換え、もういちど最初のwiringPiISRのコードに戻る。はい、おめでとうございます。最初のコードも問題なく動いた。

 やれやれ、手間がかかった。それにしても、これだけのことで大騒ぎだ。しかしいつものことながら解決した時の気分は最高である。ついでに、topコマンドで、このPGMの使用率を測る。スイッチを連打しても殆どゼロ。大満足である。

rc.localに入れてタクトスイッチでshutdown成功(10/8/2013)
  スイッチでシステムを落とすことにとりあえず成功した。次はこのプログラムの自動化である。デーモンを何処に入れるかで迷う。推奨されていないらしいが、もっとも簡単な、rc.localにコマンドを入れてテストする。

 動かない。考えてみたら、ユーザーがログオンされていない状態で、標準出力をデーモンから期待するのは無理と言うことがわかる。

 乱暴だが、shutdownコマンドを入れて、sendshut(シャットダウンさせるプログラム名)を実際に動かしてみる。 見事、システムが落ちた。これでSAMBAサーバーはスイッチひとつで安全にとめることが出来るようになった。

 デーモンプログラムは色々作法があって、最近は、このrc.localではなく別個のデーモンセットを独立して作っていくことが推奨されているようだが、まあ、それほどこだわることでもないだろう。とりあえず、このまま少し運用してみようと思う。それより、スイッチの実装をどうするかだ。

 このブログの原稿も、データをここに置くことにする。ここに置いておけば、地下でも1階でも好きな時に原稿をいじることができ、変更漏れに気を遣うこともない。寝る前に地下に降りて、スイッチを押せばSAMBAは一日の仕事を終えてお休みになる。

|

« RaspberryPiのライブカメラをストリーム画面で操作する | トップページ | RasPiライブカメラの回路図、CGIソースの公開とその他の工作 »

Raspberry」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: もう一台のRaspberryPiをSAMBAサーバーにする:

« RaspberryPiのライブカメラをストリーム画面で操作する | トップページ | RasPiライブカメラの回路図、CGIソースの公開とその他の工作 »