巷にはいくつものGNSSモジュールが販売されていて、そのなかでもu-blox製品が特にお気に入り。
小型デバイス向けのNEO-M8シリーズではUBXプロトコルというu-blox独自のプロトコルが採用されているので、知っている範囲、調べた範囲のメモ。
特徴
- バイナリプロトコル
- コマンドはチェックサムで検証
- クラスとメッセージIDで機能を分解
メッセージ
メッセージは可変長データで、メタデータが同期キャラ2バイト、クラスとメッセージIDで2バイト、データ帳2バイト、チェックサム2バイト、これにペイロードが1バイト以上ついて最低9バイトとなる。
SYNC CHAR 1 | SYNC CHAR 2 | CLASS | ID | LENGTH | PAYLOAD | OK_A | OK_B |
---|---|---|---|---|---|---|---|
1byte, 0xb5固定 | `byte, 0x62固定 | 1byte | 1byte | 2bytes, Little Endian | Nbytes | 1byte | 1byte |
チェックサム
CLASS
から PAYLOAD
全体がチェックサム計算の対象となる。
SYNC CHAR 1 | SYNC CHAR 2 | CLASS | ID | LENGTH | PAYLOAD | OK_A | OK_B |
---|---|---|---|---|---|---|---|
1byte, 0xb5固定 | `byte, 0x62固定 | 1byte | 1byte | 2bytes, Little Endian | Nbytes | 1byte | 1byte |
ここから | ここまで |
次のように計算する。なんとなく練習でPythonで書いてみる。
def calc_checksum(data):
ck_a = 0
ck_b = 0
i = 0
while i < len(data):
ck_a = (ck_a + data[i]) & 0xff
ck_b = (ck_b + ck_a) & 0xff
i += 1
return ck_a, ck_b
例: Low Power Modeを書き込む
Low Power Mode=Continuous Modeを書き込む。UBXプロトコルのメッセージをバイナリで組み立てる。
※サンプルが雑でごめんなさい。
# 同期ヘッダ、クラス、ID、ペイロード長さを指定
header = struct.pack('BBBBH', 0xb5, 0x62, 0x06, 0x11, 2)
# ペイロードは2バイト分
payload = b'\x00' + struct.pack('B', 0)
# チェックサムの計算
ck_a, ck_b = calc_checksum(struct.pack('<BBH', 0x06, 0x11, 2) + payload)
# 送信データを組み立てて書き込み
data = header + payload + struct.pack('BB', ck_a, ck_b)
gps_s.write(data)
GNSSモジュールから次のような応答が得られれば成功。
※実際にはバイナリ文字列
b5 62 05 01 02 00 06 11 1f 48
応答の意味は次のようになる。
SYNC CHAR 1 | SYNC CHAR 2 | CLASS | ID | LENGTH | PAYLOAD | OK_A | OK_B |
---|---|---|---|---|---|---|---|
1byte, 0xb5固定 | `byte, 0x62固定 | 1byte | 1byte | 2bytes, Little Endian | Nbytes | 1byte | 1byte |
b5 | 62 | 05 | 01 | 02 00 | 06 11 | 1f | 48 |