« 物理エンジンで”エンジン”作ったそうです | トップページ | Raspberry Piの起動ディスクSDメモリをバックアップ »

2014年6月 7日 (土)

Raspberry Piでサーボと距離計、LED(SOS信号)をiPadのブラウザで操作できるようにしてみた

『最近思うところがあって、Raspberry Piにいろいろとやっております』シリーズがつづいておりますが。

(1)Raspberry Piで10個のサーボモーター動かしてみた: EeePCの軌跡

(2)Raspberry Piに超音波距離計”HC-SR04”つけてみた: EeePCの軌跡

(3)Raspberry Piに”WebIOPi”入れてみた: EeePCの軌跡

(4)Raspberry Piを無線LAN接続できるようにしてみた: EeePCの軌跡

(5)Raspberry Pi用にモバイルバッテリー買ってみた: EeePCの軌跡

(6)Raspberry PiにつないだPCA9685+SG90サーボをブラウザで制御してみた: EeePCの軌跡

(おまけ1)Raspberry Piでapt-getなどを実行してたら”No space left on device”と出てしまうときの対処法: EeePCの軌跡

(おまけ2)Raspberry PiのSDメモリーカードをEeePC(Ubuntu 14.04 LTS)で編集してみた: EeePCの軌跡

今回はこれらを”iPadのブラウザから操作・確認”できるようにしてみました。

要するにWebiopiを使うんですが、前の記事(3)ではデフォルトのインターフェースを使っただけなので、今回は自分で制御できるようなHTML、pythonコードを書いたんですが。

これがどえりゃー大変(三河弁)で、なにせwebiopiの日本語の参考サイトはほとんどないのが現状。唯一、以下のサイトがあったくらい。

WebブラウザからRaspberry Pi を操作する(WebIOPi 利用)

これ以外はググると”MouseDown PCA9685, PWM - Google グループ”や”Unable to make output pin high or low - Google グループ”といったgroup.google.comの質問サイトっぽいところが見つかるくらい。

ところが、かなり省略されたコードが出てくるだけで、しかも英語だらけ。素人はすっこんでろ的な雰囲気です。

これと”ANALOG - webiopi - Internet of Things framework - Google Project Hosting”あたりを解読して、1週間がかりでなんとかコードを書き上げました。

以下にそのコードと手順を残しておきます。コードは全部載せちゃってるので、長文です。

”Webiopi”用の作業ディレクトリを作成

SSHでRaspberry Piにログインして、ホームディレクトリ /home/piの下にこれから動作させるコード(HTML、python)を置くためのディレクトリを作ります。

mkdir webiopi

このディレクトリに移動して、

cd webiopi

コードを置いていきます。

PCA9685、SC-HR04、Lチカのブラウザ操作用コード”test.html”、”test.py”の作成

長いタイトルですが、要するに以下の二つのファイルを作ります。

・ test.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
<script type="text/javascript" src="/webiopi.js"></script>
<script>
window.onload=function(){
setInterval("document.getElementById('usonic').src='test.txt'",5000);
}
</script>
<script type="text/javascript">
webiopi().ready( function()
{
                var content, button;
                content = $("#content");

// create a button which output a bit sequence on GPIO 25 with a 100ms period
button = webiopi().createSequenceButton("sos", "S.O.S", 25, 100, "01010100110011001100101010");
content.append(button); // append button to content div

var content1, button1;
content1 = $("#content1");

button1 = webiopi().createMacroButton("macro1", "Servo 0-Max", "Servo0_H_Max");
content1.append(button1);

button1 = webiopi().createMacroButton("macro2", "Servo 0-Mid", "Servo0_H_Mid");
content1.append(button1);

button1 = webiopi().createMacroButton("macro3", "Servo 0-Min", "Servo0_H_Min");
content1.append(button1);

var content2, button2;
content2 = $("#content2");

button2 = webiopi().createMacroButton("macro4", "Servo 1-Max", "Servo1_H_Max");
content2.append(button2);

button2 = webiopi().createMacroButton("macro5", "Servo 1-Mid", "Servo1_H_Mid");
content2.append(button2);

button2 = webiopi().createMacroButton("macro6", "Servo 1-Min", "Servo1_H_Min");
content2.append(button2);

var content3, button3;
content3 = $("#content3");

button3 = webiopi().createMacroButton("macro7", "Servo 2-Max", "Servo2_H_Max");
content3.append(button3);

button3 = webiopi().createMacroButton("macro8", "Servo 2-Mid", "Servo2_H_Mid");
content3.append(button3);

button3 = webiopi().createMacroButton("macro9", "Servo 2-Min", "Servo2_H_Min");
content3.append(button3);

var content4, button4;
content4 = $("#content4");

button4 = webiopi().createMacroButton("macro10", "Servo 3-Max", "Servo3_H_Max");
content4.append(button4);

button4 = webiopi().createMacroButton("macro11", "Servo 3-Mid", "Servo3_H_Mid");
content4.append(button4);

button4 = webiopi().createMacroButton("macro12", "Servo 3-Min", "Servo3_H_Min");
content4.append(button4);

var content5, button5;
content5 = $("#content5");

button5 = webiopi().createMacroButton("macro13", "Servo 4-Max", "Servo4_H_Max");
content5.append(button5);

button5 = webiopi().createMacroButton("macro14", "Servo 4-Mid", "Servo4_H_Mid");
content5.append(button5);

button5 = webiopi().createMacroButton("macro15", "Servo 4-Min", "Servo4_H_Min");
content5.append(button5);

} );

        function mousedown() {
                webiopi().setValue(25, 1);
        }

        function mouseup() {
                webiopi().setValue(25, 0);
        }

        function outputSequence() {
                var sequence = "01010100110011001100101010" // S.O.S. morse code or whatever you want
                // output sequence on gpio 7 with a 100ms period
                webiopi().outputSequence(25, 100, sequence, sequenceCallback);
        }

        function sequenceCallback(gpio, data) {
                alert("sequence on " + gpio + " finished with " + data);
        }

</script>
        <style type="text/css">
                button {
                        display: block;
                        margin: 5px 5px 5px 5px;
                        width: 160px;
                        height: 45px;
                        font-size: 14pt;
                        font-weight: bold;
                        color: black;
                }

                input[type="range"] {
                        display: block;
                        width: 160px;
                        height: 45px;
                }

                #gpio25.LOW {
                        background-color: White;
                }

                #gpio25.HIGH {
                        background-color: Red;
                }
        </style>
</head>
<body>
<table id="table">
<tr>
       <th> <div id="content" align="center"></div></th>
       <th> <div id="content1" align="center"></div></th>
       <th> <div id="content2" align="center"></div></th>
       <th> <div id="content3" align="center"></div></th>
       <th> <div id="content4" align="center"></div></th>
       <th> <div id="content5" align="center"></div></th>
</tr>
</table>
<br>
超音波距離計[cm] : <iframe frameborder="0" scrolling="no" src="test.txt" id="usonic" width="150" height="23"></iframe><br>
</body>
</html>

・ test.py

import webiopi
from webiopi import deviceInstance

webiopi.setDebug()

GPIO = webiopi.GPIO
pwm0 = deviceInstance("pwm0")

def setup():
        GPIO.setFunction( 25, GPIO.OUT )
        GPIO.output(25, GPIO.HIGH)

def loop():
    GPIO.output(25, not GPIO.input(25))
    time.sleep(5)

@webiopi.macro
def Servo0_H_Min():
    servo0_h_min()

def servo0_h_min():
    pwm0.pwmWriteAngle(0, -90)

@webiopi.macro
def Servo0_H_Max():
    servo0_h_max()

def servo0_h_max():
    pwm0.pwmWriteAngle(0, 90)

@webiopi.macro
def Servo0_H_Mid():
    servo0_h_mid()

def servo0_h_mid():
    pwm0.pwmWriteAngle(0, 0)

@webiopi.macro
def Servo1_H_Min():
    servo1_h_min()

def servo1_h_min():
    pwm0.pwmWriteAngle(1, -90)

@webiopi.macro
def Servo1_H_Max():

def servo1_h_max():
    pwm0.pwmWriteAngle(1, 90)

@webiopi.macro
def Servo1_H_Mid():
    servo1_h_mid()

def servo1_h_mid():
    pwm0.pwmWriteAngle(1, 0)

@webiopi.macro
def Servo2_H_Min():
    servo2_h_min()

def servo2_h_min():
    pwm0.pwmWriteAngle(2, -90)

@webiopi.macro
def Servo2_H_Max():
    servo2_h_max()

def servo2_h_max():
    pwm0.pwmWriteAngle(2, 90)

@webiopi.macro
def Servo2_H_Mid():
    servo2_h_mid()

def servo2_h_mid():
    pwm0.pwmWriteAngle(2, 0)

@webiopi.macro
def Servo3_H_Min():
    servo3_h_min()

def servo3_h_min():
    pwm0.pwmWriteAngle(3, -90)

@webiopi.macro
def Servo3_H_Max():
    servo3_h_max()

def servo3_h_max():
    pwm0.pwmWriteAngle(3, 90)

@webiopi.macro
def Servo3_H_Mid():

def servo3_h_mid():
    pwm0.pwmWriteAngle(3, 0)

@webiopi.macro
def Servo4_H_Min():
    servo4_h_min()

def servo4_h_min():
    pwm0.pwmWriteAngle(4, -90)

@webiopi.macro
def Servo4_H_Max():
    servo4_h_max()

def servo4_h_max():
    pwm0.pwmWriteAngle(4, 90)

@webiopi.macro
def Servo4_H_Mid():
    servo4_h_mid()

def servo4_h_mid():
    pwm0.pwmWriteAngle(4, 0)

コードを見ていただくとよく分かりますが、なんだか同じコードが何度もつづいていることが分かります。

今回はサーボを5個動かせるようにしたんですが、この5個分のコードが並んでいるためでして。

サーボのIDを入力値にして、一つのコードで書くのが正解なんでしょうけど、まず私のプログラミング技術が低いこと、いずれサーボごとに稼動角を変えたいために、こんなみっともないコードになっております。ご了承願います。

この2つのファイルにくわえて、で作成した”usonic.py”も同じフォルダにおいておきます。

■ 超音波距離計 HC-SR04の計測値を表示できるようにする

このHC-SR04をWebiopiで制御できるようにしようと試みたんですが、そんなコードを書くのは私の腕では無理でした。

そこでその代わりに、

・ Raspberry Piに”python usonic.py”を5秒おきに実行するシェルを常駐させ

・ そのアウトプットファイルを5秒おきにブラウザ上に表示させる

という原始的な方法をとることにしました。

どうせこのHC-SR04、計測に1~2秒かかるし、5秒おきで読ませればよかろうというアバウトな判断です。

まず、以下のようなファイルを作ります。

・ usonic.sh

### BEGIN INIT INFO
# Provides:           mokyu
# Required-Start:
# Required-Stop:
# Default-Start:      2 3 4 5
# Default-Stop:       0 1 6
# Short-Description:
# Description:
### END INIT INFO
while true; do python /home/pi/webiopi/usonic.py > /home/pi/webiopi/test.txt ;sleep 5; done;

この”usonic.sh”を実行可能にします。

sudo chmod 777 usonic.sh

そのあと、これを/etc/init.dにコピーし、以下のコマンドを実行しておきます。

sudo cp usonic.sh /etc/init.d

cd /etc/init.d

sudo insserv usonic.sh

再起動後、自動的にHC-SR04が動作し始めます。

このシェルでは5秒おきにusonic.pyを実行し、その結果をtest.txtに上書きし続けます。

これをまた5秒おきにブラウザで表示できるようにすればいいんですが。

これは既に”test.html”に記載済みです。

先のtest.htmlの上のほうにある

<script>
window.onload=function(){
setInterval("document.getElementById('usonic').src='test.txt'",5000);
}
</script>

という部分がまさに5秒おきにテキストファイルを読む設定でして、

そのテキストファイルが

超音波距離計[cm] : <iframe frameborder="0" scrolling="no" src="test.txt" id="usonic" width="150" height="23"></iframe><br>

という部分で表示されるという仕組みです。

表示だけなので、わざわざWebiopi様の手を煩わせることなくできました。

温度計センサーなどでも同じような方法で値取得・ブラウザ表示が出来ると思います。

■ /etc/webiopi/configファイルの編集

sudo vi /etc/webiopi/config

でWebiopiの設定ファイルを開き、以下の項目を編集します。

[SCRIPTS]に以下の一行

myscript = /home/pi/webiopi/test.py

を加えます。

[HTTP]の#doc-root =  ~の下に

doc-root = /home/pi/webiopi

と記入します。

また#welcome-file = ~というところがあるので、その下に

welcome-file = test.html

と記入しておきます。

さらに下のほうに

#pwm0 = PCA9685

というのがあるので、コメントアウトを消しておきます。

pwm0 = PCA9685

となっていればOK。

保存して終了します。

ついでに

sudo vi /etc/webiopi/passwd

を開き、中の文字を空にして保存します。

これで、Webiopiにログインするときにいちいちユーザー名とパスワードを求められなくなります。

セキュリティが低くなりますが、ハックされたところでたかだか5個のサーボとLEDの指揮権が奪えるだけです。

■ 実際に動かしてみる

念のため、一旦Raspberry Piを再起動して、ブラウザから「http://(Raspberry PiのIPアドレス):8000」でアクセスしてみます。

Webiopi_svled01

こんな画面が出てくれば成功。

うまくいかない場合は、Raspberry PiにSSHでログインして

sudo webiopi -c /etc/webiopi/config -d

とタイプしてみてください。どこかのコードでエラーが起こってるはず・・・です。

Img_5740

iPadのSafariから操作してみました。

今回のコードでは、

・ LEDランプで”S.O.S.”信号を発光

・ 5つのサーボの-90度、0度、90度の3つの角度の回転

・ 距離センサーの値の取得(5秒おき)

が出来ます。

なお、サーボ制御をスライダーではなく、ボタンにしたのには多少わけがありまして。

以前Webiopiのサンプルにあったスライダーで動かしたとき、iPad上で安定して動かなかったからなんですが。

そのうち気が変わって、ボタンからスライダーに変えるかもしれません。がんばれば何とかできそうな気がしてます。

ようやく一つの画面で複数機器の操作・表示が可能になりました。

これで、またやりたいことへ一歩近づいたわけですが。

一体何をやろうとしているのか?

実を言うと出来るかどうかまだ自信がないため、あいまいにしてるだけなんですけど。そんなたいしたことは

で、やりたいことに必要な”ブツ”は既に入手しているんですが。

ちょっとちら見せ。

Img_57331

これがなんだか分かる方なら、一体何をやろうとしているのかがわかると思われます。

システム部分はほぼ完成したため、あとはハードウェア部分をどうするかを考えるだけです。

夏のお盆休みくらいまで、じっくりかけてやろうかと思ってます。気長にお待ちください。

毎年の夏は何かにチャレンジ!してますが、今年はこれでしょうかね・・・

その前に、まずはロビを完成させなきゃいけませんね。

Raspberry Piではじめるどきどきプログラミング 電子部品キット

« 物理エンジンで”エンジン”作ったそうです | トップページ | Raspberry Piの起動ディスクSDメモリをバックアップ »

おもちゃ系」カテゴリの記事

Raspberry Pi・Arduino・電子工作」カテゴリの記事

iPad」カテゴリの記事

コメント

コメントを書く

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

トラックバック

« 物理エンジンで”エンジン”作ったそうです | トップページ | Raspberry Piの起動ディスクSDメモリをバックアップ »

無料ブログはココログ

スポンサード リンク

ブログ村