RaspberryPiでも消臭力してみた

RaspberryPiでも消臭力してみた

毎回、ダメなパターンのエントリですが、今回はそれに輪をかけて駄目なタイトルになっています。

最近、Amazon Dash Buttonを使ってみたくなったので購入を考えていました。ただ、本体にくっついているデザイン面が日用品ばかりで今ひとつ気が乗らず、購入までには至りませんでいた。この時点で正当な使い方は考えておらず、ネット情報でAmazon Dash Buttonを押してWebHookを行ったりできるネタがあったので、自分でもぜひやってみようと思っていました。

あとでネットの情報を読んでいてわかったこととしては、構造それなりなのに500円と安価で、少し溜まったAmazonポイントで購入できるのもいいなと思っています。実質はものを買えば500円割引になるので、そっちのほうがオトクなんですけど。

中身の詳しい内容は以下が詳しかったです。

itpro.nikkeibp.co.jp

1週間ほど考えて、やっと購入するものを決定しました。

ムーニーと迷っての購入です。決しておむつプレイが好きなわけではないのであしからず。

ネット情報ではDasherというnode.jsのモジュールを使っている情報が多かったのですが、これは以下のnode-dash-buttonの処理をWebhookに特化したラッパーのようですので、自分はRaspberryPiのコマンドなどを実行したかったので、オリジナルのものを使うことにしました。

github.com

IFFTとかSlackへなにかを行うのであればDasherのほうが便利です。

github.com

node-dash-buttonをインストールする

上記のリンクからreadme.mdのInstallation Instructions節で方法が書かれています。

# dependancy on libpcap for reading packets
$ sudo apt-get install libpcap-dev
$ npm install node-dash-button

これでいいようです。…が。

自分の環境では少し気になっていることがありました。そもそもnode.jsはデフォルトのRasbianではバージョンが古いため、nvmをインストールすることでバージョンを上げていました。デフォルトのバージョンではnode-dash-buttonは動作しないようです。

uepon.hatenadiary.com

ユーザからはこれで問題はありません。 しかし、インストール時に使用しているlibpcap-devは、管理者権限でないとこれを使用したプログラムは動作しません。(sudoをつける必要があるということです。)sudoで呼び出されるnode.jsはnvmでインストールしたバージョンのものは適応されず、デフォルトのものが呼び出されてしまいます。(pathなどの環境が異なるので致し方ないのですが)

そこで、根本的にはバージョンアップをすることにしました。 Dasherのreadme.mdに

note Raspberry Pi users may need to update node arm which will automatically remove nodejs-legacy. Credit @legotheboss

なる記載があり以下のコマンドでnodeを比較的新しいバージョンに変更できます。

$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb 
$ sudo dpkg -i node_latest_armhf.deb
$ $ node -v
v4.2.1

これで、比較的新しいnode.jsが準備でき(node.jsは2017/02/18現在v6.9.5まで来ているようですので気休めなのかもしれませんが、デフォルトのバージョンよりはいいと思います)、node-dash-buttonの利用ができるようになりました。 あとはnode-dash-buttonをインストールする処理を行うことになります。

$ sudo apt-get install libpcap-dev
$ npm install node-dash-button

これでOKです。

DashButtonの設定を行う

以下のページのボタンセットアップ節を見てください。このページが分かりやすかったと思います。

qiita.com

具体的には、Dash ButtonのWi-Fi設定を行った後に、ボタン押下時に注文する商品を選択する画面でキャンセルしましょう。(商品との紐付けをしないようにする点) 商品と紐付けさえ行わなければ基本的には注文はされません。(buttonを押すとエラーが発生し、白色のLEDの点滅後に赤いLEDが点灯します。)

後はnode-dash-buttonの設定と実行になります。

node-dash-buttonの設定

node-dash-buttonはarpパケットを受け取ってその中にあるMACアドレスを判別して処理を行うので、入手したDashButtonが通信するときに使うMACアドレスを取得する必要があります。node-dash-buttonにはそのMACアドレスを取得するプログラムも含まれています。(Dasherモジュールにもこのプログラムが含まれています。)

$ cd node_modules/node-dash-button
$ sudo node .bin/findbutton
Watching for arp & udp requests on your local network, please try to press your dash now
Dash buttons should appear as manufactured by 'Amazon Technologies Inc.'
Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: Amazon Technologies Inc. Protocol: udp
Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: Amazon Technologies Inc. Protocol: arp

実行後にボタンを押してください。Amazon Technologies Inc.のベンダネームとしてXX:XX:XX:XX:XX:XXというような形でMACアドレスが取得されます。(MACアドレスは伏せ字にしていますので、適宜読み替えてください。)

このMACアドレスをトリガーにして処理を実行するすることになります。

node-dash-buttonの実行

node-dasu-buttonモジュールをインストールしたディレクトリで以下のようなスクリプトを作成します。

var dash_button = require('node-dash-button');
var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); //address from step above
dash.on("detected", function (){
    console.log("omg found");
});

MACアドレスの入ったarpパケットを検出するとdetectedイベントを検出して処理を実行します。このスクリプトの場合にはconsole.log("omg found");の処理が実行されます。この処理を別のものにすることで、buttonを押すと色々な処理が行える様になります。

node-dash-buttonで検出した際にコマンドを実行する

node.jsからシェルコマンドを実行する方法としては以下を参考にしました。

tkybpp.hatenablog.com

sudo環境での実行なのでpathが心配だったのですが、特に問題はなかったみたいです。 例えば実行するディレクトリのファイルを取得するlsコマンドを実行するには以下のように記述します。

const execSync = require('child_process').execSync;
const result =  execSync('ls -la ./').toString();
console.log(result);

node.jsは非同期実行なので同期的な実行にしたほうがわかりやすくなるかなとは思いますのでこちらを使用しました。

スクリプト名をnode dash-button_shell.jsした場合

const dash_button = require('node-dash-button');
const execSync = require('child_process').execSync;

var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all'); //address from step above
dash.on("detected", function (){
    var result =  execSync('ls -la ./').toString();
    console.log(result);
});

このようになります。これを実行すると

$ sudo node dash-button_shell.js
omg found
合計 656
drwxr-xr-x  3 pi pi   4096  215 09:40 .
drwxr-xr-x 45 pi pi   4096  220 23:33 ..
-rw-r--r--  1 pi pi    204  215 01:10 dash-button.js
-rw-r--r--  1 pi pi    341  215 09:40 dash-button_play.js
-rw-r--r--  1 pi pi    336  215 09:23 dash-button_shell.js
-rw-r--r--  1 pi pi    348  215 09:32 dash-button_talk.js
-rwxr--r--  1 pi pi    503  215 09:27 jtalk.sh
drwxr-xr-x  4 pi pi   4096  215 01:05 node_modules
-rwxr--r--  1 pi pi 635436  28 23:00 riki.wav

うまくカレントディレクトリのファイル一覧を取得できています。気にしていた実行pathの問題も問題はなさそうです。

node-dash-buttonでボタンを押したら【消臭力】の音声ファイルを鳴らす。

音声を鳴らすコマンドはaplayで行えるので今回は慣らしたい音声ファイルriki.wavとして鳴らしてみます。

const dash_button = require('node-dash-button');
const execSync = require('child_process').execSync;

var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all');
dash.on("detected", function (){
    var result =  execSync('aplay riki.wav').toString();
});

これでOKです! 「しょ~しゅ~りき~♪」どこでもミゲルくんが歌ってくれる・・・素敵です!

node-dash-buttonで検出した際に音声合成で言葉を話す

以前、Open JTalkを使いましたので、今回もそこで作成したshを使用することにします。

参考: uepon.hatenadiary.com

今回使用するシェルスクリプトは以下のようなものです。(ファイル名はjtalk.sh

#!/bin/bash

#HTSVOICE=/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice
HTSVOICE=/usr/share/hts-voice/mei/mei_normal.htsvoice

voice=`tempfile`
option="-m $HTSVOICE \
  -s 16000 \
  -p 100 \
  -a 0.03 \
  -u 0.0 \
  -jm 1.0 \
  -jf 1.0 \
  -x /var/lib/mecab/dic/open-jtalk/naist-jdic \
  -ow $voice"

if [ -z "$1" ] ; then
  open_jtalk $option
else
  if [ -f "$1" ] ; then
    open_jtalk $option $1
  else
    echo "$1" | open_jtalk $option
  fi
fi

aplay -q $voice
rm $voice

node.jsからこのスクリプトを呼び出すことになるので以下のようなスクリプトを記述します。

const dash_button = require('node-dash-button');
const execSync = require('child_process').execSync;

var dash = dash_button("XX:XX:XX:XX:XX:XX", null, null, 'all');
dash.on("detected", function (){
    console.log("omg found");
    var result =  execSync('./jtalk.sh \'こんにちは\'');
});

ボタン一つで話したい音声が話せます。す・て・き(うっとり)

蛇足

今回はnode.jsを使用していましたが、通信時のarpパケットさえ捉えられればよいのでtcpdumpでも同様の処理を行えます。というか両者ともlibpcapを使っているのであれば同様なことが可能です。

まずは、libpcapを使用するtcpdumpをインストールします。

$ sudo apt-get install tcpdump

インストールが終わったら以下のようなスクリプトを作成します。 ファイル名はbutton.shとしました。

#!/bin/bash
tcpdump -i wlan0 -e | while read line
do
    if [[ $line = *XX:XX:XX:XX:XX:XX*ethertype\ ARP* ]]; then
        echo "button pressed"
    fi
done

XX:XX:XX:XX:XX:XXはDashボタンのMACアドレスを設定してください。 このシェルスクリプトは指定されたMACアドレスのパケットを受信したら標準出力にbutton pressedという表示を行うものになります。 実行は以下のように行います。(ファイルの編集が終わったらchmodで実行権限を与えてください。)

$ sudo ./button.sh
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
button pressed
^C74 packets captured
75 packets received by filter
0 packets dropped by kernel

(Ctrl-Cで処理を中断していますので一回となっていますが、基本は無限ループになります。)

おわりに

無事に同一のWi-Fiエリアであれば、ミゲルくんが歌ってくれる素敵な家になりました。それにしても、Amazon Dash Buttonはこんな価格で出してもいいもんなんでしょうか?

難点を上げるとしては、ボタンを押してからARPパケットの送出するまでの反応が遅いかなと思います。まあ、値段からみれば十分問題のない範囲ですけどね。

あとで動画を追加する予定です。

RaspberryPiでUSB接続のWebカメラを使ってみる

RaspberryPiでUSB接続のWebカメラを使ってみる

以前はRaspberryPi専用のカメラモジュールを接続していました。

uepon.hatenadiary.com

今回は一般に販売されているUSB接続のWebカメラを接続してみます。

家には2つのWebカメラがありました。

www.logicool.co.jp

www.microsoft.com

ロジクールのものはHDでの動画撮影もできてコンパクトに折りたためるのでなかなかいい感じです。 MicrosoftのLifeCamもカメラは悪くないのですが、足の部分のラバーっぽいのが固定しにくかったり、劣化したりしそうなので微妙です。こちらは720pでの撮影ができます。

今回はこちらのブログを参考にしてみました。

blog.livedoor.jp

カメラを接続してみる

とりあえず、そのまま接続してみます。

以下がUSBカメラを接続する前のlsusbの状態です。

$ lsusb
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

キャプチャデバイスも存在していません。

$ ls /dev/video*
ls: /dev/video* にアクセスできません: そのようなファイルやディレクトリはありません

接続すると以下のような状態に変化します。

【hd-webcam-c615の場合】

$ lsusb
Bus 001 Device 005: ID 046d:082c Logitech, Inc.
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

以下が追加されます。

Bus 001 Device 005: ID 046d:082c Logitech, Inc.

接続して認識されると

$ ls /dev/video*
/dev/video0

ビデオキャプチャバイスも生成されています。

【ifecam-cinemaの場合】

$ lsusb
Bus 001 Device 007: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ ls /dev/video*
/dev/video0

以下が追加されています。デバイスナンバー(Deviceの部分の数字)が連番になっていませんが、抜き差しするとこの部分が変更されるようです。

Bus 001 Device 007: ID 045e:075d Microsoft Corp. LifeCam Cinema

ともに正常に認識されている様です。

ちなみに両方を接続すると以下の用になります。

$ lsusb
Bus 001 Device 006: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 005: ID 046d:082c Logitech, Inc.
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ ls /dev/video*
/dev/video0  /dev/video1

Xの環境で使用してみる。

まずはLogicoolのhd-webcam-c615を接続してテストをしてみます。(これが今回の混乱の原因でした。)

Xの環境でカメラが使用できるか確認します。

カメラの確認するソフトは色々ありますが、今回はguvcviewを使用してみました。

インストールは簡単で

$ sudo apt-get install guvcview

でOKです。あとは

$ guvcview &

で起動して、以下のように表示されていればOKです。

f:id:ueponx:20170122150741j:plain

動作に全く問題はありません。昔はともかく、最近のカメラはHD画質も行けるため、良い画質です。

以前のエントリでKINECTを使用していましたが、そのときに使用したcamoramaでも同様です。

$ camorama -d /dev/video0 &

uepon.hatenadiary.com

f:id:ueponx:20170122154355p:plain

pythonからOpenCV経由でキャプチャしてみる

実際にはpythonからのキャプチャを行いたいのでOpenCVのインストールを行います。KINECTのエントリでもインストールしていますが、復習です。

$ sudo apt-get install python-opencv

これでインストール完了です。 最近知ったのですが、モジュールのインストールの確認だけであれば、わざわざインタラクティブシェルを起動しなくても、以下のようなコマンドで問題無いようです。

$ python -c 'import cv2'

あとはpythonからキャプチャを行います。

$ python
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> c = cv2.VideoCapture(0)
>>> r, img = c.read()
>>> cv2.imwrite('capture.jpg', img)
True
>>>

一応、Trueが返されているので成功してそうです。キャプチャしたphoto.jpgを 確認すると

f:id:ueponx:20170122160412j:plain

あれ、真っ黒?

処理もデバイスもうまく動作しているのですが、何故かキャプチャがうまくいかないようです。 とりあえず、インタラクティブシェルでは特定が難しいのでプログラム化します。

カメラ特有の設定値、解像度変更、もしかして非同期的な処理があってファイルI/Oが終わるまえに終わってしまったなどを 考慮してコーディングして確認をしてみました。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import cv2

c = cv2.VideoCapture(0) #1 
r, img = c.read() #2
cv2.imwrite('capture.jpg', img) #3
c.release() #4

このファイルでも画像は真っ黒のままでした。予想としては#2の処理が遅くなっているのかなと思い、OpenCVの処理を行っている各行間にtime.sleep(3)を挿入してみたのですが、やはり結果は同じでした。処理に時間がかかっていて問題があるというわけでは内容です。

そこで、ダメ元で以下のように

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cv2
import time

cap = cv2.VideoCapture(0)
while(cap.isOpened()):
    print('capture process')
    cap.read()
    r, img = cap.read()
    path = 'capture.jpg'
    cv2.imwrite(path, img)
    if(r == True):
    break;
cap.release()

無限ループを回して、何回もキャプチャを行ってみるという処理にしてみました。 このプログラムを動作させ、Ctrl+Cで中断すると無事にキャプチャができていました。

f:id:ueponx:20170122163047j:plain

そこで、やっと気が付きました。どうも起動後初回のキャプチャでは画像が真っ暗になるという特徴があるようです。 MicrosoftのLifeCamではどうなるかなと思い、変更すると、画像は真っ暗にはならず問題ありませんでした。

あくまでも予想ですが、Logicoolのhd-webcam-c615では初回キャプチャは空振ってしまうので、2回目以降を使用する必要があるようです。 この予想をもとに以下のようなコードに変更しました。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import cv2

c = cv2.VideoCapture(0)
c.read()
r, img = c.read()
cv2.imwrite('capture.jpg', img)
c.release()

2回目のキャプチャをファイルに保存するという変更です。 これによりキャプチャ結果も問題がなくなりました。結果からしか判断できませんが、そういうカメラの特徴があったのだと思います。

おわりに

問題なくpythonをつかってOpenCV経由でキャプチャができました。初回のキャプチャがうまくいかないというカメラもあるのだなという教訓が得られたので、今回はよしとします。以降はOpenCVを使用したトラッキングなどをやってみたいと思います。

RaspberryPiでWindowsからリモートデスクトップ接続する【Pixel版】

RaspberryPiでWindowsからリモートデスクトップ接続する【Pixel版】

新しく環境設定をしたRaspberryPiでXを使ったカメラアプリケーションをテストしようとしたのですがリモートデスクトップで接続がうまくできません。 以前にもRaspberryPiでWindowsからリモートデスクトップ接続に関するエントリを書きました…

uepon.hatenadiary.com

しかし、OSをのバージョンが新しいものになり、同じ設定では同様にリモートデスクトップ接続はできなくなってしまいました。

以前は以下のようにxrdpをインストールしていましたが、

$ sudo apt-get install xrdp

この後にリモートデスクトップ接続を行うと接続されるはずなのですが、

f:id:ueponx:20170115222256p:plain

ここまではくるのですが、ログイン後以下のようなダイアログが表示されます。

f:id:ueponx:20170115222735p:plain

OK】ボタンをクリックするとログイン画面に戻ります。 最近のRaspbianのイメージでは接続後にエラーダイアログが表示され、リモートデスクトップは開始されません。RaspberryPiでも、x86版Pixelでも例外では無いようです。

リモートデスクトップを再設定する

ググれば出てきますが、こちらの情報を参考にしました。

qiita.com

以下の手順でいいようです。

必要があればxrdpをアンインストールする

$ sudo apt-get remove xrdp

tightvncserverをインストールする

新しいRaspbianにはvncサーバがインストールされていないのが原因かと思います。

$ sudo apt-get install tightvncserver

xrdpをインストールする

sudo apt-get install xrdp

キーマップの設定を変更する

以前同様にキーマップを日本語キーボード用に設定をします。

~ $ wget http://w.vmeta.jp/temp/km-0411.ini
~ $ cd /etc/xrdp/
/etc/xrdp $ sudo cp ~/km-0411.ini .
/etc/xrdp $ sudo ln -s km-0411.ini km-e0010411.ini   
/etc/xrdp $ sudo ln -s km-0411.ini km-e0200411.ini
/etc/xrdp $ sudo ln -s km-0411.ini km-e0210411.ini
/etc/xrdp $ sudo service xrdp restart

これで終了です。

リモートデスクトップ接続する

改めてリモートデスクトップ接続を行うと…

f:id:ueponx:20170115231120p:plain

無事に成功しました。Hyper-V上のx86版のRaspberryPixelでも同様に接続できました。 やっと、目的のことをやれるようになれました。

Raspberry PixelをHyper-V環境にインストールしてみる

Raspberry PixelをHyper-V環境にインストールしてみる

以前のエントリで旧型のPCにRaspberry Pixelをインストールしました。

uepon.hatenadiary.com

今度はHyper-Vの環境にRaspberry Pixelをインストールをしてみます。仮想環境ではメモリや記憶容量などが少ないほうが良いので、その他の軽量Linuxと比べてもRaspberry Pixelはなかなかよい選択肢なのかなと思います。

ただ、isoイメージをそのまま使って起動するとDVDイメージを使ったLive設定と同じになるため設定などの変更(ロケールの設定、タイムゾーンの設定など)が行えない、ファイルの保存ができないなど色々と不都合があります。そこで今回はそれらの設定も可能な様にインストールを行います。

手順

今回行う手順を簡単に説明すると以下のようになります。

  1. isoイメージをダウンロードし、拡張子を変更
  2. イメージファイルをvhdファイルに変換
  3. Hyper-V仮想マシンを作成
  4. 仮想マシンをディスクイメージを変換する
  5. 仮想マシンの設定

ここでポイントになるのはisoのイメージをHyper-V仮想マシンで使用可能なvhd形式に変換しているところになります。


isoイメージをダウンロードし、拡張子を変更

http://downloads.raspberrypi.org/pixel_x86/images/pixel_x86-2016-12-13/2016-12-13-pixel-x86-jessie.iso

まず、上記のリンクからisoイメージをダウンロードします。(既にダウンロードしている場合には不要です) ダウンロードしたらファイルの拡張子をisoからimgに変更します。

(変更前)pixel_x86-2016-12-13/2016-12-13-pixel-x86-jessie.iso  f:id:ueponx:20170106214643j:plain

(変更後)pixel_x86-2016-12-13/2016-12-13-pixel-x86-jessie.img f:id:ueponx:20170106214847j:plain

イメージファイルをvhdファイルに変換

続いてはイメージファイルの変換を行います。先程ファイルの拡張子を変換したのは今回使用する変換ツールがisoという拡張子を使用できないために変換をしています。こちらで紹介する変換ツール以外でisoファイルを使用可能であれば、前述の拡張子変換の作業は不要です。

今回使用した変換ツールは以下です。

f:id:ueponx:20170106214702j:plain

www.starwindsoftware.com

こちらでも紹介されていました。

【レビュー】仮想ディスクフォーマットをVMDK/VHD/IMGへ相互変換「StarWind (V2V) Converter」 - 窓の杜

本当は以下のPowerShellでisoもそのまま使えるようなので使いたかったのですが、何故か起動できずハマっていたので上記で代用しています。

gallery.technet.microsoft.com

StarWind V2V Image Converterはダウンロードに登録が必要ですが、それ以外は制限はないようです。 インストールはインストーラーに従うだけなので省略します。

インストールが終わったらStarWind V2V Image Converterを起動します。

起動すると広告表示されるので、【次へ】ボタンをクリックして進みます。

f:id:ueponx:20170105215358j:plain

まずはSourceとなるイメージの場所の設定を指定します。今回はPCにダウンロードしたファイルを使用するので【Local file】を選択し【Next >】ボタンをクリックします。

f:id:ueponx:20170105220816j:plain

次はイメージファイルを選択します。先程、拡張子を変更したファイルを選択し【Next >】ボタンをクリックします。

f:id:ueponx:20170106215230j:plain

続いては変換するイメージファイルのフォーマットを選択します。今回は【Microsoft VHD growable image】(増加可能なVHDフォーマット)を選択して【Next >】ボタンをクリックします。やってみたわけではありませんが【Microsoft VHD pre-allocateed image】(固定サイズVHDフォーマット)でもいいのかなと思います。また、【Microsoft VHDX image】でも行けると思いますが、選択した場合は移行の作業も適宜読み替えて行ってください。

f:id:ueponx:20170106215241j:plain

今度はファイルの保存先を選択します。PC上に保存するので【Local file】を選択し【Next >】ボタンをクリックします。

f:id:ueponx:20170105223611j:plain

最後にファイル名を指定します。わかりやすい場所に保存すれば問題ないかと思います。

f:id:ueponx:20170106215409j:plain

【Next >】ボタンをクリックすると処理が開始されます。

f:id:ueponx:20170106215426j:plain

f:id:ueponx:20170106215437j:plain

出来上がったファイルはC:\Users\Public\Documents\Hyper-V\Virtual hard disksに保存すると、Hyper-VのデフォルトのHDDイメージを保存するフォルダなので後の処理が楽かなと思います。処理が完了したら【Finish】ボタンをクリックします。

f:id:ueponx:20170105223959j:plain

Hyper-V仮想マシンを作成

Hyper-Vマネージャ】を起動して、新しい仮想マシンを作成します。 今回の仮想マシンの名前はpixelとしています。入力したら【次へ】ボタンをクリックします。

f:id:ueponx:20170105224454j:plain

世代の指定では第1世代を選択してください。設定したら【次へ】ボタンをクリックします。

f:id:ueponx:20170105225237j:plain

メモリは多めでも良いと思いますが1024Mbyteでも大丈夫かなと思います。Raspbianベースですので。(大丈夫かなと思いますが、Xは普通に動いていました。)設定したら【次へ】ボタンをクリックします。

f:id:ueponx:20170105225633j:plain

ネットワーク構成は通信可能なものを選択してください。(インターフェースがない場合は作成をしましょう。)設定したら【次へ】ボタンをクリックします。

f:id:ueponx:20170105225717j:plain

仮想ハードディスクの接続設定になりますが、ここでは【既存の仮想ハードディスクを使用する】を選択し、先程作成したvhdファイルを指定します。設定したら【次へ】ボタンをクリックします。

f:id:ueponx:20170105225851j:plain

設定の確認画面になるのでこれで問題なければ【完了】ボタンをクリックします。これで仮想マシンが作成されます。

f:id:ueponx:20170106220340j:plain

処理が終わると仮想マシンの一覧に今回作成した仮想マシン名である【pixel】が追加されます。

f:id:ueponx:20170106220445j:plain

仮想マシンをディスクイメージを変換する

この段階ではディスクイメージがisoのイメージファイルと同じサイズなので大きくしようと思います 仮想マシンの操作の中から【ディスクの編集】を選択します。【仮想ハードディスクの編集ウイザード】が開きます。 そして、先程選択したディスクイメージのvhdファイルを選択し、【次へ】ボタンをクリックします。

f:id:ueponx:20170106221423j:plain

そして、操作の選択から【拡張】を選び、【次へ】ボタンをクリックします。

f:id:ueponx:20170106221957j:plain

仮想マシンで使用するディスクのサイズに変更します。今回は16GBに変更しました。設定が終わったら【次へ】ボタンをクリックします。

f:id:ueponx:20170106222126j:plain

処理の確認画面が表示されますので、問題なければ【完了】ボタンをクリックします。 これで処理は完了です。

仮想マシンの起動

設定が終わったので仮想マシンを起動します。

f:id:ueponx:20170106222956j:plain

起動中に以下のようなダイアログは出ますが、無視して問題ありません。

f:id:ueponx:20170106223143j:plain

起動が完了するとXが立ち上がるので端末を起動して

f:id:ueponx:20170106223233j:plain

sudo fdsik -lでディスク状況を確認します。isoイメージサイズではなく、先程指定したサイズになっていれば問題ないと思います。

仮想マシンの設定

これでOSの設定などが保存されるようになっていますので以下のブログに従って設定すると日本語化もうまくいくと思います。Pixelのx86版ではRaspbianと違ってRaspi-configコマンドがなかったので、このブログの情報はかなり助かりました。

qiita.com

sshも可能になって、WindowsからTeratermで接続も可能になり

f:id:ueponx:20170106224752j:plain

ブラウザでも日本語が表示できています。・・・↓の画像ではわかりにくいですが。

f:id:ueponx:20170106224956j:plain

おわりに

Hyper-V環境でも無事にRaspberry Pixelインストールすることができました。本当に少ないリソースで軽快に動いてくれるのでいいですね。特にメモリの少ないノートPCでも仮想環境としてLinux系のOSが使えるのが助かります。

RaspberryPiとArduinoを連携する【Firmata編】

RaspberryPiとArduinoを連携する【Firmata編】

前回のエントリではRaspberryPiとArduinoをUSBシリアルで接続をしてみたというものでした。

uepon.hatenadiary.com

すると・・・

ぐえ、スペル適当にしてあとで治そうと思っていたのですが直してませんでした。Johnny-Fiveもスペル違ってたしw。 ってことで、引き続きFirmataでRaspberryPiとArduinoを連携させてみたいと思います。

んでFirmataって?

Firmataとは?

http://firmata.org/wiki/Main_Page

いろいろググってみたところFirmataはシリアル通信を介してPC等のホストマシンから Arduinoやその他マイコンボード等のデバイスを制御するためのプロトコルのようです。

RaspberryPiというかpythonからこのプロトコルを使う場合には

github.com

github.com

上記2つがあるようです。更新履歴をみるとpyFirmataのほうが新しいようですのでそれを使用してみます。python-firmataのメンテナンスは長期間行われていないっぽいですね。

Firmata使用のためのArduino側の準備

以下のドキュメントを見ると

https://raspberrypi-aa.github.io/session3/firmata.html

  1. Click File->Examples->Firmata->StandardFirmata
  2. From the Tools->Board menu, select the type of Arduino you are using.
  3. From the Tools->Serial Port menu, choose the USB port to which your Arduino is connected.
  4. Click the upload button (it looks like a right arrow, just next to the checkmark) and wait for your sketch to upload. A message in the bottom black windowwill indicate success or failure
  5. Once the Firmata sketch is loaded on your Arduino, you can test it out with the Firmata Test Program.

という手順で準備ができるそうです。

まずはArduinoIDEを起動します。

f:id:ueponx:20170101212659p:plain

メニューバーから【ファイル】→【スケッチ例】→【Firmata】→【StandardFirmata】を選択します。

f:id:ueponx:20170101212924p:plain

するとエディタ部分にStandardFirmataのソースコードが表示されます。これを接続したArduinoに書き込みを行います。 このときArduinoを接続したポートとボードタイプを適切にしておく必要があります。

f:id:ueponx:20170101213421p:plain

【Ctrl+U】で書き込みを行います。

f:id:ueponx:20170101213725p:plain

このようにエラーが無ければ作業は完了です。

pyFirmataのインストール

続いてはRaspberryPi側でpython環境の Githubのドキュメントを見ながらのインストールになります。

$ sudo pip install pyfirmata
Downloading/unpacking pyfirmata
  Downloading pyFirmata-1.0.3-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): pyserial in /usr/lib/python2.7/dist-packages (from pyfirmata)
Installing collected packages: pyfirmata
Successfully installed pyfirmata
Cleaning up...

インストール作業としてはこれで完了です。以下のようにpipのlistで以下のように確認します。

$ pip list
()
pyFirmata (1.0.3)
()

リスト上に表示されればインストールはできています。 あとはpythonインタプリタで動作を確認します。 以下では13pinに配置されているLEDのON/OFFを行います。

$ python
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyfirmata import Arduino, util
>>> board = Arduino('/dev/ttyACM0')
>>> board.digital[13].write(1)
>>> board.digital[13].write(0)

ポートのアクセスですが、

pin13 = board.get_pin('d:13:o')
pin13.write(1)

という風にも記載することができます。d:13:oはデジタル13pinをoutputにするという意味になります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pyfirmata import Arduino, util
import time

board = Arduino('/dev/ttyACM0')
pin13 = board.get_pin('d:13:o')

print('start')
pin13.write(1)
time.sleep(3)
pin13.write(0)
time.sleep(3)
print('end')

まとめ

使っていて感じたのはFirmataはどちらかというと主従関係がはっきリしている場合に使うのかなと。 Arduino側のコードをほとんど記述しなくてもGPIOなどのポートが自由に使用できるのでそういった意味では実装が容易にできるもメリットだと思います。 接続したArduinoが並列で動作できる点ではシリアルを使っての制御がいいかなと思いますが、データの収受で同期を取るのが面倒かなと思いますが、そのあたりは臨機応変にやるということでしょうか。

RaspberryPiとArduinoを連携する【USBシリアル編】

RaspberryPiとArduinoを連携する

RaspberryPiを使っているとセンサ系での物足りなさを感じてくることが良くあります。 特にアナログ値を使うようなセンサでは回路の知識がないと悲しくなります。 そこでそういった部分をカバーすることを考えるとArduinoとの連携を行いたくなってきます。 ArduinoであればGroveインターフェースで回路側の負担が少なくできることもメリットです。 あとオリジナルのUnoではなく激安品まで考えると1枚当たりのコストはセンサより安価にもできます。 (300円程度の商品もあるようです。絶対という保証はないですが。)

Arduino以外にmbedも使うことができると思うのですが、まずはArduinoってことで。

Arduinoとの接続は

  • I2C接続
  • シリアル通信
  • Firmata

とありますが、今回はシリアル通信を行うことにします。 個人的にはシリアルが一番汎用的に使用できるロジックだと思いますが、I2Cもいい選択肢かなと思います。 コードのベースができてしまえば使いまわしができます。Firmataはどうなんでしょうか?(RaspberryPiでFirmata接続するArduinoの エントリがあんまりないなと思いますが一般的じゃない?node.jsでJohnny-Fiveのほうが一般的?)

USBポートにArduinoを接続してみる

【接続前】

$ lsusb
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

【接続後】

$ lsusb
Bus 001 Device 005: ID 2341:0001 Arduino SA Uno (CDC ACM)
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Bus 001 Device 005: ID 2341:0001 Arduino SA Uno (CDC ACM)が追加されています。Arduinoって書いてあるので発見は楽です。認識はされているので今度はシリアルデバイスとしてどのように認識されているか確認してみます。

【接続前】

$ ls /dev/ttyA*
/dev/ttyAMA0

【接続後】

$ ls /dev/ttyA*
/dev/ttyACM0  /dev/ttyAMA0

接続後にはシリアルデバイスとして/dev/ttyACM0が追加されています。これを使うことになります。

Arduinoのシリアル接続制御のひな形

Arduinoとの接続がうまく行ったのでArduinoでシリアル送受信をする処理を書いてみました。stringのライブラリがうまく使えなかったので微妙なところはあるのですが…

f:id:ueponx:20170101132859j:plain

#include <String.h>
#define maxLength 64
String inString = String(maxLength);

void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  inString = "";
}

void loop() {
  if (Serial.available() > 0) {
    char inChar = Serial.read();
    if (inString.length() < maxLength) {
      inString.concat(String(inChar));
      if (inChar == '\n') {
        if (inString.startsWith("ON")) {
          Serial.println("<--HI-->");
          digitalWrite(13, HIGH);
        } else if (inString.startsWith("OFF")) {
          Serial.println("<--LOW-->");
          digitalWrite(13, LOW);
        }
        inString = "";
      }
      Serial.println(inString);
    }
    else {
      Serial.println("Maximum number of characters.");
    }
  }
}

このコードではON【CR】【LF】(またはON【LF】='\n')を受信すると13pin(オンボード上)のLEDをONとし、 OFF【CR】【LF】(またはOFF【LF】)を受信するとLEDをOFFするという動きになります。 (厳密にいうとONから始まり【LF】で終わるような場合にONし、OFFから始まり【LF】で終わるような場合はOFFにします。)

この受信文字("ON"など)の処理部分を拡張することで多様な処理ができるかなと思います。 ただ、センサの値によりトリガとして動作させる時には別途処理は考えないといけないかと。

pythonからシリアル制御を行う

pySerialを使用します。

http://pythonhosted.org//pyserial/

このブログでも過去に使用していますので以下を参考にします。

uepon.hatenadiary.com

インタラクティブシェルで以下のようにするとLEDのON/OFFができました。

$ python
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> import time
>>> s = serial.Serial('/dev/ttyACM0',9600)
>>> time.sleep(2)
>>> s.write("ON\n")
3
>>> s.write("OFF\n")
4
>>> s.write("ON\n")
3
>>>

これでシリアル通信を介したRaspberryPiとArduinoの通信処理はうまく行ったようです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import serial
import time

s = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(2)
s.write("OFF\n")
time.sleep(10)
s.write("ON\n")
s.close()

まとめ

とりあえず、RaspberryPiとArduinoをUSB接続してシリアルで制御できました。 これでそれなりにセンサデバイスとしてArduinoが使えそうです。 なんとなくですが、能動的にセンサーのデータを取得するのはArduinoで行い、RaspberryPiは受信に徹する方がいいのかなと思います。その場合は、RaspberryPi側での受信にはtimeoutを設定することでブロッキング時間を短縮したほうがいいかなと思います。例えば以下のような感じ。

s = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=3)

折角なので他の方法も試してみたいと思います。

RaspberryPiのSDカードアダプタを使用する

RaspberryPiのSDカードアダプタを使用する

実はこれまでRaspberryPiはRaspberry Pi 1 Model B使用していたのですが、やっぱりSDカードの出っ張りが気になってきました。 ということで、出っ張らないSDカードアダプタを購入し、SDカードをMicroSDカードにに変更することにしました。 これまで使っていたSDカードはこれになります。

16GbyteのSDカードだったので以下のカードへの移行を行います。

出っ張らないSDカードのアダプタは

を使用することにしました。

早速SDカードのバックアップをとります。いつも通りWin32DiskImagerを使用します。

ja.osdn.net

バックアップはこのあたりのエントリで。(昔は使い方の勘違いがあったので)

uepon.hatenadiary.com

バックアップが作成できたらMicroSDカードに書き込むわけですが、

f:id:ueponx:20161228130224j:plain

あれ?サイズが違うエラー?

カードの刻印には16Gbyteと書いてあるのですが、どうも微妙にサイズを違う?

再インストールに向けての準備(Sambaのインストール)

これでは折角のアダプタが無駄になるのでファイルのバックアップ(イメージのバックアップではなく)を行って再インストールを行おうと思います。 FTPでバックアップをするのは面倒なので、RaspberryPiにsambaをインストールします。

Sambaのインストールと設定と接続

こちらのブログを参考にしました。以下でインストールします。かなり時間がかかるのでびっくりしますが待機です。

$ sudo apt-get update
$ sudo apt-get install samba

ファイルのバックアップをとるだけなのでブログの設定と同様に

共有設定は以下で追加します。

  • 共有名 : pi
  • 共有するフォルダ : /home/pi (ユーザー名「pi」でログインした際のホームフォルダ
  • 読み込みだけでなく、書き込みも可能
  • クライアントからの接続は、ゲスト接続
  • サーバー側では、ファイル操作を、ユーザー「pi」 によって実行

設定ファイルをvimで開き

$ sudo vim /etc/samba/smb.conf
[pi]
path = /home/pi
read only = No
guest ok = Yes
force user = pi

以上を追加します。

設定の追加後に以下のようにサービスを再起動します。

$ sudo service smbd restart

これでWindows側からアクセスが可能になります。

まとめ

単純に16GByteと書いてあるメモリカードのサイズが一致しないこともあったので結構焦ってしまいました。 折角なのでRASPBIAN JESSIE WITH PIXELも2016-11-25に出たので、これまでの環境をクリーンインストールして移行したいと思います。

www.raspberrypi.org