昨年購入しておいたWiFIモジュール WizFi360をようやくTeensyと接続させて、Ntripレシーバー
を作りました。何故遅れたかは、新しいチップを使う手間と根気がなかったからです。
2025年6月からChatGPTの有料会員になった機会に、過去に自分のできなかったプログラミング作業を
ChatGPTにやってもらうという活動を始めた一環です。
注:FIx10秒以内というのはアンテナの状況が良い場合、ESP8266で数十秒かかっていたのがWizfi360+Teensyで10秒以内になったということです。天候、衛星配置、基準局距離などの諸条件で1分を超えてしまうことはありますので、ESP8266よりはスムーズになったという結果です。
●何故WizFi360なのか
昨年の記事はこれですが、Teensyのパフォーマンスを生かせるWiFiモジュールだからです。
シリアルで1Mbpsと高速で通信できるWifiモジュールで専用なので性能が良いです。

●動作させた結果
今までのESP8266F9Pオンボード方式よりNTRIP接続速度が劇的に速くなりました。
今までは通電してから、NO RTK LEDがついて早くても数十秒経過してFIXするのですが
WizFi+TeensyだとNO RTK LEDが一瞬ついて、直ぐ消えてRTK FIXします。最初壊れたのかと
思ったのですが、あっという間にFIXしてました。
このプログラムコードを作ってくれたChatGPTに聞くと以下のコメント
いくつか考えられる要因があります。大きく分けて「RTCM3 データの到達性/レイテンシ」と「F9P 側の処理条件」の2つです。
1. RTCM3 データのレイテンシ(遅延)の低減
-
UART の安定性・速度
-
WizFi360+Teensy の組み合わせでは、UART1(115 200 bps)で AT コマンド+TCP データをほぼハードウェアDMAで流し込んでいます。
-
一方、ESP8266 では AT コマンドセット+ソフトウェアバッファを介している場合が多く、コマンド応答やデータ転送のたびに細かな遅れ(数十〜百ミリ秒)やジッタが生じやすいです。
-
-
Wi-Fi モジュールの TCP バッファリング特性
-
WizFi360 は「TCP の受信バッファ→UART 出力」のデータパスが非常に素直で、フレーム落ちやコマンドのリトライが少なく済みます。
-
ESP8266 は内部で TCP/IP スタック、Wi-Fi 再接続、AT コマンド解析などを行うため、バックプレッシャによるスループットの変動が起こり得ます。
-
-
パケットジッタの低減
-
RTCM3 のパケット(数百バイト~数キロバイト)が不定期に届くと、F9P がサーバからのストリームを欠けなく受信できず、Fix 算出に必要なサンプル数が揃うまでに余計な時間がかかります。
-
WizFi360+Teensy であれば TCP→UART の遅れ・欠落がほとんどないため、「最初の RTCM3 到着」から「必要な補正量取得」までの時間が短く済みます。
-
2. F9P 側の収束条件
-
補正データの到着タイミング
-
ESP8266 経由だと、最初の補正パケット(RTCM1005/1077 など)が届くまでに数秒以上かかることが多いですが、WizFi360+Teensy だと 1~2 秒以内に最初のパケットを連続して供給できます。
-
F9P は「初回 RTCM 取得 → 衛星測位 → 解消算出」というステップを踏むので、早く安定した補正が来るほど Fix に必要なデータ量が揃いやすくなります。
-
-
Teensy のクロック安定度
-
Teensy 4.1 は非常に高精度なクロックを持っており、UART ボーレートのジッタも極めて小さいため、F9P 側でパケット境界のズレやビット誤りが起こりにくいです。
-
ESP8266 ボードでは 3.3 V レギュレータやクロックソースによる微小な変動が時にシリアル品質に影響します。
-
まとめ
-
WizFi360+Teensy のデータパスが “よりストレート” でレイテンシ・ジッタが小さい
→ RTCM3 補正が早く欠落なく供給され、F9P が必要な補正量を最短で受け取れる -
ESP8266 経由は内部処理や AT コマンド応答のオーバーヘッドが大きく、補正到着が遅れることが多い
→ Fix までの収束時間が長くなる
こうした「補正到着から Fix 算出までのラウンドトリップ時間」の差が、10秒以内という高速 Fix の実現につながっていると考えられます。
確かに、ESP8266でのRTCM3受信をオシロでみると、不自然に分割されて時間をかけて受信されていましたのでRTCM3は難しくて不安定だと思っていたのですが、WiFiチップの構造が大きかったようです。
忙しいF9Pに対して素早く必要なRTCM3を送ってあげれば処理がスムーズになるのは当然と納得です。
●作り方
WizFi360は、日本では販売してませんので、DIGIKEYで購入しました。
1個千円程度なので、複数個買ってTeensyと合わせて6千円以上にすれば送料無料で北米から
3-5日で届きます。 私が購入したチップは技適はついてました。
WizFi360のマニュアルは丁寧です。
製品説明ページ:https://docs.wiznet.io/Product/Wi-Fi-Module/WizFi360
datasheet: https://docs.wiznet.io/img/products/wizfi360/wizfi360ds/wizfi360_ds_v112_en.pdf
コマンド解説: https://docs.wiznet.io/img/products/wizfi360/wizfi360ds/wizfi360_atset_v1119_e.pdf
使用例: https://docs.wiznet.io/img/products/wizfi360/wizfi360ds/wizfi360atcomex_v103e.pdf
クイックスタート: https://docs.wiznet.io/img/products/wizfi360/wizfi360ds/wizfi360qs_v113e.pdf
サポートフォーラム:https://maker.wiznet.io/forum/c/wifi-module/wizfi360
私はピン配置だけみて、TeensyのSerial1のRX1にTXD1とTX1にRXD1を接続するだけで
あとは、ChatGPTにプログラムをお願いしただけです。
●ChatGPTでのプログラミング作業
全部一挙に作ってしまいますが、1発では動作しませんので、一歩一歩確認しながら作量に指示したほうが
最終的には、早くできます。
①TeensyからATを送ってOKがかえって来るかの確認プログラム
=>これが動かなくて、当初WizFiのTXDとRXD0を使っていたのをTXD1とRCD1に付け替えて
TeensyのSerial1とクロス接続したらようやくATでOKがかえって正常動作になりました。
②最初に動いたコード
Wifi ntgrip接続用のヘッダファイル ntrip_cnfig.hのタブをarduinoIDEに用意しておきます。
| // ntrip_config.h #pragma once #ifndef NTRIP_CONFIG_H #define NTRIP_CONFIG_H#include <stdint.h>// === Wi-Fi 接続情報 === static const char WIFI_SSID[] =””; static const char WIFI_PASS[] = “”;// === NTRIP 接続情報 (例: rtk2go.com) === static const char NTRIP_HOST[] = “rtk2go.com”; static const uint16_t NTRIP_PORT = 2101; static const char NTRIP_MOUNTPOINT[] = “”; static const char NTRIP_USER[] = “mail address “; static const char NTRIP_PASS[] = “”; // パスワードなしの場合は空文字#endif // NTRIP_CONFIG_H |
| // Serial1_Ntrip_Client_RawAT.ino #include “WizFi360.h” #include “arduino_base64.hpp” #include “ntrip_config.h” // Wi-Fi & NTRIP 設定まとめ#define WF_SERIAL Serial1 // Teensy 4.1 の UART1 (ピン0=RX1, 1=TX1) #define BAUD_USB 115200 #define BAUD_WIFI 115200void setup() { // 1) USBシリアル初期化 Serial.begin(BAUD_USB); while (!Serial); Serial.println(“\n=== Raw AT NTRIP Client ===”);// 2) WizFi360 UART起動待ち WF_SERIAL.begin(BAUD_WIFI); delay(2000);// 3) ATパススルー確認 Serial.print(“AT? “); WF_SERIAL.println(“AT”); delay(200); while (WF_SERIAL.available()) { Serial.write(WF_SERIAL.read()); }// 4) シングルコネクション設定 WF_SERIAL.println(F(“AT+CIPMUX=0”)); delay(200);// 5) 透過モード設定 WF_SERIAL.println(F(“AT+CIPMODE=1”)); delay(200); // 6) TCP接続開始 // 7) データ送信用モードへ // 8) NTRIPリクエスト送信 // 9) Basic認証ヘッダ生成 // 10) ヘッダ終端の空行 Serial.println(“>>> NTRIP request sent raw”); void loop() { |
これでPCのUSBシリアルにはいってくるのでTeraTermでログしてバイナリエディタでみて
D3 00 89 43 D0 とRTCM3のヘッダでていれば成功です。ucenterでは、完全に認識できませんでした。
●完成コード
Ntripができたので、F9Pに接続してF9PがFixするかみます。USB出力でUcenterとつないでFixをみます。 一瞬でFixしたのは驚きました。F9Pへの接続は、Serial4のTXでRTCM3を送りますが、ubxをSeial4で受信する多重通信は、マイコン側のプログラムが忙しくなるので、リスクが高いので、F9Pのuart2のInに
460800bpsでRTCM3を送りこむことにして、UBXログは、uart1のOUTでTeensyのSerial4にいれました。
●UBXの大容量データのログ
NAV-PVT NAV-RELPOSNED NAV-SATと1-2Kbyteの大きなデータが120msecで入るので
それをSDログするために、ChatGPTでは、SD用バッファを作って対応してました。それについての
解説です。
File logFile = SD.open(“rtcm.log”, FILE_WRITE); logFile.print(data); logFile.fl ush ();
の各ステップで何が起きているかというと…
1. open():
• SD.open() が呼ばれると、まずディレクトリエントリを読み込んでファ
イルを確保します。ファイルが存在しなければ新規作成し、最初のクラ
スタを FAT 上で予約します。
2. バッファリング付き書き込み:
• logFile.print() や write() は、実際には RAM 上の小さなバッファにデー
タを溜め込みます。いちいちカードに書き込むと遅すぎるため、一時的
にメモリ内に蓄積します。 3. fl ush():
• logFile.fl ush() を呼ぶと、その RAM バッファの内容を SD カードに対し
てまとめて(1~複数の 512 バイトセクタ単位で)書き込みます。さらに
FAT テーブルやディレクトリエントリも更新し、ファイル長が反映され
ます。スケッチ内で定期的に fl ush() することで、電源断やリセットが起
きても「最後に fl ush した時点まで」のデータは確実に残ります。
4. close():
• 真にファイルを閉じるには logFile.close() が必要で、fl ush に加えてファ
イルハンドルを解放します。今回お渡ししたサンプルでは、ログを常に
開きっぱなしにして連続書き込みする設計のため、プログラム中で明示
的な close() は呼んでいません。マイコンのリセットや電源オフ時に、ラ
イブラリが自動的に全ファイルを閉じてくれます。
つまり
• fl ush() まで のデータはカード上にコミット済み
• close() はリセット/電源オフ時 にライブラリがまとめて実行
●コードはGIST
https://gist.github.com/dj1711572002/50a3254921d90c3793ab1ac3e11819d6





