2021年9月15日水曜日

気を測る

 センサーを搭載した RFID タグはそれなりに登場してきているんですが、その中の一つに farsens のタグがあります。

このタグはIOが付いていて、そこに別途センサーを接続することで測定ができるという面白い使い方ができます。仕様を見るとここに繋いだセンサーの抵抗値を値として取得できるようです。

タグのユーザ領域にデータが保存されますので、専用のリーダは必要なくどんなUHFのリーダでも読み取ることができるのもこのタグの特長になってます。

最近エクセルツールに対応した Apulsetech のリーダで試してみます。

エクセルツールをちょっと改良して、タグの値を取得できるようにしてみました。

まずは何も繋げずに測定してみます。


1億7千万くらいの値になりました。単位はオームだそうです。

次にショートさせてみます。



30オームくらいになりました。

次は両端を手で握って図ってみます。


私の抵抗は40万オームくらいらしいです(笑


さらにこんなの用意しました。板にアルミホイルを巻いただけのプレートです。昔なんかの付録だったかでこういう板と紙コップみたいなのと何か銅線を繋いで気を測るみたいなのがあったと思うんですがありませんでした?そういうの?そうですか。


このまま測ると13と低い値が出ています。


ここで気を送ってみます。はぁぁー っと。さぁ値は変わるのか?


気のせいだな。きっと。

2021年9月8日水曜日

RTKを使った位置測定を試す

 とある案件で RTK を使った位置測定のデバイスを作成したんですが、これがいろいろ使えるということで今回は納品した器材をお借りして実際に測定をやってみました。

ちなみに RTK は GPS のごっついみたいな感じで、cm単位で位置の測定ができるというスグレモノです。ドローンの位置制御みたいなのに使われてます。

こちらがデバイスになります。


右から通信用親機、基準局、移動局にあたる子機の3種類です。親機は AC電源+Wifi が必要ですがその他の機器はバッテリーで動作します。

こちらのデバイスは各デバイスの通信として LoRa を使用している所が大きな特長になります。通常の RTK では、基準局のデータをリアルタイムに移動局に渡して移動局が位置の計算を行います。この方法では基準局のデータを移動局に渡すため、基準局と移動局が通信できる必要があります。この通信はWifiを利用していることが多く、測定位置がWifiの通信範囲に縛られます。

今回のデバイスは基準局のデータを移動局に渡さず、すべてのデータをクラウドに集めて計算するようになっていますので、各機器は通信用の親機にデータを投げればよく、この通信に LoRa を使用しているため、数キロ離れた場所でも測定が可能になります。

数キロ離れた測定は検証が大変なので近い距離で試してみます。

駐車場に設置。親機は Wifi でインターネットに接続する必要があるので向こうにある建物に設置してあります。

結構なデータ量を LoRa で送らないといけないんですが LoRa は通信に時間がかかる上、複数の機器が(チャンネルが同じ場合)同時に通信できないので、PPS を使って正確な時刻計測を行い、送信時間を各機器が分割することで各機器の送信が被らないように各機器が制御を行っています。

電源をONして5分程度すると、だいたい位置がFIXしてきます。


こちらがクラウド側の結果表示画面です。写真の奥側からこっちを見てる感じなのでちょっとわかりづらくて申し訳ありません。が、だいたい位置関係は合ってるようです。右側に X,Y,Z の値が出てますが、単位は m です。X が東西方向、Y が南北方向、Z が高さ方向です。

これから計算すると、子機1と子機2の距離は5.46mだそうですので検証してみましょう。


子機1にメジャーを合わせて


子機2までの距離を測ってみるとほら!5.46mに近い!すげーぜ RTK


2021年8月19日木曜日

RFID的商品マスタの持ち方を考えてみた

RFIDを使って在庫管理をしようと思ったとき、在庫データの持たせ方は大きく2つに分類されると考えています。すなわち、

  • ユニークなタグIDに品番や品名などの商品の情報を紐づけて管理する方法
  • システムに商品マスタを持ち、タグIDの一部を使って商品マスタとマッチングして管理する方法
前者は、たとえばMANICAモバイル棚卸パッケージで採用している方法です。今回は後者の方法について考えてみたいと思います。

標準的な方法(SGTIN-96)

RFIDを使って商品の在庫管理を行う場合、JANコードベースのSGTIN-96を使った方法が一つ考えられます。このとき商品マスタはこんな感じになっていると思います。

商品マスタ(商品コード, 商品名, JANコード, 仕様, ...)

ICタグを読んで商品コード、商品名やそのほか仕様等を取得する場合は、下記のような変換を行う感じになると思います。

SGTIN-96 → JANコード → JANコードで商品マスタを検索 → 商品コードなどを取得

標準的でない方法(独自コード)

さまざまな理由で独自コードを採用するケースも考えられます。このとき商品マスタはこんな感じになっていると思います。

商品マスタ(商品コード, 商品名, バーコード, 仕様, ...)

標準的な方法のJANコードがバーコードに変わっただけですね。もしかすると、商品コードとバーコードが一致しているかもしれません。標準的な方法と同じように商品コード、商品名やそのほか仕様等を取得する場合を考えてみます。ICタグのEPCのなかに商品コードが含まれているとします。

EPC → 商品コード → 商品コードで商品マスタを検索 → 商品コードなどを取得

標準的な方法とほとんど変わらないですね。ただ、独自コードですので、EPCから商品コードへの変換は独自コードごとに対応(=カスタマイズ)が必要となります。

統一した方法(SGTIN-96、独自コード)

SGTIN-96も独自コードも統一して管理できる方法を考えてみます。まず、商品マスタはこんな形で持たせてみます。

商品マスタ(商品コード, 商品名, バーコード, 検索キー, 仕様, ...)

ここで新たに追加した検索キーには、シリアルを0として当該商品コードをEPCにエンコードした場合の値を保持しておきます。他にMaskをシステムで一つ保持しておきます。Maskはシステムで採用したタグID長のByte配列とし、EPCのうち商品コードを特定するための部分に1を立てておきます。EPCから商品コードを取得するにはこんな感じになると思います。

EPC → 検索キー(EPCとMaskをAnd) → 検索キーで商品マスタを検索 → 商品コードなどを取得

SGTIN-96、JANコードが4573228900149の場合はこんな感じになると思います。

Mask: FFFF FFFF FFFF FFC0 0000 0000
商品マスタ(商品コード1, 商品名1, 4573228900149, 302DB42318A0038000000000, 仕様1, ...)

たとえば、EPC: 302DB42318A0038000001231 を読み取ったら、Maskして、302DB42318A0038000000000 となるので、商品マスタを検索して、商品コード1などが取得できます。

一方で、独自コードの場合はこんな感じになると思います。タグIDの0~15 bit目と32~47 bit目に分かれて、商品コード相当の値が入っていたとします。

Mask: FFFF 0000 FFFF 0000 0000 0000
商品マスタ(商品コード2, 商品名2, A123B456, A1230000B456000000000000, 仕様2, ...)

たとえば、EPC: A1230000B456000000004567 を読み取ったら、MaskしてA1230000B456000000000000 となるので、商品コード2などが取得できます。

あと考える必要があるのは商品マスタの連携方法だと思います。当然検索キーに相当する列は存在しないので、連携の際にエンコードルールに基づいて変換して登録することになると思います。

商品マスタ連携部分は都度対応が求められる箇所かと思いますので、そこに修正を押し込められるのはこの持ち方のメリットかなと思います。こんなケースはどうするのか、など考慮不足などあれば、コメントでお知らせください。

2021年8月11日水曜日

DRAGINO の LoRaWAN ゲートウェイと Azure IoT Hub を接続する

 最近 LoRaWAN を触ることになったんですが、通常は The Things Network を LoRaWANサーバとして利用しますが今回は The Things Network を経由せずに Microsoft Azure IoT Hub に接続したいという特殊な状況になってしまったためいろいろやってたんですが、これがえらいハマってしまったので記録として残しておこうと思いました。

使用する LoRaWANゲートウェイは DRAGINO の LPS8 です。

設定画面をいろいろ見ていると、Azureとかの設定もあるしこれは簡単にできそうだなーと思ったら全く違っていろいろ大変でした。

まずは端末の認証ですが、ゲートウェイ単体では OTAA(Over-the-Air Activation)はできませんので、ABP(Activation by Personalization)を使うことにします。ABPの設定は端末ごとに DevADDR、APP Session Key、Network Session Key の3つを設定画面で設定して、同じ値を端末に設定すればOKです。

以降、設定画面のキャプチャ掲載しますがファームの更新が結構頻繁にあるようなので実際とは異なる可能性あります。掲載時点でのファームのバージョンは lgw-5.4.1628078462 です。

ABPの設定をしたら、LoRaWAN Configuration の画面に移ります。Service Provider のところに、Built-in for ABP Decode to MQTT というまさしくそれな的なのがあるので選んで保存します。


次にMQTTの設定です。Azure IoT Hub にMQTTで接続するには、SASと呼ばれるセキュリティトークンを使用する方法と、X.509証明書を利用する方法があるようです。

https://www.dragino.com/downloads/downloads/LoRa_Gateway/LPS8/Firmware/Application_Note/MQTT_WebUserInterface-v0.3.pdf

この辺のマニュアルを読んでみると、Azureへの接続にはSASを利用しているように見えます。ただSASには有効期限があって、できるだけ短く(1時間とか)にするのがお作法のようで、設定しても1時間で繋がらなくなるなどになってしまうのでそれでは困るなーというわけでX.509証明書の方でやってみることにします(証明書も有効期限ありますがこちらは長く設定できるので)。

X.509証明書で接続するためにいろいろやんないといけないんですが、こちらのチュートリアルが比較的簡単に実行できました。

https://docs.microsoft.com/ja-jp/azure/iot-hub/tutorial-x509-scripts

上記チュートリアルを実行した前提で話を進めます。

接続には3つのファイルが必要になります。Azure の CA認証ファイル(ゲートウェイにデフォルトでインストールされている Azure.cer です)と、上記のチュートリアルで作成したデバイスの認証ファイル2つ(cert/new-device.cert.pem と private/new-device.key.pem)です。デバイスの認証ファイルはあらかじめゲートウェイにアップロードしておきます。

Azure設定画面を見てみると、CA認証ファイルの設定しかありません。やはりSASを利用する前提のようです。


ということで MQTT Server Profile を General に変更します。


ファイルは画面の設定のように選択しますが、User IDのところは {IoT hub name}.azure-devices.net/{device id} を設定します。

ここまでで設定は完璧です。完璧なんですが…

飛ばない… データ… いくら送っても… Azureまで飛んでこない… あう・・・

何で?特にエラー出るわけでもなく Azure のログにも大した情報は出ていない。ダメか、詰んだか。そういえば上のマニュアルで mqtt のサンプルコマンドが載ってたな。そうか、それを試すのだ。

ゲートウェイに SSH で接続して、コマンドで MQTT 送信してみます。

mosquitto_pub -d -h XXXX.azure-devices.net 
      -p 8883 -u XXXX.azure-devices.net/H0001 
      --cafile /etc/iot/cert/Azure.cer 
      --cert /etc/iot/cert/new-device.cert.pem 
      --key /etc/iot/cert/new-device.key.pem 
      -i H0001 
      -t devices/H0001/messages/events/ 
      -m "{ Hello }"

するとあれ?飛ぶぞ?えっ?えっ?
何が起きてるんだろう(まぁ、こんなことはよくあるけど)。マニュアルでは MQTT の処理は mqtt_process.sh がやってるとか書いてあった。じゃ何やってるかちょっと覗いてみるか。送信部分を抜粋。

# ------------------------------------------
# Call MQTT Publish command

# 1. Case with User, Password and Client ID present  (e.g. Azure)
if [ ! -z "$pass" ] && [ ! -z "$user" ] && [ ! -z "$clientID" ]; then
	case="1"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic -u $user -P "$pass" $C $cafile $PUB_FLAG "$mqtt_data"
	
# 2. Case with Certificate, Key and ClientID present (e.g. AWS)
elif [ ! -z "$certfile" ] && [ ! -z "$key" ] && [ ! -z "$clientID" ]; then
	case="2"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic --cert $cert --key $key $C $cafile $PUB_FLAG "$mqtt_data"
	
# 3. Case with no User, Certificate or ClientID present
elif [ -z "$user" ] && [ -z "$certfile" ] && [ -z "$clientID" ]; then
	case="3"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -t $pub_topic $PUB_FLAG "$mqtt_data" 
	
# 4. Case with no User, Certificate, but with ClientID present
elif [ -z "$user" ] && [ -z "$certfile" ] && [ ! -z "$clientID" ]; then
	case="4"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic $PUB_FLAG "$mqtt_data"
	
# 5. Case with User and ClientID present, but no Password and no Certificate present
elif [ -z "$pass" ] && [ -z "$certfile" ] && [ ! -z "$user" ] && [ ! -z "$clientID" ]; then
	case="5"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos -i $clientID -t $pub_topic -u $user $PUB_FLAG "$mqtt_data"
	
# 6. Case with User and Password present, but no ClientID and no Certificate present
elif [ ! -z "$user" ] && [ ! -z "$pass" ] && [ -z "$clientID" ] && [ -z "$certfile" ]; then
	case="6"  
	mosquitto_pub $D -h $server -p $port -q $pub_qos  -t $pub_topic -u $user -P "$pass" $PUB_FLAG "$mqtt_data"
	
# 0. Else - invalid parameters, just log
else
	case="Invalid parameters"  
	logger "[IoT.MQTT]:Invalid Parameters - mosquitto_pub not called."
fi
  
設定で処理が別れている様子。ログを見ると General の設定は case 2 にあたるようだ。よくみるとあれ? User IDの設定(-u)が無い! あー、それでかー、そんなことかー、ようやく原因がわかったー。おもむろに -u の設定を追加して保存。

これでようやく無事に送信はできるようになりました。

※注意 今回はアップリンクの話だけで、ダウンリンクはまだこれから試します。



2021年7月16日金曜日

Type2 と Type5 で Capability Container の仕様が異なっていた

 今回は NDEF に関する内容です。NDEF というとスマホで URL を書き込んだりして利用しますが使用しているタグは NTAG213 だったりが多いと思います。

NTAGシリーズは Mifare の後継で NFC Forumでは Type2 のタグになります。そんなわけで NDEF は Type2 のタグだけしか使えないのかというとそういうわけでもなく、ISO15693 のような Type5 のタグでも使うことができます。

最近 NDEF のロックを使う機会があったのでロックってどうやるんだったっけかなー、確か Capability Container に設定するのが簡単だったよなー、でも実際どうやるんだったっけーといろいろ調べてたら Type2 と Type5 でロックの仕方が異なるということに気づきました。

ちなみに Capability Container ですが、

こちらがとある NTAG203 の中身で、Page3 の E1 10 12 00 のところが Capability Container になります。実際の NDEF のデータは Page4 以降に書込みされます。

ここのどっかがロックだったよなーと思いつつ仕様をみたところ、Type2 では

1バイト目 E1 マジックナンバー(固定)
2バイト目 バージョンナンバー
3バイト目 メモリサイズ
4バイト目 上位4ビットがリードコントロール 下位4ビットがライトコントロール(00 はリードもライトもOK、0F にするとライトできなくなる)

となっています。あれー、こんなんだったっけー、何か違う気がすんなー、まー、もー、歳だしなー、とブツブツ言いながら 0F を書いてみます。が… あれ?書き換えできるぞ?何だ?というところから今回の旅が始まりました。

結局いろいろ調べて、Type2 と Type5 で Capability Container の仕様が異なるということがわかりました。そうです。私が苦戦していたのはまさしく Type5 のタグだったのです。くそー。

Type5 の Capability Container の仕様は以下の通り。

1バイト目 E1 マジックナンバー これは一緒
2バイト目 上から 2bit メジャーバージョンナンバー 次 2bit マイナーバージョンナンバー 次 2bit リードコントロール 最後 2bit ライトコントロール(11 で書込み不可)
3バイト目 メモリサイズ
4バイト目 追加情報

ライトコントロールは2バイト目になっています。これだと4バイト目をいくらいじっても何の効果も無かったわけですねー。ていうかこの部分って仕様違ったんだー。

2021年6月7日月曜日

ESP32マイコンで USB接続の RFIDリーダを動かす

 前回のアレクサガジェットのときは、ESP32 マイコンと RFID リーダは Bluetooth の SPP で接続していました。ESP32 は Bluetooth も内蔵しているので、そのままで SPP や BLE のリーダを使うことが出来ます(通信仕様は調べる必要がありますが)。

その後いろいろありまして、今度は USB 接続のリーダを利用する必要が出てきました。もちろん ESP32 マイコンには USB ホストコネクタありませんので、USB ホストのモジュールを使う必要があります。

モジュールはいくつかあるようなんですが、スイッチサイエンスさんにM5Stack用のシールドがありましたのでこれなら情報もそれなりにありますし何とかなるだろうと思って使ってみることにしました。

USB Host Shield for M5Stack

回路図とにらめっこしながら作成したのがこれ。

プログラムはライブラリの USB_Host_Shield_2.0 がそのまま使えるということでサンプルプログラムの USBFTDILoopback を使います(つないでいるUSBのリーダがFTDIなので。このリーダはSPPだけでなく、USB接続して仮想COMポートで制御できます)。このサンプルでは特定のデータを送信して受信するのを繰り返すようになっています。そこで送信するデータを下記のリーダのバージョン取得コマンドに書き換えておきます(65行目)。

char strbuf[] = "~rv\r\n";

早速動かしてみると、動いてはいるようですがコマンドを投げているような気配はありません。何が起きているのかわからないのでデバッグモードにしてデバッグ出力するようにします。settings.h の42行目あたりの次の値を0から1に変更すればいいようです。

/* Set this to 1 to activate serial debugging */
#define ENABLE_UHS_DEBUGGING 1

これで動かしてみると、

FTDI Init
FTDI Init: Product not supported
Expected VID:00000403
Found VID:0403
Expected PID:6001
Found PID:6015

このような表示でました。どうも PID が合ってないようです。ということでソース側のPIDを変更します(cdcftdi.h の29行目あたり)。

もう1回動かします。

FTDI Init
Addr:01
NC:01
Conf.Val: 01
Iface Num: 00
Alt.Set: 00
Endpoint descriptor:
Length: 07
Type: 05
Address: 81
Attributes: 02
MaxPktSize: 0040
Poll Intrv: 00
Conf.Val: 01
Iface Num: 00
Alt.Set: 00
Endpoint descriptor:
Length: 07
Type: 05
Address: 02
Attributes: 02
MaxPktSize: 0040
Poll Intrv: 00
NumEP:03
Conf:01
baud_value:001A
baud_index:0000
FTDI configured
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2
.~Rv0000bl-7.2.6.2

キター!リーダからバージョン情報のリプライが来ています。これで ESP32 マイコンからUSB接続のリーダが利用できるようになりました。


2021年6月1日火曜日

RFID対応の Alexaガジェットを作る

 MANICAモバイルのゲートを作るというのを以前やったんですが、これをちゃんと作りたいということで何で作ろうかと考えたんですが、やっぱり手頃なのがなくてそういえばアレクサとか Google Nest とか最近どうなってるんだろうと思ったら、アレクサのガジェットが作れるようになっていました。

詳細はこちらに詳しく記載されておりますので参照くださいませ。

ESP32をAlexa Gadgets Toolkitデバイスにしよう

RFIDリーダとガジェットを直接接続するのは無理ですが、ESP32とRFIDリーダを接続すればガジェットとして使えそうです。ちなみにガジェット自体は上記リンクの内容で問題なく動いたんですが、なぜかスキル側でエンドポイントの取得が全然できなくて一旦諦めたんですが数日後にやってみたらあっさり取得できたので進めることができました。

こんな構成になります。

   アレクサとESP32はBLE、ESP32とRFIDリーダはSPPで接続します。

まずは家の中で使う想定で、これを使ってカギとかサイフとかを探せるようにしてみたいと思います。

・・・


というわけで作成してみたんですが、実用レベルには至らなそうな結果になってしまいました。

私「アレクサ、ICタグでカギを探して。」

アレクサ「わかりました。」 ここでリーダが自動で読み取りを開始する

アレクサ「ありませんね」

アレクサ「ありませんね」

アレクサ「反応あり」 (タグが読めた)

アレクサ「反応あり」

アレクサ「近い」 (RSSIが大きくなった)

アレクサ「近い」

アレクサ「そこ!」 (RSSIがさらに大きくなった)

アレクサ「そこ!」

私「あった」

アレクサ「よかったですね!」 ここでリーダの読み取りは停止

という動きになるんですが、なんともリアルタイム性が無いので探しづらいです(笑

ESP32側ではリアルタイムに判定できるんですが、その結果をガジェットで上げるとクラウドのスキルまでいって、そこから話すことばを選んでアレクサに降りてきてようやく話すという感じなので判定からアレクサが喋るまでどうしてもラグが出来てしまいます。

アレクサは言葉のやり取りをする前提なのでリアルタイム性を求めるのは難しいかもしれません。何かもうひと工夫必要ですね。