2015年12月27日日曜日

Kinect + Raspberry Pi 2 で監視カメラを作る(7)

ブラウザから Kinect を操作する(後編)

html の作成

とりあえず、以前作成した自動画像リロードのページをベースに制御コマンドを送信するためのフォームとボタンを追加する。

<body onload="loadimage()">
<form id="cntlform" action="/cgi-bin/control.pl" method="post"">
<div class="tcontrol">
<div class="tilt_up">
<input type="submit" class="tilt" name="cntl" value="UP">
<input type="submit" class="tilt" name="cntl" value="up">
</div>
<div class="tilt_down">
<input type="submit" class="tilt" name="cntl" value="dn">
<input type="submit" class="tilt" name="cntl" value="DN">
</div>
</div>
<div style="float:left;">
<canvas id="cv" width="640" height="480"></canvas>
<div class="vcontrol">
<input type="submit" class="video" name="cntl" value="RGB">
<input type="submit" class="video" name="cntl" value="IR">
<input type="submit" class="video" name="cntl" value="DEPTH">
</div>
</div>
</form>
</body>

正直 html はいまいち不慣れなので、divの構造などは適当。

POST と GET はどちらが良いのか毎度悩むが、POST は純粋にサーバーにデータを送信する場合(サーバーの状態を変更する)、GET はサーバーから情報を取得する時のパラメータとして送る情報(サーバーの状態は変わらない)と覚えている。
なぜそうなるかは、submit の挙動ではなく、submit 後に遷移したページをリロードしたり URL をコピペしたときにどうなる考えると想像が付くと思う。
当然今回は POST を使っている。

css をよしなに設定してあげればこんな感じで画面が表示される。

ボタンを押すたびにリロードされるのが嫌なら iframe を使うなどすれば回避できるそうだが、そんなに頻繁に押さなければ気にならないので放置。

CGI の作成

CGI自体は POST で送られてきたデータを解釈して FIFO に送るだけの非常にシンプルなもの。
一瞬 bash でも十分かと思ったが、そういえばシェルショックなる話があったなーと思い出して念のため perl で作成した。

#!/usr/bin/perl
use Fcntl;
print "Location: /kinect\n\n";
sysopen(FIFO, "/tmp/kinect", O_NONBLOCK | O_WRONLY) or die "Failef to open FIFO: $!\n";
read(STDIN, $data, $ENV{'CONTENT_LENGTH'});
foreach $item (split(/&/, $data)) {
        ($key, $value) = split(/=/,$item);
        if($key eq "cntl") {
                print $value;
                if($value eq "UP") {
                        $cmd = "P";
                } elsif($value eq "up") {
                        $cmd = "p";
                } elsif($value eq "dn") {
                        $cmd = "m";
                } elsif($value eq "DN") {
                        $cmd = "M";
                } elsif($value eq "RGB") {
                        $cmd = "R";
                } elsif($value eq "IR") {
                        $cmd = "I";
                } elsif($value eq "DEPTH") {
                        $cmd = "D";
                }
               
                $r = syswrite(FIFO, $cmd);
                if(!defined($r)) {
                        die "Write failed\n";
                }
        }
}
close(FIFO);

久々に perl 書いたけど、そういえば標準だと switch 文使えなかったのね。
正直ノンブロックにする必要はないのだが、後からFIFOが開いた時に溜まっていたコマンドが送られるケースがあり得るのがなんとなく嫌だったのでノンブロックにした。

CGIのテストと有効化

職業柄プログラムを作ったら単体で動かして見ないと落ち着かないので、一旦単体で動かして見る。
とは言え、POST に相当するものをブラウザ以外から与えるのはなかなか面倒なようで、以下のように長ったらしい呪文を追加してあげる必要がある。

echo cntl=p | env REQUEST_METHOD='POST' CONTENT_LENGTH=6 HTTP_REFERER='http://localhost/index.html' perl -d control.cgi

無事に動くのが確認できたら、cgi-bin に配置する。
ラズパイの場合は /usr/lib/cgi-bin になるが、一つトラップがあって以下のように apache の設定を変えてあげないとたとえ cgi-bin に配置しても動いてくれなかった。(apache のドキュメントを読んでもそんなことどこにも書いていないので、正直かなり苦戦した・・・)

> sudo ln -s /etc/apache2/mods-available/cgi.load /etc/apache2/mods-enabled/
> sudo service apache2 restart

これで無事にブラウザから Kinect の制御が可能になった。

どうしてもブログだとソースを全てかけないので細切れになってしまうが、需要があればそのうち GitHub なり何なりに上げようと思う。

0 件のコメント:

コメントを投稿