mosaic X5 (mosaic HAT)で RTK 測位

少し使い方もわかってきたところで、RTK接続を。 でも、場所的には最悪なんだが、実現するかどうか。。。 ここ数年、自宅ではなかなかFixしなかったり、Fixしてもすぐに落ちたりしてており、結局屋外に出かけていたので正直設定と1度でもFixして動作確認ができればいいと思っていた。

しかし、結果はそれなりのFIXを得られて満足。 測位精度は屋外での実験を待ちたいが、現状では期待以上の結果が出ている。

さて、まず環境の紹介。

環境としては最悪かも。 次にシステム構成は下記。 PCを除くと写真の通り。

Wifi-Routerとmosaic HATとM5Stack Core2

今回の目的は、M5Stack Core2とmosaic X5をつかったRTKの実現である。

まずは、Core2が20km以上離れた場所のNtrip Serverに接続し、RTCM3の情報を得て、mosaicへ送信。mosaicからは、RTKのFix状態と位置情報を確認する。

まずは、RTKの設定をしない状態。

SBASが1衛星だけ補足していたが、単独測位との表示で±80cmといったところか。

衛星を半球しか捕まえていないところを見ると、かなり良い。 もしかしたらSBASが効いている可能性があるのだろうか。

従来の受信機ではこの状態だと軽く10mぐらいずれてしまっていた。次に、RTK測位を行っている場合、下記を見ると特にmosaic側での設定は不要のようである。

見ると、COM2にRTCM3が毎秒1kB程度づつ送られているのがわかる。

RTKもFloat解が出だした。

その後、Fixになり、それなりにほおっておいた状態が下の図である。

半球しか見えていないことと、これまでの実績を加味すると、このデータは結構よさそう。

その後、NMEAの出力を100mSに変えたが、Fix率が悪くなった。また、トレースで見切れていないのだが、(ここはu-centerが便利)RTKの送信が間に合わないのではないかという想像もしている。

どちらにせよ、個々のあたりはほかのアプリも組み込んだうえで調整が必要である。

また、少し気になるところとしては、Fixed RTKからStand-Aloneに落ち、Float解を経由してFix解となったときに、アンテナの位置は移動していないのだが、同じ場所を示さないという現象がある。

±15cm程度の誤差ではあるが、さらに良い環境で確かめる必要がある。

半球というところと、Ntrip Serverまでの距離が長いことと、Ntrip Serverの位置情報を入れていない事も十分考えられる。

今回は、M5がWifi-Router経由でNtrip Serverからのデータを受信し、mosaic X5に転送し、ちゃんとFix解が出るかどうかという実験だったので、それに関しては完了!

MOSAIC HAT (MOSAIC X5)の接続

さて、今度は、Septentrio社 の mosaic を試してみる。 X5という話なのだが、シルクにはmosaicとしかかない。

でも、ここに二次元バーコードが付いているので、読んでみると(URLかと期待した。) MOSAIC-X5GRB….

となっており、ちょっと安心。 mosaic-X5として扱っていける。
Webをみると、結構情報がある。 これまでubloxを使っているのはu-centerがわかりやすいという面がおおきかったが、どちらかというとマニア向けか。

ちょっと見たところでは、

データシートやマニュアル類、最新バージョンのファームの情報などは下記ある。

https://www.septentrio.com/en/products/gnss-receivers/receivers-module/mosaic#resources

そのほか、githubにもかなりの情報が公開されている。

https://github.com/septentrio-gnss/mosaicHAT

また、各種コンフィグレーションなどはRxToolsによって行われるが、下記からDownloadができる。

https://www.septentrio.com/en/products/software/rxtools#resources

ドライバも一緒にインストールされるので、あまり困ることはない。

さて、私のWindows環境にRxToolsをダウンロードし、ドライバと一緒にインストール。

そしてボードを見てみて、ANTとFTDI(USB/シリアル変換)で電源設定があるので、とりあえず両方とも3.3Vに指定して二周波のアンテナとUSBを接続。

一応動き出したが、場所の関係もあり、1GPS,1GLONASS.1BeiDou,1NavICしか入らない。 

ちょっと少し移動せざるを得ないか。。。

部屋の反対側に来て、作業性は悪いものの、半球は開放。さすがにあっという間に衛星を確保。

4GPS,7GLONASS,4Galileo,7BeiDou,1QZSSとなった。

方位が半円しか見えないためか、Main Signalの評価は半分以下しかあてにできない。 まぁ。しょうがないか。

まぁ、ほとんど設定も必要なくここまで来た。

そういえば、入江先生がWebで設定していたような雰囲気で話していたので、もしかしてと思い、pcの設定を確かめてみると、USB経由でLAN接続されているみたい。 また、192.168.3.1が怪しいので、さっそくChromeで接続してみると、これで十分設定できそうな画面が出てくる。

なんとなく感触はつかめた。 ふむ。 これは面白い。 

では次にGPSロボットカーのGPS部に使えるかどうか考えてみる。

まず、素材としてやらなけてばならないのは、

MOSAICの立ち上げ (この投稿部分が該当)

ロボットカー CPUへのNMEA送信(接続含む)

RTKの実現

というところか。

今回はMOSAICからシリアル通信でカーCPU ( M5 Stack Core2 ) へ通信。 

カーCPUというのもめんどくさいので、今使っているM5Stack Core2で実験。 ← ちょっとの遊びには結構高いんだよねぇ。。。 

まずは、Core2のアプリを作成。

要はMOSAICから受信したデータを画面に出すことと、USBでPCに送ること。

Core2上の画面では制御文字が出るとどうなるかわからないので、一か所にAscii CodeがHexで表示されるようにした。

また、Core2からPCにシリアルを送るのは、データを見たいだけではなく、トレースデータを見たいのだが、設定Webではそのような機能を探しきれなかったので、u-centerを使ってしまおうという考え。

Core2で作ったスケッチは下記。

#include <M5Core2.h>

#define RXD2 13 //HardwareSerial Serial2;
#define TXD2 14 //HardwareSerial Serial2;

static int i;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);  //USB to PC
  delay(100);
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);  // UART for GPS module
  delay(100);
  M5.begin(true, false, true, true); //LCD:Yes, SD:No, Seria:Yes, I2C:Yes
//  M5.Power.begin(); // Power ON for GPIO21,GPIO22 and I2C
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("M5 Started");
}

void loop() {  
  i = i + 1;
  if(Serial2.available() > 0) { 
    int data = Serial2.read();     
    Serial.write(data); 
    M5.Lcd.setCursor(0,20);
    M5.Lcd.println(data,HEX);
    M5.Lcd.println(i); 
  } 
}

何をやっているかというと、端子の定義とシリアルの定義(USBと端子)。

SerialのBufferに何かデータが来たら、そのままUSBに送信。 M5にはAscii Codeの16進数表示とLoop Counterの表示。

次にMOSAICとCore2の接続は下記。

Jumperスイッチとして3V3とVCCを接続。 ESP32のUARTは3.3V系のため。

シルクをみると、PWR SRCとあるので、VCCの電圧設定だけかもしれないが、念のため。

(こんな時にジャンクでとってあるJumper Switchが役に立つ)

CORE2側は

MOSAICもCore2もたぶんどちらもDCE側(端末側)。 なので、TXとRXD、RXとTXDを接続する。

ここは、ベンダーによってさまざまなので、だめなら逆に。 というレベル。

GNDはGND同士で接続。 MOSAICにはRTS/CTSの制御線があり、設計者のきちんとした意図が感じる。

でも、ごめんなさい。 使わないです。 Core2に無いし。 (仕事だと使うんですけどね)

つぎはMOSAIC-X5の設定。 Core2とMOSAIC-X5をともにUSBにつなげて電源ON。

192.168.3.1にアクセスして

Serial Portを指定して「Next」で次に

COM2を指定して、

好きなメッセージを選択してFinish!

最後にOK!!!! うーん。 簡単。 簡単。 

さらに、この更新周期に関しては期待大!

では、Core2の画面。

よさげ。

IDEのシリアルモニタの画面。

Good!

さらに、シリアルモニタを終了してu-centerでの画面。

Very Good!

u-centerでの設定 (NEO-M8P-2)

ちょっとu-centerの設定方法という相談があったので、ちょっと思い出してみました。

まずは、u-centerを最新版へ。 昨年はv20でしたが、いまみるとv22なんですねぇ。

v20を惜しみなくアンインストールし、u-bloxのWebからダウンロードしてインストール。

さっそくM8P-2にusbとアンテナを接続し、teratermで認識しているポートを確認。

今回は、COM3でした。

ためしにOKを押して少し様子を見ると、

接続はされている。 文字化けしているが、この辺りはアスキーコードの若い番号も来てしまうので、

御愛嬌といったところです。 ポートが正しいことと、読めていることを無事に確認。

こんなことをしているうちにダウンロードが終了し、u-centerのインストールへ。

インストールとともに、u-centerが起動されたので、tera termを終了してu-centerに

まずは、受信機のコネクションでCOM3を設定。

Packet Consoleボタンを押して

まずは、通信を確認。 位置は把握できていないようですが、衛星はある程度捕まえているので、

ちょっと先に進む。 ここは、テストするには環境が悪く、一部しかダメなんですよね。。。。

こんな感じです。

位置測位を開始していないところが気になるが、どんどん設定に進んでしまいましょう。・

[View]-[Configuration View]-[MSG]

ここで必要とするMSGを定義します。 ここにはいくつかの流派はあるので、自分の思い通りに。。

私は以下の設定。

出力はUSBとシリアルの両方としています。 (一応、、、) UART-2は今回はないので、設定しようとしてもSendした段階で消されてしまいます。

Robot Carで使用するNMEA MessageはGxRMCなんですが、U-Centerで感度やほかいろいろ見るときもあるので、最初はGxGGA,GxVTG、GxGLLも出力するようにしています。 (本番走行前で余裕があったときは、これらを外しています。)

 なので、こんな感じ。 都度、Sendを忘れないように。 一応2-3回チェックしたほうが良いです。

設定したつもりが変わっていないということはよくあること。 気にしない。

そのほかのNMEA Messageは以下の感じで出力しないようにしておく。

ゆっくりした制御なら出力しなくてもよいのですが、できるだけ余分な処理はトラブルの元なの潔く削除。

いつも限界で設定しておくと、トラブったときに、何が、何に関係していたかということがわかるので、それはそれでよしとします。

これが終わったらポートの設定。

左側よりPRTを選択して、UARTとUSBにUBX,NMEA,RTCM3を送受信できるように設定します。

速度は葉や右方が良いので、115200です。 USBで通信するのであれば関係ない。

下記はUART-1の設定だが、UART-2,USBも同じ設定に。 、と、UART-2が設定できなかったので、UART2は無視。

そして、保存します。 (一応保存されるような気もするが)

Packet Consoleを見てみるとGxRMCも出始めました。 よしよしです。

さて、次は、これをどのくらいの周期で出すかという設定です。

毎秒取れればOkという人は不要ですが、早くデータ収集したいという人は、Rateというメニューで設定します。 保存を忘れずに。 この通りにデータが来ると保証されているわけではないです。

M5Stack Core2がリスタートできない。

最近使っていなかったが、考えれば手元にあるM5Stick Cは、ともかくM5Stack Core2はモータとステアリング操作に、I2C、GPSとの通信にUART、RTKにWi-Fi、アピールに音、操作関係にはタッチパネル。

ちょっとパフォーマンスの心配はあるが、サーボをI2Cでやってしまえば可能性ありかと。

本当はパフォーマンスを考慮してRaspberry pi PICO Wを使いたかったんですが、まだ技適前。自分で研究用で申請してしまうのもありだが、そのものが手に入らない。 Arduino IDEでアプリ組めるし。 と思っていたが、また次回のお遊び用に。

さて、M5StackCore2のリハビリを兼ねて数字を表示するスケッチを。

#include <M5Core2.h>

static int i;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);  //USB to PC
  delay(100);
  M5.begin(); 
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("M9 Started");
  Serial.println("M9 Started");
}

void loop() {
  i = i + 1;
  M5.Lcd.setCursor(0,15);
  M5.Lcd.println(i);
  M5.Lcd.println("123456");
  Serial.println(i);
  delay(500);
}

あれ? うまくいくときもあるが、再書き込みで止まったり、リスタートボタンの横のLEDが消えていたり、動作がおかしい。 リスタートボタンをおしてもウンスンではないか。。。

もしや、ESP32やUnoで時々苦しめられたRSTの信号不安定か?

ググってみると。 Core2においては、同現象に悩まされている人もいるが、それほど多くはない。

過去のセオリー通りにRSTとGND間にコンデンサをつけている人も確かにいる。

幸いCore2には端子もある。。。 おもちゃオシロで見てみるべきか。。。

こんな時にはリビング行ったり、冷蔵庫空けたり、、、、そういえば、Fall Guysが無料になっているんですよね。 なんとなく、Fall Guysの名前が覚えられなくて、Whole Foodsが頭の中に出てくることこの頃。

ってなことを考えながら、再度PCの前に。。。 Delayを増やしたり、カーソル処理を外したり。。。 あれ? ダウンロードするときに Time Out起こすことも、ますますCore2がひねくれている。

こうゆうときは、一度工場出荷へ。 EasyLoader_M5Core2_FactoryTest.exe を使って、最初のアプリをロード。 あれ? 動くじゃん。 リスタートも何度やっても問題ない。 これのアプリ部分だけ入れ替えたいなぁ。。。

ん? 

OSが原因か? ボード情報を取得してみると、対象外? んん? M5StackのCore2のボードと設定しているが、中身がこっそり変わっていたか??? ファームのスタイルが変わっていてIDEと一致していなかったのかも。

さっそく、ボードマネージャでM5Stackを検索。 インストールは1.0.6 最新は2.0.3。 これかぁ。。

最新に上げて、ダウンロードして事なきを得た。 コンパイルが長くてたまらん。 PCの性能もあるが、何とかしてくれ!!! 昔もコンパイル間に仮眠をとっていた時代が懐かしい。 これが原因だったのね。

すると、これまでESP32でトラブっていたのもこれが原因だったのでは??? と疑ってしまう。

動作確認して良好を確かめ一安心。 念のためにライブラリのM5Core2も0.1.2から0.1.4に挙げておいた。

再度動作確認して問題のないことを再確認してComplete!

磁気センサについて MPU-9250 (AK8963)

これまで、方位についてはGPSから入力される信号を用いていたのだが、

利点として

・移動時の測定においては移動方向の方位が取得できる。

・GPSの精度が良ければ方位も十分な精度が期待できる。

 ここでいう精度とは再現性である。

欠点として

・移動していないと方位の取得が取れない

これまでは、基本的に移動している状態で方位を算出していたので、GPSでの方位取得を行ってきた。

しかし、今回は必要性に迫られた部分もあり磁気センサから方位算出を行うこととした。

使用したのは、 MPU9250 と呼ばれる9軸センサ。
ジャイロ、加速度、磁気センサが入って9軸というわけだが、今後の遊びも含めてということでこれを選定。

値段もまぁ許される程度です。

しかし、中身はちょっと素直ではなさそう。

いくつかのサンプルを試してみたが、高速で読もうとすると時々0が戻ってきたりする。 サンプルが悪い気もしなくはないのだが、データシートを見ると、磁気センサはSDA/SCLというよりも AUX_CL,AUX_DAに接続されているので、そちらをI2Cと想定して試してみた。 というわけであくまで保証はできなく参考程度にしてください。 また、この磁気センサは旭化成の AK8963 であり、使い方などはAK8963 のデータシートが参考になる。 下記はMPU-925のブロック図です。

ESP32との配線は、以下の感じ。

MPU-9250のSCL/SDAには接続せずEDA/ECLに配線することによって磁気センサに直接アクセスが可能となる。

参考のためにソースコードを記載する。 転用などは特に連絡不要ですが無保証です。

また、勝手な想像によるキャリブレーション 機能も搭載しています。

// This software is released under the MIT License.
// See license.txt at http://moon.robots.jp/ehp/ 
// The software is provided "AS IS", without warranty of any kind, 
// express or implied, including but not limited to the warranties
// of merchantability. (c) 2021 Team Katy
// 
// 2021/5/23 ver 1.0 first released by S.K
//
//

#include <Wire.h>

const int   I2C_AK8963_addr=0x0c;   // i2c: ak8963 slave address

////// AK8963 register 
const int AK_ID= 0x00;  //  00H READ  Device ID; ID is 0x48
const int AK_ST1= 0x02; //  02H READ  Status 1  DataStatus; D0:True; data ready D1:True data overrun
const int AK_HXL= 0x03; //  03H READ  X-axis data 8190:4912uT -8190:-4912uT
const int AK_CNTL1= 0x0A; //  0AH READ/WRITE  Control1  Function Control
                          // see data sheet D0:3 mode; D4:0 is 14 bit, 1 is 16bit
const int AK_ASAX= 0x10;  //  10H READ  X-axis sensitivity adjustment value Fuse ROM
const int   AK_WAIT=100;     // Wait for mode change [us]
const int   AK_MOD_PWRDWN=0x0;   // Power down mode 
const int   AK_MOD_READ_METHOD=0x1;   
                // Read method:0x1:Single
                //             0x2:Continus 8Hz
                //             0x3:Continus 100Hz
const int   AK_MOD_FUSE=0x0f;    // mode change to read FUSE
const int   AK_MOD_BIT=0x10;   // # of read bits: 0x10:16 bit, 0x00:14 bit
const int   AK_I2C_ADD=0x48;   // I2C address for AK8963
static float x_bias = 0; // calibration value
static float x_gain = 0; // calibration value
static float y_bias = 0; // calibration value
static float y_gain = 1; // calibration value
static float z_bias = 1; // calibration value
static float z_gain = 1; // calibration value

static int  i2c_buf[8];    // read buffer for I2C
const int   max_char=8;    // max read characters from serial monitor

//********** i2c_read **********//
int i2c_read(int addr, int cnt= 1, int *buf=NULL)
{
  if (cnt<1 or 128<=cnt) return(-1);
  int   rtn_code, i, dat;

  Wire.beginTransmission(I2C_AK8963_addr);
  Wire.write(addr);
  rtn_code= Wire.endTransmission(false);
  if (rtn_code!=0) return(-1);

  Wire.requestFrom(I2C_AK8963_addr, cnt);
  for (i=0; i<cnt; i++)
  {
    dat=Wire.read();
    if (buf==NULL)
      break;
    else
      buf[i]=dat;
  }

  while (Wire.available()) Wire.read();

  if (buf == NULL)
    return(dat);
  else 
    return(buf[0]);
}

//********** i2c_write **********//
int i2c_write(int addr, int dat)
{
  int rtn_code;

  Wire.beginTransmission(I2C_AK8963_addr);
  Wire.write(addr);
  Wire.write(dat);
  rtn_code=Wire.endTransmission();
  if (rtn_code!=0) 
    return (-1);
  else 
    return(0);
}

//********** mag_read **********//
int mag_read(float &x, float &y, float &z)
{
  int   rtn_code;
  delayMicroseconds(AK_WAIT);
  rtn_code=i2c_write(AK_CNTL1, AK_MOD_READ_METHOD | AK_MOD_BIT);
  if (rtn_code!=0) {
    Serial.println("Error in configuration setting for AK8963");
    return(-1);
  }

  while ((i2c_read(AK_ST1) and 0x01)==0); // wait until ready.

  i2c_read(AK_HXL, 7,i2c_buf); // read measure data and status2 
  if (i2c_buf[6] & 0x08)        // check sensor overflow in status2
  {
    Serial.println(" Sensor overflow ");
    return (-1);
  }

  x=int ((i2c_buf[1]<<8) + i2c_buf[0]);
  y=int ((i2c_buf[3]<<8) + i2c_buf[2]);
  z=int ((i2c_buf[5]<<8) + i2c_buf[4]);

  if (x>32767) x= x-65536;
  if (y>32767) y= y-65536;
  if (z>32767) z= z-65536;
  
  x+=x_bias;
  y+=y_bias;
  z+=z_bias;

  return (0);
}

//********** calib_mag **********//
void calib_mag()
{
  int   i, pre_cnt = 10;
  float xmin=9999,xmax=0,ymin=9999,ymax=0,zmin=9999,zmax=0;
  float x,y,z;
  int   calib_count = 150;
  float cx[calib_count];
  float cy[calib_count];
  float cz[calib_count];
  x_bias =0;
  y_bias =0;
  z_bias =0;
 
  Serial.println("Entering Mag");

  for (i=0; i<=pre_cnt; i++){
    delay(1000);
    Serial.print(pre_cnt-i);
    Serial.println(" sec reamin for calibration.");
  }
  
  Serial.println(" Start calibration, please rotate the sensor.");
  for (i=0; i<calib_count-1; i++){
    mag_read(x,y,z);
    Serial.print(calib_count-i);
    Serial.print("/");
    Serial.print(calib_count);
    Serial.print(": x="); Serial.print(x);
    Serial.print(": y="); Serial.print(y);
    Serial.print(": z="); Serial.println(z);
    cx[i]=x;
    cy[i]=y;
    cz[i]=z;
    if(xmin>x) xmin = x;
    if(ymin>y) ymin = y;
    if(zmin>z) zmin = z;
    if(xmax<x) xmax = x;
    if(ymax<y) ymax = y;
    if(zmax<z) zmax = z;
    delay(100);
  }
  x_bias = 0 - (xmax + xmin) / 2;
  y_bias = 0 - (ymax + ymin) / 2;
  z_bias = 0 - (zmax + zmin) / 2;
  x_gain = 1 / ((xmax - xmin) / 2);
  y_gain = 1 / ((ymax - ymin) / 2);
  z_gain = 1 / ((zmax - zmin) / 2);
  Serial.print("Calibrated Values are X Bias ="); Serial.print(x_bias);
  Serial.print(", Y Bias "); Serial.print(y_bias,3);
  Serial.print(", Z Bias "); Serial.print(x_bias,3);
  Serial.print(", X Gain "); Serial.print(x_gain,5);
  Serial.print(", Y Gain "); Serial.print(y_gain,5);
  Serial.print(", Z Gain "); Serial.println(z_gain,5);
  
  Serial.println("Wait a 15 seconds");
  delay(15000);
}

//********** read_serial **********//
int read_serial()
{
  if (Serial.available()){
    char ch = Serial.read();
    return((int) ch );
  }
  else return(0);
}

//********** setup **********//
void  setup (void)
{
  Serial.begin(115200);
  Wire.begin();
  if (i2c_read(AK_ID) != AK_I2C_ADD) Serial.println("NOT FOUND AK8963");
  delayMicroseconds(AK_WAIT);
  
}

//********** loop **********//
void  loop(void)
{
  int ch_i = read_serial();
  Serial.print("ch = ");   Serial.print(ch_i); 
  
  if ( ch_i >= 49){ // ch_i = '1' 
    Serial.println("Calib Start");
    calib_mag();
  }
  float x,y,z;
  int rad;
  mag_read(x,y,z);
  rad=atan(y/x)*(180/3.1416) + ((x>=0)? 0: (y<0)? -180: 180);
  Serial.print(rad); 
  Serial.print(": "); 
  Serial.print(x,5); 
  Serial.print(","); 
  Serial.print(y,5); 
  Serial.print(","); 
  Serial.println(z,5); 
}

サンプルプログラム公開

GPS・QZSSロボットカーコンテスト2020で使用した測位とWaypoint算出に関するソースコードを参考用にUpします。
本ソースコードは「測位航法学会特製 F9P搭載受信機」にも対応しているはずです。

最適ではないのですが、参考になる方もいるかと思い公開に踏み切りました。 もちろん無保証なのと、これによる問題障害については一切責任は負えないので、そのあたりを理解してみてもらえば幸いです。 また、本業が忙しく、コメント・質問などに、答えられない場合があります。


2019年大会はFix率が悪く、走行テストが難航し2回目の走行をキャンセルせざるを得なかったのですが、今年は参考までに以下の対策を講じてみた。 (どれが効果的かというのは感触です。)

-F9PのFarmwareのUpgrade
これはかなり効果があったと思います。
-QZSSの無効化
これも効果があったように感じますが、FarmのUpdate後にL1Sに関する記事を読みL1Sを無効化して再登録。 Fix率は下がらないことを確認した。 L1Sの無効化が聞いたのかFarmware Updateが効いたのかは不明。
-アンテナ背面の銅箔テープによるマルチパス防止
これは気持ちの問題だった気がする。
-ntrip Serverとのアクセス手法
これは効果大だった。制御周期も早いので、制御の合間に数文字程度を読み取って制御側の処理をやっていたが、メッセージ終了までは制御は行わず一気に処理を行った。
-F9P更新周期
F9Pはカタログスペック上20Hzとなっており、51ms(50msが定義できなかった)で動作させた。Logを見るとデータが変更しないときもあるが、最速で見るれ可能性が高いと想定し使ったが、Fixしたのは1-2度のみですぐに設定を戻した。(100mS~300ms)

そのほか2019年では悩んでいたBluetooth通信であったが、ESP32 DevkitをV4にすることで同じソースコードで動作した。試しにV2に戻すと動作しない。 昨年はこれでだいぶん時間を食ってしまったが。 ただ、PC側は毎回削除し、登録している。 この辺はかなり改善の余地がある。 また、Bluetoothを使っていると、たまに処理が止まったり遅くなったりすることがある。情報取得時以外はPC側から接続しないで使っていた。

—–
本ソースコードは無保証の条件で、無償提供し、個人・商用を問わず利用は自由です。ただし、内部で使用されているライブラリなどは、そのライセンス条項に従ってください。

Sample.zip

—–