【RTK21】RTCM3をESP-NOWで送信検討<RTCM無線配信>

ここ1年RTCM3データをF9Pへ送信する方法を何種類も試してきました。
一番安定した結果が得られるのはシリアル有線接続ですが、TPOに合わせると
無線でないと使いにくい場合が多くあります。
そこで、過去の無線接続失敗の経験を生かして、ESP-NOWで接続トライしました。
とりあえず、机上では接続完成してますがRTKに関しては、フィールドで無事使える実績
がないとシステムの完成とは言えませんので、これから3か月くらいESP-NOWで
無線RTCM送信を何か所かのフィールドで評価をしていきます。
TPOに対してDebugしながら安定したら、STAシステムrev02で採用しようと思います。
rev01は実績のある有線RTCMで完結させます。

●ESP-NOWで無線接続をする理由
①STAの利便性向上
 WiFi NTRIP MASTERとかM5AtomでNTRIPレシーバーをF9P上に設置すれば
無線(WiFi)でRTCMを供給することは今までもやってきました。
しかし、スキーターンアナライザ(STA)では、2個のMovingBaseBOXにRTCMを供給しないといけませんので、ALES 接続用のNTRIPレシーバー1個から2分配配信しないといけません。STAシステムrev00、rev01では、有線で2分配してきましたが、胸のハーネスに取り付けたNTRIPレシーバーから足元のBOXまで長い線で信号と電源を送らないといけない構成になっていて、スキーを開始するまでの配線作業が1時間近くかかってしまって不便極まりなくとても実用的ではありませんでした。

②ESP-NOWの信頼性はXbeeより上のはず(BlueToothは後日確認)

ここ5年の電子工作の経験上、ロス率が低く、速度が速く同時多端末接続が簡単なESP-NOWしか知らないのでこれを採用します。
115200bpsで一挙に500byte以上を送信しないといけない場合
 Xbeeは、データロス率が1%以上になってRTCM送信には向きません。
BlueToothは、スマホとの通信でしか使ったことがありませんが、スマホCPUの性能が低かったせいか大容量データの高速受信はエラーがでましたが、
マイコン間での通信にBlueToothを使ったことがないので、ESP-NOWがこけたらBlueToothも検討してみます。
ArduSimple社でも、BlueToothを38400bpsでつかっているので、多分できるにはできると思いますが、MovingBase10HzだとF9Pが多忙なのでRTCM受信タイミングが心配です。
ようなF9Pの最高速を使うアプリケーションでは遅い速度だとシビアなRTCM送信条件では厳しいと思います。しかし、
ESP-NOWにも課題があって、250Byte以下が1パケットになります。RTCM3は、500byte以上が1パケットになります。
そこが過去数か月ESP-NOWではRTCM送信できないネックとなってました。

●ESP-NOWでのRTCM送信の構成
ESP-NOWだけならWiFiルーターは必要ありません

絵にかけば単純なのですが、プログラムが結構大変でした。

●ESP-NOWでRTCM3を連続送信する方法
送信側M5Atomで、RTCMをFrame毎に分解してESP-NOWの1パケットを1Frameで送信する。受信側M5Atomで受信したら、複数のFrameをRTCM1本にまとめてSerial2F9Pへ一括送信する。

①RTCMのFrame分解
RTCMの基礎はこちらのページに詳細あります。
 RTCMのフレームは、ヘッダが0xd3、0x00の次にデータ長がくるのでデータ長+ヘッダ6バイト分をRTCMから切り取ります。抜きとり部にif文から切り取りforループです。
 char rtcmdata[]にNTRIPから受信したデータが格納されてます。
だいたい510-~570byteくらいのサイズです。
rtcmdata[i]でヘッダ0xd3を見つけたらrtcmdata[i+2]にデータ数が格納されてます。
ヘッダが6バイトあるので、フレームデータ数はrtcmdata[i+2]+6 バイトになります。これをRTCM全データ数だけ回してFRAMEを数個抜き出します。だいたい3-5個くらいになります。

if(rtcmdata[i]==0xd3 && rtcmdata[i+1]==0x00 )
{
frameNo++;
for (k=0;k<rtcmdata[i+2]+6;k++)//header 6byte+ data
{
framdata[k]=(uint8_t)rtcmdata[k+i];
}
//ESP-NOW send framdata[]<250esp_err_t result = esp_now_send(slave.peer_addr, framdata, k); //ESP-NOW Binary Send}

ばらしたframdata[]をESP-NOWで受信側M5Atomへ送信します。

②RTCMのパケットの終了を認識してF9Pへ一塊で送信する
RTCMはバイナリの配列で、デリミタも終端マークも一切ありません。ヘッダの0xd3もデータ内に多数出現するので、0xd3を検出しても間違います。0xd3、0x00,データ数でデータ数分だけ抜き出したら次のフレームが0xd3だったら初めて抜き出したFrameが正解だとわかるという何ともつかみどころがない規格です。
ですので、一旦バイナリーで送信されるとどこがスタートで、どこで終わっているのか判別するのが大変です。
■RTCM3の観察
①受信フレーム数と時間バラツキ
TRIP受信を眺めていると結構時間ばらつきがあるように見えるのですが、
5分ほどのデータを計算すると
・個数ばらつきは97%が532バイト一定値が97%t

・受信周期ばらつきは800msec周期以上が95%

② 受信したデータをEXCELで眺めながら頭部分を解読
 MSM4フォーマットで、4個の構成で、1フレーム100~150バイト
ESP-NOWのサイズに丁度いいので、MSM4フレーム単位で送信することにしmしました。NTRIPからの受信が時間ばらつきが大きいので、全部整えてから
無線送信して、F9Pに時間正確に入力するように考えてます。
1バイト目:0xd3 目印
2バイト目:リザーブ 0x0
3バイト目:データ数 12bitだからリザーブの下位4bitと3バイト目の8bit
4-5バイト目:RTCMメッセージtypeID  12bitなので、4byte+5byte目上位4bit
5-6バイト目:参照しているSTATION ID 12bitなので、5byte目下位4bit+6byte目
これで、現在受信しているRTCMは4つのセンテンスの繰り返しでした。
メッセージタイプIDは、BLOXのinterface仕様書で番号と名称を調べました。

1074:GPS MSM4メッセージ
1084:Glonass MSM4メッセージ
1094:Galileo MSM4メッセージ
1124:Beidou MSM4メッセージ
みちびき(QZSS)無しでcm級RTKを使ってました。

それぞれのフレームバイト数が110~155で合計532バイトありました。
たまに、半端なデータフレームが入ってくるので、上記4つのメッセージをヘッダとして検出して、きれいにそろえてからESP-NOWで送信する方式のプログラムを作っていこうと思います。今回は、そこまでできなかったので、適当に数と時間で切り出す方式でしたが。これは不安定でした。

■私の使っている終端の判別方法
上記観察から 500byte以上、800msec周期以上でデータがそろった時に
F9Pに送信するアルゴリズムにしました。これで使えるかこれから
いろいろ実験評価していきますので、正解かどうかは数か月先まで判りません。

 

if(t-trcv>300 && frameNo > 0)//最後にRCVがあった時から300msec受信がなければ1パケット終了したと判断
{
frameNo_1=frameNo;
Serial.println();
Serial.print(“,t-trcv>300:,”);
for (i=0;i<frameNo;i++)
{
Serial.println();
Serial.print(“,frameNo=,”);
Serial.println(i);
for (j=0;j<framdataN[i];j++)
{
Serial.print(framdata[i][j],HEX);
Serial.print(“,”);
rtcmdata[rcount%800]=framdata[i][j];
rcount++;
}
}
// }
//RTCM packet Recive finished start to send F9P through Serial2
//if ( frameNo==frameNo_1 && rcount==rcount_1 && rcount>500 || t-t_1>800)
//{
frameNo=0;
frameNo_1=0;
fsum=0;
t_1=t;
Serial.println();
Serial.print(“rcount,”);
Serial.print(rcount);
Serial.println();
for (k=0;k<rcount;k++)
{
Serial2.write(rtcmdata[k%800]);
Serial.print(rtcmdata[k],HEX);
Serial.print(“,”);
}
Serial.println();
rcount=0;
rcount_1=0;
} //if t-trcv>300 end

 

volatile uint8_t framdata[6][250];//ESP-NOW data
volatile int framdataN[6];

■ESP-NOW受信データのvolatile宣言
ESP-NOW受信部はバックグラウンドの割り込みタスクで動いてます。void OnDataRecv()内で得たデータは、タスクが終了した時点で消えてしまいますのでloop()で使えません。通常は、タスク内でprint出力するかsd保存するかで間に合っていたのですが、今回は、Frame毎に受信されたデータを配列変数としてloop()に渡して、Frameを全部足し合わせて1本のRTCMデータに復元しないといけませんので、配列変数を固定した記憶させておく必要があります。そこで、グローバルな配列宣言を

として、framedataを6個最大250byteメモリに不揮発で保持する宣言をすることで、OnDataRcv()タスク外でも使えるようにしました。

 

●中途半端なNGプログラム備忘録
NTRIPレシーバーのM5StickCのソース
(Ntrip_clientのライブラリーが必要ですのでこちらの記事にあります)

 https://gist.github.com/dj1711572002/7c57404d6ddb0b356c50d04bc15ab404
 ESP-NOW送信側M5ATOMソース
https://gist.github.com/dj1711572002/4c8bd66ae32836c9ce958b2e92edf1f7
 ESP-NOW受信側M5ATOMソース
https://gist.github.com/dj1711572002/bfce376972a429c3bd12f73391e061d3

●動作確認
家の軒先アンテナだと5-6分でFIXして2dAcc=14mmでる基準があります。
 机上で、2時間ほど動作させるとと時々NO RTK になって2dAcc=150mmまで落ちるの点が怪しいです。ぼちぼちとデバッグを進めていきます。RTKソフトデバッグ実験は、変動要素が大きく
変動の原因がどこにあるのか、判らなくなるので、RTKプログラムデバッグ管理のやり方も改良しながら進めていきます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です