2019年6月3日月曜日

MANICAモバイル導入事例:株式会社アンドユー様

ドレスやアクセサリのレンタルサービスを展開されている株式会社アンドユー様における、MANICAモバイル導入事例の紹介記事が公開されました。

http://www.hayato.info/home/jirei_andu.htm



2019年5月28日火曜日

ItemSenseサーバをセットアップしてみた

Impinj社ItemSenseサーバをセットアップしてみました。公式ドキュメント通り進めるだけですが、備忘録を兼ねてメモしておきます。

今回使ったもの

  • Windows 10 Pro
  • Hyper-V
  • Ubuntu 16.04
  • itemsense-2.0.3+34-setup.run

Hyper-Vの有効化

PCのOSがWindows 10 Pro以上だと、Hyper-Vが使用可能です。Hyper-Vの有効化はここにやり方が書いてあります。

Ubuntuのセットアップ

ItemSenseの動作環境がUbuntu 16.04かCentOS 7となっています。今回は筆者の好みの問題でUbuntu 16.04にしました。公式サイトからisoファイルをダウンロードしてください。今回、"64-bit PC (AMD64) desktop image"を使用しましたが、"64-bit PC (AMD64) server install image"の方がよかったかもしれません。

次に仮想マシンを新規作成します。今回は第2世代を使いました。その際、「セキュアブートを有効にする」のチェックを外す必要があるそうです。あとはダウンロードしたisoを指定して、起動するだけです。Ubuntu自体のセットアップは割愛。キーボードレイアウトの設定くらいでほとんど設定項目ありませんでした。

前提条件となるソフトウェア

セットアップ後、追加で下記をインストールしました。
  • ssh 1:7.2p2-4ubuntu2.8
  • curl 7.47.0-1ubuntu2.13
  • docker.io 18.09.2-0ubuntu1~16.04.1
  • docker-compose 1.24.0
docker-composeのみ、リポジトリのバージョンが古かったので、公式サイトからダウンロードしました。
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose 
hash -r 

いざ、ItemSenseインストール

あとはスクリプトを動かすだけです。

sudo ./itemsense-2.0.3+34-setup.run install

お使いのブラウザからubuntu 16.04環境のIPアドレス:3010にアクセスすると、初回はInstance IDの入力を求められるので、入力します。すると、今度はusername / passwordを求められますので、admin / admindefault を入力してください。ログインできます。


とりあえず、ここまで。



2019年5月22日水曜日

タグの読みすぎ問題を考える

RFIDを使っていると、タグの読みすぎ問題というのが発生します。タグは読むためにあんだろーが!読めないより読めたほうがいいに決まってんじゃねーか!というのは御尤もなわけですが、特にハンディリーダなど使っていると読みたくないタグまで読んでしまっていやーなんやこれ想定外やなこれは聞いてないでー、という状況が発生します。

例えば


こういうところで、ダンボールにはタグが付いていて、出庫処理をするのに手前の3個のダンボールだけ読みたいとするじゃないですか。しかし後ろにもダンボールがあってこっちにもタグが貼ってあるわけですね。


この状態でハンディリーダを使って読み取りすると、読みたくない方のタグまで漏れなく読んでくれるわけです。これがタグの読みすぎ問題と言われるものです。もちろん読みたくないタグが近くに無いような状況を作ればいいのですがそういう状況を作れない(場所がない)場合が多いと思います。

この問題を解決するのに2つのアプローチがあります。1つは電波強度を落とすという方法、もう1つはタグの電波受信強度(RSSIと呼ばれるもの)を利用するという方法になります。(実はもう1つあって、読みたいタグが最初からわかってる場合はそれだけ読むようにするというのもありますがこちらは運用とかも絡んでくるので今回は外します)

電波強度を落とす方法は、リーダから出す電波の強度を落として遠くのタグを読みにくくすることで近くのタグだけ読ませようというやり方、受信強度を利用する方法はリーダからの出力は最大にしておいて、タグからの受信電波強度を見て、あるしきい値以下の強度だったら読まなかったことにするということでこちらも近くのタグだけ選別しようというやり方です。

で、果たしてどちらの方法が人にやさしいというか人間の感覚にフィットするのかというのが気になりましたので試してみました。

利用したのはこちらのリーダ


AT-S100ちゃんです。今流行りのスレッド型になります。出力は1Wでアンテナは円偏波です。

1番上のダンボールの写真のアングルから、ダンボールから50cm、1m、1.5m離れた場所でリーダを普通に1振りしてどんなもんかを計測します。読みたいダンボールは3個、後ろの読みたくないダンボールは3個、合計6個のタグを読み取りします。

まずは電波強度を変えるやり方、MAXの30dBmから3dBmずつ落として読み取ります。電波強度を変える方は単純に遠くのタグを読めなくする方法なので、読み取りできた枚数が3枚になるポイントを探ります(もちろんその3枚が手前のダンボールのタグである必要があります)。

結果がこちら(数値は読み取ったタグの個数です)

出力\距離 0.5m 1m 1.5m
30dBm 6 6 6
27dBm 6 5 5
24dBm 6 5 5
21dBm 6 5 5
18dBm 4 4 4
15dBm 3 3 3
12dBm 3 1 0

今回のパターンでは、15dBmにすると読みたいタグだけ読んでくれてることがわかります。

次に受信強度(RSSI)を見るやり方、こちらはリーダの出力は最大の30dBmにしておいて、手前のタグたちのRSSIと後ろのタグたちのRSSIを見てしきい値を設けられるかがポイントになります。手前3個でのRSSI値の最小値と、後ろ3個のRSSI値の最大値に差があればあるほどしきい値を設けやすくなります。

距離\RSSI 手前3個で最小のRSSI 後ろ3個で最大のRSSI
0.5m -52.3 -63.0
1m -58.3 -66.8
1.5m -61.8 -67.9
単位:dB

0.5mのときはRSSI値に結構差がありますので、-58あたりをしきい値にしていれば概ね大丈夫のようです。距離が離れていくと差が縮んでいくので、1.5mのときは一応しきい値-64くらいでやれそうですがちょっと危ないかなーという感じですね。

結果としては読み取りたいタグとリーダの距離が近い場合は受信強度を見る方法もありですが、必ずこの距離で読んでくださいねーとかそれを制限するのもちょっと難しそうなのでやはり出力を調整する方法が現実的のようです。


2019年5月13日月曜日

AR と RFID

ARのライブラリもかなりよくなってきたのではないだろうかとふと思い立ち、ちょっと試してみることにしました。以前は ARToolkit を使って車両認識をARマーカを使ってやってみよう!みたいなことをやってましたが、今回は RFID と組み合わせてみます。

RFID のハンディリーダは便利なのですが、当然のことながらタグは読めてもタグの位置まではわかりません。GPS と連動すれば位置はわかりますが、どの棚の何段目みたいのはわかりません。そこでこれを AR を使ってうまいことできないだろうかということでやってみました。

利用するライブラリはスマホでも使えるように Google の ARCore を使用しました。ついでに開発を端折るためにサンプルプログラムの augmented_image を改修して試してみることにします。

ARCore は平面の検出などかなり高度なことができるライブラリで、その中でもマーカを認識する機能と、スマホの動きをトラッキングするモーショントラッキングの機能を使います。これを使うことで、マーカの認識と、マーカーとスマホの相対位置がわかるようになります。

マーカを柱など固定されたところに貼っておいて、そのマーカとの相対位置でタグの位置を識別することで、マーカから見てどの辺りにタグがあるのかがわかるようになります。マーカは移動しない固定された位置(壁など)に貼りますから、そこからの相対位置が分かればタグの絶対位置がわかるだろうというそういう都合のいい理論です。

利用するハンディはこちらです。


ブラスターにハンディのアタッチメントを付けたものです。画像認識にスマホのカメラを使いますので、必然的にこういうリーダしか使えないというのがこれにした理由でもあります。

仮想的な倉庫としてこんな感じ


一番左にマーカ、ダンボールの中にタグが入っていて、わかりやすいように 0001~0004の4桁をエンコードしてあります。

実際に動かしてみたのがこちら。ちなみにデモ用にリーダの出力はかなり抑えてあります。


ちょっとわかりづらいですが、タグを読み取ったところでIDの看板みたいのを表示しています。


これでマーカとの相対位置はわかりますのでタグの位置管理的なことが可能になりますね。

2019年4月12日金曜日

MANICAモバイル貸出返却時にGoogle Homeに喋らせる


■環境
Android
 MANICAモバイルをインストールします。
 https://play.google.com/store/apps/details?id=info.hayato.manicamobile
Google Home
PC(Windows10)
 Node.js、google-home-notifier等をインストールします。
※Google HomeとPCは同一LAN上に設置します。

■処理の流れ

①MANICAモバイルで貸出返却時にIFTTTのWebhooksにWebリクエストを投げます。
②IFTTTのWebhooksでngrokにWebリクエストを投げます。
③ngrokへのWebリクエストをPC上のNode.jsで受け取ります。
④google-home-notifierでGoogleHomeに喋らせます。
⑤MANICAモバイルから直接ngrokにWebリクエストを投げると404が返ってきてしまうので、IFTTTを噛ますようにしました。

■環境構築
1.PC
・Node.jsをインストール  
下記サイトより8.12.0をダウンロードしてインストールします。 

 https://nodejs.org/ja/

Node.jsはJavaScriptで動作するプラットフォームで、サーバサイドプログラムをJavaScriptで記述することができます。シングルスレッドで非同期処理を行い高いスケーラビリティを持ち、リアルタイム性が必要で小規模なWebアプリケーションなどに用いられます。

・Python2.7をインストール
下記サイトより2.7.15をインストールします。

 https://www.python.org/downloads/

・コマンドプロンプトを管理者権限で起動し、作業用のフォルダを作成します。
C:\>mkdir mmbot
C:\>cd mmbot
・windows-build-toolsをインストールします。
npmを使用し、下記コマンドでインストールします。
C:\mmbot>npm install –g windows-build-tools

npmはNode Package Managerの略で、Node.jsのパッケージを管理するツールです。npmではパッケージをインストールする方法が、グローバルインストールとローカルインストールの2種類存在します。
グローバルインストールは「-g」をつけてインストールし、全てのプロジェクトで使用することができます。
ローカルインストールはプロジェクトのルート配下にあるnode_moduleフォルダにパッケージがインストールされ、対象のプロジェクトのみで使用することができます。
  
Windows-build-toolsはWindows環境でnode-gypを使用するのに必要になります。

・node-gypをインストールします。
C:\mmbot>npm install –g node-gyp
node-gypはNode.jsで書かれたクロスプラットフォームのコマンドラインツールで、Node.jsのネイティブアドオンモジュールをビルドするツールです。

・Bonjour SDK、Bonjour Print Serviceをインストールします。

https://developer.apple.com/download/more/?=Bonjour SDK for Windows

https://support.apple.com/kb/DL999?locale=ja_JP

Bonjourはgoogle-home-notifierのインストールに必要になります。

・google-home-notifierをインストールします。
C:\mmbot>npm install google-home-notifier
作業フォルダ配下にnode_modulesフォルダが作成され、各種パッケージが作成されます。
google-home-notifierはNode.jsで動作するGoogle Homeに喋らせることができるモジュールです。
google-home-notifierをインストールすると、ngrokも一緒にインストールされます。
ngrokは. ローカルPC上で稼働しているWebサーバを外部公開できるサービスです。

・example.jsをテキストエディタで編集します。
google-home-notifierをインストールすると、node_modules\google-home-notifierフォルダにexample.jsファイルが作成されるので、テキストエディタで編集します。
下記赤字部分で、GoogleHomeに喋らせる言語を日本語に設定しています。
var express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8080; 
const deviceName = 'Google Home';
const language = 'ja';

googlehome.device(deviceName, language);
googlehome.accent(language);

var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/google-home-notifier', urlencodedParser, function (req, res) {
  if (!req.body) return res.sendStatus(400)
  console.log(req.body);
  var text = req.body.text;
  if (text){
    try {
      googlehome.notify(text, function(notifyRes) {
        console.log(notifyRes);
        res.send(deviceName + ' will say: ' + text + '\n');
      });
    } catch(err) {
      console.log(err);
      res.sendStatus(500);
      res.send(err);
    }
  }else{
    res.send('Please POST "text=Hello Google Home"');
  }
})

app.listen(serverPort, function () {
  ngrok.connect(serverPort, function (err, url) {
    console.log('POST "text=Hello Google Home" to:');
    console.log('    http://localhost:' + serverPort + '/google-home-notifier');
    console.log('    ' +url + '/google-home-notifier');
    console.log('example:');
    console.log('curl -X POST -d "text=Hello Google Home" ' + url + '/google-home-notifier');
  });
})


example.jsを起動します。
コマンドプロンプトで「node example.js」を入力して起動します。
ngrokからURLが発行されます。

c:\mmbot\node_modules\google-home-notifier>node example.js
POST "text=Hello Google Home" to:
    http://localhost:8080/google-home-notifier
    https://xxxxxxxx.ngrok.io/google-home-notifier
example:
curl -X POST -d "text=Hello Google Home" https://xxxxxxxx.ngrok.io/google-home-notifier

別のコマンドプロンプトを開き、上記の赤字の部分をコピペして実行すると、Google Homeが「Hello Google Home」と喋ります。
発行されたURLは後で使用します。
※「xxxxxxxx」の部分はexample.jsを起動する度に変わります。また、8時間でURLは失効しますが、ngrokの無料アカウント登録をすることでトークンを貰えるので、それをexample.jsに加えると失効しなくなります。
アカウント登録をしてもexample.jsを止めて再度起動すると新しいURLになってしまいます。

2.IFTTT(イフト)
IFTTTのMy Applets→New AppletからAppletを新規作成します。
「this」をクリックします。



トリガとしてWebhooksを選択します。
 「Receive a web request」を選択します。Webリクエストを受け取った時に実行されるトリガーになります。
 Event Nameに適当な文言を設定します。この文言がURLの一部になります。
例では「manicamobile」と設定しています。

 次にアクションを設定します。「that」をクリックします。
 同様にWebhooksを選択します。
 「Make a web request」を選択します。Webリクエストを投げるというアクションになります。
 URLにexample.jsを起動した時にngrokから発行されたURLを記入します。
Methodは「POST」を選択します。
Bodyに「text=」と入力し「Add ingredient」から「Value1」を選択します。
「Value1」の箇所にはトリガー(MANICAモバイルからのWebリクエスト)からもらうパラメータが入ります。実際にGooogle Homeに喋らせたい文言が入ります。


3.MANICAモバイル

MANICAモバイルで店舗設定ページを開くと、貸出時/返却時のWebリクエストを設定することができるので、先程登録したIFTTTのWebhooks宛てのリクエストを登録します。


https://manica-mobile.appspot.com/

WebリクエストURL
https://maker.ifttt.com/trigger/{EventName}/with/key/{Key}?value1={Message}

{EventName}…トリガーで設定したEventNameの「manicamobile」を指定します。
{key}…Webhooksで与えられるKeyを指定します。
(IFTTTのMyApplets→Services→Webhooks→Documentationで確認できます。)
{Message}…Google Homeに喋らせる文言を指定します。
例では「MANICAモバイルで貸し出ししました」「MANICAモバイルで返却しました」が設定されています。


例)
https://maker.ifttt.com/trigger/manicamobile/with/key/xxxxxxxxxx?value1=MANICAモバイルで貸し出ししました。


以上の設定を終えAndroidアプリのMANICAモバイルで貸出/返却をすると、Google Homeがしゃべります。








2019年3月28日木曜日

Google Play以外で配布したAndroidアプリに半自動アップデート機能をつける

Google Playを使わずに直接apkを端末に配布することがあるかと思いますが、アプリにアップデートがあった場合、Google Playならコンソールでapkをアップロードすれば自動的に各端末でアップデートが行われますが、直接配布した場合はそうはいきません。

新しいapkファイルをWebからダウンロードするかメールで受信するかなど、なんらかの方法で各端末に送って、ファイル管理アプリなどでそのapkを実行して、Androidシステムのインストーラを起動してアップデート、ということを行わなくてはいけません。
台数が多い場合は大変です。かといって各ユーザーにしてもらうのも負担をかけますし、確実にしてもらえるかもわかりません。

楽にするにはどうしたらいいでしょうか。

ざっくり大きく言うと、以下の2つの機能をアプリに入れれば、自動、、、とまではいかないですが、半自動でアップデートすることができます。
(システムのバージョンアップによりいずれできなくなる、あるいは機種によりできない可能性があります。Freetel Priori5 - Android7.1.2で確認しました)

1.新しいapkを端末にダウンロードする
2.IntentにそのapkのURIを入れてインストーラ(正式名称わかりません)を起動する

1は特に問題ないと思います。HTTP,FTPなんでも良いのでサーバーからapkをダウンロードして、端末に保存すればよいです。ただし保存場所は注意しなくてはいけません。ローカル領域(openFileOutput()で取得するパス)だと、インストーラがapkにアクセスできないため、external領域(Environment.getExternalStorageDirectory()で取得するパス)に置く必要があります。

2が肝心なところです。以下のようなコードで実行できます。
Uri uri = FileProvider.getUriForFile(
    context,
    authority,
    file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

FileProvider.getUriForFile()を使用してapkのUriを取得するのがポイントだと思います。
第3引数はapkのFileです。1のときexternal領域に保存しているので、パスは「/storage/emulated/0/○○○/myapp.apk」などとなると思います。

FileProviderを使用するには、manifestなどに定義を記述する必要があります。重要なところですが、詳細は本筋と外れる部分ですので省略します。

取得するUriは「content://<authority>/<privider_path>/myapp.apk」などとなると思います。<>で囲った部分はFileProviderに定義した値を入れます。

Uriができたら、あとは上記コードの通り、ACTION_VIEWのインテントに各パラメータを入れてstartActivityをすると、インストーラが起動します。(各パラメータについて、Androidバージョンによって要不要が違ったり書き方が違ったりするようですが、詳細は省略します)

注意点として、インストーラは「Google Play」アプリを使用している、あるいはそのもののようなので、端末のセキュリティソフトでアプリの実行を制限しているような場合は「Google Play」を許可するように設定しておく必要があります。

また、この処理をいつ実行するかですが、アップデートボタンをつける、APIを用意して最新版があるかチェックして必要なときのみ実行するなど、凝ればいくらでもできますが、要件に応じて検討する必要があるかと思います。

最後に、インストーラが起動してインストールが完了するまでの画像を貼って終わります。

手動でapkダウンロードしたときと同じ画面です。「インストール」を選びます。

これは機種によって?出たり出なかったりするかもしれません。「インストールする」を選びます。「OK」が目立つので、そっちが押されそうですね。。。 

「許可」します。 

無事新バージョンがインストールされました。

以上です。





2019年3月27日水曜日

xSpan用のデモアプリ作ってみた

Impinj社が出している xSpan というかっちょいいリーダがあります。

このリーダ、アンテナが内蔵されていてこれだけ設置すれば使えます。それだけなら他にもリーダあるんですが、xSpanは(擬似的に)13枚のアンテナが内蔵されているのです。

アンテナは1列に並んでいる感じで、どのアンテナで読んでるかを見ることでタグが右に行ったとか左に動いたとかがわかるようになっています。スゲー

ちなみにどんな風にアンテナが並んでるかは、
https://support.impinj.com/hc/en-us/articles/206246824-xSpan-Documentation
こちらの「xArray/xSpan Orientation Guide」というのに記載されています。

とはいえなんせ電波なもんで見えないし、実際にはどんな風に読んでるのさ?というのがわかるといいなーと思ってデモアプリを作ってみました。

じゃーん


超シンプル。読み取ったタグのEPCと、横に読み取ったアンテナのところにRSSIが入るというそれだけです。これがなかなか遊び甲斐があります。

というわけで動画

わかりづらくてすいません。でも何となくおわかりいただけるのではないかと。画面の左下に一枚タグを置いてるんですが、これが1行目のデータで、2行目と3行目は動かしているタグのデータです。どうでしょう。わかります?わかるよね?

デモ用なんですが、リーダ設置の際とか読取りテストに使えるかなーと思ってます。

2019年3月14日木曜日

リーダの制御をうまいことする

今回の内容は RFID とはあんまり関係ないんですが、Android から RFID のリーダを制御するときのあるある的なネタです。

リーダを制御する場合、Bluetooth でつないだり 直接接続(シリアル的な)でつないだりとリーダごとに違うんですが、問題は通信先のリーダは1つということで、スマホにおいてはカメラやマイクなどハードを使うときと同じように1つのアプリで専有しちゃうとまずいということなんですね。

つまりアプリの起動時にリーダに接続(専有)して、終了時に切断(開放)する必要があるということです。さらにサスペンドしてるときとかアプリが裏に回ったときなんかも細かく切断する必要があります。

じゃぁ、Android の Activity のライフサイクルにおいて onResumeで接続して、onPauseで切断すればいいじゃん的な流れに当然なりますよね。しかし複数の画面があるアプリで画面を切り替えると onPause とか呼ばれちゃうので画面を切り替えるたびに切断、接続を繰り返すのでちょっとそれはなーってなります。

ようするに自分のアプリが画面に出ているときは接続してて、画面からいなくなったら(それが終了であれ裏に回ったであれサスペンドであれ)切断するというのをやりたいのですが簡単そうでなかなかできません。

そこでこちらの記事を参考にしてみました。
https://qiita.com/wasnot/items/e7e4699de4b21f150c63

Applicationを継承して、Activity のライフサイクルじゃなくて Application のライフサイクルを利用しようというわけです。



やり方は簡単で、Application を継承したクラスを作って、AndroidManifest.xml の application の name属性 に作成したクラス名を指定するだけです。

この onActivityStartyed と onActivityStopped がそれぞれアプリ内で Activity がスタートしたときとストップしたときに呼ばれますので、呼ばれた数をカウントして1個目だったら画面に表示されはじめた、0個になったら画面から居なくなったと判断できるわけですね。

これが正解なのかよくわかりませんが、実装は楽でした。

2019年1月10日木曜日

USBメモリにICタグを貼ってみた。(Smartrac Bling R6編)



■管理対象

今回は何の変哲もないUSBメモリにICタグを貼ってみたいと思います。


■貼ってみたICタグ

今回使用するICタグは、SmartracのBling R6、
端正なアンテナパターンが魅力の近接通信用タグ。


■貼るときの注意点/こんな貼り方が良さそう

とりあえずロゴを隠さないように貼ってみました。
本体サイズが小さいので、貼れる場所は限られてますね。


■どれぐらい読めるかな

ひとまずハンディリーダー(RF-Blaster 1Wタイプ)で読み取ってみるとだいたい、50cmぐらい。これだけ小さいのに、なかなかですね。




■まとめ

というわけで、今回はUSBメモリにSmartracのBling R6を貼ってみました。

これからいろんなものにペタペタ貼っていきたいと思いますー