RaspberryPiでgoogle-home-notifierをインストールしてお好みの言葉を話してみる

RaspberryPiでgoogle-home-notifierをインストールしてお好みの言葉を話してみる

GoogleHomeMiniが年末に安売りになったので自分も購入し、天気やキッチンタイマーのようなものに使用していました。 とはいっても、3日ぐらいで飽きるので他の使い方がないのかなと思い、IFTTTからGoogleスプレッドシートへ記録なども行っていました。 IFTTTの連携は結構便利だなーとは思っているのですが言葉をいろいろ決めたりしないといけないので、制限がおおいなあというのが、 実際のところでした。そこで、RaspberryPiと連携し、話す言葉を変更できる連携に手をだしました。

このネタは2017年のアドベントカレンダーではさんざんやりつくされた感じはしたのですが、自分もその波に乗ってみました。 それでもつまずく自分…。今年もいろいろなトラップに引っかかる予感です。

今回紹介するgoogle-home-notifierは非常に簡単な呼び出しを行うだけで話すことができるのでとても便利です。 ただ、RaspberryPiのように常時起動の機器がないと実現ができないのは少しハードルはあるかなと思います。

githubを参考に

github.com

Node.jsの準備

google-home-notifierNode.jsのモジュールなので、新しめのNode.jsの設定をします。最近のバージョンは4.x系なので昔よりはマシになりましたが 最近のLTSあたりにしておくのが無難かなと思います。

過去のエントリーを参考にして設定します。

uepon.hatenadiary.com

やっててよかった備忘録。2018/01/08現在は以下のバージョンがLTSのようです。

$ node -v
v8.9.4

google-home-notifierのインストール

ググったのサイトをみていると

# 任意のフォルダに移動し
$ npm init
$ npm install google-home-notifier

こんな感じで問題ないようなことが書いてあるのですが。 Node.jsの初心者の私にはピンときていませんでした…。

あと、モジュールのインストールを行うとエラーが発生して、インストールが完了しませんでした。

公式のドキュメントにRaspberryPiの項目があるのでそれを見ると

Raspberry Pi
If you are running from Raspberry Pi make sure you have the following before nunning "npm install": Use the latest nodejs dist.

curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
sudo apt-get install nodejs

Also install these packages:

sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

てな記載が。別途パッケージが必要なのね。(ちゃんとドキュメントを読みましょう) パッケージ名を確認するとavahiとかmdnsなライブラリが必要のようです。 (前半部分はNode.jsのインストールなので既に行っていることから省略でもも問題はありません)

インストールに必要な事前準備

以下でパッケージをインストールします。

【コマンド】

$ sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

【ログ】

$ sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
libnss-mdns はすでに最新バージョン (0.10-8) です。
libnss-mdns は手動でインストールしたと設定されました。
以下の追加パッケージがインストールされます:
  libavahi-client-dev libavahi-common-dev libavahi-compat-libdnssd1
  libdbus-1-dev
以下のパッケージが新たにインストールされます:
  git-core libavahi-client-dev libavahi-common-dev
  libavahi-compat-libdnssd-dev libavahi-compat-libdnssd1 libdbus-1-dev
アップグレード: 0 個、新規インストール: 6 個、削除: 0 個、保留: 3 個。
424 kB のアーカイブを取得する必要があります。
この操作後に追加で 1,285 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://mirrordirector.raspbian.org/raspbian stretch/main armhf git-core all 1:2.11.0-3+deb9u2 [1,410 B]
取得:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-common-dev armhf 0.6.32-2 [62.6 kB]
取得:3 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libdbus-1-dev armhf 1.10.24-0+deb9u1 [200 kB]
取得:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-client-dev armhf 0.6.32-2 [56.5 kB]
取得:5 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-compat-libdnssd1 armhf 0.6.32-2 [44.0 kB]
取得:6 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libavahi-compat-libdnssd-dev armhf 0.6.32-2 [58.8 kB]
424 kB を 4秒 で取得しました (102 kB/s)
以前に未選択のパッケージ git-core を選択しています。
(データベースを読み込んでいます ... 現在 124934 個のファイルとディレクトリがインストールされています。)
.../0-git-core_1%3a2.11.0-3+deb9u2_all.deb を展開する準備をしています ...
git-core (1:2.11.0-3+deb9u2) を展開しています...
以前に未選択のパッケージ libavahi-common-dev:armhf を選択しています。
.../1-libavahi-common-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-common-dev:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libdbus-1-dev:armhf を選択しています。
.../2-libdbus-1-dev_1.10.24-0+deb9u1_armhf.deb を展開する準備をしています ...
libdbus-1-dev:armhf (1.10.24-0+deb9u1) を展開しています...
以前に未選択のパッケージ libavahi-client-dev:armhf を選択しています。
.../3-libavahi-client-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-client-dev:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libavahi-compat-libdnssd1:armhf を選択しています。
.../4-libavahi-compat-libdnssd1_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-compat-libdnssd1:armhf (0.6.32-2) を展開しています...
以前に未選択のパッケージ libavahi-compat-libdnssd-dev:armhf を選択しています。
.../5-libavahi-compat-libdnssd-dev_0.6.32-2_armhf.deb を展開する準備をしています ...
libavahi-compat-libdnssd-dev:armhf (0.6.32-2) を展開しています...
libdbus-1-dev:armhf (1.10.24-0+deb9u1) を設定しています ...
libavahi-common-dev:armhf (0.6.32-2) を設定しています ...
libavahi-client-dev:armhf (0.6.32-2) を設定しています ...
libavahi-compat-libdnssd1:armhf (0.6.32-2) を設定しています ...
libc-bin (2.24-11+deb9u1) のトリガを処理しています ...
git-core (1:2.11.0-3+deb9u2) を設定しています ...
libavahi-compat-libdnssd-dev:armhf (0.6.32-2) を設定しています ...

google-home-notifierのインストール

google-home-notifierのインストールはnpmで行います。

今回作業するディレクトリはgooglehomeSampleとしました。適宜読み替えて作業をしてください。 任意のディレクトリとなっていますが、google-home-notifierというモジュール名と同じディレクトリ名にすると エラーになりますので気を付けてください。(自分はハマった

【コマンド】

$ mkdir googlehomeSample
$ cd googlehomeSample/
$ npm init
$ npm install google-home-notifier

公式ページではインストール前のnpm initについては言及がされていませんでしたが、事前にしておくと警告行が減ったので含めています。 npm initではパッケージバージョンの情報やライセンス情報の入力などを求められますが、そのままリターンしました。

【ログ】

$ mkdir googlehomeSample
$ cd googlehomeSample/

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (googlehomesample)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/pi/googlehomeSample/package.json:

{
  "name": "googlehomesample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes)

$ npm install google-home-notifier

> mdns@2.3.4 install /home/pi/googlehomeSample/node_modules/mdns
> node-gyp rebuild

make: ディレクトリ '/home/pi/googlehomeSample/node_modules/mdns/build' に入ります
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_sd.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_browse.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_enumerate_domains.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_get_addr_info.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_process_result.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref_deallocate.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_ref_sock_fd.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_register.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_resolve.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/dns_service_update_record.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/mdns_utils.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/network_interface.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/socket_watcher.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_ref.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_create.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_deallocate.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_set_value.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_get_length.o
  CXX(target) Release/obj.target/dns_sd_bindings/src/txt_record_buffer_to_object.o
  SOLINK_MODULE(target) Release/obj.target/dns_sd_bindings.node
  COPY Release/dns_sd_bindings.node
make: ディレクトリ '/home/pi/googlehomeSample/node_modules/mdns/build' から出ま す

> ngrok@2.2.24 postinstall /home/pi/googlehomeSample/node_modules/ngrok
> node ./postinstall.js

ngrok - downloading binary https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
ngrok - downloading progress: 5084312/5084312
ngrok - binary downloaded to /home/pi/.ngrok/aHR0cHM6Ly9iaW4uZXF1aW5veC5pby9jLzRWbUR6QTdpYUhiL25ncm9rLXN0YWJsZS1saW51eC1hcm0uemlw.zip
ngrok - unpacking binary
ngrok - binary unpacked to /home/pi/googlehomeSample/node_modules/ngrok/bin/ngrok
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN googlehomesample@1.0.0 No description
npm WARN googlehomesample@1.0.0 No repository field.

+ google-home-notifier@1.2.0
added 138 packages in 170.896s

これでインストールができました。途中でngrokなどもビルドしているようなので少し時間はかかっています。

サンプルを動かす

サンプルは以下のようになっていますが、コアの要素だけを抽出し簡単にしてみました。

【オリジナルのサンプル】 github.com

【機能を絞ったサンプル】

var googlehome = require('google-home-notifier');
var language = 'ja';

googlehome.device('テスト', language);
googlehome.ip('192.168.0.2');// IPアドレスは自分の環境のGoogleHomeの設定に合わせてください

var text = 'こんにちは';

try {
        googlehome.notify(text, function(notifyRes) {
                console.log(notifyRes);
        });
} catch(err) {
        console.log(err);
}

基本的にはgooglehomeの設定(言語設定、IP設定など)を行い、notifyメソッドを実行すると、 いったん音がなり、テキストの読み上げが行われます。

deviceメソッドの第一引数は適当でいいようなのですが、たぶん事前設定した名前にすればIP設定しなくてもいいのかなとなんとなく思いました。(未確認)

警告が表示されますが、特に問題はないようです。 (内容はavahi関連の警告で、今回のコードではIP直接のアクセスだから問題ないのかなと思います。)

【実行のようす】

$ node test.js
*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node&f=DNSServiceRegister>
Device notified

これで無事音声が出力されました。読み上げた音声はたどたどしい抑揚です。

では固定の文字列ではなくコマンドライン引数にしていした文字列を読み上げるコードに変更してみます。

var googlehome = require('google-home-notifier');
var language = 'ja';

googlehome.device('テスト', language);
googlehome.ip('192.168.0.2');// IPアドレスは自分の環境のGoogleHomeの設定に合わせてください

var text = 'こんにちは';

if(process.argv.length == 3){
        text = process.argv[2];
}

try {
        googlehome.notify(text, function(notifyRes) {
                console.log(notifyRes);
        });
} catch(err) {
        console.log(err);
}

省略した場合は「こんにちは」と出力し、引数に指定した場合には「引数に指定した言葉」を話します。

おわりに

話す言葉の制限がかなりあったGoogleHomeではありますが、これでかなり自由度が高くなりました。

RaspberryPi+OpenJTalk+Bluetoothスピーカーなどの組み合わせを、RaspberryPi+google-home-notifier+GoogleHomeに変更することも可能かなと思います。 数字の読み上げなどがどうなるのかはまだテストしていませんが、それなりに動いてくれるのでは?と思ってはいます。

cronやアラームシステムとの組合わせ、WebAPIとの連携なども簡単にできそうなのでなかなか魅力的な感じです。

それにしても、いつになったらAmazon Echoの招待が来るのだろうか…

RaspberryPiに比較的新しいTensorFlowをインストールしてみる(Python2系、Python3系)

RaspberryPiに比較的新しいTensorFlowをインストールしてみる(Python2系、Python3系)

そろそろ、TensorFlowを入れなきゃと思いインストールしてみたのですが、ネットを調べただけで、なにもしていなかったので年末だということもあり設定をしてみました。

github.com

比較的新しいバージョンのインストールエントリーがあったので以下2つを参考にさせてもらいました。基本的に1からビルドするとかなり時間がかかるのですが、これにより時間を大幅に短縮できたのでとても助かりました。ただ、この情報もそのままだとうまくいかない(インストールが失敗する)ので、失敗の状況も含めていろいろ調べて修正してみました。参考になればと思います。

qiita.com

petewarden.com

個人的にはpython3にそろそろ移行していきたいところ(個人的な来年の目標はpython3系に移行することにしています) 手順のエントリーには、python2系、python3系の両方のやり方が書いてあったので、折角なので両方セットアップしてみます。

python2系(version2.7)の手順

TensorFlowのインストール

python開発系のパッケージをインストールしていきます。インストールのログが長いのでコマンドとログを分けました。

コマンド:失敗例

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl

【ログ】

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
Reading package lists... Done
Building dependency tree
Reading state information... Done
python-dev is already the newest version (2.7.13-2).
python-dev set to manually installed.
python-setuptools is already the newest version (33.1.1-1).
python-setuptools set to manually installed.
The following additional packages will be installed:
  gfortran-6 libatlas-dev libatlas3-base libgfortran-6-dev
Suggested packages:
  gfortran-doc gfortran-6-doc libgfortran3-dbg libcoarrays-dev libblas-doc
  liblapack-doc liblapack-doc-man
The following NEW packages will be installed:
  gfortran gfortran-6 libatlas-base-dev libatlas-dev libatlas3-base
  libblas-dev libgfortran-6-dev liblapack-dev
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 11.7 MB of archives.
After this operation, 56.2 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libgfortran-6-dev armhf 6.3.0-18+rpi1 [199 kB]
Get:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf gfortran-6 armhf 6.3.0-18+rpi1 [5,422 kB]
Get:3 http://mirrordirector.raspbian.org/raspbian stretch/main armhf gfortran armhf 4:6.3.0-4 [1,352 B]
Get:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas3-base armhf 3.10.3-1+rpi1 [1,920 kB]
Get:5 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libblas-dev armhf 3.7.0-2 [114 kB]
Get:6 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas-dev armhf 3.10.3-1+rpi1 [65.9 kB]
Get:7 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libatlas-base-dev armhf 3.10.3-1+rpi1 [2,528 kB]
Get:8 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf liblapack-dev armhf 3.7.0-2 [1,483 kB]
Fetched 11.7 MB in 8s (1,304 kB/s)
Selecting previously unselected package libgfortran-6-dev:armhf.
(Reading database ... 122979 files and directories currently installed.)
Preparing to unpack .../0-libgfortran-6-dev_6.3.0-18+rpi1_armhf.deb ...
Unpacking libgfortran-6-dev:armhf (6.3.0-18+rpi1) ...
Selecting previously unselected package gfortran-6.
Preparing to unpack .../1-gfortran-6_6.3.0-18+rpi1_armhf.deb ...
Unpacking gfortran-6 (6.3.0-18+rpi1) ...
Selecting previously unselected package gfortran.
Preparing to unpack .../2-gfortran_4%3a6.3.0-4_armhf.deb ...
Unpacking gfortran (4:6.3.0-4) ...
Selecting previously unselected package libatlas3-base.
Preparing to unpack .../3-libatlas3-base_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas3-base (3.10.3-1+rpi1) ...
Selecting previously unselected package libblas-dev.
Preparing to unpack .../4-libblas-dev_3.7.0-2_armhf.deb ...
Unpacking libblas-dev (3.7.0-2) ...
Selecting previously unselected package libatlas-dev.
Preparing to unpack .../5-libatlas-dev_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas-dev (3.10.3-1+rpi1) ...
Selecting previously unselected package libatlas-base-dev.
Preparing to unpack .../6-libatlas-base-dev_3.10.3-1+rpi1_armhf.deb ...
Unpacking libatlas-base-dev (3.10.3-1+rpi1) ...
Selecting previously unselected package liblapack-dev.
Preparing to unpack .../7-liblapack-dev_3.7.0-2_armhf.deb ...
Unpacking liblapack-dev (3.7.0-2) ...
Setting up libatlas3-base (3.10.3-1+rpi1) ...
update-alternatives: using /usr/lib/atlas-base/atlas/libblas.so.3 to provide /usr/lib/libblas.so.3 (libblas.so.3) in auto mode
update-alternatives: using /usr/lib/atlas-base/atlas/liblapack.so.3 to provide /usr/lib/liblapack.so.3 (liblapack.so.3) in auto mode
Setting up libgfortran-6-dev:armhf (6.3.0-18+rpi1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...
Processing triggers for man-db (2.7.6.1-2) ...
Setting up gfortran-6 (6.3.0-18+rpi1) ...
Setting up gfortran (4:6.3.0-4) ...
update-alternatives: using /usr/bin/gfortran to provide /usr/bin/f95 (f95) in auto mode
update-alternatives: using /usr/bin/gfortran to provide /usr/bin/f77 (f77) in auto mode
Setting up libblas-dev (3.7.0-2) ...
update-alternatives: using /usr/lib/libblas/libblas.so to provide /usr/lib/libblas.so (libblas.so) in auto mode
Setting up libatlas-dev (3.10.3-1+rpi1) ...
Setting up liblapack-dev (3.7.0-2) ...
update-alternatives: using /usr/lib/lapack/liblapack.so to provide /usr/lib/liblapack.so (liblapack.so) in auto mode
Setting up libatlas-base-dev (3.10.3-1+rpi1) ...
update-alternatives: using /usr/lib/atlas-base/atlas/libblas.so to provide /usr/lib/libblas.so (libblas.so) in auto mode
update-alternatives: using /usr/lib/atlas-base/atlas/liblapack.so to provide /usr/lib/liblapack.so (liblapack.so) in auto mode

コマンドの1行目の必須パッケージのインストールはうまく行ったのですが、tensorflowの本体のインストールでは失敗してしまいます。 ブラウザでwhlファイルがあるURLを確認するとファイルのアクセスができない状態のようです。nightlyビルドってこんなものなの?かな。

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl
Collecting tensorflow==1.3.0 from http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl
Exception:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", line 353, in run
    wb.build(autobuilding=True)
  File "/usr/lib/python2.7/dist-packages/pip/wheel.py", line 749, in build
    self.requirement_set.prepare_files(self.finder)
  File "/usr/lib/python2.7/dist-packages/pip/req/req_set.py", line 380, in prepare_files
    ignore_dependencies=self.ignore_dependencies))
  File "/usr/lib/python2.7/dist-packages/pip/req/req_set.py", line 620, in _prepare_file
    session=self.session, hashes=hashes)
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 821, in unpack_url
    hashes=hashes
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 659, in unpack_http_url
    hashes)
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 855, in _download_http_url
    resp.raise_for_status()
  File "/usr/share/python-wheels/requests-2.12.4-py2.py3-none-any.whl/requests/models.py", line 893, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
HTTPError: 404 Client Error: Not Found for url: http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/bazel-out/pi/tensorflow-1.3.0-cp27-none-any.whl

いろいろと考えてnightlyビルドなのでもしかしたら新しいURLに格納されているのかなと思い、サイトを調べてみました。

nightly-pi [Jenkins]

このページから最新のRaspberryPi用のnightlyビルドが取得できそうです。現在はtensorflowのバージョンは1.4になっていますので参考にしたサイトより更に最新のものになります。(わーい)2017.12.30現在のビルドは#140なのでそれを使用してインストールを行っています。URLを変更して以下の様にします。

【インストールコマンド変更】

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl

【ログ】

$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl
Collecting tensorflow==1.4.0 from http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl
  Downloading http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl (56.3MB)
    100% |????????????????????????????????| 56.3MB 10.9MB/s
Collecting protobuf>=3.4.0 (from tensorflow==1.4.0)
  Downloading protobuf-3.5.1-py2.py3-none-any.whl (388kB)
    100% |????????????????????????????????| 389kB 550kB/s
Collecting absl-py>=0.1.6 (from tensorflow==1.4.0)
  Downloading absl-py-0.1.7.tar.gz (78kB)
    100% |????????????????????????????????| 81kB 1.6MB/s
Collecting tensorflow-tensorboard (from tensorflow==1.4.0)
  Downloading tensorflow_tensorboard-0.1.8-py2-none-any.whl (1.6MB)
    100% |????????????????????????????????| 1.6MB 154kB/s
Requirement already satisfied: six>=1.10.0 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: enum34>=1.1.6 in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Collecting backports.weakref>=1.0rc1 (from tensorflow==1.4.0)
  Downloading backports.weakref-1.0.post1-py2.py3-none-any.whl
Requirement already satisfied: wheel in /usr/lib/python2.7/dist-packages (from tensorflow==1.4.0)
Collecting mock>=2.0.0 (from tensorflow==1.4.0)
  Downloading mock-2.0.0-py2.py3-none-any.whl (56kB)
    100% |????????????????????????????????| 61kB 1.8MB/s
Requirement already satisfied: setuptools in /usr/lib/python2.7/dist-packages (from protobuf>=3.4.0->tensorflow==1.4.0)
Collecting markdown>=2.6.8 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading Markdown-2.6.10.zip (414kB)
    100% |????????????????????????????????| 419kB 646kB/s
Requirement already satisfied: werkzeug>=0.11.10 in /usr/lib/python2.7/dist-packages (from tensorflow-tensorboard->tensorflow==1.4.0)
Collecting bleach==1.5.0 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading bleach-1.5.0-py2.py3-none-any.whl
Collecting html5lib==0.9999999 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading html5lib-0.9999999.tar.gz (889kB)
    100% |????????????????????????????????| 890kB 261kB/s
Collecting funcsigs>=1; python_version < "3.3" (from mock>=2.0.0->tensorflow==1.4.0)
  Downloading funcsigs-1.0.2-py2.py3-none-any.whl
Collecting pbr>=0.11 (from mock>=2.0.0->tensorflow==1.4.0)
  Downloading pbr-3.1.1-py2.py3-none-any.whl (99kB)
    100% |????????????????????????????????| 102kB 954kB/s
Building wheels for collected packages: absl-py, markdown, html5lib
  Running setup.py bdist_wheel for absl-py ... done
  Stored in directory: /root/.cache/pip/wheels/c4/71/71/7bd70f858f062d3f99990dcbc3f45b795bde057a42f971537f
  Running setup.py bdist_wheel for markdown ... done
  Stored in directory: /root/.cache/pip/wheels/1e/5a/55/a80b200d12e234d575ad68c1528593d1ce488720b65b24e48c
  Running setup.py bdist_wheel for html5lib ... done
  Stored in directory: /root/.cache/pip/wheels/6f/85/6c/56b8e1292c6214c4eb73b9dda50f53e8e977bf65989373c962
Successfully built absl-py markdown html5lib
Installing collected packages: protobuf, absl-py, markdown, html5lib, bleach, tensorflow-tensorboard, backports.weakref, funcsigs, pbr, mock, tensorflow
Successfully installed absl-py-0.1.7 backports.weakref-1.0.post1 bleach-1.5.0 funcsigs-1.0.2 html5lib-0.9999999 markdown-2.6.10 mock-2.0.0 pbr-3.1.1 protobuf-3.5.1 tensorflow-1.4.0 tensorflow-tensorboard-0.1.8

コマンド:成功例

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo pip2 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl

一般のパッケージに比べれば少し時間はかかりますが、そんな大した時間ではありません。これでインストールが完了しましたので対話型インターフェースで実行を行ってみます。

【実行テスト】

$ python
Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>

TensorFlowが無事にインストールされたようです。やりました!

Kerasもインストールする

Kerasは,Pythonで書かれた,TensorFlowまたはCNTK,Theano上で実行可能な高水準のニューラルネットワークライブラリです. Kerasは,迅速な実験を可能にすることに重点を置いて開発されました. アイデアから結果に到達するまでのリードタイムをできるだけ小さくすることが,良い研究をするための鍵になります.

Kerasのサイトは以下になります。

Keras Documentation

https://keras.io/ja/keras.io

Keras Documentation

Kerasのインストールに関しては比較的簡単です。あとは依存系のライブラリモジュールもインストールしておきます。

【コマンド】

$ sudo apt-get install python-h5py
$ sudo pip install keras

【ログ】

$ sudo apt-get install python-h5py
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  libaec0 libhdf5-100 libsz2
Suggested packages:
  python-h5py-doc
The following NEW packages will be installed:
  libaec0 libhdf5-100 libsz2 python-h5py
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 1,790 kB of archives.
After this operation, 7,210 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libaec0 armhf 0.3.2-1 [19.4 kB]
Get:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libsz2 armhf 0.3.2-1 [5,836 B]
Get:3 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libhdf5-100 armhf 1.10.0-patch1+docs-3 [1,203 kB]
Get:4 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python-h5py armhf 2.7.0-1 [561 kB]
Fetched 1,790 kB in 3s (480 kB/s)
Selecting previously unselected package libaec0:armhf.
(Reading database ... 123241 files and directories currently installed.)
Preparing to unpack .../libaec0_0.3.2-1_armhf.deb ...
Unpacking libaec0:armhf (0.3.2-1) ...
Selecting previously unselected package libsz2:armhf.
Preparing to unpack .../libsz2_0.3.2-1_armhf.deb ...
Unpacking libsz2:armhf (0.3.2-1) ...
Selecting previously unselected package libhdf5-100:armhf.
Preparing to unpack .../libhdf5-100_1.10.0-patch1+docs-3_armhf.deb ...
Unpacking libhdf5-100:armhf (1.10.0-patch1+docs-3) ...
Selecting previously unselected package python-h5py.
Preparing to unpack .../python-h5py_2.7.0-1_armhf.deb ...
Unpacking python-h5py (2.7.0-1) ...
Setting up libaec0:armhf (0.3.2-1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...
Setting up libsz2:armhf (0.3.2-1) ...
Setting up libhdf5-100:armhf (1.10.0-patch1+docs-3) ...
Setting up python-h5py (2.7.0-1) ...
Processing triggers for libc-bin (2.24-11+deb9u1) ...

$ sudo pip install keras
Collecting keras
  Using cached Keras-2.1.2-py2.py3-none-any.whl
Collecting pyyaml (from keras)
Requirement already satisfied: six>=1.9.0 in /usr/lib/python2.7/dist-packages (from keras)
Collecting scipy>=0.14 (from keras)
  Using cached scipy-1.0.0.tar.gz
Requirement already satisfied: numpy>=1.9.1 in /usr/lib/python2.7/dist-packages (from keras)
Building wheels for collected packages: scipy
  Running setup.py bdist_wheel for scipy ... done
  Stored in directory: /root/.cache/pip/wheels/b9/3e/bd/e9f0e1707c4be2bb1f671fd4246028d5d2e10cd70740ffd801
Successfully built scipy
Installing collected packages: pyyaml, scipy, keras
Successfully installed keras-2.1.2 pyyaml-3.12 scipy-1.0.0

これでインストールできました。(2時間弱かかりました)

python3系(version3.4またはversion3.5)の手順

pippip3と明示する必要があります。

TensorFlowのインストール

pythonの動作するバージョンに合わせる必要があります。 念のためRaspberryPiで動作するpython3系のバージョンを調べましょう。

比較的新しいRaspbianではPythonのバージョンは3.5.3のようです。

動作するpythonのバージョンがversion3.4の場合

すみませんが、こちらは動かせていませんが、whlファイルも存在するので多分うまく行きそうです。

【version3.4のコマンド】

$ sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools
$ sudo <200b>pip3 install http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl

動作するpythonのバージョンがversion3.5の場合

作業自体は大きくは変化しないのですが、3.4用に作成されたwhlファイルを3.5用に名前だけ変更してインストールしています。そのため一度名前変更するためにcurlでローカルにダウンロードしてからpip3でインストールしています。また、python3用にパッケージ名も変更しています。(既にpython3-devpython3-setuptoolsインストールはされているので気にしなくてもいいかもしれません。)

【version3.5のコマンド】

$ sudo apt-get install libblas-dev liblapack-dev python3-dev libatlas-base-dev gfortran python3-setuptools
$ curl -O http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl
$ mv tensorflow-1.4.0-cp34-none-any.whl tensorflow-1.4.0-cp35-none-any.whl
$ sudo pip3 install tensorflow-1.4.0-cp35-none-any.whl

【ログ】

$ sudo apt-get install libblas-dev liblapack-dev python3-dev libatlas-base-dev gfortran python3-setuptools
Reading package lists... Done
Building dependency tree
Reading state information... Done
gfortran is already the newest version (4:6.3.0-4).
libatlas-base-dev is already the newest version (3.10.3-1+rpi1).
libblas-dev is already the newest version (3.7.0-2).
liblapack-dev is already the newest version (3.7.0-2).
python3-dev is already the newest version (3.5.3-1).
python3-dev set to manually installed.
python3-setuptools is already the newest version (33.1.1-1).
python3-setuptools set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

$ curl -O http://ci.tensorflow.org/view/Nightly/job/nightly-pi-python3/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp34-none-any.whl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 53.6M  100 53.6M    0     0  2912k      0  0:00:18  0:00:18 --:--:-- 2966k
pi@raspberrypi:~/tensorflow $ mv tensorflow-1.4.0-cp34-none-any.whl tensorflow-1.4.0-cp35-none-any.whl
pi@raspberrypi:~/tensorflow $ ls
tensorflow-1.4.0-cp35-none-any.whl

$ sudo pip3 install tensorflow-1.4.0-cp35-none-any.whl
Processing ./tensorflow-1.4.0-cp35-none-any.whl
Requirement already satisfied: numpy>=1.12.1 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Collecting absl-py>=0.1.6 (from tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/absl-py/absl_py-0.1.7-py3-none-any.whl (93kB)
    100% |????????????????????????????????| 102kB 91kB/s
Collecting protobuf>=3.4.0 (from tensorflow==1.4.0)
  Using cached protobuf-3.5.1-py2.py3-none-any.whl
Requirement already satisfied: wheel>=0.26 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Collecting tensorflow-tensorboard (from tensorflow==1.4.0)
  Downloading tensorflow_tensorboard-0.1.8-py3-none-any.whl (1.6MB)
    100% |????????????????????????????????| 1.6MB 176kB/s
Requirement already satisfied: six>=1.10.0 in /usr/lib/python3/dist-packages (from tensorflow==1.4.0)
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from protobuf>=3.4.0->tensorflow==1.4.0)
Collecting bleach==1.5.0 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Using cached bleach-1.5.0-py2.py3-none-any.whl
Requirement already satisfied: werkzeug>=0.11.10 in /usr/lib/python3/dist-packages (from tensorflow-tensorboard->tensorflow==1.4.0)
Collecting markdown>=2.6.8 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/markdown/Markdown-2.6.10-py3-none-any.whl (77kB)
    100% |????????????????????????????????| 81kB 58kB/s
Collecting html5lib==0.9999999 (from tensorflow-tensorboard->tensorflow==1.4.0)
  Downloading https://www.piwheels.hostedpi.com/simple/html5lib/html5lib-0.9999999-py3-none-any.whl (111kB)
    100% |????????????????????????????????| 112kB 165kB/s
Installing collected packages: absl-py, protobuf, html5lib, bleach, markdown, tensorflow-tensorboard, tensorflow
Successfully installed absl-py-0.1.7 bleach-1.5.0 html5lib-0.9999999 markdown-2.6.10 protobuf-3.5.1 tensorflow-1.4.0 tensorflow-tensorboard-0.1.8

無事にインストールが終了した様です。では、こちらも対話型インターフェースでテストしてみます。 importしてみると…

$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: compiletime version 3.4 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.5
  return f(*args, **kwds)
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: builtins.type size changed, may indicate binary incompatibility. Expected 432, got 412
  return f(*args, **kwds)
>>>

げーッまたしてもエラーが発生しました。

ぐぐってみたら以下のエントリーが。

qiita.com

どうもこの問題は既知の問題のようです。インストールするときにもファイル名をpython3.5に合わせるために修正したことも関係しているのでしょう。一番最初リンクしたサイトにも以下の記述がありました。

If you’re running Python 3.5, you can use the same wheel but with a slight change to the file name, since that encodes the version. You will see a couple of warnings every time you import tensorflow, but it should work correctly.

but it should work correctly.の記載があるので今後のバージョンアップに期待したいところです。では、テストを続けてみます。

$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: compiletime version 3.4 of module 'tensorflow.python.framework.fast_tensor_util' does not match runtime version 3.5
  return f(*args, **kwds)
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: builtins.type size changed, may indicate binary incompatibility. Expected 432, got 412
  return f(*args, **kwds)
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
b'Hello, TensorFlow!'
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>

いろいろメッセージは出ますが、動作には問題ないようです。ビルドさせられるのは厳しかったのでかなり助かった気分です。

Kerasもインストールする

【コマンド】

$ sudo apt-get install python3-h5py
$ sudo pip3 install keras

【ログ】

$ sudo apt-get install python3-h5py
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
  python-h5py-doc
The following NEW packages will be installed:
  python3-h5py
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 558 kB of archives.
After this operation, 2,647 kB of additional disk space will be used.
Get:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python3-h5py armhf 2.7.0-1 [558 kB]
Fetched 558 kB in 1s (396 kB/s)
Selecting previously unselected package python3-h5py.
(Reading database ... 123353 files and directories currently installed.)
Preparing to unpack .../python3-h5py_2.7.0-1_armhf.deb ...
Unpacking python3-h5py (2.7.0-1) ...
Setting up python3-h5py (2.7.0-1) ...

$ sudo pip3 install keras
Collecting keras
  Using cached Keras-2.1.2-py2.py3-none-any.whl
Collecting pyyaml (from keras)
  Downloading https://www.piwheels.hostedpi.com/simple/pyyaml/PyYAML-3.12-cp35-cp35m-linux_armv7l.whl (43kB)
    100% |????????????????????????????????| 51kB 47kB/s
Requirement already satisfied: six>=1.9.0 in /usr/lib/python3/dist-packages (from keras)
Collecting scipy>=0.14 (from keras)
  Downloading https://www.piwheels.hostedpi.com/simple/scipy/scipy-1.0.0-cp35-cp35m-linux_armv7l.whl (35.1MB)
    100% |????????????????????????????????| 35.1MB 8.4kB/s
Requirement already satisfied: numpy>=1.9.1 in /usr/lib/python3/dist-packages (from keras)
Installing collected packages: pyyaml, scipy, keras
Successfully installed keras-2.1.2 pyyaml-3.12 scipy-1.0.0

こちらも無事にインストールができました。2系のインストールが終わっていたからかもしれませんが、すぐに完了しました。

おわりに

一応これでpython2系でもpython3系でもTensorFlow1.4のインストールができました。 あとは使うだけなんですよ。使うだけ…

RaspberryPiからWio Node経由でLEDStrip(LEDテープ)を光らせる

RaspberryPiからWio Node経由でLEDStrip(LEDテープ)を光らせる

前回のエントリーではRaspberryPiからWio Nodeに接続した温度センサーの値を取得しました。

uepon.hatenadiary.com

ようやく手元にLEDStrip(俗にいうLEDテープ)が届いたのでテストしてみました。今回はクリスマスセールでSeeedさんの商品がかなり安く購入できたのでそれに含まれていた LEDテープを使用しています。(Groveコネクタもついているのでそのまま使えます。)これでNagoyaハッカソンのネタは自宅でできるようになりました。

このLEDテープなんですが、セット商品にしかついていないのが残念なので単独販売されるといいなと思います。 まあ作ればいいんですけど、最近は老眼が酷くて手元がおぼつかないのです。

このあたりはセンサー類だけでもお得なので購入おすすめ(12/28現在:クリアランスセールでセットで$24とかないよ…でも同梱されてるWio Linkは使っちゃダメなんで注意)

www.seeedstudio.com

micro:bitのコネクター付のセットもいいかなと思います。(秋月ですし)

akizukidenshi.com

Wio Nodeに接続する

設定に関しては過去のエントリーを参照していただければと思います。接続操作は簡単で、OutputのカテゴリーにあるWS2812 LED Strip 60を選択し、コネクタにドロップします。画面したに赤くConfrom Farmwareと出るのでそれも忘れずに押してください。

f:id:ueponx:20171228182318p:plain

あとは画面左上のハンバーガーボタンを押してAPIの確認をします。

温度センサーの設定をそのままにしているので温度センサーのAPIに加えてLEDテープの設定が追加されています。 点灯・消灯のAPIはこのようになっています。

f:id:ueponx:20171228182903p:plain

この設定では最大60個のLEDまでコントロールできるのですが、今回接続したものは30個なのでパラメータとしては30、後はRGBの16進6桁表記( #0xは不要です)でパラメータを送信すればOKです。 消灯する場合には000000を指定すれば消灯します。

Curlでのアクセスは以下のようになります。

$ curl -k -X POST https://us.wio.seeed.io/v1/node/GroveLedWs2812D0/clear/30/aa00aa?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{"result": "ok"}

youtu.be

点灯・消灯以外にもスタートインデックスを指定して、RGBパターンを連続して記述して、一つ一つのLEDの色を変えるようなこともできます。 また、 rainbow flowと呼ばれる色を変化させながら点滅するモードもあります。

f:id:ueponx:20171228185654j:plain

RaspberryPiからアクセスしてみる

pythonからはこんな感じでアクセスできます。恒例のrequestsモジュールを使って、今回はPOSTメソッドでアクセスしています。 コマンドライン引数からパラメータをセットしています。joinを使ったほうがキレイにできると思いましたが、それは好みでということで。

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

import sys
import requests

argvs = sys.argv
argc = len(argvs)

length = '30'
britness = '0'
speed = '1'

if(argc > 1):
    length = argvs[1]
if(argc > 2):
    britness = argvs[2]
if(argc > 3):
    speed = argvs[3]

url = 'https://us.wio.seeed.io/v1/node/GroveLedWs2812D0/start_rainbow_flow/' + length + '/' + britness + '/' + speed

payload = {'access_token': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'}
r = requests.post(url, params=payload)
print(r.text)

youtu.be

一応、うまくいったようです。

終わりに

Nagoyaハッカソンで使ったもののメモとしてはこれで終わりかなと思います。 それにしても、本当に老眼ではんだ付けがきつくなった自分にとってはGroveサマサマといった感じです。

RaspberryPiからWio Nodeにアクセスしてみる

RaspberryPiからWio Nodeにアクセスしてみる

f:id:ueponx:20171221151320p:plain

今年のハッカソンで使ったけど、エントリーとして残していなかったので備忘録として書いておきます。 NagoyaハッカソンではMamorioを使って近づいたことを特定し、Wio Nodeに接続したLEDテープを光らせるといった動作をさせていました。 以前のエントリーではRaspberryPi3のBLEでMamorioの状態を取得するところまでを行いました。

uepon.hatenadiary.com

そのあとはWio NodeにアクセスしてLEDを光らせることになります。

自分も購入はしていたのですが、設定だけして片付けてしまいました。というのも、必ずスマートフォンのアプリが必要で、購入した理由がESP8266の小型Arduinoのようなデバイスかなと思っての衝動買いだったからでした。PCで設定できるならそれでも良かったのですが、スマートフォン必須…かあという感想でした。

自分は秋月にて購入しましたが akizukidenshi.com

もちろんAmazonでも購入できます。(実質スイッチサイエンスからになりますが)

Wio Nodeとは?

スペックとしてはこんな感じです(秋月さん情報からの引用

【特長】

  • ESP8266ベースのオープンソースWi-Fiの開発ボード
  • プラグ・アンド・プレイのGroveデバイスをサポート
  • OTAでファームウェアアップデートが可能
  • RESTfulなAPIを提供
  • IFTTTアプリケーションが使用可能
  • AndroidとiOSののアプリケーションがあります

【主な仕様】

  • 入力電圧:バッテリーピン:3.0~4.2V、マイクロUSB:5V
  • 動作電圧:3.3V
  • 最大消費電力:500mA
  • デジタルI/O:x4
  • アナログI/O:x1
  • UART:x1
  • I2C:x1
  • 出力電流;最大12mA
  • フラッシュメモリ:4MB
  • CPU周波数:26MHz
  • 基板サイズ:28mmx28mm

※工事設計認証(技適)番号:206-000519

最後の一行が超重要ですね。

Groveが使えるWiFiバイスだけど、Arduinoのようなプログラミングで使えるようなものではなく、エンドポイントを持ってアクセスができという感じなのかなと思います。 本来であればLEDテープをRaspberryPiで光らせることができれば問題なかったのですが、時間が少ないこと、LEDテープの電源が5.0Vであるとかいうことがあったので、Seeedさんの助言もありWio Node経由で光らせることにしました。

結局この方法で良かったかなと思います。

Wio Nodeのセットアップ

Wio Nodeをセットアップさせるためにスマートフォンのアプリをダウンロードします。今回はAndroidで設定しています。

まずはストアから「Wio」をインストールします。

f:id:ueponx:20171221205111p:plain

インストール後に【開く】ボタン押します。

f:id:ueponx:20171221205207p:plain

すると、SIGN UPまたはLOG INを促されます。新規に登録しても問題はありませんが、下の方にGoogle+facebookでもログインできるボタンがあるので、自由に選択してください。自分はFacebookのログインを使いました。

f:id:ueponx:20171221205418p:plain

f:id:ueponx:20171221205357p:plain

ログイン処理が終わるとDeviceの登録画面に遷移します。まだ、デバイスの登録されていないので一件もでていません。画面真ん中にある【ADD YOUR FIRST DEVICE】を選択します。

f:id:ueponx:20171221205557p:plain

登録するデバイスの選択になります。Wio LinkとWio Nodeがありますが、Wio Nodeの画像のボタンを押します。

f:id:ueponx:20171221205730p:plain

位置情報などのアクセスが求められました。許可でいいかなと思います。

f:id:ueponx:20171221205824p:plain

まずはWio Nodeに電源を入れて設定モードに変更することを求められます。USB接続で給電し、Wio NodeのボードにあるFuncボタンを4秒間押して設定モードに変更します。青LEDがゆっくり点滅すればOKです。

f:id:ueponx:20171221213206p:plain

f:id:ueponx:20171221213412j:plain

次はWioNodeがインターネットに接続するためのWiFiネットワークの設定になります。現在見えているネットワークのSSIDの一覧が表示されるので適切なものを選択します。

f:id:ueponx:20171221210117p:plain

選択したらパスワードも入力します。

f:id:ueponx:20171221210157p:plain

WiFiの設定が終わると次はデバイスの接続になります。アドホックモードでWioNodeと接続し、設定を流し込むという形になるので、このような設定を行う必要があります。複数デバイスがある場合はわかりませんが、一つしかない場合はリストから選択を行います。先頭はWioという文字列になっているようです。

f:id:ueponx:20171221210437p:plain

この後設定の流し込みがスマートフォン側から行われますが、たまに失敗します。何回か行えば成功すると思います。 (昔はもっと失敗していたような気がします。) 設定が終了すると、設定したデバイスに名前をつけることができます。今回は切り良く48がついていたのでそのままにしました。

f:id:ueponx:20171221210514p:plain

名前を決めたら【Start Wio-ing】ボタンを押すと初期設定が完了します。以下のような画面になっていればデバイス登録がされています。

f:id:ueponx:20171221210859p:plain

接続するGrove機器の設定

ここまででネットワークの設定は可能になっています。あとはWio Nodeに接続するGroveセンサの接続設定になります。登録されたデバイスを押すと、

f:id:ueponx:20171221211645p:plain

このような画面に変わります、上段には接続可能なGroveモジュールが出ているので今回は温度センサを接続してみます。名前はTemperatureSensorを選びます。分類がAllになっているので、Inputに変更します。そのあと左右に操作して

f:id:ueponx:20171221212044p:plain

該当のGroveモジュールを見つけ出します。接続する場合には画面下にあるWio Nodeまの端子までドロップして設定を行います。ここで画面したにFirmware Uploadのボタンが赤く表示されるのでそれを押してください。

f:id:ueponx:20171221212255p:plain

Wio Nodeの端子部分にGroveモジュールのアイコンが入って入れば設定完了です。

f:id:ueponx:20171221212340p:plain

Deviceの画面に戻ると登録されていたデバイスに温度センサーの画像とCONNECTED 1と表示されています。無事に設定はされたようです。

Groveセンサの接続

温度センサーの接続のソフトウエアの設定が終わったら、今度は設定と同じコネクタに温度センサーを接続します。

f:id:ueponx:20171221212707j:plain

これですべての設定が完了しました。

テストしてみる

スマートフォンのアプリ上からでもテストを行うことができますのでそれをまず行ってみます。

テストを行うデバイスを選択し

f:id:ueponx:20171221213531p:plain

設定の画面に遷移し、画面の右上のハンバーガーボタンをおすとメニューが表示されます。

f:id:ueponx:20171221213624p:plain

このなかからViewAPIを選択します。すると、設定したデバイスを操作するAPIやエンドポイントが表示され、テスト用のボタンなどが表示されます。また、このAPIをテストするcURLなどのコマンドラインが表示されるのでそのままCLIでテストもできます。

f:id:ueponx:20171221214013p:plain

テストも可能で今回のテストでは温度が25.4℃としてJSONで返されています。

f:id:ueponx:20171221214030p:plain

後はこのAPIのエンドポイントをRaspberryPiから叩けばOKです。

RaspberryPiからWio Nodeに設定されたEndPointにアクセスする。

ViewAPIのページのテストでcurlコマンドが記載されますのでそのまま打ち込めはCLIでちゃんと値がでてきます。 access_tokenは伏せてありますので、自分のデバイスのものと差し替えてお使いください。

$ curl -k https://us.wio.seeed.io/v1/node/GroveTempA0/temp?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{"temperature": 22.38}

pythonのinteractive modeで実行するとこんな感じになります。 pythonなので恒例のrequestsモジュールを使っています。

Requests: 人間のためのHTTP — requests-docs-ja 1.0.4 documentation

$ python
Python 2.7.13 (default, Jan 19 2017, 14:48:08)
[GCC 6.3.0 20170124] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> payload = {'access_token': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'}
>>> r = requests.get("https://us.wio.seeed.io/v1/node/GroveTempA0/temp", params=payload)
>>> print r.url
https://us.wio.seeed.io/v1/node/GroveTempA0/temp?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>>> r.text
u'{"temperature": 22.53}'
>>>

pythonのコードにすると以下のようになります。

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

import requests
payload = {'access_token': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'}
r = requests.get("https://us.wio.seeed.io/v1/node/GroveTempA0/temp", params=payload)
print(r.text)

これを実行すると…

$ python tempSample.py
{"temperature": 22.75}

うまく動作しているようです。

終わりに

Groveのセンサーを簡単にネットワーク対応にできるのは非常に便利で、USBバッテリーの小型のものを使えば持ち運びしてそこそこの時間動作させることができるのも魅力的かなと思います。また、センサーのエンドポイントは複数のデバイスからアクセス可能なのでそのあたりも使い所があるのかなと思いました。 NagoyaハッカソンではPythonではなくNode.jsを使用しましたが、LEDテープが入手できた段階でそのあたりのコードはサンプルとして出したいと思います。

MAに対する思いについて

この記事はMashupAwards Advent Calendar 2017の12日目の記事です。

MAに対する思い

ぎりぎり間に合った…文章がおかしいところは勘弁してください。あと初投稿のため、画像アップロードのサイズが限界値超えたのではてなブログに移転しました。

このエントリーではMAに対する自分の思い出とそれに伴う考え方の変化などについてを書かせていただこうと思います。

あなたはだあれ?

自分は名古屋在住のサンデープログラマーです。プログラムに関しては学生時代にやっていて(当時はJavaWindows95がでたころ)、社会人からは営業、社内システム、設備管理と点々とし、会社にいていわゆるモノづくりにはあまり接点のない部署にいました。(今もですが)

とはいえ、技術にはなんとなく触れているものの直接何かできるわけではなかったのですが、組織的に隙間というものはあるので趣味で作ったものを業務に活かすようなことは好きでやっていました。

勉強会への参加 ~ ハッカソンとの出会い

そんな中、「会社の需要がないとモノづくりができないのってどうなの?」「本当につくりたいものってないの?」となんとなく自問自答してもやもやしている自分に気が付きました。また、会社という軸足があっての人生ってなんなんだろう。会社の所属が無くなったときに何ができるんだろうという漠然とした不安も感じていました。

そこで、一念発起し近所で開催される勉強会に参加してみることにしました。

勉強会に参加してすぐにわかったことは、自分の知っている知識がかなり昔の知識に偏っていることでした。当時はC#を少しかじった程度だったので、コミュニケーションツールや開発ツールなどに関してはほとんど無知でWebAPI?REST?なんぞというレベルでした。このころは難でも自作したがりだったような気がします。

その後、何度か勉強会に参加を通して、「勉強会で得た知識もなんからの形にしていかないと身につかないなー」「新しいことを成し遂げるにはある程度の締め切りのようなものは必要かも」と感じてはいたのですが、一人でやろうとするとちょっと継続できないなあという感覚が残っていました。

そんな中、ハッカソンというイベントの告知をみて、ここはいっちょチャレンジをしてみようという気になりました。勉強会になれてきたころからなんでも飛び込んでみようというマインドに徐々に変わっていったような気がしています。一回参加してみて向いてなかったらやめようって程度かな。

チャレンジというか他流試合のような気構えだったのかもしれません。

その時にみた告知が、MashupAward11の告知だったのが、自分のここ数年の私生活や働き方を大きく変える要因になったような気がします。

MAに参加した思い出

1年目の作品

イタズラPepper by Dr.Pepper

hacklog.jp

https://qiita-image-store.s3.amazonaws.com/0/13188/eeb6c59e-a8e4-fe7d-39a9-4e3b6c8dc68a.jpeg

https://qiita-image-store.s3.amazonaws.com/0/13188/fa51a471-1673-1e1d-f450-817254be38fb.png

【作品説明】一人っ子の家庭が増え、家では甘えん坊な子が増加中。「イタズラを繰り返すPepper」の躾を子供がすることで、お兄ちゃん(またはお姉ちゃん)気分を体験できます!

はじめての年は緊張していたのもありましたが、何もかもが初めてどんな風にやれば(時間配分・分担など)いいのかもわからず、やれるだけやってみようという感じでした。当時はあまり人とのコミュニケーションに関しても苦手で、なるようになるだろうという楽観的な感覚でいたのですが、ハッカソンでは限られた時間ないにやるべきことを見つけることや提案することが重要なんだなということがわかってきたかなというところです。

この時は無性に当時発表されたばかりのPepperを触りたい・開発したいというところが自分の中ですごく全面にでていたのですが、実質2日間ない時間の中ではアイデアと技術のすり合わせなども検討しないとなかなかうまくいかない。捨てるところは捨ててプロトタイプを作っていかなければいけないんだという点で成長ができたかなと感じていました。個人の担当はDataSpaiderのThunderBusとPhilipsのHueをdocomoAPIを使っての連携部分でした。

そして、自分の中で重要だったことはみんなでなにかを作るということが経験できたという点です。これまで家で一人でプログラムを作っていたときにはない達成感や満足感。あとアイデアが形となった喜びが最後に押し寄せてきたことを覚えています。

2nd Stageのプレゼン時の動画で自分がペッパーと絡む子役をやっていたのですが、体形をみた観衆の方のTwitterのタイムラインでジワるというコメントをいただいて、自分で苦笑していました。

初年度はこの作品で2ndステージまで行かせていただきましたが、そこで自分が見たこともない楽しいアイデアを見たり、参加者との新たな出会いがあったりと、ハッカソン初参加者としていい経験をさせていただいたなと思っています。

自分はこっちの方向だな~と思いを強くし、「次回も是非出たい!作品を作りたい!」と思うようになりました。

https://qiita-image-store.s3.amazonaws.com/0/13188/ef89f0e4-203f-5a1f-6eeb-78f692e0cce4.jpeg

↑ 会場での記念撮影

2年目

BarSota

hacklog.jp

https://qiita-image-store.s3.amazonaws.com/0/13188/b8c41329-85c3-9d26-ae11-2e1e11d58cc0.jpeg

https://qiita-image-store.s3.amazonaws.com/0/13188/6f0eff30-6d7a-6d0e-b0c6-5f8eae9fe2f2.png

【作品説明】 ストレスの多い現代社会。 紳士淑女が集まる癒しの空間BarSotaでは、 バーテンダーロボットが上質なおもてなしを提供。

2年目もロボットネタでした。大垣でのロボットハッカソン開催で開発可能なロボット集合という触れ込みだったのでSotaに一目ぼれしたので参加しました。大垣のハッカソンでは1年目に同じチームだった市川さんが運営もやってらっしゃって、1年目の関係が2年目に続いてるなあという思いでの参加でもありました。

社会的対話ロボット「CommU(コミュー)」・普及型社会的対話ロボット「Sota(ソータ)」 | ヴイストン株式会社

1年目ではタイムスケジュールに流されたなという意識もあったので、2年目は可能な限り楽しむことをより優先して行いました。ただ、楽しむためにはインプットをある程度していないと時間的な余裕が生まれないことも経験上わかっていたので、ハッカソンが開催される半年ぐらい前から自分のできることを考え直したり、いろいろな実験をしたりと行っていました。このときあたりにArduino、mbed、RaspberryPiに出会った感じです。自分はベースとなる技術が少し弱いなあと思っていて、特にWebサービスなどに関してはほかの人とは圧倒的に差がありすぎ勝ち目がないと思ったので、自分はこっちで攻めようという感じでインプットをしていきました。

Sotaの開発環境はビジュアルプログラミングではあったのですが、Pepperとは異なりJavaでの実装でした。学生時代でJavaを使うのをやめてしまったので、知識がなくどうしようと思っていましたが、「何とかしないと!」という気合でSotaから各種APIへリクエストを投げる部分の実装を行い、何とかプロトタイプを仕上げて、プレゼンにこぎつけました。(20数年ぶりにJavaのコードを書いたかも)あと、大垣での開催出なかったらたぶん出来上がってなかったかなと思ってます。(会場の公益財団法人ソフトピアジャパンさんには宿泊施設があり徹夜可能でした。)

この作品のこだわりはダンディ辞書。会話用のAPIではリターンとなる会話文が丁寧語(ですます調)になることが多かったので、文末を「だぜ」「だろ」というようなダンディな口調にすることでバーテンらしさをだすというところでした。(ほかのチームがおかん辞書をつくるというのを聞いて、このアイデアに至りました)

今回は開発もアイデア出しもかなり楽しめた感じでした。今回もメンバーにもかなり恵まれていたので、分担もうまくでき、こちらの作品も2nd Stageに進むことができました。

ただ、2nd Stageまでのブラッシュアップに関しては、一部のメンバーに負担が大きかったのが少しだけ後悔でした。やはり、ハッカソンは限られた時間の中でのプロトタイプ作成にはなりますが、 継続して開発していくには熱量が必要なんだろうなあと思います。そのことが、地方予選で敗れたものが2nd Stageでは勝ち上がるような原動力になるんだろうなというのを身をもって感じたところです。

2年目はMAに限定せず、名古屋以外でもいろいろなハッカソンに参加していきました。その中での会話で、名古屋エリアでは楽しいハッカソンが少ないねという話もあり、自分の感じたこの楽しさをなんとか伝えられないかなと思うようになり、参加者としてだけではなく、開催のお手伝いができないかなと思うようになってきました。

もちろん参加の方が楽しいけどね。

ということで、3年目は「そっち側も体験しよう!」という感じで考えていました。

https://qiita-image-store.s3.amazonaws.com/0/13188/b2345d05-7173-6357-97b7-66da00e49dc1.jpeg

3年目

3年目はいろいろ考えた末にグループの作品と個人の作品の2点を応募しました。 なんとなく「みんなで作り上げたいもの」と「本当に作りたいもの」この二つがあるなと思ってです。

プレゼン練習 with P

hacklog.jp

【作品説明】 プレゼンを練習するためのアプリ/ロボットです。 「結構」、「なんか」など、プレゼンで使わない方がよい言葉の使用回数を表示します。

f:id:ueponx:20171212225455j:plain

f:id:ueponx:20171212225511j:plain

ソーシャルストリーミングリモコン

hacklog.jp

【作品説明】 SNSの書き込み数が最も多いテレビチャンネルに自動選局をするリモコン

https://qiita-image-store.s3.amazonaws.com/0/13188/fabb6533-6f03-e569-b2ef-d8a6c02a2eba.jpeg

https://qiita-image-store.s3.amazonaws.com/0/13188/15967830-07bd-9d88-577d-39d6645dd7de.jpeg

「プレゼン練習 With P」はこちらもおおがきロボット×AI ハッカソンの作品となります。(ロボット作品が多いですね。)こちらも2nd Stageに進出できました。参加させてもらったメンバーに大感謝です。

f:id:ueponx:20171213134323j:plain

そして、「ソーシャルストリーミングリモコン」が個人制作の作品となります。

みんなで作品を作るのも楽しいのですが、ハッカソンの日程が終わってしまうと熱(パッション)が少し覚めてしまうのが、ハッカソンの難点なのかも?というのが少しわかるようになったので、今度は自分のやる気の限界まで挑戦してみようということでハッカソン以外でも作ってみたというところです。

どちらもいい出来になったなあと思っているので今年も達成感があったなあというところです。 Festaにも参加しようと思います。

イベントのお手伝いも頑張った

2年目の終りに運営側のお手伝いもしたいなあと思っていたので、今年はいろいろなイベントをお手伝いさせていただきました。

f:id:ueponx:20171212231148j:plain

個人的にはやっぱりMA関連のハッカソンが一番楽しかったなあという印象です。ほかのハッカソンも楽しいのですが、根底にある「課題解決」というキーワードが若干発想に縛りを感じたからなのかもしれません。これは個人的な感想です。

特に今年のMA予選では、9月時点でのスケジュールをみると

名古屋での開催がない!

という、状況だったので何とかして名古屋でもMA予選を開催したいと思って、急遽会場を借りることができないかとかテーマをどうするかなどをいろいろやっていたのが心に残っています。ハッカソンに限らずですが、イベントはなくなると復活が難しいということは聞いているので、名古屋からこの火を消したくありませんでした。その甲斐あって、名古屋の開催にはいろいろな方々のご協力があって開催できました。この場を持ちましてお礼申し上げます。

f:id:ueponx:20171212231230j:plain

おわりに

自分が一番好きなのはみんながアイデアを出していく、アイスブレイク → アイデアソンの流れの部分が一番楽しく感じていますいまでも個人的にアイデア出しの部分が一番好きです。

ハッカソンになると技術を持ってないと参加しにくいという話はよく聞きますが、実際にはハッカソンでもいろいろな役割があるので、プレゼンの資料作り、スケジュールのマネージメント、デザインなど技術やテクノロジーとは少し毛色が違う作業はいろいろあります。それらの作業を行うのにも躊躇がある方もいると思いますが、ぜひアイデア出しの部分に関しては参加してほしいと思っています。どんな方でもWelcomeで、みんなで自由な発想でアイデアを考え、参加者全員のアイデアに眺めていくのは本当に体験してほしいと思っています。参加者それぞれのアイデアからいろいろな発見があると思います。

参加を躊躇している方がいらっしゃったら、ぜひ少しだけでもその世界をのぞいてみてはいかがでしょうか? f:id:ueponx:20171212231334j:plain

最後になりますが、MAに参加してからの多くの出会いに心から感謝しております。

f:id:ueponx:20171212231352j:plain

このようなものがいただけるとは思ってもみませんでしたが、これをきっかけにして頑張っていきたいと思います。

f:id:ueponx:20171212231752j:plain

RaspberryPi3でReSpeaker 4-Mic Array for Raspberry Piを使用してみる【調査・追記中】

RaspberryPi3でReSpeaker 4-Mic Array for Raspberry Piを使用してみる

https://github.com/SeeedDocument/ReSpeaker-4-Mic-Array-for-Raspberry-Pi/blob/master/img/features.png?raw=true

f:id:ueponx:20171129001628j:plain

Seeedさんの商品であるReSpeaker 4-Mic Array for Raspberry PiをRaspberryPi3に接続してスマートスピーカーっぽいことをやってみようと思います。 公式のページは

www.seeedstudio.com

となります。導入方法はかなりしっかりしているので、ちょっとしたユーザであればわかるレベルかなと思います。

導入方法のページに関してはこちら ReSpeaker 4-Mic Array for Raspberry Pi - Seeed Wiki となります。以下ではその手順にのっとって設定を進めていこうと思います。

Install driver

まずはハードウエアを認識させるために【ドライバーのインストール】行います。

1. Please Make sure running the lastest Raspbian Operating System(debian 9) on Pi. (updated at 2017.09.15)

最初のステップとしては最新のRaspbianのインストールを進められます。自分の持っていた2017-09-07-raspbian-stretch.imgのイメージファイルで Raspbianをインストールしました。少しだけ古いのでたぶん何らかのバグが含まれているのでしょう…大きな相違がないと思いますので(超危険な発想)このまま作業を進めていこうと思います。 ちなみにバージョンを確認すると以下の様になっていました。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.1 (stretch)
Release:        9.1
Codename:       stretch

2. Get the seeed voice card source code.

2番目のステップとしてはseeed voice cardソースコードの入手になります。 wikiの情報を元に作業をすれば問題ありません。

Githubからソースを取得します。サイトには2mic用のドライバもあるようです。 github.com

$ git clone https://github.com/respeaker/seeed-voicecard.git
Cloning into 'seeed-voicecard'...
remote: Counting objects: 258, done.
remote: Total 258 (delta 0), reused 0 (delta 0), pack-reused 258
Receiving objects: 100% (258/258), 165.38 KiB | 0 bytes/s, done.
Resolving deltas: 100% (144/144), done.

Cloneが終わったら、ディレクトリに移動して

$ cd seeed-voicecard/

インストーラーを起動します。オプションスイッチに4micの追加をお忘れなく。

$ sudo ./install.sh  4mic
ヒット:1 http://archive.raspberrypi.org/debian stretch InRelease
取得:2 http://mirrordirector.raspbian.org/raspbian stretch InRelease [15.0 kB]
取得:3 http://mirrordirector.raspbian.org/raspbian stretch/main armhf Packages [11.7 MB]
11.7 MB を 24秒 で取得しました (479 kB/s)
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
アップグレードできるパッケージが 123 個あります。表示するには 'apt list --upgradable' を実行してください。
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが新たにインストールされます:
  raspberrypi-kernel-headers
以下のパッケージはアップグレードされます:
  raspberrypi-kernel
アップグレード: 1 個、新規インストール: 1 個、削除: 0 個、保留: 122 個。
47.1 MB のアーカイブを取得する必要があります。
この操作後に追加で 99.4 MB のディスク容量が消費されます。
取得:1 http://archive.raspberrypi.org/debian stretch/main armhf raspberrypi-kernel armhf 1.20171029-1 [31.7 MB]
取得:2 http://archive.raspberrypi.org/debian stretch/main armhf raspberrypi-kernel-headers armhf 1.20171029-1 [15.3 MB]
47.1 MB を 116秒 で取得しました (614 kB/s)
apt-listchanges: changelog を読んでいます...
(データベースを読み込んでいます ... 現在 125965 個のファイルとディレクトリがインストールされています。)
.../raspberrypi-kernel_1.20171029-1_armhf.deb を展開する準備をしています ...
'rpikernelhack による /boot/bcm2708-rpi-0-w.dtb から /usr/share/rpikernelhack/bcm2708-rpi-0-w.dtb への退避 (divert)' を追加しています
…
(中略)
…
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.9.59-v7+ /boot/kernel7.img
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
提案パッケージ:
  python3-apport menu
以下のパッケージが新たにインストールされます:
  dkms
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 122 個。
74.8 kB のアーカイブを取得する必要があります。
この操作後に追加で 289 kB のディスク容量が消費されます。
取得:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf dkms all 2.3-2 [74.8 kB]
74.8 kB を 1秒 で取得しました (69.5 kB/s)
以前に未選択のパッケージ dkms を選択しています。
(データベースを読み込んでいます ... 現在 156774 個のファイルとディレクトリがインストールされています。)
.../archives/dkms_2.3-2_all.deb を展開する準備をしています ...
dkms (2.3-2) を展開しています...
dkms (2.3-2) を設定しています ...
man-db (2.7.6.1-2) のトリガを処理しています ...

Creating symlink /var/lib/dkms/seeed-voicecard/0.2/source ->
                 /usr/src/seeed-voicecard-0.2

DKMS: add completed.

Kernel preparation unnecessary for this kernel.  Skipping...

Building module:
cleaning build area....
make -j4 KERNELRELEASE=4.9.59+ -C /lib/modules/4.9.59+/build M=/var/lib/dkms/seeed-voicecard/0.2/build......
cleaning build area....

DKMS: build completed.

Kernel preparation unnecessary for this kernel.  Skipping...

Building module:
cleaning build area....
make -j4 KERNELRELEASE=4.9.59-v7+ -C /lib/modules/4.9.59-v7+/build M=/var/lib/dkms/seeed-voicecard/0.2/build......
cleaning build area....

DKMS: build completed.

snd-soc-wm8960:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.9.59+/kernel/sound/soc/codecs/

snd-soc-ac108.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.9.59+/kernel/sound/soc/codecs/

depmod...

DKMS: install completed.

snd-soc-wm8960:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.9.59-v7+/kernel/sound/soc/codecs/

snd-soc-ac108.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.9.59-v7+/kernel/sound/soc/codecs/

depmod...

DKMS: install completed.
cp ac108_asound.state /var/lib/alsa/asound.state
------------------------------------------------------
Please reboot your raspberry pi to apply all settings
Enjoy!
------------------------------------------------------

上記のように表示されれば成功です。ac108はこのスピーカーユニットの裏面のハードウエアに乗っているチップの様です。 リブートする必要があるので再起動を行います。

$ sudo reboot

これでユニットの認識ができるようになったはずです。

3. Then select the headphone jack on Raspberry Pi for audio output:

3番目のステップはいよいよこのユニットからの音声を確認することになりますが、その前にRaspberryPiの音声出力設定を確認します。 raspi-configを起動し、Audioの設定を行っていきます。

$ sudo raspi-config

起動すると…以下のような画面になるので

その中から【7.Advance Options】を選択し

f:id:ueponx:20171128195750p:plain

画面遷移後【A4. Audio】を選択し

f:id:ueponx:20171128200032p:plain

画面遷移後【1. Force 3.5mm (’headphone’)jack】を選択した後

f:id:ueponx:20171128200200p:plain

画面下部の【了解】を選択します。(これで選択が完了しました。)

f:id:ueponx:20171128200435p:plain

すると画面がメインメニューに戻りますので【Finish】を選択します。

f:id:ueponx:20171128200506p:plain

これで設定完了です。作業的には音声の出力を強制的にイヤホンジャックに設定しました。raspi-configが終了すると以下のように表示されていました。

$ sudo raspi-config
numid=3,iface=MIXER,name='PCM Playback Route'
  ; type=INTEGER,access=rw------,values=1,min=0,max=2,step=0
  : values=1

たぶんOKなはずなんですけど…

4. Check that the sound card name looks like this:

次のステップではサウンドカードがちゃんと認識されているかの確認になります。基本はalsaのコマンドでの作業になります。 alsaarecordコマンドを使って録音デバイスの一覧を取得します。

$ arecord -L
null
    Discard all samples (playback) or generate zero samples (capture)
default
playback
dmixed
ac108
sysdefault:CARD=seeed4micvoicec
    seeed-4mic-voicecard,
    Default Audio Device
dmix:CARD=seeed4micvoicec,DEV=0
    seeed-4mic-voicecard,
    Direct sample mixing device
dsnoop:CARD=seeed4micvoicec,DEV=0
    seeed-4mic-voicecard,
    Direct sample snooping device
hw:CARD=seeed4micvoicec,DEV=0
    seeed-4mic-voicecard,
    Direct hardware device without any conversions
plughw:CARD=seeed4micvoicec,DEV=0
    seeed-4mic-voicecard,
    Hardware device with all software conversions

コマンドの出力にseeed4micとかac108が入っていれば認識されていると思っていいかなと思います。

Wikiではそのあと以下のように記載されています。

If we want to change the alsa settings, we can use sudo alsactl --file=ac108_asound.state store to save it. And when we need to use the settings again, copy it to: sudo cp ~/seeed-voicecard/ac108_asound.state /var/lib/alsa/asound.state

もし、alsaの設定を変更したいのであればalsactlで状態を保存しておき、元に戻す場合には保存しておいた設定を/var/lib/alsa/asound.stateに上書きしてねって書いてあります。とりあえず、保存だけでもしておいた方が無難かなと思います。

$ sudo alsactl --file=ac108_asound.state store

5. Open Audacity and select AC108 & 4 channels as input and bcm2835 alsa: - (hw:0:0) as output to test:

ここまできてやっと音声の入出力の確認となります。このステップではX上のAudacityを使用しての確認をしています。 Xが使えない場合には、この後のAlsaを使用した確認になります。波形が出るのでできればAudacityを使用したほうがいいかなと思いますが、好き好きといったところかなと思います。

まずはAudacityをインストールします。

$ sudo apt-get update
$ sudo apt-get install audacity

インストールが終わったら、AudacityをX上のコンソールから起動します。

$ audacity &

こんな感じでコンソールを開いて…

f:id:ueponx:20171128203530p:plain

起動すると

f:id:ueponx:20171128203024p:plain

初回起動らしいダイアログが表示されます。Welcomeダイアログを閉じてメインの画面を表示させます。

f:id:ueponx:20171128204012p:plain

画面中ほどにある、録音デバイス、録音チャンネル数、再生デバイスのプルダウンを以下の様に設定していきます。 まずはマイクのアイコンがついている横にあるプルダウンで録音デバイスを選択します。【ac108】を選択します。

f:id:ueponx:20171128204332p:plain

【seeed-4mic-voicecard】でもよさそうなんですが…Wikiに従います。

f:id:ueponx:20171128204927p:plain

続いてはマイクのチャンネルになります。ここでは4micのユニットですので【4】を設定します。【2】を選択しても録音対象にならないだけなのでエラーなどは発生しません。

f:id:ueponx:20171128205008p:plain

次はその隣にあるスピーカーのアイコンの隣のプルダウンから【bcm2835:ALSA-(hw:0,0)】を選択します。

f:id:ueponx:20171128204415p:plain

これでAudacityの入出力設定は完了です。

f:id:ueponx:20171129194839p:plain

【拡大図】 f:id:ueponx:20171129195058p:plain

では録音してみましょう。 メニューから【録音ボタン(アイコン)】をクリックしてみると以下の画像ような波形が4ch分表示されます。いったん録音を停止して、【再生ボタン(アイコン)】を押せば録音された音声が再生されます。

f:id:ueponx:20171128205138p:plain

無事に認識できたようです。

6. Or we could record with arecord and play with aplay:

こちらのステップではalsaのコマンドを使ったCLIでの確認でのになります。正直上でOKであれば、不要かなと思った自分がいたのですがとりあえずやってみました。 まずは録音になります。arecordコマンドで録音デバイスの指定、録音音声ファイルの形式の設定、チャンネルの設定を引数として渡します。 今回はデバイスac108、音声ファイルのフォーマットはSigned 32bit、16kHz、チャンネル数4として、hello.wavに出力しています。

$ arecord -Dac108 -f S32_LE -r 16000 -c 4 hello.wav
録音中 WAVE 'hello.wav' : Signed 32 bit Little Endian, レート 16000 Hz, チャネル数 4
^Cシグナル 割り込み で中断...

終了は特にないのでCtrl+Cで終了します。 ファイルは生成されていたので、あとは音声再生を確認をします。 aplayで再生を行うのですが…

$ aplay hello.wav
再生中 WAVE 'hello.wav' : Signed 32 bit Little Endian, レート 16000 Hz, チャネル数 4
^Cシグナル 割り込み で中断...
aplay: pcm_write:2011: 書込エラー: システムコール割り込み

エラーは出ないのですが、音声の再生は行われません。(ここはWikiの情報とは異なっているようです) 念のため、録音した音声ファイルをAudacityに読み込ませてみると…

f:id:ueponx:20171128211142p:plain

波形もありますし、音声の再生も行われています。 そこで、aplayで再生デバイスの指定を直接行ってみました。ヘッドホンジャックはplughw:0,0なので-Dスイッチでしていしました。 このようにして再生がうまくいきました。

$ aplay -D plughw:0,0 hello.wav
再生中 WAVE 'hello.wav' : Signed 32 bit Little Endian, レート 16000 Hz, チャネル数 4

ここで、音声デバイスとしての認識は完了します。 このデバイスは4chのマイクデバイスとして扱われalsaからも容易にコントロールができます。 また、再生デバイスはもっていないので、それは別途出力を行う必要があるようです。今回はヘッドホンジャックが出力対象となっています。

つづいてはユニットに装備されたLEDの設定になります。

Play with APA102 LEDs

LEDはAPA102というものでAdafruit DotStar LED StripというLEDテープと同じもののようです。

SPIで制御するLEDということのようなのでSPIの設定、SPIのPythonモジュールのインストールが事前に必要になります。

1. Activate SPI:

まずはSPIを有効化します。既に有効にしてる人はスキップです。 raspi-configで設定を行っていきます。

$ sudo raspi-config

メインメニューが表示されたら【5 Interfacing Options】を選択します。

f:id:ueponx:20171128212226p:plain

次のメニューが表示されたら【P4 SPI】を選択し、

f:id:ueponx:20171128212605p:plain

SPIを有効にするか尋ねられるので【<はい>】を選択します。

f:id:ueponx:20171128213235p:plain

SPIを有効にした旨のメッセージが表示されますので【<了解>】を押します。

f:id:ueponx:20171128213418p:plain

その後メインメニューに戻りますので【】を押してraspi-configを終了させます

f:id:ueponx:20171128213447p:plain

これでSPIの有効化は終了です。

2. Get APA102 LEDs Library and examples

次はAPA102のLEDはLibraryをインストールし、サンプルを実行します。

GithubからLibraryをCloneします。

github.com

$ cd ~
$ git clone https://github.com/respeaker/4mics_hat.git
Cloning into '4mics_hat'...
remote: Counting objects: 31, done.
remote: Total 31 (delta 0), reused 0 (delta 0), pack-reused 31
Unpacking objects: 100% (31/31), done.
~ $ cd 4mics_hat/

次は必須ではありませんが、python-virtualenvをインストールします。あまり馴染みはないのですがいつかはやろうと思っています>virtualenv

~/4mics_hat $ sudo apt-get install python-virtualenv
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  python3-virtualenv virtualenv
以下のパッケージが新たにインストールされます:
  python-virtualenv python3-virtualenv virtualenv
アップグレード: 0 個、新規インストール: 3 個、削除: 0 個、保留: 122 個。
138 kB のアーカイブを取得する必要があります。
この操作後に追加で 316 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python-virtualenv all 15.1.0+ds-1 [61.1 kB]
取得:2 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf python3-virtualenv all 15.1.0+ds-1 [57.7 kB]
取得:3 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf virtualenv all 15.1.0+ds-1 [19.7 kB]
138 kB を 3秒 で取得しました (46.0 kB/s)
以前に未選択のパッケージ python-virtualenv を選択しています。
(データベースを読み込んでいます ... 現在 158445 個のファイルとディレクトリがインストールされ ています。)
.../python-virtualenv_15.1.0+ds-1_all.deb を展開する準備をしています ...
python-virtualenv (15.1.0+ds-1) を展開しています...
以前に未選択のパッケージ python3-virtualenv を選択しています。
.../python3-virtualenv_15.1.0+ds-1_all.deb を展開する準備をしています ...
python3-virtualenv (15.1.0+ds-1) を展開しています...
以前に未選択のパッケージ virtualenv を選択しています。
.../virtualenv_15.1.0+ds-1_all.deb を展開する準備をしています ...
virtualenv (15.1.0+ds-1) を展開しています...
python3-virtualenv (15.1.0+ds-1) を設定しています ...
python-virtualenv (15.1.0+ds-1) を設定しています ...
man-db (2.7.6.1-2) のトリガを処理しています ...
virtualenv (15.1.0+ds-1) を設定しています ...

インストールが終わればあとはvirtualenvを有効化します。このあたりはそういうもんだと思うことにしましたw。有効化するとCLIの先頭の部分に(env)などとついて有効になっている仮想環境を教えてくれます。

~/4mics_hat $ virtualenv --system-site-packages ~/env
Running virtualenv with interpreter /usr/bin/python2
New python executable in /home/pi/env/bin/python2
Also creating executable in /home/pi/env/bin/python
Installing setuptools, pkg_resources, pip, wheel...done.
~/4mics_hat $ source ~/env/bin/activate
(env) ~/4mics_hat $

正直自分のようなニワカには不要かもしれません…

後は必要なパッケージをインストールしていきます。

先程のGithubのサイトをみると以下が必要となるようです。

  • spidev
  • google-assistant-library
  • gpiozero

今回のサンプルではgoogle-assistant-libraryは使用しないので残りの2つをインストールします。 pipでインストールをしていきます。

(env) ~/4mics_hat $ pip install spidev gpiozero
Requirement already satisfied: spidev in /usr/lib/python2.7/dist-packages
Requirement already satisfied: gpiozero in /usr/lib/python2.7/dist-packages
(env) ~/4mics_hat $

これLibraryのインストールが終わり、準備完了しました。

3. Then run the example code under virtualenv, now we can see the LEDs blink like Google Assistant.

では、サンプルを使ってLEDを点灯させてみます。

(env) ~/4mics_hat $ python pixels_demo.py

プログラムを実行すると以下のようにLEDをが点灯します。これだけでちょっと満足できてしまう自分がいました。

youtu.be

どうでしょうか。音声、LEDまでの設定ができました。後は音声の方向と言葉の認識の設定になります。

DoA on ReSpeaker 4-Mic Array for Raspberry Pi

アレイスピーカーから音声が聞こえる方向を示す機能の設定になりますというか、サンプル?の実行となります。Direction of Arrial→DoAというようですがググってもArrialという言葉の意味がでてこないんですが、どうしてなんでしょう?もしかしてスラング?か造語?(Arrivalかなと思っているんですが…)

With DoA(Direction of Arrial), ReSpeaker 4-Mic Array is able to find the direction where the sound source is located.

では始めます。

1. setup voice engine

virtualenvを有効化している場合には以下の手順は不要です。

$ source ~/env/bin/activate
(env) ~ $ cd ~/4mics_hat

続いて、libatlas-base-devをインストール、行列計算用のLibraryかな?

(env) ~/4mics_hat $ sudo apt-get install libatlas-base-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  gfortran gfortran-6 libatlas-dev libatlas3-base libblas-dev libgfortran-6-dev
提案パッケージ:
  gfortran-doc gfortran-6-doc libgfortran3-dbg libcoarrays-dev libblas-doc liblapack-doc
  liblapack-dev liblapack-doc-man
以下のパッケージが新たにインストールされます:
  gfortran gfortran-6 libatlas-base-dev libatlas-dev libatlas3-base libblas-dev
  libgfortran-6-dev
アップグレード: 0 個、新規インストール: 7 個、削除: 0 個、保留: 122 個。
10.2 MB のアーカイブを取得する必要があります。
この操作後に追加で 48.4 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://ftp.jaist.ac.jp/pub/Linux/raspbian-archive/raspbian stretch/main armhf libgfortran-6-dev armhf 6.3.0-18+rpi1 [199 kB]

…(中略)…

update-alternatives: /usr/lib/liblapack.so (liblapack.so) を提供するために自動モードで /usr/lib/atlas-base/atlas/liblapack.so を使います

続いてpythonのオーディオ用Libraryのインストール

(env) ~/4mics_hat $ sudo apt-get install python-pyaudio
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
提案パッケージ:
  python-pyaudio-doc
以下のパッケージが新たにインストールされます:
  python-pyaudio
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 122 個。
24.3 kB のアーカイブを取得する必要があります。
この操作後に追加で 99.3 kB のディスク容量が消費されます。

…(中略)…

python-pyaudio (0.2.11-1) を設定しています ...

先程Githubで取得したパッケージに含まれるWheelパッケージをインストールします。.whlはEggに変わる次世代の配布形式として作られたもののようです。 また、Snowboy(Snowboy Hotword Detection)はKITT.AIが提供しているホットワードのモデルデータをRaspberry Piなどの環境で利用できるようにするライブラリで、 音が合っているかだけをローカルで判断するので軽快なレスポンスが得られるようです。 (ホットワードとは「OK Google」に代表される呼び出しのキーワードになります。) 個人的使用であれば無償のようですね。

いよいよスマートスピーカーっぽくなってきました!

(env) ~/4mics_hat $ pip install ./snowboy*.whl
Processing ./snowboy-1.2.0b1-py2-none-any.whl
Requirement already satisfied: PyAudio in /usr/lib/python2.7/dist-packages (from snowboy==1.2.0b1)
Installing collected packages: snowboy
Successfully installed snowboy-1.2.0b1

お次はWebRTCに関係するパッケージのインストールとなります。ログをみるとaudio関係のWebRTCのパッケージの様です。

(env) ~/4mics_hat $ pip install ./webrtc*.whl
Processing ./webrtc_audio_processing-0.0.1-cp27-cp27mu-linux_armv7l.whl
Installing collected packages: webrtc-audio-processing
Successfully installed webrtc-audio-processing-0.0.1

最後にvoice-engineGithubからCloneします。

Githubのドキュメントをみると

The library is used to create voice interface applications. It includes building blocks such as KWS (keyword spotting), DOA (Direction Of Arrival).

ってことなので、ボイスインターフェース作成用のLibraryの様です。ここではDoA→Direction Of Arrivalってなっているので先程のはやっぱり誤記なんでしょうか?

github.com

(env) ~/4mics_hat $ cd ~/
(env) ~ $ git clone https://github.com/voice-engine/voice-engine.git
Cloning into 'voice-engine'...
remote: Counting objects: 156, done.
remote: Total 156 (delta 0), reused 0 (delta 0), pack-reused 156
Receiving objects: 100% (156/156), 416.40 KiB | 756.00 KiB/s, done.
Resolving deltas: 100% (88/88), done.
(env) ~ $ cd voice-engine/
(env) ~/voice-engine $ python setup.py install
running install
running bdist_egg
running egg_info
creating voice_engine.egg-info

…(中略)…

Adding voice-engine 0.0.3 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/voice_engine-0.0.3-py2.7.egg
Processing dependencies for voice-engine==0.0.3
Finished processing dependencies for voice-engine==0.0.3

これで準備完了です。

2. Run the demo under virtualenv. Please wake up respeaker with saying snowboy and we will see the direction.

準備ができたので実行してみます。先程のvirtualenv環境上で実行を行います。内容としてはユニットに対してsnowboyと声をかけるとその方向のLEDが色が変わって点灯する動作になります。

(env) ~/voice-engine $ cd ~/4mics_hat
(env) ~/4mics_hat $ python kws_doa.py
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround40
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround41
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround50
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround51
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround71
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:4996:(snd_config_expand) Args evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM bluealsa
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device'
ALSA lib conf.c:4528:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:4996:(snd_config_expand) Args evaluate error: No such file or directory
ALSA lib pcm.c:2495:(snd_pcm_open_noupdate) Unknown PCM bluealsa
ALSA lib pcm_dmix.c:990:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_dmix.c:990:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_ac108.c:469:(_snd_pcm_ac108_open) a108 is only for capture
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock

コンソール上にかなりのエラーっぽいメッセージが出てきますが、動作しているようです。初回はsnowboyと声をかけるとOFFしていた LEDが全部点灯し呼び掛けた方向のLEDが薄い青い色で点灯します。(その他は濃い青色で点灯しています)

f:id:ueponx:20171129001709j:plain

【初回呼びかけ時の動画】 youtu.be

【2回目以降呼びかけ時の動画】 youtu.be

Play with Alexa, Baidu and Snowboy

Baiduは使用していないのでAlexaを使用していきます。

1. Get Alexa or Baidu authorization

virtualenvを有効化している場合には以下の手順は不要です。

~ $ source ~/env/bin/activate

Python Alexa Voice Service Appをインストールします。Alexaになるためのパッケージということかな? Githubから取得したらsetup.pyを実行してインストールを行います。

(env) ~ $ cd ~/
(env) ~ $ git clone https://github.com/respeaker/avs.git
(env) ~ $ cd avs
(env) ~/avs $ python setup.py install

running install
running bdist_egg
running egg_info
creating avs.egg-info
writing requirements to avs.egg-info/requires.txt
writing avs.egg-info/PKG-INFO
writing top-level names to avs.egg-info/top_level.txt
writing dependency_links to avs.egg-info/dependency_links.txt
writing entry points to avs.egg-info/entry_points.txt
writing manifest file 'avs.egg-info/SOURCES.txt'
reading manifest file 'avs.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no files found matching 'AUTHORS.rst'
warning: no previously-included files matching '__pycache__' found under directory '*'
warning: no previously-included files matching '*.py[co]' found under directory '*'
warning: no files found matching '*.rst' under directory 'docs'
warning: no files found matching 'conf.py' under directory 'docs'
warning: no files found matching 'Makefile' under directory 'docs'
warning: no files found matching 'make.bat' under directory 'docs'
warning: no files found matching '*.jpg' under directory 'docs'
warning: no files found matching '*.png' under directory 'docs'
warning: no files found matching '*.gif' under directory 'docs'
writing manifest file 'avs.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-armv7l/egg
running install_lib
running build_py
creating build
creating build/lib.linux-armv7l-2.7
creating build/lib.linux-armv7l-2.7/avs
copying avs/auth.py -> build/lib.linux-armv7l-2.7/avs
copying avs/main.py -> build/lib.linux-armv7l-2.7/avs
copying avs/alexa.py -> build/lib.linux-armv7l-2.7/avs
copying avs/config.py -> build/lib.linux-armv7l-2.7/avs
copying avs/player.py -> build/lib.linux-armv7l-2.7/avs
copying avs/__init__.py -> build/lib.linux-armv7l-2.7/avs
copying avs/mic.py -> build/lib.linux-armv7l-2.7/avs
creating build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/__init__.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/alerts.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/audio_player.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/notifications.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/playback_controller.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/speaker.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/speech_recognizer.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/speech_synthesizer.py -> build/lib.linux-armv7l-2.7/avs/interface
copying avs/interface/system.py -> build/lib.linux-armv7l-2.7/avs/interface
creating build/lib.linux-armv7l-2.7/avs/resources
copying avs/resources/README.md -> build/lib.linux-armv7l-2.7/avs/resources
copying avs/resources/alarm.mp3 -> build/lib.linux-armv7l-2.7/avs/resources
creating build/bdist.linux-armv7l
creating build/bdist.linux-armv7l/egg
creating build/bdist.linux-armv7l/egg/avs
copying build/lib.linux-armv7l-2.7/avs/auth.py -> build/bdist.linux-armv7l/egg/avs
copying build/lib.linux-armv7l-2.7/avs/main.py -> build/bdist.linux-armv7l/egg/avs
copying build/lib.linux-armv7l-2.7/avs/alexa.py -> build/bdist.linux-armv7l/egg/avs
creating build/bdist.linux-armv7l/egg/avs/resources
copying build/lib.linux-armv7l-2.7/avs/resources/alarm.mp3 -> build/bdist.linux-armv7l/egg/avs/resources
copying build/lib.linux-armv7l-2.7/avs/resources/README.md -> build/bdist.linux-armv7l/egg/avs/resources
copying build/lib.linux-armv7l-2.7/avs/config.py -> build/bdist.linux-armv7l/egg/avs
copying build/lib.linux-armv7l-2.7/avs/player.py -> build/bdist.linux-armv7l/egg/avs
copying build/lib.linux-armv7l-2.7/avs/__init__.py -> build/bdist.linux-armv7l/egg/avs
creating build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/audio_player.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/alerts.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/speech_synthesizer.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/playback_controller.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/speech_recognizer.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/__init__.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/notifications.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/speaker.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/interface/system.py -> build/bdist.linux-armv7l/egg/avs/interface
copying build/lib.linux-armv7l-2.7/avs/mic.py -> build/bdist.linux-armv7l/egg/avs
byte-compiling build/bdist.linux-armv7l/egg/avs/auth.py to auth.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/main.py to main.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/alexa.py to alexa.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/config.py to config.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/player.py to player.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/audio_player.py to audio_player.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/alerts.py to alerts.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/speech_synthesizer.py to speech_synthesizer.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/playback_controller.py to playback_controller.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/speech_recognizer.py to speech_recognizer.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/notifications.py to notifications.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/speaker.py to speaker.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/interface/system.py to system.pyc
byte-compiling build/bdist.linux-armv7l/egg/avs/mic.py to mic.pyc
creating build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/PKG-INFO -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/SOURCES.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/dependency_links.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/entry_points.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/not-zip-safe -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/requires.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
copying avs.egg-info/top_level.txt -> build/bdist.linux-armv7l/egg/EGG-INFO
creating dist
creating 'dist/avs-0.0.9-py2.7.egg' and adding 'build/bdist.linux-armv7l/egg' to it
removing 'build/bdist.linux-armv7l/egg' (and everything under it)
Processing avs-0.0.9-py2.7.egg
creating /home/pi/env/lib/python2.7/site-packages/avs-0.0.9-py2.7.egg
Extracting avs-0.0.9-py2.7.egg to /home/pi/env/lib/python2.7/site-packages
Adding avs 0.0.9 to easy-install.pth file
Installing alexa-tap script to /home/pi/env/bin
Installing alexa-auth script to /home/pi/env/bin
Installing alexa script to /home/pi/env/bin
Installing dueros-auth script to /home/pi/env/bin

Installed /home/pi/env/lib/python2.7/site-packages/avs-0.0.9-py2.7.egg
Processing dependencies for avs==0.0.9
Searching for python-dateutil
Reading https://pypi.python.org/simple/python-dateutil/
Downloading https://pypi.python.org/packages/4b/0d/7ed381ab4fe80b8ebf34411d14f253e1cf3e56e2820ffa1d8844b23859a2/python_dateutil-2.6.1-py2.py3-none-any.whl#md5=342c025339de1e7c2138c74983c111d7
Best match: python-dateutil 2.6.1
Processing python_dateutil-2.6.1-py2.py3-none-any.whl
Installing python_dateutil-2.6.1-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
writing requirements to /home/pi/env/lib/python2.7/site-packages/python_dateutil-2.6.1-py2.7.egg/EGG-INFO/requires.txt
Adding python-dateutil 2.6.1 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/python_dateutil-2.6.1-py2.7.egg
Searching for tornado
Reading https://pypi.python.org/simple/tornado/
Downloading https://pypi.python.org/packages/fa/14/52e2072197dd0e63589e875ebf5984c91a027121262aa08f71a49b958359/tornado-4.5.2.tar.gz#md5=ab41f6765d58089f30ba51e8ec084a7b
Best match: tornado 4.5.2
Processing tornado-4.5.2.tar.gz
Writing /tmp/easy_install-JDQgo_/tornado-4.5.2/setup.cfg
Running tornado-4.5.2/setup.py -q bdist_egg --dist-dir /tmp/easy_install-JDQgo_/tornado-4.5.2/egg-dist-tmp-7z7sqT
no previously-included directories found matching 'docs/build'
warning: no files found matching 'tornado/test/README'
zip_safe flag not set; analyzing archive contents...
tornado.autoreload: module references __file__
tornado.options: module references __file__
tornado.testing: module references __file__
/home/pi/env/local/lib/python2.7/site-packages/setuptools/command/bdist_egg.py:419: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  symbols = dict.fromkeys(iter_symbols(code))
tornado.test.httpserver_test: module references __file__
tornado.test.iostream_test: module references __file__
tornado.test.locale_test: module references __file__
tornado.test.options_test: module references __file__
tornado.test.template_test: module references __file__
tornado.test.web_test: module references __file__
creating /home/pi/env/lib/python2.7/site-packages/tornado-4.5.2-py2.7-linux-armv7l.egg
Extracting tornado-4.5.2-py2.7-linux-armv7l.egg to /home/pi/env/lib/python2.7/site-packages
Adding tornado 4.5.2 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/tornado-4.5.2-py2.7-linux-armv7l.egg
Searching for hyper
Reading https://pypi.python.org/simple/hyper/
Downloading https://pypi.python.org/packages/96/c3/e77072050a8d3a22255695d0cd7fde19bfe962364a6f6870ef47a9f9f66b/hyper-0.7.0-py2.py3-none-any.whl#md5=475426c4c01c7470fe3b86640a519d3c
Best match: hyper 0.7.0
Processing hyper-0.7.0-py2.py3-none-any.whl
Installing hyper-0.7.0-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
writing requirements to /home/pi/env/lib/python2.7/site-packages/hyper-0.7.0-py2.7.egg/EGG-INFO/requires.txt
Adding hyper 0.7.0 to easy-install.pth file
Installing hyper script to /home/pi/env/bin

Installed /home/pi/env/lib/python2.7/site-packages/hyper-0.7.0-py2.7.egg
Searching for backports_abc>=0.4
Reading https://pypi.python.org/simple/backports_abc/
Downloading https://pypi.python.org/packages/7d/56/6f3ac1b816d0cd8994e83d0c4e55bc64567532f7dc543378bd87f81cebc7/backports_abc-0.5-py2.py3-none-any.whl#md5=8a2af5176b751b185b8cb2241e0f40fc
Best match: backports-abc 0.5
Processing backports_abc-0.5-py2.py3-none-any.whl
Installing backports_abc-0.5-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
Adding backports-abc 0.5 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/backports_abc-0.5-py2.7.egg
Searching for certifi
Reading https://pypi.python.org/simple/certifi/
Downloading https://pypi.python.org/packages/29/9b/25ef61e948321296f029f53c9f67cc2b54e224db509eb67ce17e0df6044a/certifi-2017.11.5-py2.py3-none-any.whl#md5=429fdf238d878f8090a80ccc3488049b
Best match: certifi 2017.11.5
Processing certifi-2017.11.5-py2.py3-none-any.whl
Installing certifi-2017.11.5-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
Adding certifi 2017.11.5 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/certifi-2017.11.5-py2.7.egg
Searching for singledispatch
Reading https://pypi.python.org/simple/singledispatch/
Downloading https://pypi.python.org/packages/c5/10/369f50bcd4621b263927b0a1519987a04383d4a98fb10438042ad410cf88/singledispatch-3.4.0.3-py2.py3-none-any.whl#md5=d633bac187d681455ab065c645be845d
Best match: singledispatch 3.4.0.3
Processing singledispatch-3.4.0.3-py2.py3-none-any.whl
Installing singledispatch-3.4.0.3-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
writing requirements to /home/pi/env/lib/python2.7/site-packages/singledispatch-3.4.0.3-py2.7.egg/EGG-INFO/requires.txt
Adding singledispatch 3.4.0.3 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/singledispatch-3.4.0.3-py2.7.egg
Searching for hyperframe<4.0,>=3.2
Reading https://pypi.python.org/simple/hyperframe/
Downloading https://pypi.python.org/packages/d8/89/44ff46f15dba53a8c16cb8cab89ecb1e44f8aa211628b43d341004cfcf7a/hyperframe-3.2.0-py2.py3-none-any.whl#md5=82a3051da4d90d6a60e43ee3dff683d9
Best match: hyperframe 3.2.0
Processing hyperframe-3.2.0-py2.py3-none-any.whl
Installing hyperframe-3.2.0-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
Adding hyperframe 3.2.0 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/hyperframe-3.2.0-py2.7.egg
Searching for h2<3.0,>=2.4
Reading https://pypi.python.org/simple/h2/
Downloading https://pypi.python.org/packages/d7/8b/8d5610e8ddbcde6d014907526b4c6c294520a7233fc456d7be1fcade3bbc/h2-2.6.2-py2.py3-none-any.whl#md5=753dc9c217b9d5dfb19d9aba1e44713c
Best match: h2 2.6.2
Processing h2-2.6.2-py2.py3-none-any.whl
Installing h2-2.6.2-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
writing requirements to /home/pi/env/lib/python2.7/site-packages/h2-2.6.2-py2.7.egg/EGG-INFO/requires.txt
Adding h2 2.6.2 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/h2-2.6.2-py2.7.egg
Searching for hpack<4,>=2.2
Reading https://pypi.python.org/simple/hpack/
Downloading https://pypi.python.org/packages/8a/cc/e53517f4a1e13f74776ca93271caef378dadec14d71c61c949d759d3db69/hpack-3.0.0-py2.py3-none-any.whl#md5=49a5b2e287863bf7dba2fa0799990051
Best match: hpack 3.0.0
Processing hpack-3.0.0-py2.py3-none-any.whl
Installing hpack-3.0.0-py2.py3-none-any.whl to /home/pi/env/lib/python2.7/site-packages
Adding hpack 3.0.0 to easy-install.pth file

Installed /home/pi/env/lib/python2.7/site-packages/hpack-3.0.0-py2.7.egg
Searching for requests==2.12.4
Best match: requests 2.12.4
Adding requests 2.12.4 to easy-install.pth file

Using /usr/lib/python2.7/dist-packages
Searching for click==6.6
Best match: click 6.6
click 6.6 is already the active version in easy-install.pth

Using /usr/lib/python2.7/dist-packages
Searching for six==1.10.0
Best match: six 1.10.0
six 1.10.0 is already the active version in easy-install.pth

Using /usr/lib/python2.7/dist-packages
Searching for enum34==1.1.6
Best match: enum34 1.1.6
enum34 1.1.6 is already the active version in easy-install.pth

Using /usr/lib/python2.7/dist-packages
Finished processing dependencies for avs==0.0.9

Python Alexa Voice Service Appは以下のパッケージを必要するようなのですが、

  • gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gir1.2-gstreamer-1.0
  • python-gi python-gst-1.0 python-pyaudio
  • respeaker python library and pocketsphinx (optional, for hands-free keyword spotting)

Wikiではこの中の一部とtornadoをインストールしているようです。さっきのインストーラでもインストールしてそうなんですが…

ググるTornadoは、Pythonで書かれたWebフレームワーク/非同期通信ライブラリで、 GStreamerはストリーミングメディアアプリケーションを作成するためのフレームワークとのことでした。

(env) ~/avs $ sudo apt-get install gstreamer1.0 gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly
(env) ~/avs $ sudo apt-get install python-gi gir1.2-gstreamer-1.0
(env) ~/avs $ pip install tornado

パッケージのインストールの途中で以下のような表示がでるかもしれませんが

…(中略)…

以下の情報がこの問題を解決するために役立つかもしれません:

以下のパッケージには満たせない依存関係があります:
 gstreamer1.0-omx-dbg : 依存: gstreamer1.0-omx (= 1.0.0.1-0+rpi12+jessiepmg) し かし、1.10.4-1+rpt2 はインストールされようとしています
E: 問題を解決することができません。壊れた変更禁止パッケージがあります。

スルーしますw。スルーできねっす。

本来はパッケージマネージャで依存関係を解決するのですが、gstreamer1.0が依存するgstreamer1.0-omxだけ古いバージョンのものをインストールしようとして インストール失敗をしているようです。別途単体でインストールはできるので以下の様にすればよいようです。

(env) $ sudo apt-get install gstreamer1.0-omx

これもうまく行っていなかったようです。

※ Githubのドキュメントでは

For Ubuntu/Debian:
$ sudo apt-get install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gir1.2-gstreamer-1.0 python-gi python-gst-1.0 python-pyaudio
$ sudo pip install avs respeaker pocketsphinx

となっているのでこの手順でインストールしました。

$ sudo apt-get install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gir1.2-gstreamer-1.0 python-gi python-gst-1.0 python-pyaudio

以降の作業はVNC側のコンソールで行うようになっていますが、X上でももちろん大丈夫です。

virtualenvを有効化している場合には以下の手順は不要です。

~ $ source ~/env/bin/activate

f:id:ueponx:20171130214137p:plain

alexa-authをターミナルから実行します。

(env) $ alexa-auth

すると、Alexaの認証ダイアログがX上に現れます。

f:id:ueponx:20171130214324p:plain

そのダイアログに認証情報を入力すると/home/pi/.avs.jsonに認証情報が保存されます。

ダイアログで認証情報を入力が正常に行われるとこのような画面になります。

f:id:ueponx:20171130220208p:plain

注意点としては

If we want to switch between alexa-auth and dueros-auth, please delete /home/pi/.avs.json first. The file is hidden and use the ls -la to list the file.

AlexaとBaiduで認証情報のファイル(/home/pi/.avs.json)を共有しているので、切り替える場合には削除する必要があります。 あと、ファイルの属性が非表示のようなのでls -laを付けないと所在が確認できないようです。

f:id:ueponx:20171130224627p:plain

ちゃんと存在していますね。

2. Let’s Enjoy!(ここからはうまく行っていないようです…シクシク)

あとは楽しめばいいようです。

virtualenv環境上でns_kws_doa_alexa_with_light.pyを実行させると大量のデバックメッセージが出力されますが気にしないことにします。

(env) ~/avs $ cd ~/4mics_hat
(env) ~/4mics_hat $ python ns_kws_doa_alexa_with_light.py

ステータスコード204が出力されたら、respeakerに対してsnowboyと呼びかけてみます。するとユニットにあるLED点灯し、音声認識可能の状態になります。

f:id:ueponx:20171130224801p:plain

“who is the most handsome guy in the world?”とか“Do you know how to beat-box?”と話しかけてみましょう。

認識モードには移行してもらえたのですがちっとも認識してもらえません…

f:id:ueponx:20171130235506j:plain

問題発音?あるいはソフトウエアの設定?

おわりに

スマートスピーカーっぽいことができました(?)でも、個人的にはLEDがピカピカ光っているのをみているだけでも心落ち着くのはなぜでしょうか。 問題は自分の英語の発音が悪いというところでしょうかw

RaspberryPi3でMAMORIOの信号を受信する

RaspberryPi3でMAMORIOの信号を受信する

秋にいろいろハッカソンに参加したので、来年また使うかもしれないので、その時のメモをまとめていきます。といっても2-3件ですけどね。

先日あった【Nagoya Hackathon】で自分のチームでは位置情報を取得する必要があったので、技術協力でお越しになっていたMAMORIOさんが出している【MAMORIO】を使用しました。

mamorio.jp

「なくすを、なくす」というコンセプトはシンプルで素敵です。

MAMORIOが手元から離れると、いつどこで失くしたかをお知らせ。あなたのスマートフォンで、大切なものを見守れます。

Android版、iOS版のSDKも準備されていますのでスマートフォンでの開発も可能になっています。 ただ、自分はAndroidの開発をしたことがないので、ハッカソンという早期のプロトタイプ開発の場面では全くダメ人間となってしまいます。 なんとかせねばということで、AndroidStudioのインストールをしたりSDKをダウンロードしていたのですが、隣のチームでも同じような開発をしていたので 聞いてみたところ「iBeaconでいけるっすよ」という天の言葉が。

ということで、2日間あるハッカソンの1日目が終了した深夜。ネットをググりながらコーディングをしました。ただ、この作業中にRaspberryPi3の環境のBluetoothの環境の壊してしまったので、 深夜にもかかわらずRaspbianの新規インストール~Bluetooth設定の確認~Node.jsのインストール~MAMORIOを使ったLチカまで数時間でかたずけなければならず正直泣きたかったです。2日目はかなりポンコツになっていたと思います。

基本スペックはこんな感じです。

スペック
サイズ 縦35.5mm×横19mm×厚さ3.4mm
重さ 3g
電池 リチウム電池 / 最大で1年間ご利用が可能(ご利用環境によって短くなる場合がございます。)電池交換プログラムあり(有償)
保証期間 3ヶ月
通信方法 Bluetooth4.0(Bluetooth Low Energy)
有効距離 約30m
価格 3,780円(税込)
カラー BLACK / RED / BLUE / YELLOW / GRAY

Node.jsでiBeaconの信号をキャッチする

こちらのページを参考にしました。 qiita.com

npmbleaconというパッケージをインストールすれば信号のキャッチが可能になるようです。

RaspberryPi3ではBluetoothは標準で対応しているので、ハードの設定に関してはあまり気にしなくて良いようです。RaspberryPi Zero Wも調べてみたいです。

RaspberryPi3のBLEの設定

設定するRaspberryPiのリビジョンとしては以下を使用しています。(イメージファイルは2017-09-07-raspbian-stretch.imgを使用)

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.1 (stretch)
Release:        9.1
Codename:       stretch

npmを使用して``bleacon```をインストールする

bleaconはNode.jsのモジュールなのでNode.jsの比較的新しいバージョンを使用できるように設定をします。

Node.jsの設定に関しては過去記事とかを参考にしてください。

uepon.hatenadiary.com

$ sudo apt-get update
$ sudo apt-get install libbluetooth-dev
$ npm install bleacon

これでインストールできました。(beeaconはリビルドが行われるのですこし時間かかります)

bleaconを使用してみる

先程の参考サイトをみてコードを書いてみます。

var Bleacon = require("bleacon");
Bleacon.startScanning();
Bleacon.on("discover", function(bleacon) {
        console.dir(bleacon);
        if(bleacon.rssi > -75){
                console.log("近いです")
        }
        console.log(bleacon.proximity)
});

RaspberryPiで取得したiBeaconのrssiの値が-75 より大きい場合には近いですという表示をします。 その後にはproximityの状態も表示しています。

では実行してみましょう。実行するにはsudoが必要で付けないと以下のような警告が出ます。

【sudoのないエラー】

$ node beacon_discover.js
noble warning: adapter state unauthorized, please run as root or with sudo
               or see README for information on running without root/sudo:
               https://github.com/sandeepmistry/noble#running-on-linux
bleno warning: adapter state unauthorized, please run as root or with sudo
               or see README for information on running without root/sudo:
               https://github.com/sandeepmistry/bleno#running-on-linux

【成功例】

$ sudo node  beacon_discover.js
{ uuid: 'b9407f30f5f8466eaff925556b57fe6e',
  major: XXXX,
  minor: YYYYY,
  measuredPower: -75,
  rssi: -77,
  accuracy: 1.104503890181195,
  proximity: 'near' }
near
{ uuid: 'b9407f30f5f8466eaff925556b57fe6e',
  major: XXXX,
  minor: YYYYY,
  measuredPower: -75,
  rssi: -58,
  accuracy: 0.4296139514262019,
  proximity: 'immediate' }
近いです
immediate

取得したrssiの値でも良いのですが、proximityの値でみたほうが処理は楽に記述できるかもしれません。proximityにはimmediate(近接)、near(近い)、far(遠い)の値があるようです。 また、取得した値にはmajorminorがありますが、この値が各タグごとに異なる値になりますので、複数タグがある場合にはこの値をつかって個体の判別をします。(ハッカソンでは複数になることが多いので事前にわかっていると楽です)

MAMORIOが近接したらLEDを光らせる

先程のソースを改良してGPIOを使ったLチカを行います。簡単のためにgpioファイルに値を書き込んでGPIOの制御を行っています。

var fs = require('fs');

var dir = '/sys/class/gpio';
var gpio2 = dir + '/gpio2';
var count = 0;

fs.writeFileSync(dir + '/export', 2); // 2ピン
fs.writeFileSync(gpio2 + '/direction', 'out'); // 出力に設定

function flashLED() {
        count++;
        fs.writeFileSync(gpio2 + '/value', count % 2);
        if (count < 14) {
                setTimeout(flashLED, 500);
        }
}

process.on('SIGINT', () => {
        console.log('Got SIGINT. ');
        fs.writeFileSync(gpio2 + '/value', 0);
        fs.writeFileSync(dir + '/unexport', 2); // 処理の終了
        process.exit(1);
});

var Bleacon = require("bleacon");
Bleacon.startScanning();
Bleacon.on("discover", function(bleacon) {
        console.dir(bleacon);
        if((bleacon.major == "XXXX") && (bleacon.minor == "YYYYY")){
                if(bleacon.proximity == "immediate"){
                        console.log("my_tag_near");
                        count=0;
                        flashLED();
                }
        }
        console.log(bleacon.proximity)
});

今回は特定のタグが近接(proximityの値がimmediateになったら)したらLチカ(点滅)を行うようにしています。また、途中でCtrl+Cを押してしまうとgpioの状態が不定になり、次回の起動が失敗してしまうので、SIGINTシグナルをキャッチして終了処理を入れています。

$ sudo node  beacon_discover_led.js
{ uuid: 'b9407f30f5f8466eaff925556b57fe6e',
  major: XXXX,
  minor: YYYYY,
  measuredPower: -75,
  rssi: -70,
  accuracy: 0.7799771419043033,
  proximity: 'near' }
near
{ uuid: 'b9407f30f5f8466eaff925556b57fe6e',
  major: XXXX,
  minor: YYYYY,
  measuredPower: -75,
  rssi: -59,
  accuracy: 0.45150441487569565,
  proximity: 'immediate' }
my_tag_near
immediate
{ uuid: 'b9407f30f5f8466eaff925556b57fe6e',
  major: XXXX,
  minor: YYYYY,
  measuredPower: -75,
  rssi: -72,
  accuracy: 0.8614877874857131,
  proximity: 'near' }
near
^CGot SIGINT.

おわりに

無事にMAMORIOを検知して制御を行うことができました。タグの検出周期は約5秒ぐらいなので、即応性はそれほどという感じですが、この小ささであればとてもいいかなと思います。個人的にはもう少しお安い感じだといいんですが…2年程度持つとか、スイッチのオンオフがあるとかなら即買いかなと思います。ただ、これくらい削ぎ落としても「いいなあ、ほしいなあ」と思える商品だなとは思います。