2019年12月20日金曜日

MANICAモバイルのゲート機能を試してみる

安価にRFIDを導入できるAndroidアプリで簡単に入出庫・棚卸しが可能なMANICAモバイルですが、ゲート機能が追加になりましたので試してみました。

ゲート機能とは、Androidアプリを使用せずにRFIDゲートにタグを読ませるだけで、あらかじめ登録しておいた入庫/出庫の処理を自動で行う機能です。

ゲート自体はまだ出来てないのですが、Webフックで機能しますのでMANICAコレクタを使用して代用できます。

まずはハヤト管理者にゲートを払い出してもらいます。そうするとユーザのメニューに「ゲートの管理」という項目が追加されます。ここでゲートの設定をします。


ゲート名と、読み取ったときの処理(入庫か出庫か)を選択します。入庫のときは保管場所も選択できます。さらにゲートの場所をマップ上から設定できます。今回の図の設定ではゲートで読み取ったら、「名護マルチメディア館の倉庫1に入庫」という処理になります。

実際のゲートを準備します。MANICAコレクタは様々なリーダが使えるので何でもいいんですが、とりあえずそのへんにあるもの使います。


ゲートと言ってもただリーダとアンテナ置いただけです(笑。よく言えばテーブルスキャナ的な。

このゲートをMANICAモバイルのゲートとして使用できるようにMANICAコレクタの設定をします。


MANICAモバイルのゲート機能はPOST対応なんですが、現行のMANICAコレクタ(バージョン2.1.1以下)はGETのみの対応なのでPOST対応に修正しました(次期バージョンの標準機能になります)。

テスト用の物品を準備します。


今回は特別にドラゴンボールを準備しました。単なるテストにこんな大事なものを使うなんて何て贅沢なことをしてるんでしょうか。画面ではステータスが出庫になっています。これからドラゴンボールが届いて、入庫させようとそういう流れです。

というわけでドラゴンボールが3つだけ届きました。


早速読取り!
結果!


見事3つのドラゴンボールが入庫処理されました!

MANICAコレクタでも十分機能するのですが、こういう読取りのさせ方をする場合、読み取ったときに何個読み取ってるのかがわからないととても不安な状態になりますので、読取り数の表示機とかが必要になるわけですね。そのあたりの試作的なものは以前の記事「MANICAモバイル用のゲートを作る その1」に記載しておりますのでご覧ください。

2019年12月13日金曜日

棚卸しパッケージをクラウド化してみる

当社で販売しております「棚卸しパッケージ」ですが、おかげさまで大変ご好評いただいております。このパッケージは、無償でご提供しております「MANICA EXCEL TOOL」をベースに棚卸しの機能をエクセルのマクロで追加し、ハンディリーダ用の専用アプリとのセット製品になっています。

エクセルなので基本的にはスタンドアロンでの運用となります。が、「Googleスプレッドシート」などエクセルのようなクラウドのアプリもありますね。こっちで動くとカッコいいかなーと考えたところ、そういえば棚卸しパッケージではハンディとPCの通信自体はそんなに大したことをしていません。じゃそれをWebとの通信にしちゃえばよくね?ということでやってみました。

Googleスプレッドシートには、Google Apps Scriptというマクロ的なのがあって、これがなんとWebAPIとして公開できるようになっています。ここに棚卸しパッケージのハンディとのやり取り部分を実装して棚卸しパッケージのフリをすることでハンディのアプリそのままに動かそうという目論見で試しました。

こんなイメージ

で、やってみたらこれまたいろんなハードルがあって思ったより相当大変だったんですが何とか動きました。

スプレッドシートで棚卸しパッケージと同じ内容でデータを作ります。


ロケーションのデータも作成


ハンディを起動します。ハンディはデータの送信先を作成したGoogle Apps ScriptのAPIにしただけで、特に大きな修正は入れていません。


棚卸し画面に移動して、マスタダウンロードをします。


キター!ロケーションの情報が表示されました。
部屋Aを選択すると


物品が3個あります。モニタのタグを読むと


この状態でデータ送信ボタンを押します。


するとスプレッドシートの棚卸しの部分にデータがアップロードされました。

これで【棚卸しだけ】をやるのであればスプレッドシートでも問題なく利用できます。ICタグを探す探索機能なども実装できそうです。

しかし問題点もいろいろわかりました。通信がWebAPIなのでサーバ側からハンディに任意のタイミングでデータが送信できない とか 棚卸しパッケージの通信ではSJISでBASE64エンコード使ってたりしますが、これが Google Apps Script ではそう簡単に実装できないとか。

どう進めていくかはもう少し検討が必要ですかね。

2019年11月29日金曜日

ItemTestを使ってxSpanをDirectionモードで動かしてみた

前回はSpeedway Connectを使ってxSpanを制御してみました。今回はItemTestを使ってxSpanを制御してみようと思います。ItemTestはImpinjが出しているテストツールで、上記ページからダウンロード可能です。

今回使ったもの


  • Impinj xSpan
  • ItemTest (v1.14.0)

セットアップ

ダウンロードしたzipファイルを解凍し、exeを実行し、ウィザードを進めれば、セットアップが完了します。

初期設定~読取

  1. アプリを起動し、メニュー左上の「Reader Settings」をクリック
  2. 「New」ボタンをクリックし、xSpanのIPアドレスを入力
  3. 追加されたリーダの「Configure」ボタンをクリックすると、「Field of View」や「Age Interval」「Tag Population」などConnect同様の項目が設定可能
  4. OKを押してメイン画面に戻って「Direction」タブを選択
  5. 「Start」ボタンを押すとタグ読取が開始
  6. 「Stop」ボタンを押すとタグ読取が終了

ログファイル

左下のLog fileのところに、ファイル名を入力しておくと、Start~Stop間で読まれたタグの情報が下記フォルダにCSVファイルとして出力されます。

C:\Program Files (x86)\Impinj\ItemTest\log

出力例はこんな感じです。

// 2019/11/29 22:08:14
// Sector2=True, Sector3=True, Sector4=False, Sector5=False, Sector6=False, Sector7=False, Sector8=False, Sector9=False, Mode=Mode 0 : Max Throughput, Power=30, FieldOfView=Narrow, AgeInterval=4, UpdateInterval=2, EnableSendUpdates=False, TagPopulationLimit=50, ReaderName=192.168.0.91
1575032894605449,Entry,E280117000000209839C2903,2,OK,FirstSeenSector=2,FirstSeenTime=1575032894605449
1575032894639373,Entry,30147A24C415FD81F4500001,3,OK,FirstSeenSector=3,FirstSeenTime=1575032894639373
1575032897771621,Entry,30352E22B81F6D9400000014,3,OK,FirstSeenSector=3,FirstSeenTime=1575032897771621

それぞれの列の意味は多分下記のようです。
  • 1列目はTimestampっぽいのですが、16桁あります。先頭10桁がUnix Timeのようです。
  • 2列目はEntry(タグが範囲に入った)かExit(範囲から出たか)です。
  • 3列目がタグID(EPC)です。
  • 4列目が読まれたSectorです。
  • 5列目がTag Population Statusで読取範囲にタグが多すぎると正しく推定できずエラーになるそうです。
  • 6列目が最初に読まれたSectorです。
  • 7列目が最初に読まれたTimestampっぽいのですが、例のごとく16桁あり、先頭が10桁がUnix Timeのようです。

Tag Population Statusについては、XARRAY AND XSPAN GATEWAYS DEPLOYMENT AND BEST PRACTICESに下記記載がありました。タグ読取数が設定したTag Populationを超えると、User Overflowに、High Performance Modeの場合、50タグを超えると、System Overflowとなり、正しく方向を推定できないそうです。



Rx Sensitivityを設定して、ある程度返信強度の強いタグに絞って推定すればよいのかなとも思ったのですが、Directionモードでは設定できないようです。ItemSenseの場合は確かRx Sensitivityも設定できたような気がするので、方向検知を使いこなすにはItemSenseを使うべきということでしょうか。いずれにしろ方向検知を使いこなすにはいろいろと知識が必要そうです。

2019年11月15日金曜日

Speedway ConnectをxSpanにセットアップしてみた

前回Speedway ConnectRevolutionにセットアップしてみましたが、今回はxSpanにセットアップしてみます。さらに各パラメータについても少し調査してみたので、まとめてみます。

今回使ったもの

  • Impinj xSpan
  • Impinj Speedway Connect (v2.8.0 トライアル版)

セットアップ

前回同様まずはxSpanのFirmwareを最新にアップグレードし、そのあとにConnectをセットアップしました。

Directionモード

xSpanの場合、Reader ProfileでDirectionが選択可能です。Directionを選択すると、Direction Configurationが設定可能となります。


今回はタグがリーダのField of Viewから抜けて10秒後に通知するようにしてみます。そのために下記のように設定しました。

Tag Age Interval: 10 secs
Send Entry Reports: false
Send Exit Report: true

たとえば、環境によってタグがFOVをチラチラしている場合にはTag Age Intervalを長めにとってあげればよさそうです。タグがFOVに入った時に通知したい場合はSend Entry Reportsをtrueに設定すればよいです。

Filtering Software


上記とは別のパラメータにFiltering Softwareという項目があります。こちらはRead Windowの間に同じタグを読んだ場合はそのタグを読み飛ばすという設定のようです。ようです、というのは設定秒経過させてから読ませてみてもうまく通知されず、もう少し経ってからでないとタグの読取が通知されなかったためです。そのため、パラメータの理解が間違っているかもしれません。(あるいは実験の仕方が)


Read Window: 60 secs
ちなみに読取結果は下記のようなJSON形式(かKey-Value Pairs)で通知されます。


{
 "reader_name": "Impinj RFID Reader",
 "mac_address": "00:16:25:13:08:7B",
 "tag_reads": [{
  "epc": "30352E22B80E2C0800000008",
  "type": "exit",
  "tagPopulationStatus": "ok",
  "firstSeenTime": "2019-11-15T12:17:59.323644Z",
  "lastSeenTime": "2019-11-15T12:18:04.109023Z",
  "firstSeenSector": 3,
  "lastSeenSector": 3
 }, {
  "epc": "30352E22B80E2C0800000008",
  "type": "exit",
  "tagPopulationStatus": "ok",
  "firstSeenTime": "2019-11-15T12:23:09.397258Z",
  "lastSeenTime": "2019-11-15T12:23:18.743426Z",
  "firstSeenSector": 3,
  "lastSeenSector": 3
 }]
}

HTTP POST

最後にこれはトライアル版特有なのかもしれませんが、一度POSTした内容を何回もPOSTしているようです。特有といったのはトライアル版には読取できるタグ枚数が500までという制限があるため、読んだタグを保持し続けているのかもしれません。

今回は10秒間隔でHTTP POSTするように設定しています。


Update Interval: 10 secs

すると、下記のように同じ内容のデータが10秒間隔で通知されてきます。



まとめとこれから

Speedway ConnectをxSpan上で動かしてみました。いくつかパラメータを設定することで、あるタグがいつからいつまでその場に留まったかを通知できることが分かりました。今回は試していませんが、認証機能も持っているため、直接クラウドと連携することも可能です。そういう意味でいわゆるIoTにおけるエッジコンピューティングを担う存在と言えます。今後はパラメータの理解を深め、面白い事例につなげていきたいと思います。


2019年11月1日金曜日

フロントガラスにICタグ貼るだけのETC!?

先日、台北で見かけたトラック、よく見るとフロントガラスにICタグが貼られてました。


街中の市場に停めてあるトラックだったんですが普通にパッシブのICタグが貼られていて、気になって調べてみると、日本でいう所謂ETCの役割を果たすものだったんですね。

何とも合理的で素晴らしいなぁ、さっそく真似したいなぁと思うのですが、日本だとフロントガラスにシール貼るだけで道交法違反になりますのでご注意くださいね(笑

ちなみに、フロントガラスにICタグ貼る系で気になってるのが、ブラジルの事例。
https://www.nfcw.com/2019/09/10/364322/nissan-to-build-rfid-payments-into-all-cars-sold-in-brazil/



新車のフロントガラスに、最初からICタグはった状態で販売してるというのだから驚きです。

高速道路はもちろん、駐車場やガソリンスタンド、それからマクドナルドみたいな飲食系も対応してるみたいで、どこでもドライブスルーだそうです。アイデア次第で、ほんと色んな使いみちありますね!

2019年10月26日土曜日

第27回 宜野座村まつり

10月26日、27日に宜野座で開催されている宜野座村まつりに出展しています。

ゲスト豪華

もりだくさんの内容

のんびりな展示

近くの方はぜひ遊びにきてくださいねー

2019年9月17日火曜日

Speedway ConnectをRevolutionにセットアップしてみた

据置リーダを使う場合、たいてい隣にパソコンだったり、Raspberry Piだったりの制御用のコンピュータを置いて使うことが多いと思います。Impinj社のSpeedway Connectはリーダ単体で読取して、外部に通知することができるそうなので、セットアップして試してみました。

今回使ったもの


セットアップ


こちらの手順通りなのですが、一つつまずいたので(No. 1の項目)、記載します。
  1. Speedway Revolutionのファームウェアをアップグレード
    • もともとのバージョンが4.12.0.240だったのを6.2.0.240にアップグレードしました
  2. Speedway Connectのダウンロード
    • ここからLatest Releaseをダウンロードしました
  3. 管理画面をウェブブラウザで開く
    • Speedway RevolutionのIPアドレスをブラウザで開きました
  4. ログイン
    • デフォルトのままなら、root/impinjでログイン可能です
  5. ファイル選択
    • Select Upgrade Fileのファイルを選択ボタンをクリックして、ダウンロードしたupgファイルを開きます
  6. アップグレード
    • Upgradeボタンをクリックすると、ファイルがアップロードされます
  7. 再起動
    • アップグレード完了後に、Rebootボタンをクリックすると、リーダが再起動されアップグレードが完了します
  8. リーダのIPアドレスにHTTPSで接続
    • 証明書のエラーが表示されるので、回避してください
  9. ログイン
    • root/impinjでログイン可能です
  10. 設定画面
    • うまく行けば、こんな感じで設定画面が表示されると思います

設定

いくつか設定項目はあるのですが、最低限の設定を行って動かしてみました。今回は読取内容をWebサーバにPOSTしようと思います。その場合はHTTP POSTにチェックを入れて、サーバのURLを入力すればOKです。


Webサーバ側でログを見てみると、JSON形式で送られて来ているのが分かります。
(実は今回一番苦労したのがこのサーバ側の準備でした。動画の通り、Pythonでやるのがスムーズと思います)


まとめとこれから

今回はSpeedway ConnectをRevolutionにセットアップして、Webサーバにタグ読取結果をPOSTできることを確認しました。さて、以前こんな記事を書きました。そのとき課題として挙げたのが、HTTPSが使えないことと認証ができないことでした。Speedway Connectの場合、どちらも解決できそうなので、その辺をおいおい調べてまた記事にまとめたいと思います。

追記(2019/10/02)

Speedway Connectが起動状態だと、ExcelToolに接続できないことに気が付きました。他のツールと連動して使いたい場合は、Speedway Connectの左上にあるStatusのアイコンをクリックし赤くした上で、Applyボタンを押してください。他のツールと連動できるようになると思います。



2019年9月12日木曜日

第21回自動認識総合展

今年も出展しています。


 KCKCさんとのコラボ製品も展示しています。 


もちろん光るタグの試作機も展示してますよ。


 遊びにきてくださいねー。

2019年9月9日月曜日

RFIDの読取結果を機械学習でクラス分類してみた

前回に引き続き、今回はRFIDの読取結果を機械学習クラス分類してみようと思います。クラス分類にはk近傍法を利用します。では、さっそく始めます。

今回使ったもの(前回同様)


ICタグの読取手順(前回同様)

まず、ICタグを5枚ずつ、数十㎝離して4箇所に配置しました。読取は各箇所の上空にRF Blasterを順番にかざすような感じで読み取りました。(なんだか恣意的ですが)各箇所には上位ビットが同じで下位のシリアルが1~5となっているものをひとまとめにして置いてあります。

Microsoft Azure Notebooks

前回同様Microsoft Azure Notebooksを使用しました。使ったプロジェクトはこちらです。CSVファイルは同じものを使いました。使ったNotebookはこちらです。初めに、pandas, numpyをimportしています。次にDataFrameにデータを取込んで加工しています。今回は前回一番よかった秒単位の読取回数を使ってクラス分類してみようと思います。

pvCountT = df.reset_index().pivot_table(index=[pd.Grouper(freq='1s', key='DateTime')], columns=["TagID"], values="RSSI", aggfunc=np.count_nonzero).fillna(0).T

TagIDの上位7文字をlocationとして設定します。

pvCountT['location']=pvCountT.index.str.replace('[0-9]{9}$','')

各ロケーションに置かれたタグのうち、タグIDの末尾が'0001', '0002', '0003'のものを教師データとします。

train_data=pvCountT.iloc[pvCountT.index.str.endswith(('0001','0002','0003')),:]

同様に末尾が'0004', '0005'をテストデータとします。

test_data=pvCountT.iloc[pvCountT.index.str.endswith(('0004','0005')),:]

kの値を3としたときのk近傍法の結果です。

knn = KNN(n_neighbors=3, n_jobs=-1)
knn.fit(
    X = train_data.iloc[:,use_column].values, 
    y = train_data["location"].values,
)
pred_target =knn.predict(
    X = test_data.iloc[:,use_column].values, 
)
print(sum(test_data['location']==pred_target)/len(pred_target))
0.875

結果は87.5%の正答率でした。まずまずでしょうか。次にkの値を5としたときのk近傍法の結果です。

knn5 = KNN(n_neighbors=5, n_jobs=-1)
knn5.fit(
    X = train_data.iloc[:,use_column].values, 
    y = train_data["location"].values,
)
pred_target5 =knn5.predict(
    X = test_data.iloc[:,use_column].values, 
)
print(sum(test_data['location']==pred_target5)/len(pred_target5))
1.0

今度は100%の正答率が得られました。各位置ごとに3つの教師データがあるので、近傍の5個のデータを見ると、位置が正確に分かるということでしょうか。 最後にkの値を7としたときの結果です。

knn7 = KNN(n_neighbors=7, n_jobs=-1)
knn7.fit(
    X = train_data.iloc[:,use_column].values, 
    y = train_data["location"].values,
)
pred_target7 =knn7.predict(
    X = test_data.iloc[:,use_column].values, 
)
print(sum(test_data['location']==pred_target7)/len(pred_target7))
0.5

今度は正答率が50%まで下がってしまいました。教師データが3つしかないのに、近傍7個のデータを見に行って下がってしまったということでしょうか。

まとめとこれから


今回はRFID読取結果を機械学習のk近傍法を使ってクラス分類してみました。結果に対する考察と背景の勉強はまだまだ行っていく必要がありますが、クラスタリング同様RFIDの読取結果に対して分析することができました。

応用としては、前回記載した通り、RFIDを使った棚卸で位置の決まったタグの読取結果を教師データとして、その他の物品の位置を推定するのに使えるかもしれません。ただ、一般には位置タグの数<<<物品タグの数なので、その辺がどうなるのかもう少し大きなデータセットで試してみたいと思います。


2019年9月6日金曜日

RFIDの読取結果を機械学習でクラスタリングしてみた

RFIDタグを読むといったら、多くの場合、その場にあるモノを自動で識別することを指していると思います。一方で、UHF帯のRFIDを使って、移動の向きであったり、モノの位置であったりを検出するハードウェアや、ソフトウェア的に高精度に向きや位置を検出する技術(RFLocus, Impinj ItemSense)が出てきています。

このように今後はUHF帯RFIDを使って、移動の向きや位置を検出するといった用途が増えていくのではと思われます。そこで、おおざっぱにでも近くに置かれたタグ同士を判別できないかを、読み取ったICタグの時系列データを使って、KMeansでクラスタリングして試してみました。
(いろいろ書いてますが、初心者がPythonの機械学習に触れてみた的な記事です)

今回使ったもの

(*) 結果的にはMANICAコレクタでよかったかも。

ICタグの読取手順

まず、ICタグを5枚ずつ、数十㎝離して4箇所に配置しました。読取は各箇所の上空にRF Blasterを順番にかざすような感じで読み取りました。(なんだか恣意的ですが)各箇所には上位ビットが同じで下位のシリアルが1~5となっているものをひとまとめにして置いてあります。

Microsoft Azure Notebooks

今回機械学習でクラスタリングしてみるのに、Microsoft Azure Notebooksを使いました。使ったプロジェクトはこちらです。RF Blasterを使って読み取った結果がこちらのCSVファイルになります。読取時刻にタグIDとRSSI, Phaseの値が並んでいる形になります。

こちらが使ったNotebookになります。初めに、pandas, numpy, KMeansをimportしています。次にDataFrameにデータを取込んで加工しています。そのあと、下記コードで時系列データを毎秒のRSSI値の平均をとり、タグID単位に集計しています。表示されるタグIDは上から順に5枚ずつ同じ箇所に置いてあります。

pvT = df.reset_index().pivot_table(index=[pd.Grouper(freq='1s', key='DateTime')], columns=["TagID"], values="RSSI", aggfunc=np.mean).fillna(0).T

集計したデータをKMeansでクラスタリングしてみたのが下記のコードになります。

pred = KMeans(n_clusters=4).fit_predict(pvT.values)

結果を見てみると、

print(pred)
[2 2 2 2 2 3 1 1 3 3 1 1 1 3 1 0 2 0 0 2]

先頭から5個ずつ順に同じ箇所にタグを置いたので、同じ数字が5個ずつ並んでほしいところですが、そうなっていません。
同じように、Phase値の平均をとってクラスタリングした結果を見てみます。

pvPhaseT = df.reset_index().pivot_table(index=[pd.Grouper(freq='1s', key='DateTime')], columns=["TagID"], values="Phase", aggfunc=np.mean).fillna(0).T
predPhase=KMeans(n_clusters=4).fit_predict(pvPhaseT.values)
print(predPhase)
[3 3 3 3 3 0 2 2 0 0 2 2 2 0 2 1 1 1 1 3]

こちらも残念ながらうまく並んでいません。そもそも秒単位に平均をとることに意味があるのかわからなくなってしまったので、箱ひげ図を出力してみました。
(データの加工はもうちょっとやり方ありそうですが、思いつかなかったので、適当です)



重なっていてよく分かりませんが、秒単位で集計してもわりと振れ幅があって、平均取ることに意味がなさそうです。同じくPhaseだとこんな感じです。そもそもどういう意味がある数値なのかすら分かってないですが、これも平均取ることの意味がないのかもしれません。


平均ではうまくいかなかったので、もっと単純に秒単位の読取回数でクラスタリングしてみました。

pvCountT = df.reset_index().pivot_table(index=[pd.Grouper(freq='1s', key='DateTime')], columns=["TagID"], values="RSSI", aggfunc=np.count_nonzero).fillna(0).T
predCount = KMeans(n_clusters=4).fit_predict(pvCountT.values)
print(predCount)
[0 0 0 0 0 2 2 2 2 2 1 1 1 1 1 3 3 3 3 3]

これだと、きれいに5個ずつ同じクラスタと判定されました。初期値を変えて、何回かやってみましたが、いずれもうまく判定されました。

まとめとこれから


とりあえず、少数のタグを使ったきれいなデータであれば、うまいこと判別できることが分かりました。次はもう少し実際に近い(いくつかの箱にもっと多くのタグが入っている)イメージで試してみたいと思います。あとは、あらかじめ位置の決まったタグ(いわゆる位置タグ)を教師として、クラス分類してみても面白いかもしれません。

最終的にはUHF帯RFIDを使った棚卸の場面で、庫内のどこかで読んだのだけれど、特定のタグIDの商品がどこにあるか分からないという場面でモノ探しに役立てるようにしたいです。