tag:blogger.com,1999:blog-17187311532198109292024-02-20T10:08:27.140+09:00ON THE HANDArduino, Raspberry Pi などを使って適当に工作したメモを残していきます。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.comBlogger73125tag:blogger.com,1999:blog-1718731153219810929.post-74729266471275651572023-01-09T22:21:00.000+09:002023-01-09T22:21:00.489+09:00SDカードサイズ液晶のゲーム機を作るRaspberry Pi W と同じサイズの液晶&ジョイスティックの基板を使って、1.4インチ液晶のコントローラー一体型ファミコンを作ってみました。<br />
こんな感じ。<div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/O269su50s9c" width="320" youtube-src-id="O269su50s9c"></iframe></div><br /><div><br />
<br />
ボードを買ったら取説も何もないし取説通りやってもゲーム画面出てこないし、、、とまぁまぁ試行錯誤したので上手くいく方法をメモします。<br /><br /></div><div>
大まかな流れは次の通り。<br /><ol style="text-align: left;"><li>SDカードにゲームエミュレータ(Retropie)同梱の OS(Raspbian)をインストール</li><li>WiFi & SSH を設定してRaspberry Pi Zero W に接続</li><li>液晶のドライバをインストール</li><li>液晶基板に付いているジョイスティックを有効化</li><li>遊ぶ</li></ol><div><br /></div>
<h3>
材料</h3>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07BHMRTTY&linkId=18f724413bfbce614b662afce3390ff0" style="height: 240px; width: 120px;"></iframe></div>
<div>
Pi Zero でも良いのですが WiFi 付いていた方が作業が楽です。<br />
Amazon は無茶苦茶ぼったくりの値段になっていることがあるので要注意。</div>
<div style="clear: both;">
</div>
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07QL8C397&linkId=de95f90e1dbb0cee06f05916a33fdcc1" style="height: 240px; width: 120px;"></iframe></div>
<div>
今回のメインのパーツです。<br />
Amazon の説明には取説付きと書いてありますが一切ついておらず、チップの種類も不明。<br />
何も情報なしでぶつかると手も足も出なくて詰みます。<br />
</div>
<div style="clear: both;">
</div>
<br />
<div>
そのほか、SDカードとかモバイルバッテリー、USBケーブルは適当に。</div>
<div style="clear: both;">
</div>
<br />
<h3>
Raspberry Pi に Retropie をインストールする</h3>
<a href="https://www.raspberrypi.com/software/ " target="_blank">Raspberry Pi の公式サイト</a>からOS Imagerをダウンロードして PCにインストールします。<br />
Imager の使い方は非常にわかりやすいので説明を省略します。<br />
<br />
ここでインストールするOSは普通の Raspbian ではなくてこれです。<br />
Emulation and game OS → Retropie → Retropie 4.8 (RP 1/Zero)<br />
<br />
<h3>
WiFi & SSH を有効化する</h3>
SDカードにOSを書き込んだら自動でアンマウントされるので、SDカードを抜き差しして再度PCにマウントします。<br />
<ol style="text-align: left;">
<li>「boot」フォルダがマウントされるので、フォルダ直下にwpa_supplicant.confという名前のファイルを作成し、以下の内容をコピペ。
<pre class="brush:shell">country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="{SSID}"
psk="{平文のWiFiパスワード}"
}</pre></li>
<li>「boot」フォルダ直下に「ssh」という名前の空のテキストファイルを作成。<br />これでRaspberry Pi の初回起動時に SSH が有効化されます。</li></ol>
<br />
<h3>
Raspberry Pi Zero W に SSH 接続する</h3>
SDカードを Raspberry Pi Zero W に挿入してモバイルバッテリーを接続。<br />
液晶の表示は真っ白ですがこの時点では気にしなくてOKです。<br />
<br />
WiFi の設定が上手くいっていれば、しばらくして PCから「retropie.local」というホスト名に ping を打つと応答が返ってきます。<br />
<pre class="brush:shell">ping retropie.local</pre>
さらにその後、SSH が起動すれば「pi@retropie.local」にSSH接続するとログインできます。<br />
デフォルトパスワードは「raspberry」ですね。<br />
<br />
<h3>
液晶モニタのドライバをインストール</h3>
Waveshare のマニュアルに沿ってドライバを入れていきます。<br />
<a href="https://www.waveshare.com/wiki/1.44inch_LCD_HAT" target="_blank">https://www.waveshare.com/wiki/1.44inch_LCD_HAT</a><br /><ol style="text-align: left;"><li>raspi-config でSPI Interfaceを有効化<br />
<pre class="brush:shell">sudo raspi-config
「Interfacing Options > SPI > Yes」を選択
sudo reboot
</pre>
</li><li>BCM2835ライブラリをインストール
<pre class="brush:shell">wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.71.tar.gz
tar zxvf bcm2835-1.71.tar.gz
cd bcm2835-1.71/
sudo ./configure && sudo make && sudo make check && sudo make install
</pre>
</li><li>wiringPiライブラリをインストール
<pre class="brush:shell">sudo apt-get install wiringpi
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb
gpio -v
# v2.5.xのバージョンが表示されればOK
git clone https://github.com/WiringPi/WiringPi
cd WiringPi
./build
gpio -v
# v2.6かv2.7が表示されればOK</pre>
</li></ol>
マニュアルではこの後で Python のライブラリをインストールしていますが、今回は不要です。<br />
<br />
<br />
<h3>
FBCPドライバをインストール</h3>
フレームバッファーの制御をするドライバらしいですがよく分かりません。<br />
この手順を実行するとようやく画面にコンソールが表示されます、、、が、あまりに文字が小さすぎて全く読めません。<br />
<ol style="text-align: left;"><li>ドライバをビルド<br />
<pre class="brush:shell">cd ~
sudo apt-get install cmake -y
sudo apt-get install p7zip-full -y
wget https://www.waveshare.com/w/upload/f/f9/Waveshare_fbcp.7z
7z x Waveshare_fbcp.7z -o./waveshare_fbcp
cd waveshare_fbcp
mkdir build
cd build
cmake -DSPI_BUS_CLOCK_DIVISOR=20 -DWAVESHARE_1INCH44_LCD_HAT=ON -DBACKLIGHT_CONTROL=ON -DSTATISTICS=0 ..
make -j
sudo ./fbcp</pre>
</li><li>起動時に読み込まれるように設定<br />
<pre class="brush:shell">sudo cp ~/waveshare_fbcp/build/fbcp /usr/local/bin/fbcp
sudo nano /etc/rc.local
# rc.local 末尾の「exit 0」の手前に「fbcp &」を追記</pre>
</li><li>画面解像度を設定<br />
/boot/config.txt の末尾に設定を追記。<br />
Raspberry Pi 4 の場合は追加の設定が必要なので適宜 Waveshare のマニュアルに従ってください。<br />
<pre class="brush:shell">hdmi_force_hotplug=1
hdmi_cvt=300 300 60 1 0 0 0
hdmi_group=2
hdmi_mode=87
display_rotate=0</pre></li><li>再起動
<pre class="brush:shell">sudo reboot</pre></li></ol>
<br />
<br />
<h3>
Retropie の画面を液晶に表示する</h3>
ここまでの手順で液晶にコンソールは表示されるのですが、Retropie (emulation station)の画面は表示されません。<br />
そこで、raspi-config で「Advanced > GL Driver」から「Fake KMS」を有効化します。<br />
うまくいかない場合は「Full KMS」でもいいらしいです。<br />
設定後に再起動するとemulation stationの起動画面が出るようになるはず。<br />
<br />
ところが、コントローラーの設定画面になってしまい、ジョイスティックが認識されていないために何もできません。<br />
もしUSB接続のコントローラーが手元にあるようなら、Raspberry Pi Zero W の Micro USB に接続すると操作できます。<br />
<br />
<br />
<h3>ジョイスティックを有効化する</h3>
emulation station にジョイスティックを認識させるのに地味に手間取ったのですが、このページが参考になりました。<br />
「<a href="https://ayasuke2.exblog.jp/26285006/" target="_blank">てきとうにブログ 〜 ラズパイZEROのたとえ(例) </a>」<br />
<br />
<pre class="brush:shell">curl -O https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/retrogame.sh
sudo bash retrogame.sh
# よくわからないけど「3」を選択</pre>
再起動後に「/boot/retrogame.cfg」に次のように記載します。<br />
<pre class="brush:shell">LEFT 5 # Joypad left
RIGHT 26 # Joypad right
UP 6 # Joypad up
DOWN 19 # Joypad down
LEFTCTRL 13 # 'A' button JOY PRESS
LEFTALT 16 # 'B' button BTN3
Z 20 # 'X' button BTN2
X 21 # 'Y' button BTN1
ESC 13 16 # Exit ROM JOY + BTN3</pre>
この記載内容はここからパクりました。<br />
<a href="https://pihw.wordpress.com/guides/mini-retro-pi-setup/" target="_blank">MELTWATER's RASPBERRY PI HARDWARE</a>
<br />
実際には再起動後にジョイスティックとボタンが動作するようになり、改めてキーアサインを設定する画面が表示されるので後から変更可能です。<br />
<br />
<br />
<h3>遊ぶ</h3>
retropie.local をファイル共有で参照し「roms」フォルダに ROM ファイルをコピーします。<br />
サンプルの ROM は retropie のイメージなどに入っていることがあるのでそれを使うのが手っ取り早いです。<br />
手持ちのファミコンカセットから抜く方法は他のサイトをご参照。</div><div><br /></div><div>出来上がるとこんな感じに。<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR-v-hSFoOz31x8L2CL3lOKeoQfRjJ6dpxw6KGd8JJj4Jp9IXF2Gqf3eMzI6fPJi6LuaH8k74fh_R_sxDfXxmGtootj5QBGCEiDmJkH3Oo4zmiW9h88IF61Ybr8AILbtfu11oQbTBXY2lt_8XVtPE5SNJnCk3iyAbhhQv9OxwPR88mwmvZt17S-ka0tQ/s2048/324849049_1228790177734941_4675746676485020714_n.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1536" data-original-width="2048" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR-v-hSFoOz31x8L2CL3lOKeoQfRjJ6dpxw6KGd8JJj4Jp9IXF2Gqf3eMzI6fPJi6LuaH8k74fh_R_sxDfXxmGtootj5QBGCEiDmJkH3Oo4zmiW9h88IF61Ybr8AILbtfu11oQbTBXY2lt_8XVtPE5SNJnCk3iyAbhhQv9OxwPR88mwmvZt17S-ka0tQ/s320/324849049_1228790177734941_4675746676485020714_n.jpeg" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><br />
</div>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-35989433426004958212020-04-18T21:08:00.001+09:002020-04-18T21:11:28.343+09:00液晶モニタを1,500円で石膏ボードに壁掛けする在宅勤務になってリビング脇で仕事していたら、家族が気を遣うと言うことで追い出されることに。<br />
寝室の片隅に机を入れたものの、奥行きが無いので液晶モニタの壁掛けに挑戦。<br />
<br />
<div style="float: left; margin: 8px;">
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00CJ7MONS&linkId=cbbb05f8fb1d4c9808eb2b984bd8144d"></iframe></div>
<div>
・・・と思ったのですが、普通にamazonで調べると、石膏ボード用の壁掛け金具は1万円オーバー。</div>
<div style="clear: both;">
</div>
もうちょっと安上がりにならないかと調べたところ1,500円で実現できました。<br />
必要なものはこの2つだけ。<br />
<br />
<div style="float: left; margin: 8px;">
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07C4FWDVB&linkId=95c59de3bf4e03fa7fcb5263983b6e69"></iframe><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00TP4TZ76&linkId=8e6be02206fad4ab5dbc626eab920b8e"></iframe></div>
四角い留め具は貧相に見えますが、金属製のパンチングボードを固定するもので耐荷重が20kgもあります。<br />
液晶モニタは24インチで5kg前後なので余裕で支えられます。<br />
石膏ボード用のピンで固定するため壁にもほとんど痕が残りません。<br />
<br />
液晶モニタはVESA規格であれば何でもOK。<br />
VESA規格対応のモニタは背面に4つネジ穴が開いています。<br />
<div style="clear: both;">
</div>
<br />
で、出来上がりはこんな感じ。<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi74WxoTC32QC4ijRlsk5O4M8xmBd-lQ3irqL4dB5gbhBlIAzSQvkPzNnX17F_f-hTgi3eeahanuJV_YMsdM63N-tKbTBPyMakNagLuvuaNOWW2dlPG1JvbZWHb6KFbPSxVfocAApVyjXM-/s1600/IMG_4643.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi74WxoTC32QC4ijRlsk5O4M8xmBd-lQ3irqL4dB5gbhBlIAzSQvkPzNnX17F_f-hTgi3eeahanuJV_YMsdM63N-tKbTBPyMakNagLuvuaNOWW2dlPG1JvbZWHb6KFbPSxVfocAApVyjXM-/s200/IMG_4643.JPG" width="200" height="200" data-original-width="1600" data-original-height="1600" /></a></div>
<div style="clear: both;">
</div>
おしまい。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-60650692014930888432019-03-03T12:25:00.001+09:002019-03-25T17:48:25.582+09:00NOOBS+Raspberry PiにRaspbian+Node-REDを入れてDHT11で温度測定NOOBSがSDカードにプリインストールされているRaspberry Piのキットが売られているようです。<br />
これを使ってRaspbian、Node-REDをセットアップします。<br />
さらにNode-RED上でDHT11の値を取得してクラウドにデータを送るところまでやってみます。<br />
<br />
<h3>
材料</h3>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07FQ9678G&linkId=a850070a9412eb2d9b57294e25fb43e2" style="height: 240px; width: 120px;"></iframe></div>
<div>
Raspberry Pi 3B+ に NOOBS プリインストール SD カードがセットになっているスタータキット。<br />
ハードウェア的には一通り揃っていますが、OS (Raspbian) が動くようにするまで一手間かかります。</div>
<div style="clear: both;">
</div>
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B06ZZSB77C&linkId=332074206fcb74db3a266db0b9079e9a" style="height: 240px; width: 120px;"></iframe></div>
<div>
激安の小型ブレッドボード。<br />
6個も何に使うんだよ、という気もしますが。</div>
<div style="clear: both;">
</div>
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B0728J4XCC&linkId=795beaca1143cdcb395d21a7b4b30bf6" style="height: 240px; width: 120px;"></iframe></div>
<div>
DHT11 温湿度センサ。<br />
A/Dコンバータが内蔵されているのでとりあえずセンサを扱いたい時におすすめ。<br />
ただし、Node-REDを使う場合はライブラリを別途入れる必要があります。</div>
<div style="clear: both;">
</div>
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B012ALI166&linkId=d19d3a78ca382d9146f81b75b15af468" style="height: 240px; width: 120px;"></iframe></div>
<div>
発光ダイオードの5色セット。100個入り!<br />
電光掲示板でも作るつもりかよ、と言いたくなる量ですが、少量で買っても別に安くならないのでまとめ買い推奨。<br />
DHT11とは関係ないですがGPIOの動作確認用。</div>
<div style="clear: both;">
</div>
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B077N1BV3Y&linkId=c0830671347c4cc7e159ad31abdf7e80" style="height: 240px; width: 120px;"></iframe></div>
<div>
各種抵抗600本入り!<br />
多いことは美しい。</div>
<div style="clear: both;">
</div>
<br />
<h3>
NOOBSとは?</h3>
NOOBSをSDカードにファイルとして書き込んでおくことで、初回起動時にRaspbianのインストーラが起動します。<br />
Raspbian以外のOSもインストールできるようですが、Raspbianであればネットワーク不要でインストールできます。<br />
<a href="https://www.raspberrypi.org/downloads/noobs/" target="_blank">NOOBSのオリジナルファイルはここからダウンロードし、WindowsやMacであらかじめSDカードに書き込んでおきましょう。</a><br />
(キットを購入した場合は書き込み済み。)<br />
<br />
NOOBSからRaspbianをインストールする際は1時間くらい掛かるので要注意。<br />
<br />
<h3>
NOOBSでRaspbianをインストール</h3>
あらかじめSDカードに設定を書き込んでおくと、Raspbianのインストールをヘッドレス(モニタなし)でできます。<br />
やり方はこのあたりのブログで詳しく説明されています。<br />
<a href="https://tom2rd.sakura.ne.jp/wp/2018/07/18/post-7893/" target="_blank">Tom's Hobby「【ラズパイ】Raspberry Pi NOOBS Wifi設定、VNCインストールなど事前設定しておく【インストール】」</a><br />
<br />
NOOBSからRaspbianをインストールする方法はこのあたりを参照。<br />
このステップでかなり時間がかかります。<br />
<a href="https://deviceplus.jp/hobby/raspberrypi_entry_056/" target="_blank">第56回「改めましてラズベリーパイの基本!(1) Raspberry Pi NOOBSインストール 2017年度版」</a><br />
<br />
<h3>
WiFi設定してSSHを有効化する</h3>
Raspbianセットアップが済んだSDカードにMacやWindowsから設定ファイルを書き込んでおくと、Raspberry Piにモニタをつながなくても続きの作業ができるようになります。<br />
<br />
●Macで設定する場合<br />
<a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html" target="_blank">「Raspberry Pi Zero W をヘッドレスでWiFi対応セットアップする」</a><br />
<br />
●Windowsで設定する場合<br />
Macの場合と同様に次の2つのファイルを書き込めばOKです。<br />
<br />
(1) {SDカードのドライブ名}¥boot¥wpa_supplicant.conf<br />
通常は設定済みのRaspberry Piから/etc/wpa_supplicant/wpa_supplicant.confをコピーするのが簡単です。<br />
<pre class="brush:shell">country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="{SSIDを書く}"
#psk="{WiFiパスワード}"
psk=暗号化したWiFiパスワード
}</pre>
(2) {SDカードのドライブ名}¥boot¥ssh<br />
このファイル名で空ファイルを置きます。<br />
<br />
●セットアップ中のRaspberry Piにモニタを繋いで設定する場合<br />
<a href="http://tech.andhandworks.com/2016/04/raspberry-pi3-pc.html" target="_blank">「Raspberry Pi3 に液晶モニタを付けて一体型 PC に」</a><br />
SSHは「sudo raspi-config」コマンドから「5 Interfacing Options」でSSHを有効化すれば使えるようになります。<br />
<br />
<h3>
WindowsからSSH接続する</h3>
まず、Raspberry PiのIPアドレスを調べます。<br />
Raspberry Piのターミナル上で次のコマンドを打てばIPアドレスがわかります。<br />
<pre class="brush:shell">$ ifconfig</pre>
<br />
WindowsでSSHを頻繁に使う場合は<a href="https://ja.osdn.net/projects/ttssh2/releases/" target="_blank">TeraTerm</a>をインストールします。<br />
一時的にSSH接続したいだけの場合はDOSプロンプトでも大丈夫です。<br />
<br />
Windows上で次のように進めるとWindowsからRaspberry PiにSSH接続できます。<br />
(1) WindowsでDOSプロンプトを開く。(タスクトレイで「DOS」と検索すると出てきます。)<br />
(2) 次のコマンドを実行。<br />
<pre class="brush:shell">ssh pi@{Raspberry PiのIPアドレス}</pre>
(3) 初回は何か質問されるのでYESを答える。
(4) piユーザのデフォルトパスワードは「raspberry」<br />
<br />
<h3>
パスワードを変更する</h3>
デフォルトパスワードのまま公衆WiFiなどに接続するとあっさり乗っ取られます。<br />
(そもそもRaspberry Piで公衆WiFiにつなぐなよ、という気もしますが。。。)
次のコマンドでパスワードを変更。<br />
<pre class="brush:shell">$ passwd</pre>
<br />
<h3>
Node-REDをセットアップする</h3>
ここまででようやくRaspberry Piをコマンドラインで操作できるようになりました。<br />
Node-REDをセットアップして、ブラウザからRaspberry Piの動作を定義できるようにします。<br />
最近はRaspbianに標準でインストールされていますが、バージョンが古いなど問題がある場合はアップデートした方が良いかもしれません。<br />
<br />
Node-REDのセットアップについては<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html" target="_blank">過去記事</a>、、、と言いたいところですが、以下のコマンドをSSHで実行するだけです。<br />
<pre class="brush:shell">$ bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)</pre>
<br />
<h3>Node-REDでLチカ</h3>
Node-REDとGPIOの動作確認としてLチカさせます。<br />
※Lチカ=LEDをチカチカさせること。ソフトウェアで言うところの「Hello World」みたいなもの。<br />
世の中には詳しいブログがたくさんあるのでそっちを見てください。<br />
<a href="http://www.ohmaker.net/2018/02/23/raspberry-pi-node-red-lchika/" target="_blank">oh-maker「Raspberry PiとNode-REDでLチカ」</a><br />
<br />
<h3>
Node-REDでDHT11をつかえるようにする</h3>
Node-REDでGPIOを使えることが分かったので、DHT11と繋ぎます。<br />
DHT11から値を取得するには、SSH接続(もしくはローカルのターミナル)で少し準備が必要です。<br />
設定方法はこのブログが分かりやすいです。<br />
<a href="http://sigpipe.hatenablog.com/entry/2017/12/10/122138" target="_blank">EPIPE「Raspberry Pi + Node-RED + DHT11 で温度・湿度取得」</a><br />
<br />
ノードのつなぎ方はここを参考に。<br />
<a href="https://www.nic.ad.jp/ja/materials/iw/2018/proceedings/h1/h1-egusa.pdf" target="_blank">ラズパイで始めるIoTハンズオン</a><br />
<br />
ちなみに、GPIOのピン番号はRaspberry Piの公式サイトにドキュメントがあります。<br />
<a href="https://www.raspberrypi.org/documentation/usage/gpio/" target="_blank">GPIO - Raspberry Pi Documentation</a><br />
<br />
<h3>Node-REDで取得した温度をクラウドに飛ばす</h3>
Node-RED のノードリストの「ソーシャル」にある email ノードを使うと簡単にメールを飛ばせます。<br />
デフォルトで Gmail の SMTP サーバ(メール送信サーバ)が指定されているので、自分のGoogleアカウントの情報を設定するだけです。<br />
<br />
もう少し頑張りたい場合は Twitter に飛ばすこともできますが、事前にTwitter API keyを取得しておく必要があります。<br />
「<a href="https://qiita.com/y_ishihara/items/501bb6fddc785a56780e" target="_blank">Qiita Twitter のAPIキーの取得方法が変わった</a>」<br />
<br />
Node-REDからTwitterにダイレクトメッセージを飛ばす方法はここで解説されています。<br />
<a href="https://qiita.com/conservativerad/items/6d7df4284888c08a6377" target="_blank">Qiita「Node-RED で Twitter ダイレクト・メッセージ を送る場合の備忘録」</a>
たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-41271340502747550182019-01-16T23:17:00.002+09:002019-01-16T23:21:52.009+09:00光を追いかける自動走行車:(2)A/D変換とは?Raspberry Pi でアナログセンサの値を取得するために、<a href="http://tech.andhandworks.com/2019/01/blog-post.html">前回掲載したA/Dコンバータ</a>を使います。<br />
<br />
arduinoをよく使う人は、ここで「あれ?」と思うかもしれません。<br />
と言うか、私は思いました。<br />
<br />
Arduino UNOなどのアナログ入力ピンは、A/Dコンバータ(ADC)なしでアナログセンサを接続することができます。<br />
実は、Arduino UNOなどに使われているマイコンチップ ATmega328P は、チップにADCが埋め込まれているので<br />
アナログ入力ピンに繋ぐといきなりA/D変換後の値を取得できます。<br />
<br />
ところで、ハードウェア屋さんにとってはA/D変換は常識ですが、IT屋さんは、<br />
A/D変換というのを分かっているようで分かっていないことが多いです。<br />
そもそも、「アナログ」と「デジタル」の違いも実は怪しい人が少なくありません。<br />
と言うか、私は分かっていませんでした。<br />
<br />
と言うわけで、今回はA/D変換について。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2019/01/blog-post.html">材料を揃える</a></li>
<li>A/D変換とは?(今回)</li>
<li>コンバータからSPI通信で値を取得する</li>
<li>Raspberry PiのPWMで擬似アナログ出力する</li>
<li>モータドライバでモータ制御する</li>
<li>光センサからの入力とモータ制御を連動させる</li>
</ol>
<br />
<h3>
アナログ値とデジタル値とA/D変換</h3>
意外とよくあるのが「実数値=アナログ値」という勘違いです。<br />
プログラム中で値を参照できている時点でそれは全て「デジタル値」です。<br />
<br />
また、「アナログ入力から取得した値は連続値が取れる」という勘違いもよくあります。<br />
アナログ値がA/D変換された時点で実数の離散値になります。<br />
<br />
さらに厄介なのが「A/D変換後の値は工学値ではない」という罠。<br />
当然ですが、デジタル値 20(0x14) は温度20度ではありません。<br />
<br />
ざっくり絵で描くとこんな感じ。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRqMPaA9ZPb18uHus17pzEAk91Ymbz0GHkMo0mP6b-wMqTn6SsUmq2Hl8o82TE1OOJe7Z9tpTCQavneeNLuTPrSsu2_k11n0M07li1RHuEAOPIS0qkYjt4l4bWH5elSEiDkVJ3pFvnd6Yq/s1600/ADC.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="722" data-original-width="292" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRqMPaA9ZPb18uHus17pzEAk91Ymbz0GHkMo0mP6b-wMqTn6SsUmq2Hl8o82TE1OOJe7Z9tpTCQavneeNLuTPrSsu2_k11n0M07li1RHuEAOPIS0qkYjt4l4bWH5elSEiDkVJ3pFvnd6Yq/s640/ADC.png" width="257" /></a></div>
(1) センサの役割<br />
大抵のアナログセンサは環境変化によって抵抗値が変化します。<br />
この変化の仕方はセンサの特性として決まっていて、非線形なことが多いようです。<br />
例えば、明るさが2倍になっても抵抗が2倍や0.5倍になるわけではありません。<br />
ここまでがアナログセンサのお仕事。<br />
<br />
(2) A/Dコンバータの役割<br />
次に、アナログセンサをA/Dコンバータに繋いでA/D変換します。<br />
センサの抵抗値が変わると言うことは、その両端での電圧の値が変わります。<br />
A/Dコンバータはそれを決められたビット数に量子化します。<br />
例えば、最大5Vの8bit A/Dコンバータなら0〜5Vを256分割。(たぶん)<br />
本当はもっと賢いことをやっているらしいのですがイメージとしてはそんな感じ。<br />
<br />
(3) 工学値変換の役割<br />
最終的に摂氏などの工学値が欲しい場合はデジタル値を工学値に戻します。<br />
センサ特性が非線形なので工学値変換も非線形になります。<br />
また、(2)の時点で離散値になっているので、変換した工学値も離散値です。<br />
<br />
多くの場合、A/D変換後の値をソフトウェア的に変換してやる必要がありますが、この工学値変換曲線を作るのが結構難しいと思います。<br />
モジュール化して売られているアナログセンサの中にはは、メーカーから配られているライブラリを使うと(1)〜(3)をまとめてやってくれるものもあるようです。(温湿度センサのDHT11など)<br />
<br />
<h3>
小学生に説明してみた</h3>
A/D変換について小学四年生に説明してみました。<br />
どこまで伝わったかは謎。<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/S5XWT5n9KtU/0.jpg" src="https://www.youtube.com/embed/S5XWT5n9KtU?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<br />
A/D変換の話が長くなってしまったので、A/Dコンバータの使い方はまた次回。<br />
次回はSPI通信を使ってA/Dコンバータから値を取得します。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-78462351277951851162019-01-10T21:36:00.001+09:002019-01-16T23:16:38.920+09:00光を追いかける自動走行車:(1)準備毎週、小学4年生(息子)にプログラミング教室を開いて9ヶ月。<br />
ようやくそれらしいものが動きました。<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/FpouCiPuw9A/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/FpouCiPuw9A?feature=player_embedded" width="320"></iframe></div>
<br />
光センサで周囲の明るさを調べて、明るい方に向かって走っていく自動走行車。<br />
講義内容の振り返りを兼ねて少しずつ書いていきます。<br />
<br />
<h3>
作成の流れ</h3>
<ol>
<li>材料を揃える(今回)</li>
<li>A/D変換とは?</li>
<li>コンバータからSPI通信で値を取得する</li>
<li>Raspberry PiのPWMで擬似アナログ出力する</li>
<li>モータドライバでモータ制御する</li>
<li>光センサからの入力とモータ制御を連動させる</li>
</ol>
<br />
<h3>
材料</h3>
<h2>
Raspberry Piで学ぶ電子工作</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=4062579774&linkId=d82dceeab35badfdae18013e69dff08b" style="height: 240px; width: 120px;"></iframe>
</div>
教科書。<br />
この本ではスマホから操作するラジコンの作り方が紹介されています。<br />
その途中でA/D変換やモータ制御の話が出てくるので、分からなくなったらこれを参照しながら作りました。<br />
<div style="clear: both;">
</div>
<br />
<h2>
Raspberry Pi 3 B+</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07BFH96M3&linkId=18a7f97126b62516cf4b6f58294a4209" style="height: 240px; width: 120px;"></iframe></div>
Raspberry Pi2や3Bでも構いません。<br />
<s>Raspberry Pi Zero/Zero W はシングルコアなのでダメです。</s><br />
Raspberry Pi Zero W でも動作しますが、VNCでデスクトップを表示しながらカメラを動かそうとするとかなり重くなってしまいます。<br />
<div style="clear: both;">
</div>
<br />
<h2>
フォトレジスタ×2個</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00Q6ZIK1O&linkId=8bac7c89b7b0e84a4768ad7296feb6cb" style="height: 240px; width: 120px;"></iframe></div>
フォトレジスタというのは光センサのことです。<br />
電子工作のスターターキットなどにもよく入っています。<br />
車の左右の明るさを計測するので2個使います。<br />
<div style="clear: both;">
</div>
<br />
<h2>
A/Dコンバータ:MCP3008</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07KP2PL9J&linkId=5e340f0cf60dc80d6fdd7d0a5b4a8825" style="height: 240px; width: 120px;"></iframe></div>
今回は8チャンネル10bitのA/Dコンバータを使いました。<br />
amazonで探すと何故か1万円越えの異常な値付けになっていることがあるので要注意。<br />
実際には2チャンネルあれば十分なので、手に入るもので構わないと思います。<br />
見つからない場合は秋月電子で。<br />
<div style="clear: both;">
</div>
<br />
<h2>
HiLetgo L9110S モータードライバ</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B011DT3OAY&linkId=e29bf2f8991a08ff5885d7bb781b069e" style="height: 240px; width: 120px;"></iframe></div>
ものすごく雑なつくりですが、激安のモータードライバ。<br />
このドライバ1個でモーターを2チャンネル制御できるので、全体を小型化できます。<br />
<div style="clear: both;">
</div>
<br />
<h2>
ダブルギヤボックス</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001Q13BIU&linkId=d1864735c5ad7704273c467ed7ff10d9" style="height: 240px; width: 120px;"></iframe></div>
左右独立で動くタミヤのギヤボックス。<br />
モーターも同梱されているので、これ1つで色々遊べます。<br />
<div style="clear: both;">
</div>
<br />
<h2>
キャタピラ</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001VZJDY2&linkId=9d19da5f9ec2b00b682ba533dbea0cb2" style="height: 240px; width: 120px;"></iframe></div>
タミヤのキャタピラセット。<br />
キャタピラの長さやホイールの配置を柔軟に変えられて便利。<br />
<div style="clear: both;">
</div>
<br />
<h2>
ユニバーサルプレートセット</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001VZHRXG&linkId=a4aea5b9ddd17c20dea88474dedee664" style="height: 240px; width: 120px;"></iframe></div>
シャシーの代わり。<br />
別にこれでなくてもかまぼこの板でもなんでも構いません。<br />
<div style="clear: both;">
</div>
<br />
その他、電池ボックス、モバイルバッテリー、ジャンパワイヤ多数。<br />
<br />
<br />
<br />
今回はここまで。<br />
気が向いたら続きを書きます。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-16018307688395590482018-11-10T22:04:00.001+09:002018-11-10T22:05:43.022+09:00Raspberry Piでジュークボックス(番外):現状<a href="http://tech.andhandworks.com/2018/08/raspberry-pi_19.html">先日準備編だけ書いたままだったジュークボックス</a>のその後。<br />
リビングの家電を一通り音声操作できるようにしてリモコンを撲滅したところ、家族から次々とリクエストが出てきて意見箱が設置されることに。<br />
意見箱の投書を粛々と実装するうち、何なのかよく分からないデバイスに進化してきました。<br />
そもそも「デバイス」と言っても、家中に散らばったデバイスが連動して動いているので、どれが本体なのか誰も気にしていません。と言うか「本体」など存在しない状態に。<br />
<br />
<h3>主な構成</h3>
<ol><li>音声入力<br />
ダイニングに置いてあるAmazonEcho。</li>
<li>音声出力<br />
メインはリビングのスピーカー(サウンドバー)<br />
AmazonEcho自体の機能に関する音声フィードバックはAmazonEchoから出るので、あちこちで違う声で喋りまくり。</li>
<li>制御系<br />
AmazonEchoとRaspberry Pi2台とArduinoとアンプが連動しているのでどれがどうとも。。。<br />
音声入力系については、基本的にはこの流れ。<br />
AmazonEcho → Node-RED(Raspberry Pi) → 赤外線(Raspberry Pi) → アンプ切り替え&各機器制御<br />
そのほか、時間での自動起動系はRaspberry Piとアンプが赤外線で連携。</li></ol>
<br />
<h3>主な実装済み機能</h3>
<ol><li>テレビ/プロジェクター/ルンバの音声操作</li>
<li>携帯やPCからリビングのスピーカーで音楽再生</li>
<li>操作対象に合わせてアンプの音声入出力を自動切り替え</li>
<li>朝夕と夜に時報を喋る。</li>
<li>早朝にYoutubeからそれっぽいPlaylistを検索して自動再生。</li>
<li>誰かの誕生日には勝手に祝う。</li>
<li>学校に行く時間になったら音声で急かす。</li>
<li>週末も学校と同じ時間に学校と同じチャイムが鳴る。</li>
<li>時報などの音声案内は音声合成の話者をランダムに入れ替えて再生。</li></ol>
<br />
<h3>未実装の機能というか要望</h3>
<ol><li>音声合成の話者入れ替えに関して、OpenJTalkのおっさんの声が偶然私の声に似ていたらしく、娘から「もっとやれ」との指示。</li>
<li>Logicoolのカメラをハードオフのジャンク箱から100円でゲットしたので画像入力を使いたい。</li>
<li>家電からのフィードバックパスが無く、細かい使い勝手に制限が出る。<br />
(家電用リモコンで電源を切ると音声入出力の組み合わせが連動しないとか)</li>
<li>AmazonEchoからキーワード入力できないので、ジュークボックスにキーワード検索させようとすると携帯操作になる。</li>
<li>制御系を全部隠してあるのに、AmazonEchoが存在感を出しすぎ。どこかに隠したい。</li>
<li>音声入力を分散配置したいが質の良いマイクを自前で用意するのが厳しい。</li>
<li>対象機器にアナログ掛け時計を入れたい。Raspberry Piを組み込んでデジタル鳩時計にしたい。</li></ol>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-27524181685963862772018-09-30T03:10:00.000+09:002018-09-30T03:19:30.807+09:00Raspberry Piでネットワークルーティングまたしても需要がなさそうですが、Raspberry Piで2つのプライベートネットワーク間をルーティングします。<br />
<br />
ググるとRaspberry PiをDHCP & default gateway にする方法はたくさん出てくるのですが、<br />
DHCP と default gateway は普通の WiFi ルータに任せて、プライベートセグメントだけルーティングする、という面倒なことをやろうとしたら情報がなかったので。<br />
<br />
<h4>やりたいこと</h4>
図のように、WiFiルータが2つあって、それぞれ LAN1(192.168.1.0/24) と LAN2(192.168.2.0/24) のネットワークを作っています。<br />
LAN1 には NAS がぶら下がっていて、普段作業する Mac なども繋がっています。<br />
一方、LAN2 には子供が使う Windows マシンが繋がっています。<br />
このままでもそれぞれの WiFi ルータからネット接続できるのですが、<br />
LAN2 側から NAS を使いたかったので Raspberry Pi でゲートウェイすることにしました。<br />
ただし、DHCPはそれぞれのWiFiルータなので default gateway はWiFiルータです。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeZWbe1NmII6NyPgAPVVRQvqOuo6Yz5A-yJ3g5Jh3xeUv2d5crp3pbGOSCopvwH_yp0YdyceTJXDrlxNnUfztbGDpqOQQDpI6qJue_0n8PyVhNq_9qq7D9w2OC5ag_DnkZ-NBl3f3rGc2u/s1600/routing.001.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeZWbe1NmII6NyPgAPVVRQvqOuo6Yz5A-yJ3g5Jh3xeUv2d5crp3pbGOSCopvwH_yp0YdyceTJXDrlxNnUfztbGDpqOQQDpI6qJue_0n8PyVhNq_9qq7D9w2OC5ag_DnkZ-NBl3f3rGc2u/s320/routing.001.png" width="320" height="216" data-original-width="931" data-original-height="628" /></a>
<br />
普通はWiFiルータ2をWiFiコンバータにすれば済む話なのですが、<br />
たまたまWiFiルータが1台余っていたので。<br />
<br />
しかも、自宅の壁面にマルチメディアコンセントが埋め込まれているのですが、<br />
そこにLANケーブルを挿すとグローバルネットワークになってしまうのでこんなことに。<br />
本当は天井裏のハブをルータに置き換えて、壁面配線をプライベートネットワークにしたいのですがそれはまた別の話。<br />
<br />
<h4>Raspberry Piでルーティングする</h4>
Raspberry Piを有線と無線の両方につないだとしても、そのままではルーティングしてくれません。<br />
IP forwardを許可して iptables を設定すればOKです。<br />
<br />
まず、/etc/sysctl.conf に「#net.ipv4.ip_forward=1」という行があるのでコメントを外します。<br />
その後、/proc/sys/net/ipv4/ip_forwardに「1」を書き込んで reboot。<br />
<pre class="brush:shell">
root@raspberrypi:~ # echo -n 1 > /proc/sys/net/ipv4/ip_forward
root@raspberrypi:~ # reboot
</pre>
さらに、ルーティングされるようにiptables に設定を追加。<br />
素通しするだけだから「nat」とか要らないかなぁ、という気もしますが、細かい設定はよく分かりません。<br />
誰かちゃんとした設定を教えて、エロい人。<br />
<pre class="brush:shell">
root@raspberrypi:~ # iptables -F
root@raspberrypi:~ # iptables -X
root@raspberrypi:~ # iptables -t nat -F
root@raspberrypi:~ # iptables -t nat -X
root@raspberrypi:~ # iptables -t mangle -F
root@raspberrypi:~ # iptables -t mangle -X
root@raspberrypi:~ # iptables -P INPUT ACCEPT
root@raspberrypi:~ # iptables -P FORWARD ACCEPT
root@raspberrypi:~ # iptables -P OUTPUT ACCEPT
root@raspberrypi:~ # iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
root@raspberrypi:~ # iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
</pre>
「iptables -L」でこんな感じの出力になれば成功です。<br />
<pre class="brush:shell">
root@raspberrypi:~ # iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
</pre>
この状態で Raspberry Pi はルーティングしてくれるはずですが、<br />
Windows マシンから 192.168.1.x のアドレスに ping を打っても返ってきません。<br />
それは Raspberry Pi とは別の理由なので後で対応します。<br />
<br />
<h4>iptables が起動時に設定されるようにする</h4>
Raspbian は標準で iptables が入っていますが、起動時に設定を反映してくれないようです。<br />
「iptables-persistent」というパッケージを入れれば良い模様。<br />
<br />
インストールは単に「sudo apt-get install iptables-persistent」でOK。<br />
インストール時に現在のiptablesを保存するか聞かれるので「YES」。<br />
その後、再起動すれば iptables が再設定されます。<br />
<br />
<h4>Windowsから別セグメントのファイルサーバにアクセスできるようにする</h4>
これでルーティングされているはずなのですが Windows から NAS に ping が通りません。<br />
なぜなら、Windows の default gateway が WiFi router2 になっているから。<br />
WiFi router2 は NAS のアドレスを知らないため、インターネット側にルーティングしてしまいます。<br />
<br />
もし、WiFi router2 の設定で、192.168.1.0/24 を Raspberry Pi にルーティングできるなら設定します。<br />
普通の家庭用 WiFi ルータではそんな細かい設定ができないことが多いので、今回は Windows 側で頑張ります。<br />
<br />
とは言え、Windows でも通常のコントロールパネルからは設定できません。<br />
管理者権限でDOSプロンプトを開いて次のコマンドを実行。<br />
<pre class="brush:shell">
# route -p add 192.168.1.0/24 192.168.2.10
</pre>
「192.168.2.10」は Raspberry Piの LAN2 側アドレスです。<br />
「-p」オプションは persistent のことで、このオプションを付けると再起動後にも反映されます。<br />
もしいきなり試すのが怖ければ「-p」無しで実行すれば再起動で元に戻ります。<br />
<br />
ここまで設定できたら Windows から ping を打ってみます。<br />
<pre class="brush:shell">
# ping 192.168.2.10
PING 192.168.2.10 (192.168.2.10): 56 data bytes
64 bytes from 192.168.2.10: icmp_seq=0 ttl=64 time=2.546 ms
:
# ping 192.168.1.10
PING 192.168.1.10 (192.168.1.10): 56 data bytes
64 bytes from 192.168.1.10: icmp_seq=0 ttl=64 time=2.546 ms
:
# ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
</pre>
・・・あれ?<br />
Raspberry Pi の LAN1 側アドレスからは応答があるので、ルーティングはできています。<br />
ところが、LAN1に繋がっているNASから応答がありません。<br />
<br />
これは、NAS までは ping が通っています。<br />
NAS から戻ってくるときに、NAS 側の default gateway が WiFi router1 になっているからです。<br />
またかよ。<br />
<br />
基本的に NAS からインターネットアクセスすることはないと思いますので、<br />
NAS の default gateway を Raspberry Pi (192.168.1.10) にすれば大丈夫です。<br />
もちろん、192.168.2.0/24 だけを振っても良いですが、家庭用NASではそんな設定はできないと思います。<br />
<br />
<h4>Windowsのhostsファイルを編集する</h4>
これで、 LAN2 側の Windows から LAN1 側の NAS につながるようになりました。<br />
ただし、このままだと名前解決できないので常に IP アドレスで繋ぐことになります。<br />
<br />
Raspberry Pi で DNS を動かしても良いですが面倒なので Windows の hosts ファイルに直接書き込んでしまいます。<br />
メモ帳を管理者権限で開いて hosts ファイルの末尾に設定を追加します。<br />
Windows10 の hosts ファイルは「C:\Windows\System32\drivers\etc\hosts」です。<br />
<pre class="brush:shell">
# cat C:\Windows\System32\drivers\etc\hosts
:
192.168.1.10 NAS
</pre>
これでホスト名でファイルサーバにアクセスできるようになりました。<br />
<br />
おわり。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-2939878671050323512018-08-19T14:33:00.002+09:002018-08-19T14:41:59.116+09:00Raspberry Piでジュークボックス:(1)準備iPhoneでYoutubeから曲を選ぶと、Raspberry Pi経由で室内のスピーカーから流れるようにしました。<br />
<br />
<h3>
何をしたいのか</h3>
私よりも自宅にいることの多い顧客(家族)からのリクエストだったものの、<br />
本人もどうなっていれば良いのか分からなかったようで試行錯誤しながらのヒアリングになりました。<br />
結局のところ次のことを言っていたようです。<br />
<ul>
<li>スピーカーでリビングに音楽を流して欲しい。</li>
<li>楽曲指定は基本的にキーワード指定。お気に入りとかプレイリストとか要らない。</li>
<li>簡単に再生開始したい。音声操作でもスマホでもどちらでも良いがハードウェアボタンを押しに行くのは嫌だ。</li>
<li>再生中にスマホで他の操作をしたいので占有されたくない。</li>
<li>1曲終わったら関連楽曲を連続再生して欲しい。</li>
<li>途中、気に入らない楽曲が再生されたらスキップ or 他の関連曲に変えたい。</li>
<li>レスポンスが良いに越したことはないが、再生開始に時間がかかっても許容可能。(どうせ再生しっぱなしだから)</li>
<li>再生時に余計な家電が動いてしまうのはNG。</li>
<li>コンテンツに定額が発生しても構わないが、気に入った曲が無いならダメ。</li>
</ul>
<br />
<h3>
できるようになったこと</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL-qYNk-JHYEf6teWnjwzq6ipznXW_VJrS1Ua_6CQRYU4NH0BFXeKHNBxiB1tzy2KqnXjjudaiXs_p-Vigp3OCUuGvwsn-Pd7FIDSZEPclvr5o9pjWf0lxzNRKv5BAVjhGcUukIfoL4xje/s1600/youtube.001.png" imageanchor="1"><img border="0" data-original-height="502" data-original-width="599" height="335" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL-qYNk-JHYEf6teWnjwzq6ipznXW_VJrS1Ua_6CQRYU4NH0BFXeKHNBxiB1tzy2KqnXjjudaiXs_p-Vigp3OCUuGvwsn-Pd7FIDSZEPclvr5o9pjWf0lxzNRKv5BAVjhGcUukIfoL4xje/s400/youtube.001.png" width="400" /></a>
<br />
iPhoneでSiriに「Youtubeで◯◯を検索」と頼んで、検索結果からworkflowに共有するとRaspberry PiのNode-REDにリクエストが飛ぶようにしてあります。<br />
最初からWorkflowにキーワードを入力してもOK。<br />
<br />
Node-REDはリクエストされたYoutubeコンテンツIDまたはキーワードをShellScriptに渡します。<br />
ShellScriptでは内部でmps-youtube(mpsyt)を呼び出して、Youtubeの楽曲を検索して再生。<br />
<br />
その際、Raspberry Pi Zero Wを使うと再生開始まで非常に時間がかかる(1分くらい)ので、<br />
Open JTalkで音声案内を入れるようにしました。<br />
<br />
ここまでできてしまうと、mpsytの関連検索コマンドなどを駆使すれば連続再生なども簡単にできます。<br />
処理が重すぎて、再生中のコマンドはうまく受け付けてくれないことがあるので、<br />
停止やスキップについてはShellScriptから強制終了させるなどの対応にしました。<br />
<br />
ついでにAmazon Echoに「ジュークボックスを消して」と言うとNodeREDから停止するようにしてあります。<br />
<br />
<h3>
試したこと</h3>
今回の構成に至るまでの試行錯誤の経緯。。。<br />
<br />
<h2>
Amazon Echo Dot + Amazon Music Unlimited</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B072B5BTLK&linkId=c025871c508991c9d7bd6367cdeb6b1c" style="height: 240px; width: 120px;"></iframe></div>
・選曲操作:Amazon Echo Dot<br />
・音楽配信:Amazon Music<br />
・再生端末:Amazon Echo Dot<br />
・音声出力:Amazon Echo Dot<br />
<br />
声を掛けるだけで再生されるしレスポンスも良く、再生デバイスとしてはGood。<br />
ところが「Amazon Music Unlimitedが対応している曲がイマイチ」ということでお客様としてはNG。<br />
<br />
Google Homeも買おうとしましたが、顧客から「なんでやねん」というツッコミが入って断念しました。<br />
<div style="clear: both;">
</div>
<br />
<h2>
iPad + Youtube + AirPlay + Amazon Fire TV Stick</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B01ETRGGYI&linkId=456e62a6af403a65a8b16a678c7124a6" style="height: 240px; width: 120px;"></iframe></div>
・選曲操作:iPad + Youtubeアプリ<br />
・音楽配信:Youtube<br />
・再生端末:iPad + AirPlay<br />
・音声出力:Amazon Fire TV Stick<br />
<br />
それで良いのか?と言いたくなりますが、Amazon MusicのコンテンツがイマイチならYoutubeで。。。<br />
ちなみに、Apple Music は宗教的理由により見送りました。<br />
死んだ爺さんから「月額課金はAmazon大明神の思し召しのままに」と言われているので。<br />
<br />
Amazon Fire TV Stick にAirPlayのアプリを入れてiPadからYoutubeの音声を飛ばしました。<br />
コンテンツ的にはOKらしいのですが、Fire TVにAirPlayを繋いだ瞬間にHDMI経由で画面(プロジェクター)が起き上がってしまいNG。<br />
いや、だって、映像再生デバイスなんだから仕方ないじゃん。。。<br />
<br />
また、iPadだとYoutubeが関連楽曲を連続再生してくれずご不満とのこと。<br />
ふーん。<br />
<br />
<h2>
iPhone + Youtube + AirPlay + Raspberry Pi + スピーカー</h2>
・選曲操作:iPhone + Youtubeアプリ<br />
・音楽配信:Youtube<br />
・再生端末:iPhone + AirPlay<br />
・音声出力:Raspberry Pi + スピーカー<br />
<br />
Fire TVが画面出力してしまうならRaspberry Piでヘッドレスにしてみよう、ということで。<br />
<a href="http://tech.andhandworks.com/2018/08/raspberry-piairplay.html">具体的な方法は以前説明した通り。</a><br />
iPhoneであればYoutubeの連続再生も可能です。<br />
<br />
しばらく良い感じに使っていたのですが、iPhoneで他の操作をしようとしてYoutubeアプリをバックグラウンドにすると音が切れてしまい、微妙なイライラが残ります。<br />
<a href="http://appllio.com/youtube-background-play-music-iphone-android">ブラウザを駆使するとバックグラウンドで再生できるようです</a>が、毎回この操作をするのは耐えられないとのことでNG。<br />
<br />
<h2>
iPhone + workflowアプリ + Raspberry Pi + Node-RED + Youtube + mpsyt + OpenJTalk + スピーカー</h2>
・選曲操作:iPhone + workflowアプリ(キーワード指定のみ)<br />
・音楽配信:Youtube<br />
・再生端末:Raspberry Pi + mpsyt<br />
・音声出力:Raspberry Pi + スピーカー<br />
<br />
最終的にたどり着いた構成がこれ。<br />
結局、楽曲検索から再生から何から全部をRaspberry Piに詰め込んでしまい<br />
「それミュージックプレイヤーやないかい」という状態。<br />
<br />
<br />
前置きが長くなったので続きは次回。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-16614268032469683142018-08-16T00:51:00.000+09:002018-08-19T14:40:57.877+09:00Raspberry Pi に日本語を喋らせる<div style="float:left;margin:8px"><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B01CSFZ4JG&linkId=949688aa5c2b61195119ecb7ba2ef2d2"></iframe></div>
<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">Alexa でルンバに掃除させる際の試行錯誤で、色々な家電を音声コマンドで動かせるようになりました。</a><br />
<br />
便利にはなったものの、Alexa Home Skill は返事が毎回「はい」なので無愛想に感じてしまいます。<br />
そこで、Raspberry Piで家電を操作する際にもう少し丁寧に喋ってもらうようにしました。<br />
<div style="clear:both"></div>
<br />
<h3>
Raspberry Piから音声出力できるようにする</h3>
<div style="float:left;margin:8px"><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B0053N3NVW&linkId=d8f111b9dc27afab7b29d23ad90dc36f"></iframe></div>
Raspberry Piにはスピーカーがありません。<br />
そのため、何らかの方法で音声出力できるようにする必要があります。<br />
<br />
今回は家電が近くにあるのでHDMI出力を使いました。<br />
HDMIから音声出力する方法は前回の「<a href="http://tech.andhandworks.com/2018/08/raspberry-piairplay.html">Raspberry PiをAirPlayレシーバにする</a>」をご参照ください。<br />
<br />
特にHDMIにこだわらない場合は、USBスピーカーを使うのが音質が良く、動作も確実なようです。<br />
<a href="http://www.yam-web.net/raspberry-pi/music.html" target="_blank">音声設定についてはこのサイトが詳しいです。</a>
<br />
<div style="clear:both"></div>
ちなみに、今回のように音声合成の結果をHDMI出力すると次の問題があってちょっと面倒です。<br />
<ul>
<li>音声をデジタル変換する処理が追いつかず、合成音の最初の2〜3文字分の音が出ない。</li>
<li>家電操作の対象が出力先の音声デバイスとバッティングすると厄介なことになる。</li>
</ul>
前者については、合成音の冒頭に「はい」「えーと」など無意味なセリフを入れて回避するしかなさそうです。<br />
後者は、対象デバイスのHDMI入力を一旦Raspberry Piに切り替えてから合成音を再生し、その後で家電操作する、という流れになります。<br />
<br />
単に「切り替えてから」と書きましたが、大抵のデバイスは音声再生程度で自動切り替えしない仕様なので、<br />
自分で赤外線リモコンコードをコピーして操作することになると思います。<br />
方法は<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">ルンバの掃除</a>の際に書いたものが使えると思います。<br />
<br />
<h3>
Open JTalkをインストールする</h3>
次のようにOpen JTalkをインストールします。<br />
<pre class="brush:shell">$ sudo apt-get install open-jtalk
$ sudo apt-get install open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001
</pre>
hts-voice-nitech-jp-atr503-m001 はおっさんの声の辞書です。<br />
音声合成と言えば女性の声だろう、ということで女性の声の辞書を入れます。<br />
<pre class="brush:shell">$ wget http://downloads.sourceforge.net/project/mmdagent/MMDAgent_Example/MMDAgent_Example-1.7/MMDAgent_Example-1.7.zip
$ MMDAgent_Example-1.7.zip
$ sudo cp -r ./MMDAgent_Example-1.7/Voice/mei /usr/share/hts-voice/
</pre>
<br />
<h3>
Open JTalkに喋ってもらう</h3>
コマンド引数にテキストと音声辞書を指定すると合成してくれるのですが、<br />
次のようなスクリプトを作っておくと便利です。<br />
<pre class="brush:shell">#!/bin/sh
msg="$1"
voice_type=/usr/share/hts-voice/mei/mei_normal.htsvoice
echo "$msg" |
open_jtalk -m $voice_type -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow /dev/stdout |
aplay -
</pre>
こんな感じで、このスクリプトの引数に日本語を渡せば再生してくれます。<br />
<pre class="brush:shell">$ ./voice.sh "抵抗は無意味だ"
</pre>
<br />
<h3>
使ってみる</h3>
open_jtalk には合成時のオプションを色々と指定できるのですが、<br />
あまりいじっても音質が劣化して残念なことに。<br />
よほど意味が分かっていない限りは、デフォルトのまま使うのがおすすめです。<br />
<br />
crontab に次のようにスクリプトを仕込んでおくと、毎日7時〜22時に鳴る時報になります。<br />
(タイムゾーンがUTCの場合は9時間引くなりなんなり)
<br />
<pre class="brush:shell">$ crontab -e
0 7-22 * * * /home/pi/bin/tone.sh
</pre>
呼び出されるスクリプトはこんな感じで適当に。<br />
<pre class="brush:shell">#!/bin/sh
DIR=`/usr/bin/dirname $0`
y=`/bin/date +%Y`
m=`/bin/date +%-m`
d=`/bin/date +%-d`
h=`/bin/date +%-h`
msg="$y年 $m月 $d日 h時です。"
$DIR/voice.sh "$msg"
</pre>
<br />
<h3>
Alexaと連携する</h3>
<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">Alexa Home Skill と Raspberry Pi の連携については以前の説明をご参照ください。</a><br />
NodeREDで家電の起動コマンドを送る前に音声合成のShell Execを挟み込めばOKです。<br />
<br />
例えば、こんな感じです。<br />
これでプロジェクターの起動待ちの間に「しばらくお待ちください」などのセリフを挟み込めます。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPk7riUyEC2taPC48NnWAfSqYohNvAu43DiXcy9YAcsS0Euao7b_kNQI8FdD2cF1_5EO9Fm4bNFpIK5qA52vc3uYkC1VcRn1NbI6zc15dbWHeVL13Ntbd_5RyqZ3re-NJUpedFCeokDzfQ/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.39.56.png" imageanchor="1"><img border="0" data-original-height="265" data-original-width="968" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPk7riUyEC2taPC48NnWAfSqYohNvAu43DiXcy9YAcsS0Euao7b_kNQI8FdD2cF1_5EO9Fm4bNFpIK5qA52vc3uYkC1VcRn1NbI6zc15dbWHeVL13Ntbd_5RyqZ3re-NJUpedFCeokDzfQ/s320/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.39.56.png" width="320" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwzyswmhj_gZF9YPy7UX1NWLOzwGWS2j5XIqzXzYkvUHVX3ICo3p2UOHHYxwbhT6jHfgmdrSunrGeJTG4xXKmFizAywak-iXb7rLpRGl9deLAOfpksMVtCG8owkzv91n8RmKlJyH1zTLX2/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.43.31.png" imageanchor="1"><img border="0" data-original-height="200" data-original-width="871" height="73" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwzyswmhj_gZF9YPy7UX1NWLOzwGWS2j5XIqzXzYkvUHVX3ICo3p2UOHHYxwbhT6jHfgmdrSunrGeJTG4xXKmFizAywak-iXb7rLpRGl9deLAOfpksMVtCG8owkzv91n8RmKlJyH1zTLX2/s320/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.43.31.png" width="320" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKwxSibEHhHZMVtMzijvAy1_jMMt3D5BlZK8NNxx_R_kZxa4TZpXgQWZVdKrtSplR6ShQEKQgWw5VshKxD_RYYjx9dwtvSx6pL_VUgB0HHYvoneuxd4W2ZkqcH69ixbNq-1IiKGTlVYVxM/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.46.05.png" imageanchor="1"><img border="0" data-original-height="484" data-original-width="497" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKwxSibEHhHZMVtMzijvAy1_jMMt3D5BlZK8NNxx_R_kZxa4TZpXgQWZVdKrtSplR6ShQEKQgWw5VshKxD_RYYjx9dwtvSx6pL_VUgB0HHYvoneuxd4W2ZkqcH69ixbNq-1IiKGTlVYVxM/s320/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-08-16+0.46.05.png" width="320" /></a>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com2tag:blogger.com,1999:blog-1718731153219810929.post-13015513736501593552018-08-13T01:12:00.004+09:002018-08-13T12:13:56.562+09:00Raspberry PiをAirPlayレシーバにするまるでニーズがないと思いますが、Raspberry PiとAVアンプを組み合わせてiPhoneの音楽をリモート再生する方法。<br />
<br />
<h3>なぜそんな構成にしたのか</h3>
我が家のリビングはAVアンプのHDMI入力にAmazon Fire TV stickを挿しています。<br />
出力はHDMIでプロジェクター。<br />
<br />
Amazon Fire TV はアプリを入れるとAirPlayレシーバになるので、<br />
iPhoneから音楽を飛ばしてAVアンプのスピーカーで音楽を鳴らすことができます。<br />
<br />
ところが、AirPlayで飛ばした瞬間にAmazon Fire TV stick がスリープから起き上がってきます。<br />
すると、プロジェクターが状態変化を自動的に検知して起動してしまいます。<br />
<br />
音楽を聴きたいだけなのに、フルスペックで起きがってくるAV機器ども。<br />
<br />
さすがにちょっと鬱陶しいので、Raspberry PiをAirPlayの音楽用レシーバに仕立てあげることにしました。<br />
こうすると、Amazon Fire TV stickを使わないのでスリープから起き上がってきません。<br />
また、Raspberry PiはAirPlayを受け取っても画面は切り替わらないのでプロジェクターにも影響ありません。<br />
<br />
ただし、AVアンプも自動で入力切り替えしてくれなかったので、そのあたりはRaspberry Piでごにょごにょします。<br />
<br />
<h3>Raspberry Piの音をHDMIで出力する</h3>
Raspberry PiはデフォルトではHDMIから音が出ないようです。<br />
「/boot/config.txt」で次の行のコメントを外して再起動すればOK。<br />
<pre class="brush:shell">
hdmi_drive=2<br />
</pre>
<br />
次のコマンドを実行して、HDMI出力先のスピーカーから音が出れば成功です。<br />
<pre class="brush:shell">
$ speaker-test -t sine -f 600
</pre>
<br />
<h3>Raspberry Piにshairport-syncをインストールする</h3>
shairport-syncというAirPlayレシーバをインストールします。<br />
「shairport」というツールもあるようですが、全く別物らしいので注意。<br />
<br />
まず、依存するパッケージをインストール。<br />
<pre class="brush:shell">
$ sudo apt-get install -y build-essential git xmltoman autoconf automake libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev avahi-daemon libavahi-client-dev libssl-dev libsoxr-dev
</pre>
<br />
次に、gitからshairport-syncをcloneしてビルド。
<pre class="brush:shell">
$ git clone https://github.com/mikebrady/shairport-sync.git
$ autoreconf -i -f
$ ./configure --with-alsa --with-avahi --with-ssl=openssl --with-metadata --with-soxr --with-systemd
$ make
$ sudo make install
</pre>
<br />
インストールできたら自動起動を設定します。<br />
<pre class="brush:shell">
$ sudo systemctl enable shairport-sync
</pre>
<br />
<h3>設定変更</h3>
ここまででiPhoneからAirPlayを飛ばせるようになりますが、音量が妙に小さいです。<br />
そこで、iPhone側の音量を無視してRaspberry Pi側(正確には、Raspberry PiからHDMI出力したAVアンプ側)で音量設定できるようにします。<br />
<br />
まず、音量を100%に設定。<br />
<pre class="brush:shell">
$ sudo amixer cset numid=1 100%
</pre>
<br />
shairpoint-sync の設定ファイルが「/usr/local/etc/sharepoint-sync.conf」にあります。<br />
サンプルの設定ファイルから次の箇所を変更します。<br />
コメントアウトされていた場合はコメントを外します。<br />
<pre class="brush:shell">
general = {
:
interpolation = "soxr";
ignore_volume_control = "yes";
</pre>
interpolationをsoxrにした方が音質が良いらしいです。<br />
ただし、Raspberry Pi Zero Wで有効にした場合、CPU処理が追いつかなくなって音飛びしました。<br />
音飛びしてしまう場合はinterpolationの行をコメントアウトすればデフォルトに戻ります。<br />
<br />
ignore_volume_control を yes にするとiPhoneの設定を無視するようになります。<br />
<br />
<h3>AVアンプの設定を切り替える</h3>
AVアンプの機種によると思いますが、私が使っているものだと、Raspberry Piが音声をHDMI出力しても自動で音声入力が切り替わりませんでした。<br />
そこで、AVアンプの赤外線リモコンコードを読み取って、Raspberry PiからHDMI入力を切り替える信号を送ります。<br />
<a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">赤外線リモコンのコピーの仕方は以前掲載した説明をご参照ください。</a><br />
<br />
問題はどのタイミングで赤外線信号を送るかです。<br />
実は、sharepoint-sync.confの設定の中に用意されています。<br />
次の行のコメントを外して設定値を記載します。<br />
<pre class="brush:shell">
sessioncontrol = {
:
run_this_before_play_begins = "/usr/bin/irsend SEND_ONCE AV hdmi2";
run_this_after_play_ends = "/usr/bin/irsend SEND_ONCE AV tv";
</pre>
<br />
run_this_before_play_begins はiPhoneからAirPlayで送信先として指定したタイミングで実行されます。<br />
run_this_after_play_ends はAirPlayの終了(音楽生成終了)の際に実行されます。<br />
<br />
設定を変更したあと、サービスを再起動すれば反映されます。<br />
<pre class="brush:shell">
$ sudo service shairport-sync restart
</pre>
<br />
一通り設定が終わったら、iPhoneからAirplayでRaspberryPiに音楽を飛ばすと
AVアンプの入力系統が自動的に切り替わって再生が始まります。
たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-41038359375302148352018-07-01T22:36:00.001+09:002019-01-10T21:38:42.826+09:00Alexa と Raspberry Piでルンバに掃除してもらう:【最終回】Node-REDからFlashAir/Arduino経由でルンバを動かす<a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">前回、Arduinoからルンバに赤外線コードを送れるようにしました。</a><br />
今回は、Node-REDからFlashAirを呼び出して、Arduinoの赤外線送信をキックします。<br />
<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a>【今回】</li>
</ol>
<br />
<h3>
FlashAirのGPIO</h3>
FlashAirではSDカードの各ピンをGPIOとして使用できます。<br />
詳しくは<a href="https://flashair-developers.com/ja/documents/tutorials/users/2/" target="_blank">FlashAir Developers</a>で説明されています。<br />
<br />
準備として、FlashAirのSD_WLANフォルダにある「CONFIG」ファイルに「IFMODE=1」と書き足します。<br />
CONFIGは隠しフォルダになっているのですが、MacやLinuxの場合はTerminalで普通にアクセスできます。<br />
Windowsでも隠しフォルダにアクセスできるツールを使えばOKです。<br />
<br />
今回、FlashAir Developersで紹介されているものと同様に秋月電子通商の「<a href="http://akizukidenshi.com/catalog/g/gK-05818/" target="_blank">SDカードスロットDIP化モジュール</a>」を使いました。<br />
意外に盲点なのですが、このDIP化モジュールはFlashAirの全てのピンが引き出されている訳ではありません。<br />
そのため、FlashAirのGPIOピンを全て使えるわけではありません。<br />
<br />
具体的には、<a href="http://akizukidenshi.com/download/ds/cixiborui/SD%E3%82%AB%E3%83%BC%E3%83%89%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%ABVer1.2.pdf" target="_blank">DIP化モジュールの取り扱い説明書の回路図</a>を参照すると分かります。<br />
下図の通り、DAT1とDAT2はプルアップ抵抗で3.3Vに繋がっているだけなので、ピンが引き出されていません。<br />
つまり、FlashAirの0x04と0x08を使えません。(使うにはジャンパーを半田付けする必要があります。)<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOx0raclWEL6_JwDylBTMfM53sv1gjKGSMswM5PGrl889Q_Ovy8ClG8bH8qPFl_ldfAsaa621fqh1N8gpMhAKhAz6qi24hGJaQ5xHBBnQ9x5hC5_eGuJg9qd7yhsxmVCrNda8UWmoWJGNt/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-07-01+17.52.53.png" imageanchor="1"><img border="0" data-original-height="725" data-original-width="1041" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOx0raclWEL6_JwDylBTMfM53sv1gjKGSMswM5PGrl889Q_Ovy8ClG8bH8qPFl_ldfAsaa621fqh1N8gpMhAKhAz6qi24hGJaQ5xHBBnQ9x5hC5_eGuJg9qd7yhsxmVCrNda8UWmoWJGNt/s320/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2018-07-01+17.52.53.png" width="320" /></a>
<br />
半田付けなしで使用できるピンの対応付けは次のようになります。<br />
「Arduino」列は今回接続したArduino側のピン、「用途」列は今回の用途です。<br />
<ol>
<li><table border="1" cellpadding="0" cellspacing="0"><tbody>
<tr><th>ビット<br />
割り当て</th><th>FlashAir</th><th>DIP化<br />
モジュール</th><th>Arduino</th><th>用途</th></tr>
<tr><td><div style="text-align: center;">
0x01</div>
</td><td><div style="text-align: center;">
CMD</div>
</td><td><div style="text-align: center;">
SDI</div>
</td><td><div style="text-align: center;">
D5</div>
</td><td>ルンバON</td></tr>
<tr><td><div style="text-align: center;">
0x02</div>
</td><td><div style="text-align: center;">
DAT0</div>
</td><td><div style="text-align: center;">
SDO</div>
</td><td><div style="text-align: center;">
D4</div>
</td><td>スリープ enable/disable</td></tr>
<tr><td><div style="text-align: center;">
0x10</div>
</td><td><div style="text-align: center;">
DAT3</div>
</td><td><div style="text-align: center;">
CS</div>
</td><td><div style="text-align: center;">
D2</div>
</td><td>ソフトウェアリセット</td></tr>
<tr><td><div style="text-align: center;">
-</div>
</td><td><div style="text-align: center;">
3.3V</div>
</td><td><div style="text-align: center;">
VCC</div>
</td><td><div style="text-align: center;">
3.3V</div>
</td><td>FlashAirへの給電</td></tr>
<tr><td><div style="text-align: center;">
-</div>
</td><td><div style="text-align: center;">
GND</div>
</td><td><div style="text-align: center;">
GND</div>
</td><td><div style="text-align: center;">
GND</div>
</td><td>GND</td></tr>
</tbody></table>
</li>
</ol>
<br />
<h3>
ArduinoとFlashAirの接続</h3>
上の表の配線を使って、Arduinoには次のような動作をさせます。<br />
<ol>
<li>D2ピンのHIGH/LOWが変化するとソフトウェアリセットでスリープから復帰する。</li>
<li>D5ピンがHIGHになっていたらルンバに赤外線送信する。</li>
<li>D4ピンがHIGHになっていたらスリープする。</li>
</ol>
ルンバの起動にしか使わないのであればD5ピン無しでも可能です。<br />
とは言え、DAT2, DAT3 を外部に引き出すと、WiFi経由で合計3ビット分のコマンドを表現できるので、<br />
8種類(2の3乗)の赤外線コードを出し分けられます。<br />
そのような将来的な拡張を考慮してD5ピンにFlashAirのCMDを割り当てました。<br />
<br />
<h3>
Node-REDからFlashAir</h3>
Node-REDからFlashAirへは次のようにHTTPリクエストを出すことでArduinoを動作させます。<br />
<ol>
<li>FlashAirの全てのピンをLOWにする。つまりFlashAirに0x00を送信する。(http://〜/command.cgi?op=190&CTRL=0x1f&DATA=0x00)</li>
<li>一秒待つ(1.がFlashAir側で確実に受け取り完了させるため)</li>
<li>FlashAirの0x10, 0x01, 0x02 をHIGHにする。つまり、FlashAirに0x13を送信する。(http://〜/command.cgi?op=190&CTRL=0x1f&DATA=0x13)</li>
</ol>
このリクエストによって、DAT3(0x10)がLOWからHIGHになります。<br />
つまり、ArduinoのリセットピンをLOWからHIGHに変えることで、Arduinoをスリープから復帰させます。<br />
<br />
スリープ復帰時にArduinoがCMD(0x01)を参照してルンバに赤外線コードを送信してくれれば、ルンバが起動します。<br />
<br />
さらにその後、ArduinoがDAT0(0x02)を参照し、HIGHの時にスリープさせることで省電力化します。<br />
本当は、LOWでスリープさせた方が省電力になるのかもしれません。<br />
ところが、FlashAirは最初に電源が入った時点で全てのGPIOピンをHIGHにしてしまいます。<br />
つまり、DAT0=LOWでスリープに入るようにしてしまうと、電源投入時にスリープしなくなってしまいます。<br />
DAT0=HIGHをスリープに割り当てておけば電源投入直後にいきなりスリープしてくれます。<br />
<br />
<h3>
Arduinoのコーディング</h3>
以上の動作をArduinoに組み込むと次のようになります。<br />
赤外線の記憶と送信に関しては前回と同じなので省略します。<br />
<pre class="brush:cpp">#include <EEPROM.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
// Arduino - board - SD
// 2 pin - CS - DAT3 - 1pin - 0x10 (RESET)
// 4 pin - SDO - DAT0 - 7pin - 0x02 (SLEEP)
// 5 pin - SDI - CMD - 2pin - 0x01 (CLEAN)
#define PIN_IR 10
#define PIN_IR_SENSOR 11
// FlashAir SDD pin (0x02)
#define PIN_SD_SLEEP 4
// FlashAir SDI pin (0x01)
#define PIN_SD_CLEAN 5
#define SCAN_INITIAL_TIMEOUT 10000000
#define SCAN_TIMEOUT 10000000
#define IR_BUF_LEN 64
volatile int IR_BUF[IR_BUF_LEN];
volatile bool SETUP_FLAG = false;
void setup() {
Serial.begin(9600);
SETUP_FLAG = true;
pinMode(PIN_IR, OUTPUT);
pinMode(PIN_IR_SENSOR, INPUT);
pinMode(PIN_SD_CLEAN, INPUT);
pinMode(PIN_SD_SLEEP, INPUT);
pinMode(2, INPUT_PULLUP);
Serial.println("Start!");
}
// リセットからの復帰時はloopさえ動けば良いので特に処理無し
void wakeup(){
Serial.println("Wakeup");
}
// Arduino起動直後は全てHIGHになっているがSETUP_FLAGを使って無視させる
// 一旦LOWに落ちてからHIGHになると清掃開始
void loop() {
//Serial.println(".");
Serial.println("Run");
if ( ! SETUP_FLAG ) {
if ( digitalRead(PIN_SD_CLEAN) == HIGH ){
Serial.println("Run Roomba in clean mode");
loadBuffer(0);
executeIR();
executeIR();
executeIR();
}
// FlashAirの他のピンを引き出してコマンド拡張する場合はここに書く
}
SETUP_FLAG = false;
delay(500);
check_sleep(digitalRead(PIN_SD_SLEEP));
delay(500);
}
// sleep pinがHIGHだったらスリープ
void check_sleep(bool flag) {
if ( ! flag ) { return; }
Serial.println("Sleep");
delay(1000);
// リセットピンの状態が変化したら復帰する
attachInterrupt(0, wakeup, CHANGE);
set_sleep_mode(SLEEP_MODE_STANDBY);
sleep_enable();
sleep_mode();
sleep_disable();
}</pre>
<br />
<h3>
完成</h3>
以上で完成です。<br />
テレビ、プロジェクター、ルンバを音声操作できました。<br />
紹介しませんでしたが、Node-REDを工夫すると1つの音声コマンドで複数機器を同時に動作させることも可能です。<br />
この動画の例ではプロジェクターを起動する際にアンプの音声出力をテレビからプロジェクターに切り替えています。<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/KXWFWUunE7g/0.jpg" src="https://www.youtube.com/embed/KXWFWUunE7g?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-91476584225245180912018-06-17T00:35:00.000+09:002019-01-10T21:39:00.822+09:00Alexa と Raspberry Piでルンバに掃除してもらう:(6)Arduinoから赤外線でルンバを動かす<a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">前回、ROIを使ってルンバをシリアル経由で操作する方法を紹介しました。</a><br />
ROIを使うとかなり細かいコントロールができる一方、シリアル接続なのでルンバにArduinoを載せる必要があります。<br />
頑張ってルンバから電源を取りつつArduinoをルンバに内蔵することも可能ではありますが。。。<br />
今回やりたいことは単なる電源ON/OFFだけなので、ルンバとは有線接続せずに赤外線で済ませたいところです。<br />
<br />
lircでやろうとしたところ、リモコンコードを読み取れずエラーになってしまいました。<br />
テレビと同様に38Hzのようですが、信号が長すぎるのかもしれません。<br />
<br />
そこで、Arduinoで赤外線のリモコンコードを読み取って赤外線LEDでルンバに送ります。<br />
やっていることはRaspberry Pi+licdと同じですが、Arduinoなのでもっと泥臭い感じになります。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<br />
<h3>回路を組む</h3>
Arduinoに赤外線受信モジュールと赤外線送信モジュールを繋ぎます。<br />
受信モジュールは赤外線リモコンを覚えさせる際に使用するだけなので、覚えた後は外しても構いません。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUp0XpcdG1oiosRqXAChQxouQ8m9kAudEZZIl0KBXYl5_Qr4bhX48gQssP707deCB6iyjJJb0ADWBFNvyqkwlkSWkvqHaZuRwhB-313UnNwXc1JWsKH2J7cPfY-VqdSKyKT_TUe13Eu8Cs/s1600/roomba.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUp0XpcdG1oiosRqXAChQxouQ8m9kAudEZZIl0KBXYl5_Qr4bhX48gQssP707deCB6iyjJJb0ADWBFNvyqkwlkSWkvqHaZuRwhB-313UnNwXc1JWsKH2J7cPfY-VqdSKyKT_TUe13Eu8Cs/s320/roomba.png" width="320" height="320" data-original-width="400" data-original-height="400" /></a><br />
<br />
<h3>リモコンコードをArduinoのEEPROMに書き込む</h3>
赤外線受信モジュールからの入力信号がHIGHとLOWの変化する時間間隔を計測します。<br />
計測結果を配列に詰めてEEPROMに書き込めばOK。<br />
このコードでは2種類のリモコンコードを覚えられるようになっています。<br />
<pre class="brush:cpp">
#include <EEPROM.h>
#define PIN_IR_SENSOR 11
#define SCAN_INITIAL_TIMEOUT 10000000
#define SCAN_TIMEOUT 10000000
#define IR_BUF_LEN 64
volatile int IR_BUF[IR_BUF_LEN];
volatile bool SETUP_FLAG = false;
void setup() {
Serial.begin(9600);
SETUP_FLAG = true;
pinMode(PIN_IR_SENSOR, INPUT);
updateIR(0);
updateIR(1);
}
int updateIR(int pos) {
Serial.println("SCAN START");
memset(IR_BUF,0,IR_BUF_LEN);
for( int i=0; i<3; i++ ){
Serial.print("PUSH BUTTON ");
Serial.println(pos);
int result = scanIR(i);
for(int j=0; j<result; j++){
Serial.print(IR_BUF[j]);
Serial.print(" ");
}
Serial.print("\n");
Serial.print(result);
Serial.println(" bytes were read");
delay(3000);
}
saveBuffer(pos * IR_BUF_LEN*2);
Serial.println("SCAN END");
return 1;
}
int scanIR(int repeat) {
int idx=0;
int ir_status = HIGH;
unsigned long lastStatusChanged = 0;
unsigned long timeout = SCAN_INITIAL_TIMEOUT;
while(1){
if ( ir_status == LOW ){
while( digitalRead(PIN_IR_SENSOR) == LOW){
// wait
;
}
} else {
if( wait_high_signal( micros() + timeout ) < 0 ){
break;
}
}
unsigned long now = micros();
if( lastStatusChanged > 0 ){
int val = (int)((now - lastStatusChanged) / 10);
if( repeat > 0 ){
if( IR_BUF[idx] > 1 ){ break; }
if( abs((int)(IR_BUF[idx] - (int)val)) > IR_BUF[idx]*0.3 ){ idx = 0; break; }
IR_BUF[idx] = (int)( IR_BUF[idx] * repeat + val ) / (repeat + 1);
} else {
IR_BUF[idx] = val;
}
idx++;
if( idx == IR_BUF_LEN -1 ){ break; }
}
lastStatusChanged = now;
if (ir_status == HIGH) {
ir_status = LOW;
} else {
ir_status = HIGH;
}
timeout = SCAN_TIMEOUT;
} // while 1
if( idx > 0 ){ IR_BUF[idx] = -1; }
return idx;
}
int wait_high_signal(unsigned long timeout) {
while( digitalRead(PIN_IR_SENSOR) == HIGH ){
if( micros() > timeout ) { return -1; }
}
return 1;
}
void saveBuffer(int pos) {
Serial.println("SAVE START");
byte buf;
for( int i=0; i < IR_BUF_LEN; i++ ){
buf = lowByte(IR_BUF[i]);
EEPROM.write( pos+i*2, buf );
delay(5);
buf = highByte(IR_BUF[i]);
EEPROM.write( pos+i*2+1, buf );
delay(5);
if( buf < 0 ){ break; }
}
Serial.println("SAVE END");
}
</pre>
<br />
<h3>EEPROMから読み込んだコードで赤外線送信する</h3>
今度はEEPROMから配列を読み込んで、覚えていた時間間隔でLEDを点滅させます。<br />
我が家のRoombaが具合悪いだけかもしれませんが、<br />
1回送信しただけでは正常に反応しないことが多いので、3回連続で送信しています。<br />
また、loop関数で繰り返し送信されてしまうので送信し終わったらスリープさせます。<br />
<pre class="brush:cpp">
#include <EEPROM.h>
#define PIN_IR 10
#define IR_BUF_LEN 64
volatile int IR_BUF[IR_BUF_LEN];
void setup() {
Serial.begin(9600);
pinMode(PIN_IR, OUTPUT);
Serial.println("Start!");
}
void loop() {
Serial.println("Run");
loadBuffer(0);
executeIR();
executeIR();
executeIR();
check_sleep(true);
}
void wakeup(){
Serial.println("Wakeup");
}
void check_sleep(bool flag) {
if ( ! flag ) { return; }
Serial.println("Sleep");
delay(1000);
attachInterrupt(0, wakeup, CHANGE);
set_sleep_mode(SLEEP_MODE_STANDBY);
sleep_enable();
sleep_mode();
sleep_disable();
}
void loadBuffer(int pos) {
Serial.println("LOAD START");
int h, l;
for( int i=0; i<IR_BUF_LEN; i++ ){
l = EEPROM.read(pos+i*2);
h = EEPROM.read(pos+i*2+1);
IR_BUF[i] = (h << 8) + l;
Serial.print(IR_BUF[i]);
Serial.print(" ");
if( IR_BUF[i] < 0 ){ break; }
}
Serial.println("\nLOAD END");
}
void executeIR() {
for(int i=0; IR_BUF[i] > 0; i++){
unsigned long len = (unsigned long)IR_BUF[i] * 10;
unsigned long now = micros();
do {
digitalWrite(PIN_IR, 1-i&1);
delayMicroseconds(8);
digitalWrite(PIN_IR, 0);
delayMicroseconds(7);
} while( now + len > micros() );
}
}
</pre>
<br />
<br />
ここまででArduinoからRoombaに掃除をスタートするコマンドを送れるようになりました。<br />
ところが、このままではArduinoの電源を入れた直後にしか信号が飛びません。<br />
次回、Node-REDからのリクエストをFlashAirで受けて、Arduinoをスリープから復帰させるように改造します。<br />たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-52012670508569513542018-04-29T00:32:00.002+09:002019-01-10T21:39:15.309+09:00Alexa と Raspberry Piでルンバに掃除してもらう:(おまけ)ArduinoからROI経由でルンバを動かす<a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">前回まで</a>でAlexaからNode-RED経由でArduinoを呼び出せるようになりました。<br />
で、Arduinoからルンバを動かすにはいくつかの方法があります。<br />
<br />
1つが今回紹介するROI(Roomba Open Interface)です。<br />
この方法のメリットはルンバ側にArduinoを載せるので、ルンバが移動しても通信し続けることができることでしょうか。<br />
一方で、当然ながらルンバに出っ張りが出来てしまうので、掃除中に引っかかるリスクがあります。<br />
<br />
もう一つの方法として、ルンバから離してArduinoを設置して赤外線経由で操作することもできます。<br />
この方法の場合はルンバに何も付ける必要はありません。<br />
その代わり、ドックにいる時にしかコマンドを送れません。<br />
<br />
通常、ルンバは掃除が終われば自動的にドックに戻ってくるので、掃除中にコマンドを送りたいケースは少ないように思います。<br />
そのため、普通に掃除させたいだけなら赤外線経由の方が本命だと思います。<br />
<br />
そのような理由から、ROI経由での制御は「おまけ」として紹介します。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li>(おまけ)ArduinoからROI経由でルンバを動かす【今回】</li>
<li>Arduinoから赤外線経由でルンバを動かす</li>
<li>Node-REDからFlashAir/Arduino経由でルンバを動かす</li>
</ol>
<br />
<h3>
ROIとは?</h3>
ROIは外部機器からルンバを制御するためのシリアルインターフェイスです。<br />
<a href="http://cfpm.org/~peter/bfz/iRobot_Roomba_500_Open_Interface_Spec.pdf">ROIの詳細についてはiRobotのサイトに仕様書があります。</a><br />
<br />
コネクタが付いている場所は機種によって微妙に異なるのですが、我が家にあるルンバ760では上部ハンドルの裏に付いています。
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF3zeZi2XiayVZA77ovfBSTzNBDQ56FK4mi7jMtoMpn5ty6YyOP19VoGmwUf0BTCzy1dvr4nYd2ibdzhsJYWPf-V4W9fyLmZKzjy9pm4g0O43dQsXe7b-rSFgrxbu81lpgrn4QW2gk8Jli/s1600/IMG_4141.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF3zeZi2XiayVZA77ovfBSTzNBDQ56FK4mi7jMtoMpn5ty6YyOP19VoGmwUf0BTCzy1dvr4nYd2ibdzhsJYWPf-V4W9fyLmZKzjy9pm4g0O43dQsXe7b-rSFgrxbu81lpgrn4QW2gk8Jli/s320/IMG_4141.JPG" width="320" /></a></div>
<br />
他の機種だと天板パネルを剥がした中に隠されている場合もあるようです。<br />
<h3>
Arduinoとルンバを接続する</h3>
ROIは7ピンのミニDINコネクタです。<br />
秋葉原などに行くとプラグが売っているようですが、ジャンパピンを挿して接続しても何とかなります。<br />
<br />
ピンアサインはROIの仕様書に載っています。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVLAMoDmPQSkaOVo2881iVvIscjvBzlfykf_wut7zDeIKZpY65SJigmJOs1RQTP0e1UtJXK78zp-TBVkTaap4CJnX2ZVePm-nvSp9JTwWRYiHAvn0HtoEC3bajJ_L0dldBJJ_3gKbaSWGw/s1600/RoombaROI.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="739" data-original-width="1092" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVLAMoDmPQSkaOVo2881iVvIscjvBzlfykf_wut7zDeIKZpY65SJigmJOs1RQTP0e1UtJXK78zp-TBVkTaap4CJnX2ZVePm-nvSp9JTwWRYiHAvn0HtoEC3bajJ_L0dldBJJ_3gKbaSWGw/s320/RoombaROI.png" width="320" /></a><br />
<br />
今回の場合、3番(RXD), 4番(TXD), 6番(GND) だけ接続すれば通信できます。<br />
Arduino側のRX,TXは0番,1番ですが、それを使ってしまうとPCとのシリアル通信ができなくてデバッグしにくいです。<br />
そのため、Arduinoの0番,1番を避けて、他のピンに繋ぎ、ソフトウェアシリアルで通信させます。<br />
<br />
また、ルンバの電源でArduinoを駆動する場合はルンバの1番ピンから引き出してレギュレータを通してからArduinoのVinピンに入れれば良いと思います。<br />
<br />
<h3>
Arduinoからコマンドを送る</h3>
前回、FlashAirと接続するようにしたArduinoのコードにルンバとのシリアル通信を追加します。<br />
下記の例ではArduinoの12番,13番ピンにルンバのTXDとRXDを繋いでいます。<br />
ちなみに、ルンバのデフォルトのボーレートは115200らしいです。<br />
<pre class="brush:cpp">#include <softwareserial.h>
#define PIN_SD_CLEAN 11
SoftwareSerial device(12, 13);
void setup() {
Serial.begin(9600);
pinMode(PIN_SD_CLEAN, INPUT);
}
// Arduino起動直後は全てHIGHになっているが無視させる
// 一旦LOWに落ちてからHIGHになると清掃開始
volatile bool clean_flag = HIGH;
void loop() {
if ( clean_flag == LOW && digitalRead(PIN_SD_CLEAN) == HIGH ){
Serial.println("Run Roomba with clean mode");
device.begin(115200);
byte buffer[] = {
byte(128), // Start
byte(135) // Clean
};
device.write(buffer, 2);
}
clean_flag = digitalRead(PIN_SD_CLEAN);
delay(1000);
}
</pre>
はい、これだけ。<br />
ROIは1コマンドが1バイトになっていて、コマンド順に並べたバイト列を送り込めばその順に実行されます。<br />
ルンバはいくつかのモードを持っていて、低レベルコマンドを送るにはモードを切り替える必要があります。<br />
128が起動なのですが、起動後のデフォルトはPassiveモードになっています。<br />
Passiveモードではルンバのセンサ読み込みと掃除スタートができます。<br />
今回は掃除したいだけなので、いきなりCleanコマンド(135)を送っています。<br />
<br />
モードとコマンドについてはROIの仕様書に書かれています。<br />
駆使すると、ルンバをラジコン化したり音を鳴らしたりインジケータを表示したり色々できます。<br />
<br />
<h3>
完成</h3>
出来上がると、こんな感じになります。<br />
<div class="separator" style="clear: both; text-align: left;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/gVSPG5Mz3js/0.jpg" src="https://www.youtube.com/embed/gVSPG5Mz3js?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
次回はROIではなく赤外線で起動します。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-40564696853852168002018-04-21T22:31:00.001+09:002019-01-10T21:39:27.460+09:00Alexa と Raspberry Piでルンバに掃除してもらう:(5)FlashAirのGPIO機能でArduinoのHTTP API<a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">前回まで</a>で、Alexaからテレビを操作できるようになりました。<br />
同じ方法でルンバも操作しようとしたところ、lircでルンバのリモコンコードを読み取る際にエラーになってしまいました。<br />
理由がまるで分からず。。。<br />
<br />
そこで、Raspberry PiではなくArduinoからルンバを操作することにしました。<br />
ただ単に、Raspberry PiとArduinoのどちらでも赤外線が使える、というだけの話ですが。<br />
<br />
Arduinoを使う場合、まずは母艦のNode-REDからの通信を受け取らないとどうにもなりません。<br />
とは言え、数ビットの無線信号を受け取れれば良いだけなので、ESP-WROOM-02やBluetoothなど手段はいくらでもあります。<br />
今回は、余っていた古いFlashAir(W-02)を使いました。<br />
<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<br />
<h3>
FlashAirのGPIO機能</h3>
FlashAirのGPIO機能を使うと、SDカードの端子のうちの5つをHTTP経由でGPIOピンとして使用できます。<br />
<a href="https://flashair-developers.com/ja/documents/tutorials/iot-hub/4/">FlashAir Developers</a>に詳しく説明されています。<br />
<br />
つまり、FlashAirの端子とArduinoのピンを接続すると、ArduinoのピンのHigh/LowをHTTPから切り替えられます。<br />
そのかわり、FlashAirのストレージとしての機能は使えなくなります。<br />
<br />
FlashAirの動作を変更するには /SD_WLAN/CONFIG ファイルを編集します。<br />
通常は不可視フォルダになっていますが、LinuxやMacでマウントするとShell経由で普通に編集できます。<br />
Windowsの場合は不可視フォルダを表示すれば良いと思います。<br />
<br />
このファイルを開いて末尾にIFMODE=1を追加すればGPIO機能が有効になります。<br />
<br />
<h3>
FlashAirをWiFi子機にする</h3>
通常、FlashAirはWiFiの親機として動作します。<br />
そのため、自宅のLANの中にあるNode-REDからのHTTPリクエストを受け取れません。<br />
そこで、FlashAirを無線子機としてWiFiルータに接続させます。<br />
<br />
この設定についてもFlashAir Developersに詳しく書かれています。<br />
「<a href="https://flashair-developers.com/ja/documents/tutorials/advanced/1/">ステーションモードの利用</a>」<br />
<br />
そんなこんなで、出来上がったCONFIGファイルは次のようになります。<br />
<pre class="brush:shell">APPMODE=5
APPNAME={FlashAirの名前}
APPSSID={WiFiのSSID}
APPNETWORKKEY={WiFiのパスワード}
CIPATH=/DCIM/100__TSB/FA000001.JPG
VERSION=F19BAW3AW2.00.00
CID=02544d535730384708c00b7d7800d201
PRODUCT=FlashAir
VENDOR=TOSHIBA
MASTERCODE=18002d4ff0a2
IFMODE=1
</pre>
<br />
<h3>
FlashAirとArduinoを接続</h3>
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B01J5F4718&linkId=5a861038d8853421a48eb629ca58e7e9" style="float: left; height: 240px; width: 120px;"></iframe>
こんな感じのSDカードスロットを使ってArduinoと接続します。
今回はルンバの起動ができれば良いだけなので1ビット送れれば十分です。<br />
そのため、信号ピン1つと3.3V、GNDの3ピンだけ接続します。<br />
<br />
FlashAirのSDIをArduinoの11ピンに繋ぎました。<br />
3.3VとGNDは適宜。<br />
<div style="clear: both;">
</div>
<br />
<h3>
HTTPからFlashAirのGPIOを書き換える</h3>
GPIO機能のHTTP APIについてはFlashAir Developersの「<a href="https://flashair-developers.com/ja/documents/api/commandcgi/#190">SDインターフェース端子のI/O利用(op=190)</a>」に書かれています。<br />
今回はSDOピン(CMD)をGPIOとして使うので、0x01のHIGH/LOWを切り替えられれば良いです。<br />
<br />
つまり、URLパラメータとGPIOの組み合わせは次の通りです。<br />
<ul>
<li>SDO=HIGH → op=190&CTRL=0x1f&DATA=0x01</li>
<li>SDO=LOW → op=190&CTRL=0x1f&DATA=0x00</li>
</ul>
<br />
<h3>
ArduinoでFlashAirのGPIOを読む</h3>
Arduinoからピンの状態を読むのは普通に「digitalRead」で良いです。<br />
ライブラリも何も必要ありません。<br />
注意点としては、FlashAir起動時は全てのピンがHIGHになっていることでしょうか。<br />
<br />
つまり、SDOピンがHIGHの状態を検知してルンバを起動させようと考えた場合、<br />
FlashAirの電源投入時にHIGHなのでいきなりルンバが起動してしまいます。<br />
<br />
電子回路的にHIGH/LOWを反転させても良いのですが、部品点数が増えて面倒なので、<br />
Node-RED側で一旦LOWに落としてからHIGHにするようなリクエストを投げることで回避しました。<br />
もしかしたら、Arduinoで一旦pinModeをOUTPUTにしてLOWに落とせるのかもしれませんが試していません。<br />
<br />
Arduinoのコードはこんな感じです。<br />
<pre class="brush:cpp">#define PIN_SD_CLEAN 11
void setup() {
Serial.begin(9600);
pinMode(PIN_SD_CLEAN, INPUT);
}
// Arduino起動直後は全てHIGHになっているが無視させる
// 一旦LOWに落ちてからHIGHになると清掃開始
volatile bool clean_flag = HIGH;
void loop() {
if ( clean_flag == LOW && digitalRead(PIN_SD_CLEAN) == HIGH ){
Serial.println("Run Roomba with clean mode");
}
clean_flag = digitalRead(PIN_SD_CLEAN);
delay(1000);
}
</pre>
<br />
<h3>
Node-REDからArduinoにHTTPリクエスト</h3>
少々ブサイクですが、次のようにしました。<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn1YcDv0fNWQRWjae7aETePNvVLf00eXWffOHknZpyDaMjuYNJqmryDwt4QcR7UZwGQYbzil74CAnuOdQ1fiBNodauT0iP_O4Wc6V3LsIbkCoBq7ZGUX5gep5vNe0zkOlYsgv-Eh6GWXth/s1600/RoombaGPIO.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="164" data-original-width="881" height="60" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn1YcDv0fNWQRWjae7aETePNvVLf00eXWffOHknZpyDaMjuYNJqmryDwt4QcR7UZwGQYbzil74CAnuOdQ1fiBNodauT0iP_O4Wc6V3LsIbkCoBq7ZGUX5gep5vNe0zkOlYsgv-Eh6GWXth/s320/RoombaGPIO.png" width="320" /></a></div>
Alexaに「ルンバで掃除して」と言うと左端の「ルンバ」ノードが呼ばれます。<br />
まず最初に真ん中のフローで「Roomba reset」が呼ばれます。<br />
「Roomba reset」はHTTPリクエストのノードです。<br />
FlashAirに「op=190&CTRL=0x1f&DATA=0x00」を投げて全てのピンをゼロリセットしています。<br />
FlashAirの起動後、2回目以降の「ルンバ掃除して」の場合は前回呼び出し時にゼロリセットされているので、この処理は無意味になります。<br />
<br />
先ほどのRoomba resetが先に実行されるように、上部のフローでは2秒delayが入っています。<br />
本当はdelayよりも、Roomba resetの実行後にフラグを書き換えるなどしてロックした方が良さそうに思いますが手抜きです。<br />
この手抜きのせいで、「ルンバ掃除して」と言ってから実行されるまでに2秒掛かってしまうので微妙に違和感があります。<br />
<br />
2秒後に「Roomba clean」が呼ばれます。<br />
これは「op=190&CTRL=0x1f&DATA=0x01」でSDOピンをHIGHにしています。<br />
この時点でArduino側ではルンバの制御に入ります。<br />
<br />
その後、5秒delayを掛けて再度ゼロリセットしておきます。<br />
5秒というのは、Arduino側がHIGHを確実に検知できるよう、長めに取っています。<br />
<br />
最初のdelayについては、もし検知し損ねても処理に失敗するのは起動後最初の1回だけなのでイライラが少ないです。<br />
また、長すぎると「ルンバ掃除して」からのタイムラグが長くなってしまうため、できるだけ短く。<br />
2回目のdelayは短かすぎると毎回失敗し、長くてもユーザビリティに影響ないので長めに。<br />
<br />
ここまででNode-REDからHTTP経由でArduinoに1ビット信号を送ることができるようになりました。<br />
次回はArduinoからルンバを操作します。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-28718779847519689572018-04-17T22:58:00.002+09:002019-01-10T21:39:38.031+09:00Alexa と Raspberry Piでルンバに掃除してもらう:(4)Node-REDからテレビを操作前回までで<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">Node-REDでRaspberry PiとAlexaを連携させ</a>、さらに<a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">赤外線リモコンのコードをコピー</a>しました。<br />
今回はついに、Alexa → Node-RED → 赤外線 → テレビ という流れを全部繋ぎます。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<br />
Node-REDから赤外線機能を呼ぶ場合、次の二種類のケースがあると思います。<br />
<ul>
<li>母艦のRaspberry Piに赤外線LEDを付ける場合</li>
<li>母艦とは別のRaspberry Piに赤外線LEDを付ける場合</li>
</ul>
まずは前者から。<br />
<h3>
母艦のNode-RED から母艦の lirc を呼ぶ</h3>
1台のRaspberry Piの上でNode-RED と lirc を連携させるのは非常に簡単です。<br />
<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">Node-REDをセットアップした時</a>と同じ手順でノードの追加画面を開きます。<br />
「lirc」というキーワードでノードを検索すると「node-red-contrib-lirc」というノードが見つかるので追加します。<br />
すると、こんな感じで出力のリストに「lirc」が増えます。<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj620kc8e99bdrnH3fS6ZRZ2MwfF-djMlvpW1L9xKL51987-nmcjubio14Fz58pZd3kRoHiVtxwO70PzT-azH4EZSVDxUHrwAGZOu91_BANNPh8S66GcrDEYVZIXuoMBouvKDP-HfHwJ9Tt/s1600/NodeRED_lirc1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="469" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj620kc8e99bdrnH3fS6ZRZ2MwfF-djMlvpW1L9xKL51987-nmcjubio14Fz58pZd3kRoHiVtxwO70PzT-azH4EZSVDxUHrwAGZOu91_BANNPh8S66GcrDEYVZIXuoMBouvKDP-HfHwJ9Tt/s320/NodeRED_lirc1.png" width="262" /></a></div>
<br />
この「lirc」をドラッグして右の広いところにドロップ。<br />
ドロップした「lirc」ノードをダブルクリックして図のように入力します。<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTuvgD-UWYbvNQ14YpjtEcnkq6-1fqc_da2wD_tvzXJDiJ05Xg6ViLjNdAaV57HjKadmIS5GbTs4J4FkOt7CR3WRMYykrErVFFc84wVa6HUIvjudZhoJi62CwTm0EmMjNejgFmGVUJ-TJp/s1600/NodeRED_lirc2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="1264" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTuvgD-UWYbvNQ14YpjtEcnkq6-1fqc_da2wD_tvzXJDiJ05Xg6ViLjNdAaV57HjKadmIS5GbTs4J4FkOt7CR3WRMYykrErVFFc84wVa6HUIvjudZhoJi62CwTm0EmMjNejgFmGVUJ-TJp/s320/NodeRED_lirc2.png" width="320" /></a></div>
<br />
「Name」は何でも良いです。分かりやすい名前をつけます。<br />
<br />
「Controller」はLinuxのlircコマンドの第一引数です。<br />
今回は1回送信したいので「SEND_ONCE」です。<br />
<br />
「Device Name」はirrecordコマンドで指定したデバイス名です。<br />
前回「TV」というデバイスを登録したので「TV」。<br />
<br />
「Output」は「1」固定です。<br />
lirc が複数の赤外線LEDをサポートした時のために用意されているようですが、現状では1個しか使えないので「1」。<br />
<br />
ここで勘の良い方は「あれ?」と思うかもしれません。<br />
デバイス「TV」には複数のリモコンボタンがあるはずなのですがその設定がありません。<br />
例えば「on」とか「ch1」とかをどこかで指定する必要があるはずです。<br />
lircノードではメッセージペイロードでこれらのボタン名を指定します。<br />
<br />
<h3>
メッセージペイロードとは</h3>
<br />
Node-RED では前のノードから後のノードに対してメッセージが渡されます。<br />
デフォルトではメッセージはJSON形式で書かれるようです。<br />
このメッセージには「msg」というオブジェクト名がつけられています。<br />
msgオブジェクト内の要素は上流の入力次第なのですが、どの入力も「payload」という要素を1つ持っています。<br />
多くのノードで、この msg.payload を入力パラメータとして解釈する仕様になっています。<br />
<br />
lirc ノードでは msg.payload の値をリモコンのボタン名として解釈します。<br />
つまり、lirc ノードにフローを繋ぐ際、msg.payload に「on」を代入すればテレビに対してonの信号が飛びます。<br />
(TV.lircd.conf に「on」が定義されていれば、ですが。)<br />
<br />
この約束を頭の片隅に入れておいて、Node-RED の入力側からフローを繋いでいきます。<br />
<br />
<h3>
Alexa からの入力とつなぐ</h3>
Node-REDの「入力」のリストから「alexa local」を追加します。<br />
名前は「テレビ」。<br />
前にも説明しましたが、この名前がAlexaで呼びかける時のデバイス名になるので要注意です。<br />
<br />
さらに、「機能」のリストから「template」を追加して、alexa local の右側からtemplate の左側に線を繋ぎます。<br />
繋いだらtemplateノードをダブルクリック。<br />
このtemplateノードで、lirc に渡す msg.payload を代入します。<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoV9G9dbiva1HQHYPQtRH07nipU4q7xzV0bDnxuCqzzCnV60sCr8YTDbmhwdD14etjUUd-lcQOQ4BnMRq67eUBH4nrE4lUm9imETb2tAZ1hOGxs8wEnR6QmjjoDe2TWJqr8sTrFw_kJ0XW/s1600/NodeRED_lirc3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="717" data-original-width="977" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoV9G9dbiva1HQHYPQtRH07nipU4q7xzV0bDnxuCqzzCnV60sCr8YTDbmhwdD14etjUUd-lcQOQ4BnMRq67eUBH4nrE4lUm9imETb2tAZ1hOGxs8wEnR6QmjjoDe2TWJqr8sTrFw_kJ0XW/s320/NodeRED_lirc3.png" width="320" /></a></div>
<br />
「名前」は適当に分かりやすい名前を付けます。<br />
「設定先」は代入したい変数。今回は「msg.payload」ですね。<br />
今回は固定文字列を埋め込みたいので「形式」は「平文」で構いません。<br />
<br />
テンプレートのところに書いた内容が msg.payload に代入されます。<br />
今回は「on」です。<br />
「{{hoge}}」などと書くと、入力に渡された msg.hoge 変数の値が埋め込まれます。<br />
「構文」を指定するとJavaScriptで演算した結果を代入することもできます。<br />
<br />
設定できたら、templateノードの右側(出力側)をlircノードの左側(入力側)に繋いで完成。<br />
右上の「デプロイ」ボタンを押すと保存されます。<br />
<br />
もし、Alexa に「テレビ」デバイスを認識させていなければ「Alexa デバイスを探して」と言うと見つけてくれます。<br />
<br />
<br />
<h3>
Alexa から実行</h3>
Raspberry Piの赤外線LEDをテレビの赤外線受光部の近くに貼り付けておきます。<br />
この状態で「Alexa テレビをつけて」と言うとテレビがつく、、、はずです。<br />
<br />
うまくいかない場合は、debug ノードを追加して msg オブジェクトの中身を確認していき、lirc に正しくメッセージが渡っていることを確認します。<br />
メッセージが渡っているようであれば、今度は Linux 上で lirc がエラーになっていないかを確認するとか。<br />
それでも問題ないようなら、赤外線LEDを普通のLEDに付け替えてみて、ちゃんと光るかどうかを確認。<br />
ハード/ソフト/ネットワークが絡み合っているので、1つずつ接点を潰しながら不具合箇所を特定する地味な作業になります。<br />
<br />
<br />
<h3>
別々のRaspberry PiでNode-REDとlircを動かす場合</h3>
Node-RED から何らかの方法でネットワークに飛ばし、lirc側も何らかの方法でリクエストを受け取れば良いです。<br />
lirc 側で Apache からShellコマンドを読んでも良いのですが、いっそのこともう1つNode-REDを立ち上げても良いです。<br />
オーバースペックですが。<br />
<br />
lirc 側の Node-RED では「入力」の「http」ノードを追加して、好きなパス名を指定。<br />
ここで指定したパスを、母艦側から呼び出します。<br />
http ノードと lirc ノードを接続すれば、lirc 用 HTTP API の完成。<br />
<br />
母艦側では「機能」の「http request」ノードを追加。<br />
ダブルクリックして、lirc 側の IP アドレスと、「http」ノードのパスを設定すれば呼び出せます。<br />
<br />
その他は同じRaspberry Piで Node-REDとlircの両方を動かす場合と同じです。<br />
まぁ、Node-REDを両方に立ち上げるなら、lirc 側のNode-REDにalexa localノードを作った方が手っ取り早いですが。。。<br />
<br />
<h3>
完成</h3>
そんなこんなで、Alexa とテレビの連携が完成しました。<br />
頑張ってNode-REDを設定すると、テレビのON/OFFの他に録画リストから番組を選んで再生したり色々できます。<br />
<div class="separator" style="clear: both; text-align: left;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/lOZ_KynNWB0/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/lOZ_KynNWB0?feature=player_embedded" width="320"></iframe></div>
<br />
次回からはさらにルンバと連携させていきます。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-90718801451012489472018-04-14T21:52:00.001+09:002019-01-10T21:39:49.617+09:00Alexa と Raspberry Pi でルンバに掃除してもらう:(3)Raspberry Piを赤外線リモコンにする<a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">前回まで</a>でRaspberry Pi上でNode-REDが動きました。<br />
ここまでが母艦側になります。<br />
今回は母艦からコントロールされるエッジ側の準備です。<br />
<br />
余談ですが、、、<br />
ちょっと前までのIoT分野ではデータ収集がメインだったので<br />
「エッジ」→「ゲートウェイ」→「サーバ」という名前の付け方が<br />
多かったように思います。<br />
<br />
今回のように母艦が複数のエッジデバイスを制御するような場合、<br />
サーバ/クライアントモデルとかデータフローがあまり関係ないので<br />
「サーバ」とか「ゲートウェイ」という名付け方は不適切に感じます。<br />
<br />
呼び方がよく分からないので、ここでは制御の頭脳側を「母艦」と呼ぶことにします。<br />
母艦から制御されるデバイス側を「エッジ」と呼ぶことにします。<br />
<br />
<br />
エッジ側は複数のデバイスそれぞれに対応させる必要があります。<br />
最終的にはルンバを動かしたいのですが、実はルンバの赤外線は<br />
結構面倒だということがわかったので、まずはテレビを動かしてみようと思います。<br />
<br />
【注意】<br />
今回のやり方ではルンバは動きません。<br />
後日説明しますが、ルンバの場合はRaspberry PiではなくArduinoを使います。<br />
<div>
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<div>
<br />
<h3>
lircをインストールする</h3>
<br />
<a name='more'></a>Raspberry Piで赤外線を使うためにRaspbianにlirdをインストールします。
<br />
ググると数年前のブログが頻繁にヒットしてlircが酷評されていますが、<br />
私が試した範囲では普通に使えています。<br />
使い方に若干クセがあるようにも思いますがさほど問題ないように思います。<br />
<br />
インストールは普通に apt-get で。<br />
<pre class="brush:shell">$ sudo apt-get install lirc
</pre>
<br />
続いて、/boot/config.txtを編集します。<br />
古いバージョンだと別の設定ファイルだったり、書き方が異なっていたりして混乱の元になっています。<br />
Raspbian Stretch + lirc 0.9.4 の場合は /boot/config.txt の「#dtoverlay=lirc-rpi」という行を探して書き換えます。<br />
<pre class="brush:shell">$ sudo vi /boot/config.txt
# Uncomment this to enable the lirc-rpi module
dtoverlay=lirc-rpi
dtparam=gpio_in_pin=24
dtparam=gpio_out_pin=25
</pre>
gpio_in_pin は、赤外線受信モジュールのセンサピンを繋ぐピン番号です。<br />
gpio_out_pin が、赤外線LEDのアノード側。モジュールを使う場合は当然、入力ピンです。<br />
<br />
<a href="https://www.raspberrypi.org/documentation/usage/gpio/README.md">Raspberry Piのピンアサインはここ</a>に書かれています。<br />
config.txt に書くのは、ピン番号ではなくてGPIO番号です。<br />
端から連番ではありません。<br />
ちなみに、基板の半田付けする部分が1個だけ正方形になっていて、そこが3.3Vピンです。<br />
<br />
次に、元々置かれている設定ファイルを読み込まないようにします。<br />
デフォルトの設定は送信に対応していないようで、消し忘れると後々面倒なことになります。<br />
<pre class="brush:shell">$ sudo mv /etc/lirc/lircd.conf.d/devinput.conf /etc/lirc/lircd.conf.d/devinput.conf.disabled
</pre>
<br />
この他、lirc についてググると「hardware.conf」に関する設定が出てくることがあります。<br />
hardware.conf は現在では必要ないようです。<br />
modprobeも必要ありません。<br />
<br />
ここまでできたらRaspberry Piを再起動します。<br />
再起動後に /dev/lirc0 デバイスが出来ていればとりあえずOKです。
<br />
<h3>
赤外線受信モジュールを接続する</h3>
赤外線受信モジュールと送信モジュールを図のように接続します。<br />
基板に「-」と書いてあるピンがGND、何も書いていないピン(真ん中)が3.3Vです。<br />
「S」と書いてあるピンがGPIOの入出力。<br />
受信モジュールはRaspberry Piから見れば入力センサなのでIN側のピン、つまりGPIO24に繋ぎます。<br />
送信モジュール(赤外線LED)はRaspberry Piの出力なのでOUT側(GPIO25)です。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHWbzINJfJ6UdBTNhDH8jyPop3hCegDbUIAJ1-QC4cVaHFUSo2Tc-PG50gcmedum2cq5MDLzfo-gxPg5S_vyQc3BBa0Z7pVGJ9WmLTtTVLsR-vcW4ZTHCltKw-M2xvoXQ91jAxOLTc2Iy5/s1600/raspi_IR.007.png" imageanchor="1"><img border="0" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHWbzINJfJ6UdBTNhDH8jyPop3hCegDbUIAJ1-QC4cVaHFUSo2Tc-PG50gcmedum2cq5MDLzfo-gxPg5S_vyQc3BBa0Z7pVGJ9WmLTtTVLsR-vcW4ZTHCltKw-M2xvoXQ91jAxOLTc2Iy5/s320/raspi_IR.007.png" width="320" /></a><br />
接続できたらRaspberry Piを起動し、mode2コマンドでlirc0デバイスを呼ぶと読み込み待ちになります。<br />
この状態でテレビのリモコンを赤外線受信モジュールに向けてボタンを押します。<br />
ボタンを押すと「Partial read 8 bytes on /dev/lirc0」と表示されると思います。</div>
</div>
コマンドが終了してプロンプトが返ってくれば成功。<br />
<pre class="brush:shell">$ mode2 -d /dev/lirc0
Using driver default on device /dev/lirc0
Trying device: /dev/lirc0
Using device: /dev/lirc0
</pre>
<br />
<h3>
テレビのリモコンコードをコピーする</h3>
ここまででようやくRaspberry Piをリモコン化する準備が整いました。<br />
lirc ではリモコンコードを読み込ませるツールが整っているので簡単にリモコン化できます。<br />
<pre class="brush:shell">$ irrecord -n -d /dev/lirc0
:(中略)
Please take the time to finish the file as described in
https://sourceforge.net/p/lirc-remotes/wiki/Checklist/ an send it
to <lirc bartelmus.de=""> so it can be made available to others.
Press RETURN to continue.
{リターンキーを押して何もしないで待つ}
Checking for ambient light creating too much disturbances.
Please don't press any buttons, just wait a few seconds...
No significant noise (received 0 bytes)
Enter name of remote (only ascii, no spaces) :{「TV」など、設定の名前をつける}
Using TV.lircd.conf as output filename
Now start pressing buttons on your remote control.
It is very important that you press many different buttons randomly
and hold them down for approximately one second. Each button should
generate at least one dot but never more than ten dots of output.
Don't stop pressing buttons until two lines of dots (2x80) have
been generated.
Press RETURN now to start recording.
{リターンキーを押した後、赤外線受信部に向かってリモコンのボタンをランダムに押しまくる}
................................................................................
Got gap (106874 us)}
Please keep on pressing buttons like described above.
{もう1回押しまくる}
...................................................................................................................
Please enter the name for the next button (press <enter> to finish recording)
{「on」とか「ch1」など、覚えさせたいリモコンボタンの名前を付ける}
Now hold down button "on".
{名前を付けたボタンを1回だけ押す}
Please enter the name for the next button (press <enter> to finish recording)
{以下、ボタンごとに繰り返し。名前を付けずにリターンキーを押すと終了}
Checking for toggle bit mask.
Please press an arbitrary button repeatedly as fast as possible.
Make sure you keep pressing the SAME button and that you DON'T HOLD
the button down!.
If you can't see any dots appear, wait a bit between button presses.
Press RETURN to continue.
{何でも良いので同じリモコンボタンを連打する}
Cannot find any toggle mask.
Successfully written config file TV.lircd.conf
</enter></enter></lirc></pre>
カレントディレクトリに「TV.lircd.conf」というファイルが出来上がります。<br />
このファイルを/etc/lirc/lircd.conf.d/に移動します。<br />
<pre class="brush:shell">$ sudo mv TV.lircd.conf /etc/lirc/lircd.conf.d/
</pre>
この状態で、lircdを起動。
<br />
<pre class="brush:shell">$ sudo service lircd start</pre>
設定が読まれているか確認します。
<br />
<pre class="brush:shell">$ irsend LIST "" ""
TV
$ irsend LIST TV ""
0043000001000251 on
004d000001000248 ch1
:
</pre>
では、実際にテレビに向かって送信してみます。<br />
<pre class="brush:shell">$ irsend SEND_ONCE TV on
</pre>
これでテレビが反応すれば成功です。<br />
もし、次のようなメッセージが出た場合はlircの最初の設定で「devinput.conf」を消し忘れている可能性が高いです。<br />
<pre class="brush:shell">$ irsend SEND_ONCE AV tv
transmission failed
Error running command: Input/output error
</pre>
このエラーはググっても全く情報がなくてかなりハマりました。<br />
一旦この状態に陥ると、後から「devinput.conf」を消してもダメです。<br />
なぜなら、先ほど作成した TV.lircd.conf の中で、ドライバとして devinput が呼ばれてしまっています。<br />
<br />
解決するには、devinput.conf と TV.lircd.conf の両方を消した上で、<br />
lircd を再起動してから TV.lircd.conf を作り直します。<br />
<br />
<br />
ここまでで Raspberry Pi からテレビを制御できるようになりました。<br />
次回は Node-RED と結合して、ついにAlexaからテレビを動かします。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-69036838109894952102018-04-13T00:05:00.001+09:002018-04-21T22:32:31.556+09:00Raspberry Pi Zero W をヘッドレスでWiFi対応セットアップするAlexaでルンバを動かすことを目指していますが、今回はちょっと脱線します。<br />
単にRaspberry Piのセットアップを簡単にする方法を紹介するだけなので必須ではありません。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li>(おまけ)Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする(今回)</li>
<li>Raspberry Piで赤外線リモコンのコードをコピーする</li>
<li>Node-REDから赤外線機能を呼び出してテレビを操作する</li>
<li>FlashAirのGPIOモードでArduinoをHTTP API経由で制御する/li>
<li>(おまけ)ArduinoからROI経由でルンバを動かす</li>
<li>Node-REDからFlashAir/Arduino経由でルンバを動かす</li>
</ol>
Alexa で色々な家電の操作ができる仕組みを作成していく中でRaspberry Pi Zero Wは良い選択肢だと思います。<br />
赤外線で家電を操作することを考えると、どうしても家電の近くにRaspberry PiかArduinoを置くことになりがちです。<br />
その際の条件を考えていくと、次のような感じになります。<br />
<ol>
<li>安い → 家電の数だけ設置する必要がある。</li>
<li>目立たない → あちこちに無骨な基板が転がっていると気になるので。。。</li>
<li>配線が少ない → 少なくとも無線化は必須。ACアダプタなしでUSBケーブル程度。</li>
</ol>
Raspberry Pi Model Bだと価格がネック。<br />
Arduinoだと無線が貧弱なのでちょっと厳しい。<br />
そんなこんなでRaspberry Pi Zero Wに行き着きます。<br />
<br />
ただ、Raspberry Pi Zero WはHDMIやUSBがマイクロタイプなので、セットアップの際に配線がごちゃごちゃしがち。<br />
そんな訳で、キーボードもモニタも無しでRaspberry Pi Zero Wをセットアップします。<br />
<br />
<a name='more'></a><br />
<br />
<h3>
micro SDカードに書き込む</h3>
まずは<a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank">ここからOSイメージをダウンロード</a>します。<br />
「LITE」の方です。DESKTOP なんか選んじゃダメです。<br />
GUIを使いたいならヘッドレスでセットアップする意味ないので。<br />
<br />
MacやLinuxの場合は次のコマンドでmicro SDカードにイメージを書き込めます。<br />
Windowsの場合は適当にツール使って書き込めば良いのではないでしょうか。ググればすぐ見つかります。<br />
<pre class="brush:shell">$ df
$ unmountDisk /Volumes/NO\ NAME
$ dd bs=1m if=~/Downloads/2018-03-13-raspbian-stretch-lite.img of=/dev/disk2
</pre>
dfコマンドでSDカードが認識されているデバイス名を確認するのを忘れずに。<br />
確認したらそのデバイス名を dd コマンドの of オプションに指定します。<br />
デバイス名を間違うと残念なことになるので要注意。<br />
<br />
Macの場合、正常に書き込みができたら自動的に「/Volumes/boot」にbootパーティションがマウントされます。<br />
Windowsの場合はFドライブなどにマウントされるのではないでしょうか。<br />
以下、「/Volumes/boot」を適宜読み替えてください。<br />
<br />
<h3>
WiFiの設定を入れる</h3>
bootパーティションにWiFiの設定ファイルを置きます。<br />
<pre class="brush:shell">$ echo '
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="{SSIDを書く}"
#psk="{WiFiパスワード}"
psk=暗号化したWiFiパスワード
}
' > /Volumes/boot/wpa_supplicant.conf
</pre>
「country」は国コードです。これを指定しておかないとOS起動時のWiFi設定に失敗します。<br />
「network」の設定値は Raspbianのwpa_passphrase コマンドで作れます。<br />
ただし、既にセットアップ済みのRaspberry Piを持っている場合だけですが。。。<br />
<pre class="brush:shell">$ wpa_passphrase: {SSID} {PASSWORD} >> wpa_supplicant.conf
</pre>
<br />
<h3>
SSHの設定を入れる</h3>
最近のRaspbianはデフォルトではSSHが起動しないようです。<br />
OS起動時にSSHが立ち上がるようにします。<br />
<pre class="brush:shell">$ touch /Volumes/boot/ssh
</pre>
以上、設定終わり。<br />
ここまでできたら、一旦micro SDを取り出してRaspberry Pi Zero Wに入れます。<br />
<br />
<h3>
起動する</h3>
Raspberry Pi Zero Wのmicro USBポートから給電すると起動します。<br />
この時、LEDが点灯しないことがあります。<br />
点灯しないのは故障ではなく、起動可能なOSがmicro SDに書き込まれていない場合です。<br />
つまり、Rspbianの書き込みに失敗しています。<br />
<br />
LEDが点灯するが赤くなる場合、OSは書き込まれているものの起動に失敗しています。<br />
黄緑色が点滅して、しばらくしたら点灯状態になるようであれば成功。<br />
<br />
ここで、micro SDを再度PCにマウントして見てみると、bootパーティションに作ったwpa_supplicant.confファイルとsshファイルが消えていると思います。<br />
これらのファイルは正常に起動すると/etcに移動されて削除されるので、消えているのが正常です。<br />
消えていなければブート中に何か問題が起きています。<br />
<br />
<h3>
SSH接続する</h3>
起動したらPCからSSHで接続してみます。<br />
接続先IPアドレスについては、Raspberry Pi Zero WはDHCPでアドレスを取得するのでルータの状態を見るのが手っ取り早いと思います。<br />
ちなみに、Raspberry Pi Zero WのMACアドレスは現在出荷されているものは「B8:27」で始まるようです。<br />
「B8:27」のMACで最近割り振られたIPアドレスを探すと見つけやすいです。<br />
IPアドレスが変わると面倒なので、ルータ側で固定IPを振り直しておきます。<br />
<br />
SSH接続できればセットアップ成功。<br />
あとは自由にいじり倒せます。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-72369134871112645822018-04-07T19:12:00.002+09:002019-01-10T21:40:21.460+09:00Alexa と Raspberry Pi でルンバに掃除してもらう:(2)Node-RED<a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html" target="_blank">前回説明した構成</a>を実際に作っていきます。<br />
今回はNode-REDの部分です。<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<br />
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B075Z6T457&linkId=1d34584534a50b222634a1f16d88eab6" style="float: left; height: 240px; margin: 8px; width: 120px;"></iframe>
Alexa で家電を操作するには、Node-REDの他には<a href="https://ja.wikipedia.org/wiki/IFTTT" target="_blank">IFTTT</a>を使う方法もあるようです。<br />
ただ、IFTTTの場合はAlexaへの呼び掛けが<br />
「Alexa、ルンバをトリガー!」<br />
という、作者が過労で首を痛めそうな感じになってしまいます。<br />
いや、むしろ、「トリガー ON」と言うだけのために IFTTT を使うのも良いかもしれません。<br />
<div style="clear: both;">
</div>
<br />
<h3>
Node-REDとは</h3>
<br />
話が逸れましたが、Node-REDとAlexaを組み合わせると<br />
「ルンバで掃除して」<br />
という比較的自然な呼び掛けで電源を入れることができます。<br />
<br />
Node-REDはフローベースの開発環境です。<br />
開発環境と言っても、基本的にプログラムを書く必要はありません。<br />
Raspberry Pi上で動作するWebアプリになっていて、<br />
ブラウザ上で部品を並べて行くだけで処理を指定できます。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVsfQr_J_OWoO4xfT3HGLIojW-CFSDZ8bZUp5JFwBv_804bN7pTj6Mo7Dp3wXT6Re9pnVhfqR2thNXy6D4SxcxBr4v5Z9-MufkJbZRfJDmfd-MXTOXO6koLQ5NQs6QMrfnUwCgSLkD2Bj2/s1600/Node_RED.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="813" data-original-width="1430" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVsfQr_J_OWoO4xfT3HGLIojW-CFSDZ8bZUp5JFwBv_804bN7pTj6Mo7Dp3wXT6Re9pnVhfqR2thNXy6D4SxcxBr4v5Z9-MufkJbZRfJDmfd-MXTOXO6koLQ5NQs6QMrfnUwCgSLkD2Bj2/s320/Node_RED.png" width="320" /></a></div>
<br />
<br />
指定できるノードは、GPIOやShellコマンド呼び出し、メール送信や<br />
HTTP Request, Response など Raspberry Piとの親和性の高いものが用意されています。<br />
<br />
ここに拡張用のノードでAlexa Home Skillを追加すれば Alexa と連携できる、という仕組みです。<br />
<br />
<a name='more'></a><br />
<br />
<h3>
セットアップ</h3>
<br />
Raspberry Pi自体のセットアップについては過去記事をご参照ください。<br />
「<a href="http://tech.andhandworks.com/2015/03/raspberry-pi.html" target="_blank">Raspberry Piをファイルサーバにする</a>」<br />
<br />
Raspberry PiでNode-REDをセットアップするには次のようにします。<br />
アップデートに20〜30分程度かかるので気長に待ちます。<br />
<br />
<pre class="brush:shell">$ bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)
</pre>
<br />
Node-REDのWebサーバの起動はpiユーザで行います。<br />
Shell実行してしまうので root は避けましょう。<br />
とは言え、Node-REDのページを外部からアクセスされた時点で、ユーザ権限でも何でもダメな感じがするので、気にしても仕方ないですが。<br />
<br />
起動は「node-red-start」コマンドで。<br />
<pre class="brush:shell">$ node-red-start
</pre>
起動したらブラウザから「http://{IPアドレス}:1880/」にアクセスするとNode-REDを使えます。<br />
再起動時に自動起動するようにします。<br />
<pre class="brush:shell">$ sudo systemctl enable nodered.service
</pre>
<br />
<h3>
Alexa Home Skill</h3>
続いて、Node-REDにAlexa用のノードを追加できるようにします。<br />
「Node-RED Alexa」でググると、大抵はNode-RED Alexa Home Skill Bridge(以下「Bridge」)が紹介されていると思いますが、実は必要ありません。<br />
<br />
Node-REDの画面右上の設定メニューから「パレットの管理」を選びます。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLFXKw4-s5EOsLvxlwxR1IziQo8NvU1FKTOvD1IPWBzMFJiz2LSx-tx9_j806MxJcJ0io_1S9GjCKO09G5L7wqaJA2dCRj36rtyYD9_dQdXOKcBje6BdKNulB7G7OFH0Rh5quTy68lUjE3/s1600/manage_Node_RED.png" imageanchor="1"><img border="0" data-original-height="538" data-original-width="515" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLFXKw4-s5EOsLvxlwxR1IziQo8NvU1FKTOvD1IPWBzMFJiz2LSx-tx9_j806MxJcJ0io_1S9GjCKO09G5L7wqaJA2dCRj36rtyYD9_dQdXOKcBje6BdKNulB7G7OFH0Rh5quTy68lUjE3/s320/manage_Node_RED.png" width="306" /></a><br />
<br />
「ノードを追加」タブで「node-red-contrib-alexa」で検索するといくつかのノードがヒットします。<br />
今回は「node-red-contrib-alexa-local」を使います。<br />
<br />
node-red-contrib-alexa-localはBridgeなしで動作するローカルのHome Skillです。<br />
Bridge と組み合わせる場合は「node-red-contrib-alexa-home-skill」です。<br />
では、Bridge有りと何が違うのかと言うと、、、ほとんど同じです。。。<br />
むしろBridgeのサーバに依存しない分、安定して動作するように思います。<br />
また、全てNode-RED上で設定できるため、localの方が分かりやすいです。<br />
<br />
なお、Bridgeの有無に関係なく、Home Skillのノードはスキルを自作しないので手軽です。<br />
一方で、あまり複雑なことはできません。<br />
基本的に照明の操作用なので、次の3つのことができます。<br />
<br />
<h2>
ON/OFF操作</h2>
「○○をON」または「○○をつけて」と言うとAlexaがON/OFFの命令をノードに送って来ます。<br />
どうやら、Alexaは照明以外の動詞でも「ON」だと認識してくれるようです。<br />
そのため、「ルンバで掃除して」でもOKでした。<br />
<br />
<h2>
相対値指定</h2>
「○○を明るくして」「○○を上げて」と言うとAlexaは「+1」を送って来ます。<br />
もちろん「下げて」なら「-1」です。<br />
これもキーワードにゆとりを持たせてあるので「○○を大きくして」でもOK。<br />
ところが「テレビの音量を上げて」はNGでした。<br />
<br />
<h2>
絶対値指定</h2>
「○○を10にして」と言うとAlexaは「10」を送って来ます。<br />
どうやら照明の明るさを絶対値指定できるようです。<br />
これを使うと「テレビを8にして」と言えばチャンネルを変える設定を作ることが可能です。<br />
「チャンネル」というデバイスを作っておけば「チャンネルを8にして」でもOK。<br />
<br />
<h2>
Alexa Home Skillのノードを作成する</h2>
Node-REDの左ペインの「入力」から「alexa local」のノードをドラッグして追加します。<br />
追加したらダブルクリックして「ルンバ」という名前を付けます。<br />
この名前はAlexaに呼びかける時のデバイス名になるので「Roomba」などと書くと認識してもらえません。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia4t3yx4AUBFaH5u5zu2Hxyzblb2y5Rl4kJZvTjD7dDVi6EC6SgpUivm6h0p_3vREVPJAdtu7zMvm3Auwa9c-fncMvbxJFauCg7oTtgCKOFjeSyZwAqFcdoNUG3hj9L9nHzxH3AQ1l_wyx/s1600/Alexa_Local.png" imageanchor="1"><img border="0" data-original-height="608" data-original-width="1112" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEia4t3yx4AUBFaH5u5zu2Hxyzblb2y5Rl4kJZvTjD7dDVi6EC6SgpUivm6h0p_3vREVPJAdtu7zMvm3Auwa9c-fncMvbxJFauCg7oTtgCKOFjeSyZwAqFcdoNUG3hj9L9nHzxH3AQ1l_wyx/s320/Alexa_Local.png" width="320" /></a><br />
<br />
今度は出力ノードの「debug」を追加して、先ほどの「ルンバ」ノードと接続します。<br />
「debug」ノードは入力された文字列をコンソールに出力してくれます。<br />
設定できたら右上の「デプロイ」をクリックして反映します。<br />
<br />
<h2>
Amazon Echo</h2>
ここまででNode-REDの準備は一旦終わりです。<br />
Amazon Echoに「Alexa、デバイスを探して」と言ってしばらく待ちます。<br />
「ルンバという新しいデバイスを見つけました」<br />
と回答してもらえれば成功。<br />
<br />
「ルンバで掃除して」と言うとNode-REDのデバッグ用コンソールに何か表示されると思います。<br />
<br />
<br />
次回はひとまずAlexaやNode-REDから離れて赤外線リモコンを作ります。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com7tag:blogger.com,1999:blog-1718731153219810929.post-82904587236871111642018-04-07T12:13:00.002+09:002019-01-10T21:40:31.859+09:00Alexa と Raspberry Pi でルンバに掃除してもらう:(1)準備Amazon Echo Dot を手に入れたのですが、あまり使い道がありません。<br />
音楽を掛けるか、子供が「豆しば」を連呼する程度。<br />
<br />
「音声操作のスマートホーム!」とか言っても、家中の家電を一気に買い換えるわけにもいかず。<br />
<br />
そこで、Amazon Echo Dotで拾った音声コマンドを赤外線で飛ばして家電を操作します。<br />
「<a href="https://amzn.to/2ErzR5l" target="_blank">Alexa対応の赤外線リモコンを買えばいいじゃん</a>」という意見は無視して、最終的に次の構成を目指します。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0F33yi2Dy4_iKqgpARFtg4yrcxNdkmlOw7LDcB0T-jFfO74z4gqQVHiC_UgCsP-5mYzxPyoDyS8-h_5KD6veOc6V26dHLr4NVvHsQXjOh9wz3Ths4YOKhadU3Ch2h2qj5PK9P8ZK4hGbj/s1600/Alexa.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="437" data-original-width="816" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0F33yi2Dy4_iKqgpARFtg4yrcxNdkmlOw7LDcB0T-jFfO74z4gqQVHiC_UgCsP-5mYzxPyoDyS8-h_5KD6veOc6V26dHLr4NVvHsQXjOh9wz3Ths4YOKhadU3Ch2h2qj5PK9P8ZK4hGbj/s320/Alexa.png" width="320" /></a></div>
<br />
<br />
Alexa からの音声コマンドは Raspberry Pi 上の<a href="https://nodered.org/" target="_blank">Node-RED</a>で受け取ります。<br />
Alexa + Node-RED でググると大抵は<a href="https://alexa-node-red.bm.hardill.me.uk/" target="_blank">Node-RED Alexa Home Skill Bridge</a>を使う方法が出てきますが、今回は Home Sill Bridge なしのローカル構成で組みます。<br />
<br />
Node-RED で中継した後、別の Raspberry Pi に飛ばして赤外線で家電を操作します。<br />
なぜ Raspberry Pi が1台ではダメなのかと言うと、赤外線の到達距離が短いので家電の近くにRaspberry Piを置く必要があるからです。<br />
<br />
(2018/04/08追記)<br />
ルンバのリモコンはRaspberry Piで上手くリモコンコードをコピーできないようです。<br />
コードを自力で解析すると結構しんどいので、FlashAirで中継してArduinoからシリアル経由でROSをハックするという強硬手段に切り替えました。<br />
<div>
<br /></div>
<h3>
作成の流れ</h3>
材料は少ないのですが、構成が結構複雑です。<br />
次の順番で作っていきます。<br />
<br />
<ol>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w.html">材料を揃える。</a>【今回】</li>
<li><a href="http://tech.andhandworks.com/2018/04/amazon-echo-raspberry-pi-zero-w-node-red.html">母艦のRaspberry PiにNode-REDをセットアップしてAmazon Echo Dotに認識させる</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/raspberry-pi-zero-w-wifi.html">Raspberry Pi Zero WをヘッドレスでWiFi対応セットアップする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pi-raspberry-pi.html">Raspberry Piで赤外線リモコンのコードをコピーする</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-pinode-red.html">Node-REDから赤外線機能を呼び出してテレビを操作する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piflashairgpioarduinoht.html">FlashAirのGPIO機能でArduinoをHTTP API経由で制御する</a></li>
<li><a href="http://tech.andhandworks.com/2018/04/alexa-raspberry-piarduinoroi.html">(おまけ)ArduinoからROI経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/06/alexa-raspberry-piarduino.html">Arduinoから赤外線経由でルンバを動かす</a></li>
<li><a href="http://tech.andhandworks.com/2018/07/alexa-raspberry-pinode.html">Node-REDからFlashAir/Arduino経由でルンバを動かす</a></li>
</ol>
<br />
完成するとこうなります。<br />
Alexa + Raspberry Pi (Node-RED) + FlashAir + Arduino + ルンバ。<br />
<div class="separator" style="clear: both; text-align: left;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/gVSPG5Mz3js/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/gVSPG5Mz3js?feature=player_embedded" width="320"></iframe></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Alexa + Raspberry Pi(Node-RED) + 赤外線 + テレビ。</div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/6s4dYsfpwlo/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/6s4dYsfpwlo?feature=player_embedded" width="320"></iframe><br />
<br />
<br />
<a name='more'></a><br />
<br />
<h3>
材料</h3>
<div>
まずは材料を揃えます。</div>
<div>
今回は電子工作というよりデバイス連携</div>
<div>
<br /></div>
<h2>
Amazon Echo Dot</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B072B5BTLK&linkId=66384cbaaf20e10048cb374896b06026" style="height: 240px; width: 120px;"></iframe></div>
Google Home とか Siri に比べたら頭悪い感じがしますが気にしません。
<br />
<div style="clear: both;">
</div>
<br />
<br />
<h2>
Raspberry Pi 3 Model B</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B01CFHHYF4&linkId=abfbe607d326655814820f881301762d" style="height: 240px; width: 120px;"></iframe></div>
3でなくても構いません。<br />
ネットワークに繋がればどのモデルでも OK です。<br />
<a href="http://tech.andhandworks.com/2015/03/raspberry-pi.html">Raspberry Piのセットアップについては以前に書いた説明をご参照ください</a>。<br />
<div style="clear: both;">
</div>
<br />
<br />
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B07446WLQV&linkId=b27bdcfbfba23f538745237cc45fe0b9" style="height: 240px; width: 120px;"></iframe></div>
Raspberry Pi Zero W<br />
家電の近くに置くため小さくて目立たないモデルを使います。<br />
<a href="https://amzn.to/2qf1nxV" target="_blank">こんな感じのケース</a>に入れておくとかっこいいかも。<br />
なお、赤外線LEDを付ける必要があるので最初からピンヘッダの付いているタイプが楽です。<br />
<div style="clear: both;">
</div>
<br />
<br />
<h2>
赤外線LEDと赤外線受信モジュール</h2>
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B074KCM7D3&linkId=ddc501bacfa628181495c504f240fa53" style="float: left; height: 240px; margin: 8px; width: 120px;"></iframe>
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B074KCNHY3&linkId=fe661f418fd97b19f594034cb7839a52" style="height: 240px; margin: 8px; width: 120px;"></iframe>
<br />
<div style="clear: both;">
</div>
家電の赤外線リモコンをコピーするため、受信モジュールが必要です。<br />
LEDはRaspberry Pi Zero Wの数だけ必要ですが、受信モジュールは1個だけでもOKです。<br />
<br />
また、赤外線LEDを単体で用意しても良いのですが、抵抗などを付ける必要があってごちゃごちゃします。<br />
モジュールを使った方がコンパクトに収まるのでおすすめです。<br />
受信機の方は一時的に使用するだけなのでどちらでも良いかも。<br />
<br />
<br />
<h2>
Arduino Pro mini</h2>
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B013QV2EQM&linkId=81c647d8c9108a65a23cae676aaedad7" style="float: left; height: 240px; margin: 8px; width: 120px;"></iframe>
ルンバをシリアルポート経由で制御するのに使います。<br />
Arduinoなら何でも良いのですが、とりあえず安くて小さいのでPro mini。<br />
ただし、Pro miniの場合はUSBポートが無いのでPCから書き込むためにFTDIシリアル変換モジュールが必要です。<br />
<div style="clear: both;">
</div>
<br />
<br />
<h2>
FlashAir(W-02以降)</h2>
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00UMTNB2S&linkId=674b7541960fcc89c100adba9314e8fa" style="float: left; height: 240px; margin: 8px; width: 120px;"></iframe>
Arduinoを無線対応させるために使います。<br />
ストレージは使わないのでわざわざ大容量のものを用意する必要はありません。<br />
また、W-02以降であればGPIOモードを使える(ファームアップデートが必要だけど)ので、型落ちでもOKです。<br />
<div style="clear: both;">
</div>
<br />
<br />
では、次回から実際に作っていきます。たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-27337485270297838882017-11-23T11:47:00.000+09:002018-04-07T12:54:00.211+09:00古い歯ブラシで虫ロボット子ども工作教室などで使い古されたネタですが、、、<br />
古い歯ブラシに振動モータを乗せて虫ロボットを作ります。<br />
<br />
あっと言う間に出来上がる割には結構盛り上がります。<br />
お父さんの威厳を取り戻したい方に最適。<br />
<br />
完成するとこんな感じ。<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/Y1uUDNvBXq8" width="560"></iframe><br />
<br />
<br />
<a name='more'></a><br /><br />
<h3>
材料</h3>
材料は歯ブラシと振動モータとコイン電池とセロハンテープだけ。<br />
とは言え、歯ブラシが用済みになったタイミングでささっと作り上げるのがポイントなので、<br />
いつでも作れるようにモータと電池をストックしておくことが重要です。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOGuHS9lGM4RnmLUSeAo7a9Fy_q05Dn2sq-hW2PDIzKbqe-iD7-b3s_a-PBcBLUmhDg9yg4PnfQu_nUMxVx-lRzZyqsWOiJJUDOB3y_kGLx6iO5p2rZvamhpc1yRWmLuTRsWuWbyzD6HlG/s1600/fullsizeoutput_1a6.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOGuHS9lGM4RnmLUSeAo7a9Fy_q05Dn2sq-hW2PDIzKbqe-iD7-b3s_a-PBcBLUmhDg9yg4PnfQu_nUMxVx-lRzZyqsWOiJJUDOB3y_kGLx6iO5p2rZvamhpc1yRWmLuTRsWuWbyzD6HlG/s320/fullsizeoutput_1a6.jpeg" width="320" /></a></div>
<br />
<br />
<div style="clear: both;">
</div>
<h2>
振動モータ</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B073W5D3H6&linkId=61acc24da9590fb6755280d573cd3eab" style="height: 240px; width: 120px;"></iframe></div>
<br />
マイクロモータに振動用の重りが付いています。<br />
リード部分が非常に脆弱なので取り付け中に千切れてしまうことが多いです。<br />
購入時の輸送中に断線していたり、取り付けに失敗したりと、あらゆるタイミングで切れます。。。<br />
数個消費することを覚悟しておいた方が良いかもしれません。<br />
運が良ければ10個パックなどでかなり安く手に入ることがあります。<br />
<br />
<div style="clear: both;">
</div>
<h2>
コイン電池:CR2016</h2>
<div style="float: left; margin: 8px;">
<iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B006K895HU&linkId=5957b3353d455dbd7baa65c345dd5a5f" style="height: 240px; width: 120px;"></iframe></div>
<br />
電子工作の友、CR2016。<br />
<br />
コイン電池でよく使われる CR2032のちょうど半分の厚さです。<br />
1枚が3Vなので2枚重ねてCR2032用の電池ケースに入れると6V。<br />
つまり、Arduino など 5V 用マイコンをCR2032の電池ケースで駆動できるようになるという優れものです。<br />
<br />
今回は電池ケースを使わずにそのままセロハンテープで貼り付けて使います。<br />
薄い分、電池容量が少ないです。<br />
マイクロモータをつけると5分くらいで使い切ってしまいます。<br />
<br />
百均で買うと1枚100円しますが、Amazonでまとめ買いすれば1枚あたり40円程度です。<br />
<br />
当然ながら、今回の用途ならCR2032でも構いません。<br />
電卓など普通の機器用のストックにする場合はCR2032の方が使い勝手が良いかも。<br />
<br />
<div style="clear: both;">
</div>
<h3>
作り方</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggN9uEnT1foQmvJA4vLxlCq5yIUoD0uP9dTSftxMwJyNVdV9hERkY6qfFuec4jlxrLAIUIX6MkFZmfglZVOWR-e1nCCbXzS1mbMqBJPe9QmYhnZW2nIGNvphDcorxmOF2N6jVFAQva6naU/s1600/fullsizeoutput_1a8.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggN9uEnT1foQmvJA4vLxlCq5yIUoD0uP9dTSftxMwJyNVdV9hERkY6qfFuec4jlxrLAIUIX6MkFZmfglZVOWR-e1nCCbXzS1mbMqBJPe9QmYhnZW2nIGNvphDcorxmOF2N6jVFAQva6naU/s320/fullsizeoutput_1a8.jpeg" width="320" /></a></div>
<br />
(1) ペンチで歯ブラシの頭を切り落とします。<br />
<div style="clear: both;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNmpMHYLObPLiz1V6XSv6HbWjtFPwueoQ_Wm-p3zJdHzQb1DP5c7KLoDIGLb42hnVQio-IYXDS6W87U1xbnoiox3guq1Dx-zytPy37WwxGWgIb51H8HCJ27IATPlEJN6NLn0QXqX6cIQ6y/s1600/fullsizeoutput_19c.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNmpMHYLObPLiz1V6XSv6HbWjtFPwueoQ_Wm-p3zJdHzQb1DP5c7KLoDIGLb42hnVQio-IYXDS6W87U1xbnoiox3guq1Dx-zytPy37WwxGWgIb51H8HCJ27IATPlEJN6NLn0QXqX6cIQ6y/s320/fullsizeoutput_19c.jpeg" width="320" /></a></div>
<br />
(2) ハサミでブラシの部分を斜めにカットします。このカットの仕方で走り方が変わります。<br />
<div style="clear: both;">
</div>
(3) コイン電池にセロハンテープで振動モータを直接貼り付けて、さらに歯ブラシの背中に固定すれば完成。<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/Y1uUDNvBXq8" width="560"></iframe><br />たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-48808550541655297152017-06-11T12:42:00.000+09:002017-06-11T12:47:28.037+09:00Xcode の古いシミュレータを削除して Mac のディスクを節約Mac Book Air で Xcode を使っていると、すぐにディスク不足になってしまいます。<br />
<br />
消費量を調べてみると、使わなくなった古い iOS シミュレータが残ったままになっていたので<br />
掃除方法を調べてみたのですがググっても情報が少なかったので方法を書いておきます。<br />
<br />
<h3>現状把握</h3>
まずはディスク消費量を確認。<br />
<pre class="brush:shell">
MacBook-Air:~ $ du -sh ~/Library/Developer/*
4.5G Library/Developer/CoreSimulator
4.2M Library/Developer/Shared
30G Library/Developer/Xcode
</pre>
CoreSimulator の下にシミュレータが格納されています。<br />
4.5GB。<br />
<br />
最新のiOSの分だけ使っているつもりでもこんな感じで100個くらい入っています。<br />
<pre class="brush:shell">
MacBook-Air:~ $ ls ~Library/Developer/CoreSimulator/Devices/
02920FBA-70BB-4151-A812-2781B21C9310 85294178-C816-445D-B721-0F5B66EB6C1C
0C6A0874-5BA9-4C67-BB20-F57BF0BCAD3B 857ED83C-660E-4DA0-9B47-93604E175793
0F9F2A17-034E-416E-A871-1FBE54F6C6ED 85B3622F-4C8B-4ADA-8F82-4C9CF4759E39
11E82193-8207-4AF1-A6B4-286113C0490C 85D35A3C-6682-48DD-B35E-C5870E8975A9
16469CC0-4DD0-42C8-A782-CEFE4C505756 8A8FDA9A-F064-420A-8684-7666559F4D61
:
</pre>
<br />
<h3>必要のないシミュレータを確認する</h3>
大量のシミュレータについて、1個ずつ内容確認して削除するとか、、、絶対嫌ですね。<br />
そこはさすが Apple さんです。ちゃんとコマンドを用意してあります。<br />
「xcrun simctl list」で全シミュレータの状態を表示してくれます。<br />
<pre class="brush:shell">
MacBook-Air:~ $ xcrun simctl list
== Device Types ==
iPhone 4s (com.apple.CoreSimulator.SimDeviceType.iPhone-4s)
iPhone 5 (com.apple.CoreSimulator.SimDeviceType.iPhone-5)
:
== Runtimes ==
iOS 10.3 (10.3 - 14E269) (com.apple.CoreSimulator.SimRuntime.iOS-10-3)
tvOS 10.2 (10.2 - 14W260) (com.apple.CoreSimulator.SimRuntime.tvOS-10-2)
watchOS 3.2 (3.2 - 14V243) (com.apple.CoreSimulator.SimRuntime.watchOS-3-2)
== Devices ==
-- iOS 10.3 --
iPhone 5 (1AD05780-679D-4819-B841-97DDF6F572F6) (Shutdown)
iPhone 5s (3D7CBDDC-6D4D-4154-A815-A85CE2953F25) (Shutdown)
iPhone 6 (822F3C1D-C566-42A5-A888-8864FEA1C5D0) (Shutdown)
:
-- tvOS 10.2 --
Apple TV 1080p (2E35F89E-2C32-4689-83D9-D2ADCEBE34F3) (Shutdown)
-- watchOS 3.2 --
Apple Watch - 38mm (0C6A0874-5BA9-4C67-BB20-F57BF0BCAD3B) (Shutdown)
Apple Watch - 42mm (BDB19BBE-8386-4DF2-B103-E1A5B969D4D3) (Shutdown)
Apple Watch Series 2 - 38mm (B58B5DB4-9F9F-4FF0-A830-AEF9C2AF057B) (Shutdown)
Apple Watch Series 2 - 42mm (6ACBB806-43DE-47F7-838F-EF1BA64DCB1C) (Shutdown)
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-10-0 --
iPhone 5 (435DED31-5DCA-4FBF-8CC5-3BA5E6FFD1D0) (Shutdown) (unavailable, runtime profile not found)
iPhone 5s (76FDA547-B754-4100-B51C-0731EB62F7CB) (Shutdown) (unavailable, runtime profile not found)
iPhone 6 (C28739B4-4A8B-40BB-A311-CB1DDCBD60E2) (Shutdown) (unavailable, runtime profile not found)
:
-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-10-1 --
iPhone 5 (E72D4C90-3589-40F9-9A8E-A63DD3239BFA) (Shutdown) (unavailable, runtime profile not found)
iPhone 5s (1AE73560-DDB7-4BDA-BC32-B36A0000EF57) (Shutdown) (unavailable, runtime profile not found)
:
</pre>
<br />
ここで、ポイントになるのは「Unavailable」と書かれているところです。<br />
私の場合、最新のiOS(現時点で10.3)のシミュレータしか入れていないつもりなのですが、<br />
10.0や10.1のシミュレータが存在して「Unavailable」になっています。<br />
<br />
これらは10.0のシミュレータをインストールして使った後、<br />
シミュレータ本体を削除したにも関わらず、デバイスイメージだけ残ったもののようです。<br />
<br />
<h3>不要なデバイスイメージを削除する</h3>
これで不要なフォルダを特定できましたが、これらを1個ずつ削除するのもちょっと嫌です。<br />
そこはさすがAppleさん。一撃で削除するツールがあります。<br />
<pre class="brush:shell">
MacBook-Air:~ $ xcrun simctl delete unavailable
</pre>
はい、以上、終わり。<br />
4.5GB も使っていたフォルダが 140MB になりました。<br />
<br />
<pre class="brush:shell">
MacBook-Air:Devices isao$ du -sh ~/Library/Developer/*
140M /Users/isao/Library/Developer/CoreSimulator
4.2M /Users/isao/Library/Developer/Shared
2.9G /Users/isao/Library/Developer/Xcode
</pre>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-66937337537270791072017-04-29T17:19:00.000+09:002017-04-29T17:22:22.088+09:00iOSアプリ - Oyakodon世の中でマストドンというサービスが話題になっているようなので勢いだけでクライアントアプリを作ってみました。<br />
名前も勢いだけの語呂で「Oyakodon」。<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://itunes.apple.com/jp/app/oyakodon/id1229174544" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzgWTfRYw5mSkV_-fL2yKOGF6s6DsY9kLp4Wp_Rsd6_hPwDayWDknJMN-wXJla8YkcokpQ7JCUEOzOdo0FA4aKfr6RTjEmll3mVMeH7pdjHhUFtPcluUDOKEfI_q4CtGFGfA5hyxgOpAU/s1600/Download_on_the_App_Store_Badge_US-UK_135x40.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1jBeP_QXHDKM2suHG0SDEnH2V1dszm4m62WKSMaP-GhBAeYXS3mSKH53yRa6c_psALq5gdS18Atppn0UhE2Hx5LYFyYozY41Na_8LUyG31ZeIf5m6YtzkPViJyO6ozpxdXYDeEXLo-AXf/s1600/iTunesArtwork%25403x.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1jBeP_QXHDKM2suHG0SDEnH2V1dszm4m62WKSMaP-GhBAeYXS3mSKH53yRa6c_psALq5gdS18Atppn0UhE2Hx5LYFyYozY41Na_8LUyG31ZeIf5m6YtzkPViJyO6ozpxdXYDeEXLo-AXf/s320/iTunesArtwork%25403x.png" width="320" height="320" /></a></div>
<br />
<h4>マストドンとは?</h4>
ざっくり言うと Twitter のようなサーバ(インスタンス)があちらこちらに立ち上がっている状態でしょうか。<br />
各インスタンスは独立な存在で、ユーザアカウントも別々です。<br />
<br />
ただし、異なるインスタンスのユーザをフォローしたり、他のユーザがフォローしている<br />
外部インスタンスのユーザの投稿がタイムラインに出てきたりと、インスタンス間で微妙な繋がりがあります。<br />
<br />
そのため、Twitter や Facebook のように中央集権的に特定の企業が権限を持っていたり、<br />
サーバダウンによってサービス全体が停止することがありません。<br />
<br />
<h4>マストドンクライアントアプリ - Oyakodon</h4>
<b>特徴その1:複数インスタンスのタイムラインをフリック切り替え</b><br />
インスタンスが分散して存在しているため、マストドンを使っていると複数のアカウントを使い分けたくなってきます。<br />
他のマストドンアプリは設定画面からアカウントを切り替える仕組みになっているものが多いようです。<br />
それはそれでインスタンスを独立に扱えるので良いのですが、多数のタイムラインを一度に見るには不向きですね。<br />
<br />
そこで、画面を横フリックすることで次々にタイムラインを見ることに特化したアプリを作ってみました。<br />
とにかくサクサクとインスタンスを切り替えることに特化したので、同一インスタンス内で表示できるタイムラインは1つです。<br />
マストドンには「連合」「ローカル」など複数のタイムラインがありますが、それらの切り替えはあえて設定内に押し込みました。<br />
他のアプリではインスタンス内の切り替えが表に出ていてインスタンス切り替えが設定内なので、このアプリでは逆の考え方ですね。<br />
<br />
<b>特徴その2:ストリームタイムライン表示</b><br />
マストドンのWeb表示の特徴の1つにストリームタイムラインがあります。<br />
ストリームタイムラインではユーザ操作なしでほぼリアルタイムにタイムラインが更新されていきます。<br />
これをアプリでやろうとすると色々問題があるので不採用としているアプリが多いようです。<br />
<br />
Oyakodon では問題点に目を瞑ってストリームタイムライン表示にしました。<br />
バッテリー消費が大きいと思うので外出中などの使用の際はご注意ください。<br />
また、若干強引にWebの表示をそのまま嵌め込んだので、時折表示が乱れる場合があります。<br />
おかしくなるケースを見つけた方はご指摘ください。<br />
<br />
<h4>既知の問題</h4>
v1.0 では既知の問題がいくつかあります。<br />
数点については既に修正済みバージョンをAppStoreに申請中なのですがレビューに時間がかかっているようです。<br />
他にも見つけた方はコメント欄等でご指摘いただけると助かります。<br />
<ul><li>iOSのバージョンによってはPawoo など一部のインスタンスへのログインに失敗する。</li>
<li>Pixiv, niconico などのアカウント連携でのログインができない。</li>
<li>ヘッダ部分のタイトル等は不要。</li></ul>
<br />
<h4>今後の機能拡張予定</h4>
AppStore レビュー欄や Twitter, mstdn.jp などでもご指摘をいただいていますが、<br />
今後、次の点について拡張する予定です。<br />
<br />
<ul><li><b>タイムライン切り替えを快適にする目的の拡張</b><br />
- タイムラインを表示する順序の並び替え機能。<br />
- 広告削除手段</li>
<li><b>iPhone/iPad を立て掛けてタイムラインを流しっぱなしにする目的の拡張</b><br />
- 横向き表示</br>
- ヘッダ部分を一切表示しない設定<br />
- iOSのスリープを無効化する設定</li>
<li><b>マストドンをマルチインスタンスで利用する目的の拡張</b><br />
- インスタンス追加の画面の改良<br />
- インスタンス追加の画面で他のインスタンスを紹介</li></ul>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com1tag:blogger.com,1999:blog-1718731153219810929.post-15501256549070738852017-04-08T09:57:00.000+09:002019-01-10T21:40:48.205+09:00FlashAir+Arduino+Raspberry Piで温湿度計(4):Raspberry Pi で見える化する〜完成[<a href="http://tech-en.andhandworks.com/2017/04/temperature-and-hygrometer-with_67.html" target="_blank">This report is also available in English.</a>]<br />
<br />
もくじ<br />
<ol><li><a href="/2017/04/flashairarduinoraspberry-pi.html">準備〜センサから値を読む</a></li>
<li><a href="/2017/04/flashairarduinoraspberry-piisdiosd.html">iSDIOを使いながらSDカードを読む</a></li>
<li><a href="/2017/04/flashairarduinoraspberry-piarduino.html">Arduino から Raspberry Pi に測定値を送る</a></li>
<li style="font-weight:bold">Raspberry Pi で見える化する〜完成</li></ol>
<br />
ようやく最終回です。<br />
Arduino から送られてきたデータを Raspberry Pi で受け取り、<br />
Java Script で見える化します。<br />
<br />
<a href="https://github.com/onthehand/HumidityBubbleChart" target="_blank">今回作成する PHP, JavaScript は Github に置きました</a>。<br />
<br />
おさらいですが、全体の通信シーケンスは次のようになります。<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-kaASOO4oDRGJyQ40Fu3YrOQDHKaIgCtqMmx7ytKmBdRHe3PGNEZzWFPiRnzNC8NPw4s-vyT7EHG4q9kQV2Rq67QeOx_Pu1WWfFak7Y65tlFR9ALv2LxYysPUP0qaGdAFuiz-A1IUwgK7/s1600/Humidity_sequence.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-kaASOO4oDRGJyQ40Fu3YrOQDHKaIgCtqMmx7ytKmBdRHe3PGNEZzWFPiRnzNC8NPw4s-vyT7EHG4q9kQV2Rq67QeOx_Pu1WWfFak7Y65tlFR9ALv2LxYysPUP0qaGdAFuiz-A1IUwgK7/s320/Humidity_sequence.png" width="320" height="128" /></a><br />
<br />
データ収集APIでArduinoからの送信を受け付けます。<br />
受け取ったデータはログファイルに書き込んでおき、<br />
タブレット用表示ページのJavaScriptから参照させる流れです。<br />
<br />
<h3>Raspberry PiでWeb APIを動かす</h3>
Apache と PHP で Web API を作ります。<br />
単にパッケージをインストールするだけです。<br />
ググればたくさん情報が見つかりますので詳細は省略します。<br />
<pre class="brush:shell">
pi@raspberrypi ~ $ sudo apt-get install apache2
pi@raspberrypi ~ $ sudo apt-get install php
pi@raspberrypi ~ $ sudo systemctl start apache2
</pre>
インストール後、/var/www/html/ に置いたファイルを HTTP 経由で参照できるようになります。<br />
<br />
<h3>データ収集API</h3>
<a name='more'></a>Arduino から HTTP 経由でデータを受け取ってログに書き込みます。<br />
厳密に言うと、同時アクセスを考慮したファイルロックや、<br />
ログが肥大化した時の対応を考えるべきですが、<br />
今回はArduinoの数が少ないので、とりあえず動くレベルで済ませます。<br />
<br />
ポイントは次のあたりでしょうか。<br />
<ul><li>Arduino は起動時刻からの経過時間しか取得できないので、<br />
ログのタイムスタンプは Raspberry Pi 側の時刻を書き込む。<br />
<li>場所IDごとにログファイルを切り替える。</li>
<li>Arduinoから異常な値を送信された場合にログに書き込まない。</li></ul>
<br />
まずはログ書き込み先フォルダを作ります。<br />
<br />
<pre class="brush:shell">
pi@raspberrypi ~ $ mkdir /var/www/html/data/
pi@raspberrypi ~ $ chmod 777 /var/www/html/data/
</pre>
<br />
次の PHP を /var/www/html/api.php に保存し、<br />
Arduino 側で「http://{IPアドレス}/api.php」にデータを送ると<br />
/var/www/data/log_{場所ID}.txt に計測値が書き込まれます。<br />
<br />
<pre class="brush:php">
<?php
// HTTP ヘッダ
header('Content-type:text/plain');
// ログの書き出し先。ファイル名は「log_{場所ID}.txt」
define('LOG_PREFIX','./data/log_');
define('LOG_SUFFIX','.txt');
// Raspberry Pi 側の時刻をタイムスタンプにする。
date_default_timezone_set('Asia/Tokyo');
$timestamp = date('Y/m/d H:i:s');
$id = 0;
$h = 0;
$t = 0;
// HTTP GET パラメータを取得
// filter_var 関数で、数値以外の値を削除
if ( isset($_GET['ID']) ){
$tmp = filter_var($_GET['ID'], FILTER_VALIDATE_INT);
if ( $tmp ) { $id = $tmp; }
}
if ( isset($_GET['H']) ){
$tmp = filter_var($_GET['H'], FILTER_VALIDATE_FLOAT);
if ( $tmp ){ $h = $tmp; }
}
if ( isset($_GET['T']) ){
$tmp = filter_var($_GET['T'], FILTER_VALIDATE_FLOAT);
if ( $tmp ){ $t = $tmp; }
}
// 全てのパラメータがデフォルト値「0」のままだったら
// Arduino 側が異常になっているのでログに書かない。
if ( $h == 0 && $t == 0 && $id == 0 ){ echo 'NG'; return; }
// ログ1行分を作る
$log_msg = $timestamp.','.$h.','.$t."\n";
// ファイルがない場合は書き込みモード
// すでにファイルがある場合は追記モードでログを書く
$log_file = LOG_PREFIX.$id.LOG_SUFFIX;
$fp = ( file_exists($log_file) )
? fopen($log_file,'a')
: fopen($log_file,'w');
fwrite($fp,$log_msg);
fclose($fp);
?>OK
</pre>
<br />
<h3>表示用ページ</h3>
表示用の方もあまり汎用化を考えずに、とりあえず動くレベルで作りました。<br />
<br />
グラフ表示には <a href="http://www.chartjs.org" target="_blank">Chart.js</a> のバブルチャートを使います。<br />
ググってもバブルチャートの説明があまり見つかりませんが、<br />
使い方は棒グラフなどとあまり違いはありません。<br />
<br />
まずは枠の HTML を置きます。<br />
JavaScript を読み込んで canvas を作っているだけです。<br />
canvas の中身は全て「mychart.js」で描画します。<br />
<br />
<pre class="brush:html">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>
<script src="mychart.js"></script>
<title>Temperature</title>
</head>
<body onLoad=main() >
<div style="margin:60px; width:80%">
<canvas id="myChart" style="width: 100%; height: auto;"></canvas>
</div>
</body>
</html>
</pre>
<br />
と言うわけで、mychart.js という名前でバブルチャート本体を作ります。<br />
<br />
onLoad で呼び出される main メソッドではログファイルのリストを作って描画用関数に渡します。<br />
それを setInterval で10分おきに呼び出して再描画します。<br />
<br />
readyChart メソッドはバブルチャートの座標軸や凡例など書き変わらない部分を定義しています。<br />
詳細は <a href="http://www.chartjs.org/docs/#bubble-chart-dataset-structure" target="_blank">Chart.js のマニュアル</a>で説明されています。<br />
全部ハードコーディングにしてしまったので、測定場所が増えると書き換えが必要です。<br />
<br />
<pre class="brush:javascript">
function main() {
var filePath = [
'./data/log_1.txt?'+new Date().getTime(),
'./data/log_2.txt?'+new Date().getTime(),
'./data/log_3.txt?'+new Date().getTime(),
'./data/log_4.txt?'+new Date().getTime(),
'./data/log_5.txt?'+new Date().getTime(),
'./data/log_6.txt?'+new Date().getTime()
];
var myChart = readyChart();
updateChart(filePath, myChart,0);
setInterval(updateChart(filePath,myChart),60000);
}
function readyChart() {
var data = [{},{},{},{},{},{}] ;
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bubble',
data: {
datasets: [
{
label: "リビング",
data: data[0],
borderColor: '#FF0000',
borderWidth: 3,
showLine: true
},
:(中略)
{
label: "洗面所収納",
data: data[5],
borderColor: '#666666',
borderWidth: 3,
showLine: true
}
]
},
options: {
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: '温度 [℃]'
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: '湿度 [%]'
}
}]
}
}
});
return myChart;
}
</pre>
<br />
続いて、チャートの描画です。<br />
渡されたファイルリストから1個ずつログファイルを取得してJSON形式に変換します。<br />
JavaScript が結構煩雑になるので、ログを JSON-P 形式にするPHPを作っておき、<br />
HTML から script タグでロードした方が楽だったかもしれません。<br />
<br />
とは言え、今回は JavaScript で CSV をパースするように作ってしまったのでこのまま進めます。<br />
XMLHttpRequest を連続で呼び出すと非同期で再描画が走って表示が崩れるので、<br />
XMLHttpRequest の onLoad の末尾で再帰呼び出しすることで、シーケンシャルに<br />
各ログを読み込みました。<br />
そのため、途中のログでエラーが発生すると再描画されなくなります。。。<br />
<br />
バブルチャートの注意点としては、単純にデータ点数をバブルサイズにしてしまうと、<br />
測定時間が長かった場所だけバブルが巨大になってしまいます。<br />
そこで、今回は測定値を整数に丸め込んで(DHT11の場合は元から整数です)おき、<br />
同一測定値のデータ点数最大値で全体を割り算しています。<br />
簡易ではありますが、この方法でバブルの最大サイズを固定しました。<br />
<br />
<pre class="brush:javascript">
function updateChart(filePath, myChart, idx) {
if ( idx >= filePath.length ){ return; }
var req = new XMLHttpRequest();
req.open("GET", filePath[idx], true);
req.onload = function() {
var data = convertData(csv2Array(req.responseText));
myChart.data.datasets[idx].data = data;
myChart.update();
updateChart(filePath, myChart, idx+1);
}
req.send(null);
}
function convertData(source) {
var data = [];
var max = 1;
var buf = {};
for (var row in source) {
y = String(parseInt(parseFloat(source[row][1]) + 0.5));
x = String(parseInt(parseFloat(source[row][2]) + 0.5));
if ( buf[x] == undefined ){
buf[x] = {};
buf[x][y] = 1;
} else if ( buf[x][y] == undefined ){
buf[x][y] = 1;
}else{ buf[x][y] ++; }
if ( buf[x][y] > max ){ max = buf[x][y]; }
};
for (var i in buf) {
for (var j in buf[i]) {
data.push( { x:i, y:j, r:20*buf[i][j]/max } );
}
}
return data;
}
function csv2Array(str) {
var csvData = [];
var lines = str.split("\n");
for (var i = 0; i < lines.length; ++i) {
var cells = lines[i].split(",");
csvData.push(cells);
}
return csvData;
}
</pre>
<br />
<h3>完成</h3>
そんなこんなで Raspberry Pi 側は色々とやっつけ仕事ですが一応完成。<br />
iPad などで表示用ページにアクセスすると次のように表示されます。<br />
寝室だけ夜間に測定したので寒いです。<br />
洗面所よりも湿度の高い子供部屋。<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmv0pWPe01S8EPb0OdpgqgDsso8_Lx1mERNNtPruZ5a9Q0JMlE-ECFFCcRp75wdg_pI1NUl_rMGrHmU_xMYD8OIjrSbrEyew-HJ_0Ed9_1qyyzDOYoWC6mF-ZTeNDQPf5c5v2f-QhTMOCk/s1600/Humidity_DHT22.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmv0pWPe01S8EPb0OdpgqgDsso8_Lx1mERNNtPruZ5a9Q0JMlE-ECFFCcRp75wdg_pI1NUl_rMGrHmU_xMYD8OIjrSbrEyew-HJ_0Ed9_1qyyzDOYoWC6mF-ZTeNDQPf5c5v2f-QhTMOCk/s320/Humidity_DHT22.png" width="320" height="159" /></a>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com0tag:blogger.com,1999:blog-1718731153219810929.post-14009723544499602512017-04-03T22:20:00.001+09:002019-01-10T21:41:00.583+09:00FlashAir+Arduino+Raspberry Piで温湿度計(3):Arduino から Raspberry Pi に測定値を送る[<a href="http://tech-en.andhandworks.com/2017/04/temperature-and-hygrometer-with_60.html" target="_blank">This report is also available in English.</a>]<br />
<br />
もくじ<br />
<ol><li><a href="/2017/04/flashairarduinoraspberry-pi.html">準備〜センサから値を読む</a></li>
<li><a href="/2017/04/flashairarduinoraspberry-piisdiosd.html">iSDIOを使いながらSDカードを読む</a></li>
<li style="font-weight:bold">Arduino から Raspberry Pi に測定値を送る</li>
<li><a href="/2017/04/flashairarduinoraspberry-piraspberry-pi.html">Raspberry Pi で見える化する〜完成</a></li></ol>
<br>
<div style="float:left; margin:8px"><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00UMTNB2S&linkId=c08dbb912a718b83644f7d99797fb70c"></iframe></div>
<a href="http://tech.andhandworks.com/2017/04/flashairarduinoraspberry-piisdiosd.html" target="_blank">前回までで Arduino から FlashAir を使う準備が整いました。</a>
<br>
今回はついに FlashAir から Raspberry Pi にデータを送ります。<br>
<a href="https://github.com/onthehand/Humidity" target="_blank">今回作成したソースコードは Github に置いてあります。</a><br>
<div style="clear:both"></div>
<br>
<h3>Arduino と FlashAir を接続する</h3>
図のように接続します。<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrHnE6MdtNqptB4aqugHYiG4ikVZPNb86EOK0bwijYoVsj1ipx4m5wsFZcpyixth7G0ct70sawR9-gPpULzRkYgOt7Kau-jr8T-lmp1t7xqgaXD8cYSHNeVsYZEQWNGUqRQNcL8zdqy4ji/s1600/Humidity_circuit.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrHnE6MdtNqptB4aqugHYiG4ikVZPNb86EOK0bwijYoVsj1ipx4m5wsFZcpyixth7G0ct70sawR9-gPpULzRkYgOt7Kau-jr8T-lmp1t7xqgaXD8cYSHNeVsYZEQWNGUqRQNcL8zdqy4ji/s320/Humidity_circuit.png" width="320" height="201" /></a><br>
<br>
SD カードの各ピンの意味は次の通りです。<br>
今回はチップセレクトを4番ピンにしました。<br>
<table border=1 cellpadding=0 cellspacing=0>
<tr><td>シルク</td><td>意味</td></tr>
<tr><td>CD</td><td>未使用</td></tr>
<tr><td>CS</td><td>チップセレクト</td></tr>
<tr><td>CLK</td><td>同期用クロック</td></tr>
<tr><td>SDO</td><td>データ出力</td></tr>
<tr><td>SDI</td><td>データ入力</td></tr>
<tr><td>GND</td><td>グランド</td></tr>
<tr><td>3.3V</td><td>3.3V 電源</td></tr>
<tr><td>5V</td><td>5V電源</td></tr>
</table>
<br>
<br>
<h3>FlashAir から設定値を読み込む</h3>
せっかく SD 読み書きと iSDIO の両方を使えるようにしたので、SD カード領域に保存した設定値を参照できるようにします。<br>
<a name='more'></a><br>
今回は測定場所のIDを FlashAir に保存しておきます。<br>
「id.txt」というファイル名でファイル本文には数字を1個(測定場所ID)だけ書いておきます。<br>
<br>
今回、Raspberry Pi 側では測定場所IDと温湿度を紐付けで管理させます。<br>
温湿度計(Arduino)を置いた場所を FlashAir に書き込んでおけば、1台の温湿度計を全ての場所に使いまわすことができます。<br>
<br>
こうしておくと、いちいち Arduino IDE を開いてコードを書き換えなくても、FlashAir のファイルを書き換えるだけで場所を変えられて楽です。<br>
<br>
ちなみに、測定場所IDだけでなく、無線関係の設定値も全て SD カードに保存したかったのですが、あまりたくさん実装するとメモリを使い尽くして動作が不安定になってしまったのでやめました。<br>
<br>
<pre class="brush:cpp">
// 改造した SD カードライブラリを include
#include <iSdio.h>
#include <SDExt.h>
// SD カードのチップセレクトピン番号
#define CHIP_SELECT_PIN 4
// 設定値を保存してあるファイルパス
#define ID_FILE "/id.txt"
int ID = 0;
// SD カードからファイルを読み込む関数
char* SD_read( char* path, char* buf, size_t s ) {
// FlashAir に連続アクセスすると不安定になることがあるので適当に delay
delay(1000);
// ファイルを開く
File file = SD.open(path,FILE_READ);
if ( !file ) { return ""; }
// ファイルの中身を読み込む
String str = "";
while (file.available()) { str += char(file.read()); }
file.close();
// 文字配列にして返す
str.toCharArray(buf, s);
return buf;
}
// SD カードのセットアップ
void setup_SD() {
// Initialize SD card.
Serial.println(F("Initializing SD card..."));
// SS ピンを出力にしておかないと SD カードライブラリが動作しないらしい
pinMode(SS, OUTPUT);
if (!SD.begin(CHIP_SELECT_PIN)) {
Serial.println(F("Card failed, or not present"));
abort();
}
: (中略)
// SD カードから読み込んだデータを数値に変換
char buf[32];
ID = atoi(SD_read(ID_FILE,buf,32));
Serial.print(F("ID="));
Serial.println(ID);
}
void setup() {
// Initialize UART for message print.
Serial.begin(9600);
while (!Serial) {
;
}
setup_SD();
}
</pre>
<br>
<br>
<h3>送信するときだけ WiFi を起動して測定値を送信</h3>
WiFi を起動したままだと電力の消費が激しいので、使用しないときは切っておきます。<br>
<br>
<pre class="brush:cpp">
#include <iSdio.h>
#include <SDExt.h>
// 計測間隔
#define LOG_INTERVAL 600000
char SSID[] = "{WiFiのSSIDを指定}";
char NETWORKKEY[] = "{WiFiのパスワードを指定}";
char API_HOST[] = "{Raspberry PiのIPアドレス}";
char API_PATH[] = "/api.php";
uint8_t buffer[512];
uint32_t nextSequenceId = 0;
// FlashAir Developers のチュートリアルにある
// iSDIO_waitResponse を流用
boolean iSDIO_waitResponse(uint32_t sequenceId) {
// 記載略
}
// FlashAir Developers のチュートリアルにある
// iSDIO_disconnect を流用
boolean iSDIO_disconnect(uint32_t sequenceId) {
// 記載略
}
// FlashAir Developers のチュートリアルにある
// iSDIO_connect を流用
boolean iSDIO_connect(uint32_t sequenceId, const char* ssid, const char* networkKey) {
// 記載略
}
// FlashAir Developers のチュートリアルにある
// iSDIO_http をベースに、接続先を引数で指定できるよう改造
boolean iSDIO_http(uint32_t sequenceId, char* host, char* path, char* param) {
Serial.println(F("http command: "));
memset(buffer, 0, 512);
uint8_t* p = buffer;
p = put_command_header(p, 1, 0);
// SSL 無しで接続するため「0x21」
p = put_command_info_header(p, 0x21, sequenceId, 2);
// 接続先ホストは Raspberry Pi の IP アドレス
p = put_str_arg(p, host); // Argument #1.
// HTTP ヘッダを生成
char getParam[128];
sprintf(getParam,
"GET %s?%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: FlashAir\r\n"
"\r\n", path, param, host);
Serial.println(getParam);
p = put_str_arg(p, getParam);
put_command_header(buffer, 1, (p - buffer));
return SD.card.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}
// SD セットアップで iSDIO を設定
void setup_SD() {
// Initialize SD card.
Serial.println(F("Initializing SD card..."));
pinMode(SS, OUTPUT);
if (!SD.begin(CHIP_SELECT_PIN)) {
Serial.println(F("Card failed, or not present"));
abort();
}
// Read the previous sequence ID.
if (SD.card.readExtMemory(1, 1, 0x420, 0x34, buffer)) {
if (buffer[0x20] == 0x01) {
nextSequenceId = get_u32(buffer + 0x24);
iSDIO_waitResponse(nextSequenceId);
nextSequenceId++;
} else {
nextSequenceId = 0;
}
} else {
Serial.println(F("Failed to read status."));
nextSequenceId = 0;
}
char buf[32];
ID = atoi(SD_read(ID_FILE,buf,32));
Serial.print(F("ID="));
Serial.println(ID);
}
}
void setup() {
// Initialize UART for message print.
Serial.begin(9600);
while (!Serial) {
;
}
setup_SD();
}
void loop() {
// 時間を測る
unsigned long start = millis();
digitalWrite(13,HIGH);
//温湿度を測定
int chk = DHT.read22(DHT_PIN);
if ( chk != 0 ){
Serial.println(F("Fail to read humidity."));
delay(1000);
return;
}
// HTTP パラメータを生成
char humid[8];
char temp[8];
char param[32];
sprintf(param,"ID=%d&H=%s&T=%s",
ID,dtostrf(DHT.humidity,5,2,humid),dtostrf(DHT.temperature,5,2,temp));
Serial.print(F("PARAM:"));
Serial.println(param);
// WiFi を起動する
// 繋がらない場合は間隔をあけてリトライ
for ( int retry = 3; retry > 0; retry -- ) {
delay(1000);
if( iSDIO_connect(nextSequenceId, SSID, NETWORKKEY) &&
iSDIO_waitResponse(nextSequenceId) ) {
Serial.println(F("Connected"));
retry = 0;
} else {
Serial.print(F("Failed or waiting. errorCode="));
Serial.println(SD.card.errorCode(), HEX);
}
nextSequenceId++;
}
// HTTP GET で送信。うまくいかないならリトライ
for ( int retry = 3; retry > 0; retry -- ) {
delay(1000);
if ( iSDIO_http(nextSequenceId,API_HOST,API_PATH,param) &&
iSDIO_waitResponse(nextSequenceId)) {
Serial.println(F("OK"));
retry = 0;
} else {
Serial.print(F("Failed or waiting. errorCode="));
Serial.println(SD.card.errorCode(), HEX);
}
nextSequenceId++;
}
//用が済んだらWiFiを停止
if (iSDIO_disconnect(nextSequenceId) &&
iSDIO_waitResponse(nextSequenceId)) {
Serial.println(F("Success."));
} else {
Serial.print(F("Failed or waiting. errorCode="));
Serial.println(SD.card.errorCode(), HEX);
}
nextSequenceId++;
digitalWrite(13,LOW);
//次の送信まで停止
unsigned long span = millis() - start;
if ( span > LOG_INTERVAL ) { return; }
unsigned long sleep_time = LOG_INTERVAL - span;
Serial.print(F("SLEEP => "));
Serial.println(sleep_time,DEC);
// 省電力停止
delaySleep(sleep_time);
}
</pre>
<br>
<br>
<h3>省電力停止させる</h3>
<div style="float:left; margin:8px"><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B01LVUBUJC&linkId=41bc810fe4b75e0bcdd1047de0cdad96"></iframe></div>測定と送信は数秒で終わるため、大半の時間は待ち時間です。<br>
<br>
真面目に省電力対応をするにはリレーで電源を分離し、Arduino 停止中は FlashAir, DHT11 も停止させる必要がありそうです。<br>
その上で WDT (Watch Dog) を使って Arduino を停止させます。<br>
<br>
とは言え、少々面倒なので今回は気休め程度に delay だけ省電力させたなんちゃって対応です。<br>
盛大に電源を消費するので、長時間の測定にはスマホ用のバッテリーなどが必要です。<br>
<div style="clear:both"></div>
<br>
delay の省電力化についてはこちらのサイトを参考にしました。<br>
「<a href="http://radiopench.blog96.fc2.com/blog-entry-485.html" target="_blank">ラジオペンチ:Arduinoでdelay関数を実行時の消費電流を減らす</a>」<br>
<br>
<pre class="brush:cpp">
void delaySleep(unsigned long t) {
//
// 注意:millis関数を使っているので50日以上の連続動作は出来ない。
//
unsigned long t0;
if( t <= 16 ) { // 16ms以下なら普通のdelayで処理
delay(t);
}
else{ // 17ms以上ならスリープ入れたdelayで実行
t0 = millis(); // 開始時のmillisの値を記録しておき
set_sleep_mode (SLEEP_MODE_IDLE); // アイドルのモード指定
while( millis() - t0 < t ) { // 設定値になるまでループ
sleep_mode(); // スリープに入れる(自動復帰するので何度も指定)
}
}
}
</pre>
<br>
<br>
これで Arduino 側は完成です。<br>
動作させるとエラーになります、、、え?<br>
<br>
送信先が無いので当たり前ですね。<br>
次回は母艦となる Raspberry Pi を作っていきます。<br>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com1tag:blogger.com,1999:blog-1718731153219810929.post-24544732658768892592017-04-01T19:26:00.002+09:002019-01-10T21:41:15.144+09:00FlashAir+Arduino+Raspberry Piで温湿度計(2):iSDIOを使いながらSDカードを読む[<a href="http://tech-en.andhandworks.com/2017/04/temperature-and-hygrometer-with_13.html" target="_blank">This report is also available in English.</a>]<br />
<br />
もくじ<br />
<ol><li><a href="/2017/04/flashairarduinoraspberry-pi.html">準備〜センサから値を読む</a></li>
<li style="font-weight:bold">iSDIOを使いながらSDカードを読む</li>
<li><a href="/2017/04/flashairarduinoraspberry-piarduino.html">Arduino から Raspberry Pi に測定値を送る</a></li>
<li><a href="/2017/04/flashairarduinoraspberry-piraspberry-pi.html">Raspberry Pi で見える化する〜完成</a></li></ol>
<br>
<a href="/2017/04/flashairarduinoraspberry-pi.html" target="_blank">前回はDHT22で温度と湿度を計測しました。</a><br>
<br>
今回は計測結果を送信、、、と言いたいところですが、その前に FlashAir の iSDIO ライブラリを改造します。<br>
<br>
<h3>FlashAir の iSDIO と SDカード機能を両立させる</h3>
<div style="float:left; margin:8px"><iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=onthehand-22&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B00UMTNB2S&linkId=c08dbb912a718b83644f7d99797fb70c"></iframe></div>
FlashAir Developers のチュートリアルに従うと、FlashAir で iSDIO を使って HTTP 接続できます。<br>
<a href="https://flashair-developers.com/ja/documents/tutorials/arduino/" target="_blank">FlashAir Developers:Arduino 向けチュートリアル</a><br>
<br>
ところが、このチュートリアルでは SD カードアクセス機能が殺されています。<br>
このチュートリアルのソースを使っていると Arduino 標準の SD カードライブラリが動作しなくなるので、自力でライブラリを改造する必要があります。<br>
<div style="clear:both"></div>
<a name='more'></a><br>
<ol><li>まず、チュートリアルのソースコードをダウンロードしてZIPを解凍します。<br>
<a href="https://flashair-developers.com/files/samplecode/arduino/arduino_tutorial_06.zip">arduino_tutorial_06.zip</a></li>
<li>Arduino の標準 SD カードライブラリから、次のファイルを解凍後の「iSDIO」フォルダ内にコピーします。<br>
File.cpp, FatStructs.h, SdFatUtil.h, SdFile.cpp, SdVolume.cpp。<br>
さらに、SD.cpp, SD.h をそれぞれ SDExt.cpp, SDExt.h という名前に変えてコピーします。<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3g4WfOJutRZZDen8teYK39buT5eyAMPdG04chPjeZ8nDYHeVWz32tvZrOizFBsEmqJ0jpqptuIYYihGpo5QcNA9N5deyR6osHRjdww2T2L8eSU0KaFF7lA_2Uep-uKXhh7Shc74PtrKj4/s1600/Humidity_SDlib.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3g4WfOJutRZZDen8teYK39buT5eyAMPdG04chPjeZ8nDYHeVWz32tvZrOizFBsEmqJ0jpqptuIYYihGpo5QcNA9N5deyR6osHRjdww2T2L8eSU0KaFF7lA_2Uep-uKXhh7Shc74PtrKj4/s320/Humidity_SDlib.png" width="320" height="224" /></a><br>
<br>
コピーが終わると iSDIO フォルダは次のようになります。<br>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGAkbZKsTSigciZav-zYyTgYJ66ZvvZ6U9p6Ye-s8k4ERpnO3PIuMeEYhVUu0FP4WgmCkvjPTioxkbc6xxuBEwusQHs3zClEF0df1oPJsTrrzWQJthPdwJ10CDWjMBOJx59gjNVfyB8t-k/s1600/Humidy_iSDIOlib.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGAkbZKsTSigciZav-zYyTgYJ66ZvvZ6U9p6Ye-s8k4ERpnO3PIuMeEYhVUu0FP4WgmCkvjPTioxkbc6xxuBEwusQHs3zClEF0df1oPJsTrrzWQJthPdwJ10CDWjMBOJx59gjNVfyB8t-k/s320/Humidy_iSDIOlib.png" width="320" height="200" /></a></li>
<li>iSDIO フォルダの SDExt.h, SdFat.h, SdVolume.h を開き、「Sd2Card」という単語を全て「Sd2CardExt」に置換します。</li>
<li>iSDIO フォルダの File.cpp と SDExt.cpp を開き、「SD.h」を「SDExt.h」に置換します。</li>
<li>iSDIO フォルダを ZIP 圧縮します。</li>
<li>Arduino IDE で次のメニューを選んで ZIP ファイルを読み込みます。<br>
スケッチ > ライブラリをインクルード > .ZIP 形式のライブラリをインストール</li></ol>
<br>
出来上がった iSDIO ライブラリを GitHub に置きました。<br>
<a href="https://github.com/onthehand/iSDIO" target="_blank">GitHub - onthehand - iSDIO</a><br>
<br>
<br>
<h3>改造した iSDIO ライブラリの使い方</h3>
改造した iSDIO ライブラリで FlashAir のストレージにアクセスする場合は次のようにします。<br>
<pre class="brush:cpp">
#include <SDExt.h>
void loop() {
File file = SD.open("file.txt", FILE_READ);
:
file.close();
delay(1000);
</pre>
<br>
具体的には、「SD.h」を include する代わりに「SDExt.h」を include しています。<br>
また、SDカードへのアクセス後に delay を挟んでいます。<br>
理由はよく分かりませんが、SDカードにアクセスした直後にWiFi にアクセスすると不安定になるようです。<br>
それ以外は通常の SD.h の使い方と同じです。<br>
<br>
<br>
改造した iSDIO ライブラリで FlashAir の WiFi を使う場合、<br>
FlashAir Developers のチュートリアルから次の点を変更します。<br>
<ul><li>「utility/Sd2CardExt.h」ではなく「SDExt.h」を include する。</li>
<li>「Sd2CardExt card;」をグローバルで宣言しない。</li>
<li>「card.readExtMemory」など cardオブジェクトを使っているところを<br>
全て「SD.card.readExtMemory」など SD.card に変更する。<br>
<br>
そもそも Sd2CardのcardオブジェクトはSDクラスのメンバ変数です。<br>
SDクラス(SDExtクラス)が使えるようになったのでメンバ変数としてアクセスする必要があります。<br>
外部から直接 card オブジェクトにアクセスすると挙動がおかしくなるので。</li></ul>
<br>
<br>
ようやく準備が揃ったので、次回では WiFi でセンサデータを送信します。<br>たけやすhttp://www.blogger.com/profile/10300074768307128090noreply@blogger.com1