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」でアクセスしてみます。
こんな画面が出てくれば成功。
うまくいかない場合は、Raspberry PiにSSHでログインして
sudo webiopi -c /etc/webiopi/config -d
とタイプしてみてください。どこかのコードでエラーが起こってるはず・・・です。
iPadのSafariから操作してみました。
今回のコードでは、
・ LEDランプで”S.O.S.”信号を発光
・ 5つのサーボの-90度、0度、90度の3つの角度の回転
・ 距離センサーの値の取得(5秒おき)
が出来ます。
なお、サーボ制御をスライダーではなく、ボタンにしたのには多少わけがありまして。
以前Webiopiのサンプルにあったスライダーで動かしたとき、iPad上で安定して動かなかったからなんですが。
そのうち気が変わって、ボタンからスライダーに変えるかもしれません。がんばれば何とかできそうな気がしてます。
ようやく一つの画面で複数機器の操作・表示が可能になりました。
これで、またやりたいことへ一歩近づいたわけですが。
一体何をやろうとしているのか?
実を言うと出来るかどうかまだ自信がないため、あいまいにしてるだけなんですけど。そんなたいしたことは
で、やりたいことに必要な”ブツ”は既に入手しているんですが。
ちょっとちら見せ。
これがなんだか分かる方なら、一体何をやろうとしているのかがわかると思われます。
システム部分はほぼ完成したため、あとはハードウェア部分をどうするかを考えるだけです。
夏のお盆休みくらいまで、じっくりかけてやろうかと思ってます。気長にお待ちください。
毎年の夏は何かにチャレンジ!してますが、今年はこれでしょうかね・・・
その前に、まずはロビを完成させなきゃいけませんね。
« 物理エンジンで”エンジン”作ったそうです | トップページ | Raspberry Piの起動ディスクSDメモリをバックアップ »
「おもちゃ系」カテゴリの記事
- なぜか急にサイクリングマシーンを買ってしまいまして(2025.01.07)
- 2025年もヴィレッジヴァンガード福袋を購入(2025.01.02)
- 最近買った小物類(2024.06.23)
- 東京オートサロン、CARGO BASE & 秋葉原へ行ってきました(2024.01.13)
- 毎年恒例のヴィレッジヴァンガード福袋を買ってきました(2024.01.02)
「Raspberry Pi・Arduino・電子工作」カテゴリの記事
- 名古屋 大須へ行ってきました(2024.04.28)
- Raspberry Pi 5用電源購入(2024.04.19)
- Interface 2024年5月号はRaspberry Pi 5特集(2024.03.26)
- Raspberry Pi 5とPCがつながらなかった理由は「プライバシーセパレーター機能」のせいでした(2024.03.12)
- Raspberry Pi 5に日本語LLM(ELYZA-Japanese-Llama-2-7b-fast-Instruct)を入れてみた(2024.03.10)
「iPad」カテゴリの記事
- 電子レンジとWi-Fiが干渉してました(2024.02.03)
- iPhone 12とPixel 6a、iPad miniをいっぺんにアップデートしてみた & レトロPCの整理(2023.10.07)
- iPad miniの激安ケースを購入(2023.07.24)
- iOS版のChatGPTを入れてみた(※ インストール時には要注意)(2023.05.27)
- iPad mini用のサンワサプライ製スタンド付きのキーボードを買った(2023.03.19)
« 物理エンジンで”エンジン”作ったそうです | トップページ | Raspberry Piの起動ディスクSDメモリをバックアップ »
コメント