Tag Archives: Pixhawk

芝刈りロボットへの道 ~試作版の車体製作3~

前回は芝刈りモーターを取付けて実際に芝生を刈り取れる事が確認できました。
今回は電源回りを整理していきます。

これまでの配線

自動走行ローバーに後付けで芝刈りモーターを追加したので、走行系と芝刈り系が完全に分離しており、芝刈りモーターは単にスイッチでON/OFFするだけでした。

構想

・走行系と芝刈り系のバッテリーを共通にしたいので、小型刈払い機(草かるぞう)に元々付いていた18Vバッテリー1個で両方に供給する。
・草刈るぞうバッテリーはマキタ18Vと接点共通なのでマキタバッテリーも使用可となる!
・バッテリー電圧をPixhawkから測定する為に、抵抗で分圧してAD入力端子に入れる。
・バッテリー電流検出機構も後付けできる様にしておく。
・芝刈りモーターのON/OFFをフライトコントローラーから制御する。

あとついでに・・
・方位取得精度を上げたいので外付け磁気コンパスを取付ける。
・重心が後ろ気味なので前輪(駆動輪)がスリップしがち問題への対策。

となると必要な電圧は、芝刈りモーターに18V、走行モーターに12V、Pixhawk他に5V の計3種類となります。

でも考えたのですが走行用モーターは18VをPWMの上限67%に制限してやれば、わざわざDCDCで12Vに下げなくても良さそうですね。
但し前回使用したモータードライバーIC(TB6612FNG)は扱える最大電圧が15Vなので耐圧不足です。定格18Vバッテリーの充電直後は21V程度あるので、少なくともそれ以上の耐圧があるドライバーが必要です。 そこで秋月電子で探すとTB67H450FNGというのがあり、これだと最大定格が50Vでした。 またこのICをモジュール化したAE-TB67H450というのも売られているので、これのモジュールを使ってみましょう。

芝刈りモーターをパワーMOSでPWM制御するのも含め、前回同様のArduino NANOを使って計3個のモーターを制御するESCを作ろうと思います。

回路検討

前回のTB6612FNGとTB67H450FNGとでは制御信号の仕様が異なっています。
TB6612FNGでは動作状態を制御するIN1,IN2とは別にPWM端子があり、1CHあたりデジタル出力2本+PWM1本で制御していました(あと全体を止めるSTBYにもデジタル出力1本)。


一方TB67H450FNGではIN1,IN2に直接PWMを入力する事になります。

という事はモーター2個を制御するにはPWMが4端子必要ですね。
元々ArduinoNANOは最大6本のPWM出力が可能ですが・・・

実はモーター駆動用PWMの周波数は可聴域以上に上げていたので前回はTimer1だけ周波数を上げて、これに繋がるD9,D10端子を使っていました。
今回更に2本の端子を使うとすると、Timer0又はTimer2に接続されているD5,D6,D3,D11の内から選ぶことになりますが、Timer0はシステム内でmillis()等に使われており、Timer2はtone()等に使われているので周波数を変えてしまうと他に影響が出るのです。

こうなると周波数を変えても他に影響しないPWM端子が足りませんね。
ArduinoNANOに拘らずSTM32F103とかに変更すればいいんですけど、できれば前回のプログラムを流用したいのです。
また芝刈りモーターをパワーMOSで駆動するならゲートに3.3Vだと少し心許なく、かといってゲートドライバーを追加するのは面倒という理由もあります。

そこでArduinoNANOとTB67H450FNGの間に下の様なロジック回路を入れてみました。

ArduinoNANOから出すのはPWM値と方向信号です。TB67H450FNGではIN1,2の一方がPWMで他方がHになり、方向信号でIN1,2を切替えます。
実はこの回路で試すと大体は動作しながらも、時々モーターが回転しないことがありました。どうやら起動の瞬間に過電流検出か何かの状態に陥っている気がします。TB67H450FNG異常解除にはIN1,2両方をLにする必要があるのですが上の回路だとこれができないんですよね。

という事で苦しまぎれですが、更にANDゲートを追加しました。
起動直後はGPIOからSTBY端子をLにしておく事で異常を解除できます(と言うか過電流にならなくなる筈)。
ANDゲートは74HC08を使いたかったのですが手持ちが無かったので74LS08を使いました。実際にはこのままだと電源投入の瞬間(マイコンが動き出すまでの間)はSTBY端子がHなのでモーターが一瞬(クッと)反応しており、できればSTBY端子をプルダウンしたいところです。が、LSだと結構小さな値の抵抗になるので現状プルダウンしていません(マイコンが動き出せば直ぐにSTBY状態になるので大丈夫だとは思いますが)。

芝刈りモーター制御

芝刈りモーターは逆転する必要がないのでパワーMOS-FET 1個でPWM制御します。
実際にはほぼフル回転で使うのでPWM周波数にはこだわらずD11端子を490Hzのまま使っています。サーボ信号入力が1000~1400msは停止、1600~2000mSで回転とし、回転開始/停止時はArduinoNANOのプログラムで等加減速制御としました。

芝刈りモーターを起動するとArduinoがリブートしてしまう問題発生

RC送信機から芝刈りモーターをONにするとArduinoがリブートする現象が発生したので
ゲート抵抗を1KΩとしました。1KΩは結構大きい気がしますが当初の100Ωだと効果が無かったのです。本当は100Ωと1KΩの間の丁度良さそうなところを調べるべきでしょうけど、1KΩでもゲート容量をざっと1000pFとするとCR時間は1μSなので、PWM周波数490Hzの周期は約2mSもあり影響は少ないと思います。

という事で現状の回路図

今の所こんな回路図です。
バッテリー電圧検出は18KΩと3KΩで分圧。電流検出回路はまだ実装していません。

基板の写真・・・
最後に追加したAND回路はユニバーサル基板を空中配線しています。
左下のスペースに電流検出回路を取り付ける予定(今は太線で直結状態)。

バッテリーはAmazonで¥999で売っていたマキタ18V用コネクタ(ソケットと呼ぶのかな?)で接続します。

ついでに磁気コンパスを外付けしたい

前回走らせたとき、Missionplannerに表示される車体アイコンが走行方向に対して微妙に角度がずれた状態で直進しているのが気になりました(ドリフトしながら直進している様に見える)。  また特定の場所にくると次のウェイポイントに向かう角度が定まらず時間がかかったり止まってしまったり。。。
コンパスをキャリブレーションしてもまだ怪しい感じなので外付けコンパスを追加してなるべく地面やモーターから遠い位置に取り付けたいと思います。

使った磁気コンパスはQMC5883LというAliexpressで300円程で買った基板で、かつての定番HMC5883Lに似ているけど微妙に違うセンサーです(HMC5883Lは廃版になっているらしい)。

QMC5883LモジュールはI2CでPixhawkに接続するだけでMissiponplannerを開いたら認識されていました。 設定画面でこちらのセンサーの優先順位を上げてキャリブレーションをやり直したのですが、暫く使っていると磁気コンパスの不一致的なエラーが出てきたので内臓コンパスは止めました。

もう一つついでに全体の重心を前に移動。

これまで時々車輪が空回りしていました。たぶん重心が後ろ気味だった為に前輪(駆動輪)の荷重が小さかったのが原因と考えて、少しでも前に荷重をかける為にGPSアンテナとその支柱を前に移動しました。
外付け磁気コンパスはGPSアンテナから離したかったので車体後部に載せますが、軽くするため塩ビパイプで支柱を作りました。

これでスリップによるスタックはほぼなくなりましたね!!

という事で現状のブロック図

では実際に芝生を刈ってみます。
一気にやるのは不安なので2分割した経路をつくって・・・

航空写真とRTKで取った座標は微妙にずれていて、実際の経路は写真に対し少し右側になります。

動作前の庭の状態は1週間程前に手作業で刈っており、奥の方はまた雑草が伸び始めています(手前側は何度か試走したので刈れている)。

刈り込み前

刈り込みの様子を動画で・・・

刈り込み終了後

刈り込み後

向きを変える時にしばらく考え込むとか、刈り込みラインとラインの間に少し残るとか、まだ問題はありますが何とか動き始めました。
何より猛暑の中を自分で歩き回らなくて済むのがいいです。

この後は・・・

現時点で最低限の自動刈り込みは出来たのですが、実行する為にPC側でMissionplannerを動かしたりRC送信機でスタートを掛けたり(ヤバくなったら止める目的もあるけど)と色々手間がかかります。
安全性も含めてもうちょっと簡単に稼働できる様にしたいのですが、それにはArdupilotだけだと厳しくなってきたのでコンパニオンコンピューターを積み、そっちで色々プログラムしたいです。
と言っても経路は固定なのでROS2を動かすほどでもなく、ラズパイ上のpythonで制御するのがいいかなと思っています。
これにはRaspberry pi ZERO2Wあたりが小型で積みやすいのですが、今なぜかどこも品薄なんですよね。秋月電子では11月入荷予定となっているしAliexpressだと1万円以上の値段で売られています。 という事で手持ちにあったRaspberry pi3でやってみて、ZERO2Wが手に入る様になったらその時点で考えようと思います。

Drone-Bridge for ESP32を使ってみる。

前回RTK基準局を稼働させたので、いよいよ草刈りロボットを検討していきます。
まだまだ道は遠いですが。。。

第一段階としてArdupilotで動作するローバーを作って庭を走らせてみようと思います。これにはPC上で動くGCS(Missionplanner)とフライトコントローラー(PixHawk)との間を何らかの方法で無線接続する必要があります。

色々と方法はあると思いますが、比較的安価なESP32でできないかと調べたらDrone-Bridge for ESP32というのに行き当たりました。

ドキュメントによるとDrone-Bridge for ESP32はGCSとフライトコントローラー間をシリアルブリッジ、無線LAN、ESP-NOW等で接続できる様です。
また動作できるマイコンはESP32,ESP32-C3,ESP32-C5,ESP32-C6が使えるそうなので、手元にあるマイコンボードで直ぐに試す事が出来そうです。

インストールでハマる。

では手始めに手元にあったESP32 Devkit基板に書き込んでみましょう。
ESP32 Devkit基板はこんなのです。(いつだか3枚959円で買った微妙に怪しい基板)。


Drone-Bridge ESP32のドキュメントによるとブラウザーで動作するフラッシュツールを使うと手軽に書き込めるようです。→ https://drone-bridge.com/flasher/
PCとESP32基板間をUSBケーブルで接続してこのURLにアクセスすると下のフラシュツールが現れたので・・・

書込みを試したのですが「Not connected.」と言ってきます。

BOOT-RESETボタンを順番通り押したり、ブラウザーをChrome/Edge両方試したり、基板もPCも交換したけれど変化ありませんでした。

ならばバイナリーをダウンロードしてESPtoolで書き込みをと考えましたが、バイナリーのダウンロード先が見つからないのです。
フラッシュツールは内部でダウンロードしている筈なのでどこかにはあると思うのですが・・・

あきらめてビルドする。

という事でビルドする方が早かろうという考えに至りました。
で、やってみたのですが、こちらも下記の様に色々ありました。

  • ESP-IDFv6.0(この時点の最新)でビルド
    →Ninja、npm等が入っていないエラー、日本語パス名が悪さしているらしきエラーが発生。これらは順に解決していったのですが、最後にprotocomm_security1′ undeclaredというエラーが発生。。
    このエラーはChat-GPTさんによると古いESP-IDFのAPIを使っているためで、ESP-IDFをVer4番代に下げろと。。。
  • ESP-IDFv4.4.6でビルド
    →今度はVer5.3以上でやれというメッセージを含むエラー。
  • ESP-IDFv5.5でビルド
    →すんなり完了。

という事で上手くいったビルド手順を整理すると・・・

https://dl.espressif.com/dl/eim/からeim-gui-windows-x64.exeをダウンロードして実行。
インストーラーが開くのでメッセージに従って進んで行き、ターゲットチップ選択ページでESP32に加えて後で試したいESP32-C3を選択。

バージョンのところでV5.5.4を選択。


あとは大体基本通りにインストール。
インストールが完了するとデスクトップにESP-IDF 5.5 PowerShellのアイコンが出来ているのでダブルクリックするとターミナルが現れ、この中で作業すれば一通りの環境が設定済になっています。

ターミナル内で適当なディレクトリ(パスに日本語が無い方が無難)に移動して、まずGithubからソース一式を取ってきます(gitはインストール済みの前提)。

> git clone https://github.com/DroneBridge/ESP32

取ってきたディレクトリの下にあるDroneBridge/ESP32に移動して・・・

> cd DroneBridge/ESP32

ビルドを実行!!

> idf.py build

これでビルドが始まりますが、結構時間がかかりました(PCが古いからか・・・?)。
ビルドが完了したらPCとESP32 Devkit基板とをUSBでつないで下記コマンドで書き込みます(COM番号はそれぞれの環境での番号)。
この時、ESP32マイコンが持っているMACアドレスが表示されるので控えておくと後で役立つかもしれません。

idf.py -p COM4 flash


設定

書き込みが完了したらリブートするとWi-Fiアクセスポイントモードで立上がります。
つまりPCのWi-Fi設定を開くとDroneBridge for ESP32という名前のWi-Fiアクセスポイントができているので、ここに接続して設定を行うのです。
まず上記アクセスポイントを選択し、パスワード:dronebridgeでWi-Fi接続します(このときWindowsであればインターネットに未接続的なメッセージが出るけど気にせず先に進みます)。
そしてブラウザーでhttp://dronebridge.local又は192.168.2.1に接続すると下の設定画面が現れます。

私の場合、当面は自宅のWi-Fiに接続するので下記の設定に変更しました。

  • ESP32 Mode → Wi-Fi Clinent Mode
  • SSID → 自宅環境のSSIDに設定。
  • Password → 自宅環境のパスワードに設定。
  • UART TX GPIO → 18
  • UART RX GPIO → 19
  • UART RTS GPIO → 22
  • UART CTS GPIO → 23
  • UART baud → 115200

UART信号のGPIO番号は使っているチップ(ESP32,ESP32-C3…)によって制限があります。上記設定は動作していますが、他のGPIOピンを使う場合は公式サイトの説明を読む方が良いです。

再起動後、自宅Wi-Fiに接続するIPアドレスとか・・・

以上の設定が終わったら[SAVE SETTINGS & REBOOT]ボタンを押せばリブートします。動作モードをWi-Fi Client Modeに変更したので既に自宅のWi-Fiに接続している筈なのですが、上記の方法だとDHCPからIPアドレスを割り振ってもらうので何番になるかが分かりません。私の場合はDHCPサーバーのログを見てIPアドレスを調べましたが、書込時に表示されたMACアドレスに対するIPアドレスをDHCPサーバー側で固定する方が良いかもしれません。
もしDHCPサーバーを弄れない場合は地道にpingを投げる等して調べる必要があります。
なおDroneBridge設定画面の[Advanced Wi-Fi Settings]をクリックすると(DHCPを使わず)IPアドレス固定の設定がでてくるので、ここで設定してしまうという手もあります。

DroneBridgeのIPアドレスが分かったらブラウザーで指定して開くと先程の設定画面が(変更を反映した状態で)表示されます。

フライトコントローラーと接続する

DroneBridgeとフライトコントローラー(PixHawkのTELEM1コネクタ)との接続には下記の配線でケーブルを作りました。

PixHawkESP32(Devkit)
1pin(VCC)V5
2pin(TX)RX(GPIO19)
3pin(RX)TX(GPIO18)
4pin(CTS)RTS(GPIO22)
5pin(RTS)CTS(GPIO23)
6pin(GND)GND

動作確認の為ブレッドボードを使って接続してみます。

ところで私の使っているPixHawkはAliexpress等で比較的安く売られているPixHawk2.4.8と書かれた物ですが、コネクタの型がPixHawkの公式マニュアルにるJST-GHと違ってMolex-PicoBladeでした。
GH買って挿せなかったのでPicoBladeを買い直したのは私です。

MissionPlannerと接続する

ここまでくるとMissonPlannerからDroneBridgeを経由してフライトコントローラーに接続できます。
下図の様にポート選択欄をUDPCIに、通信レートを115200bpsに設定して[接続]ボタンを押します。

すると接続先のIPアドレスを聞いてくるので上で調べた(又は設定した)アドレスを入力し、次にポート番号を聞いてくるので14550(これは固定)を入力して[OK]を押すと接続できます。

ESP32-C3版

Devkit基板+ブレッドボードのままだと引っ掛けて壊しそうなのでちゃんとした形で作り直したいです。
DroneBridgeはESP32-C3もサポート対象になっているので、昨年ラジコンミニ四駆を作った時の基板を流用して実装してみます。

ミニ四駆用RC受信機

この基板は単三電池2本で動作させるため、サーボ電圧用に一旦5Vに昇圧していましたが、このDCDCコンバータは実装せず直接5Vを供給します。またモータードライバーやピンヘッダも不要となります。

これら不要な部品を除外して実装し、電線を引き出してコネクターを取付けました。

Devkit&ブレッドボード式よりもだいぶスッキリした。

配線は次の通りです。

PixHawkESP32-C3(RCミニ四駆受信機改)
1pin(VCC)5Vライン
2pin(TX)RX(GPIO0)
3pin(RX)TX(GPIO1)
4pin(CTS)RTS(GPIO21)
5pin(RTS)CTS(GPIO3)
6pin(GND)GND


ハードウェアが出来たのでファームをビルドして書き込みます。

まずESP32-C3用にビルドして・・・

> idf.py set-target esp32c3 build

書き込む為のPCとの接続ですが、ESP32-C3の場合はUSBを直接接続できます(USB-シリアル変換IC不要)。
このあたりの詳細は以前「ミニ四駆をラジコン化 ~その4~ 回路とプログラム」の投稿に書きました。

接続が出来たら下記コマンドで書込みます(COM番号はそれぞれの環境での番号)。

 idf.py -p COM5 flash

ESP32-C3版の設定

ESP-32 Devkit版と同じ様にして接続し、下記設定しました。

  • ESP32 Mode → Wi-Fi Clinent Mode
  • SSID → 自宅の環境に設定。
  • Password → 自宅の環境に設定。
  • UART TX GPIO → 1
  • UART RX GPIO → 0
  • UART RTS GPIO → 21
  • UART CTS GPIO → 3
  • UART baud → 115200

という事で・・・

ESP32-C3にしてコンパクトになりました。製作費も安い(というか全て手持ち部品)ですしね。。。

RTK基準局を設置

Ublox ZED-F9P受信機を入手したので前から気になっていたRTKをやってみます。
最終的には庭で自動運転車を走らせて芝生を自動的に刈り込ませるのが目標です。

RTK

RTKというのはReal time kinematicの略でGPS(GNSS)衛星からの信号を高精度に解析してセンチメートル単位の測位を可能にする技術です。
※GNSSは測位システム全般を指す言葉でその内の一つがGPSですが、ここでは全てGPSと呼ぶ事にします。

センチメートル級測位というと日本の衛星「みちびき」のCLAS等もありますが、みちびきはまだ7機の完全体制になっていないし、精度的にもRTKの方が良い(らしい)のです。

RTKではGPS受信機を2つ使います。一方はアンテナの位置が既知である基準局で、衛星からの電波を受けて、その誤差を補正データとして出力します。もう一方は実際に測定する側(今回だと自動運転車、以下ROVERと呼びます)の受信機で、自分が受信した信号を基準局のデータで補正して自己位置を推定します。

GPSの誤差は近い距離内にある受信機間だとほぼ同じになるので基準局が近くにあるとROVERの位置が精度良く測定できる事になります。

基準局は必ずしも自分で用意する必要はなく、こんなところや、こんなところを見ると日本各地に基準データーを公開して頂けているサイトがあり、近い場所にあればそちらを利用するのが手っ取り早いです。
でも折角なので今回は自宅に基準局を設置して庭で測位してみようと思います。

受信機

入手した受信機はジオセンス社のF9PX1という機種で、Ublox社のZED-F9Pモジュールを搭載した基板です。
基板のままだと不安なので写真のケースを3Dプリントしました。
(このケースの3DデータはThingiverseにアップしました)

アンテナ

アンテナもUblox社製のANN-MB-00です。
基準局のアンテナは一旦設置したらあまり場所を動かしたくありません。cm単位で測位するための基準点なので1cm足りとも動かしたくないのです。 なので有り合わせの鉄板とアングルを溶接してアンテナ基台を作り、屋根に固定しました。
ここは屋根の一番高い所ではないので空を遮ってしまう部分が結構あります。本当はもっと高い位置に取り付けたいのですが、まずはこれでやってみます。

基準局のアンテナ位置を調べる。

基準局はアンテナの位置(座標)が正確に分かっている必要があります。
座標を知るには色々と方法がある様ですが、一番現実的な方法として暫く受信したデーターをファイルに書き出し、これを国土地理院の電子基準点のデーターから補正する方式でやってみます。
電子基準点のデーターは無料だとリアルタイムには提供されず、一時間毎に更新されるデーターをダウンロードする事になります。よって受信データーも一旦ファイルに落としておき、後付けで解析するのです。

手順としては以下の様に実施しました。
・ZED-F9P受信機を設定する。
・暫くの間データーを受信し、結果をファイルに落とす。
・電子基準点のサイトから補正データーをダウンロードする。
・rtklibに含まれる後付け解析ツールrtkpostを使って測位結果を算出する。
・測位結果はある程度ばらつきがあるので、その平均値を基準局の座標とする。

ZED-F9P受信機の設定

最初にZED-F9Pを設定します。
参考にしたのは下記書籍及びサイトです・・・

・トラ技2019年10月号 F9Pの設定詳細・RTKLIB・専用基準局製作
・ZED-F9Pの設定方法
・高精度衛星測位 RTK-GNSSチュートリアル

u-center(u-bloxの設定ツール)を開き、まずは上記資料の中で今回の座標特定に必要な内容だけを変更しました。

デフォルト設定値から変更した内容は・・・
・BaudRateを230400に設定
・受信衛星の選択画面(Viewメニューの「Generation 9 Advenced Configuration View」)を開いたが特に変更する箇所が見当たらなかったのでデフォルトのまま。
・ViewメニューのMessage Viewを開く。
・UBX-CFG-NAV5のMin SV Elevationをとりあえず15°程度に設定。
・UBX-CFG-RXMの中でRAWX,SFRBXを出力。
・NMEAではGxGGA,GxRMC,GxGSVを残してあとは停止する。
・UBX-CFG-NMEA内で、「High precision mode」にチェックを入れる。
・現段階ではRTCM出力は不要。
・変更を書込む。

なおデーターの更新レートを標準の1秒間隔から0.2秒間隔に変更できる様な事が色々なサイトに書いてありますが、私の所では0.2秒間隔だと受信中にRAWXデータが止まってしまうという現象が発生しました。色々試すと約0.7秒より長くすると安定したので、今回は1秒間隔(デフォルト通り)で使用しました。
(当面の用途ではRAWXはアンテナ座標を調べるとき以外は出力しなくて良いので大きな問題はない筈です)。

RTK-LIB

RTKを弄るにはrtklibをインストールしておくのが定番です。
私の環境ではrtklibのサイトを開くとブラウザから「この接続ではプライバシーが保護されません」というメッセージが出ますが、気にせず先に進みます。
そしてWindows版の最新2.4.3b34(ベータ版ですが)をダウンロードしてzipを解凍します(特にインストーラー等はなく解凍するだけ)。

まずはRTK-Naviで受信してみる。

その前にF9P基板とPCをUSBケーブルで接続し、デバイスマネージャーでCOM番号を調べておきます。

そしてRTK-LIBを解凍した階層下のbinディレクトリにある、rtknavi.exeを実行するとこんな画面が開きます。

右上の「I」というボタンを押すと次のダイアログが開きます(「I」は入力設定用ボタン)。

(1)Roverにチェックを入れ、TypeはSerialに設定してCmd列の「…」ボタンを押すと下のダイアログが出るので、PortのところにCOM番号、Bitrateのところに先程設定した230400bpsをセットして「OK」を押します。

そしてFormat列をu-blox UBXに設定してOKを押すとメイン画面に戻ります。

メイン画面の下の方の「Options…」を押すと次のダイアログが開くので、GPS,GLONASS,GAlileo,QZSSにチェックをいれて「OK」をクリック。

この時点で試しに受信してみましょう。
メイン画面左下の「▶Start」を押すと受信データがグラフで表示されます。

こんな感じで受信出来ていたら「■Stop」を押して一旦止めます。

受信ログを取得する。

ではログを取得する準備をします。
メイン画面右上の「L」を押してログ設定のダイアログを開きます。
(6)Roverにチェックを入れ、TypeにFileを設定し、LogFilePathsに適当なファイル名を設定します。
(ログファイル名には日付や時刻を含めておくと後で分かりやすいです。拡張子は.ubxにしておきます。)。

OKを押してMAIN画面で「▶Start」を押すと受信が始まるので、この状態でしばらく放置します(私は半日程置きました。長い方が良い筈ですが、どれくらいが適当かは不明。なお最初は短い時間で一度試してからが良いと思います。)。

取ったデータを解析する

データを解析するには上で落としたログをRINEX形式のファイルに変換します。
これにはRTKLIBに付属のRTKCONV.exeを実行します。
先頭の「RTCM,RCV RAW or RINEX OBX ?」に先程落としたログファイル名を指定すると出力ファイル名は自動的に設定されます。

「Options…」を押して出力形式が「RINEX Ver3.03」になっている事を確認します(違っていたら設定する)。

「OK」でMAIN画面に戻って「▶Convert」を押すと変換が始まり、XXX.obs(これがRINEX形式のファイル)が出来ていればOKです。

電子基準点からデータを取る。

受信したデータを解析する為に電子基準点の補正データを取得します。
まず下記にアクセスして・・・
https://terras.gsi.go.jp/
「観測データ取得」をクリック。なにやら「同意するか?」と聞かれたら「同意」をクリック・・

するとこんな地図が現れます。
各地の電子基準点で埋め尽くされていますね。。。

地図を拡大して最も近い基準点を選択し・・・

「ダウンロード」をクリック・・・

下の様に開始日時、終了日時には上記受信ログを落とした時間帯を含む範囲を指定します。
そして衛星はGRJE、RINEXverは3.02を指定。
「任意時間のデータダウンロード」をクリック。

するとこんな画面が開くので、「観測ファイル」、「衛星軌道情報ファイル」それぞれダウンロードします。

これでxxxx.o.gz , xxxx.tar.gzの2つのファイルがダウンロード出来ている筈です。
これらを解凍してxxxx.n,xxxx,g,xxxx,q,xxxx.l等に戻します。
(*.gzやtar.gzはUNIXでは一般的な圧縮/アーカイブ形式です。解凍方法が分からない場合は検索すると沢山出てきます。なおWindowsでも10あたりからtarコマンドが入っている様です。)
なお最近発見したのですが、xxxx.o.gzは解凍しなくても、そのまま指定すればRTKPOSTが読んで貰える様です。
またxxxx.tar.gzをそのまま指定するとエラーは出るものの解凍だけしてくれる様です。
 なので一旦エラー覚悟で実行して解凍されたファイルを改めて指定すればtarコマンドを実行せずに処理できます(今イチ良く分からん動作ですが)。

※素のままのファイル名だと後で分かりにくいので時刻範囲が分かるファイル名に変更しておいた方が良いと思います。

RTKPOSTで解析する。

以上により一通りのデータが揃ったので解析します。これにより自分のアンテナ位置の正確な位置(座標)を得るのです。

ではRTKLIBに付属のrtkpost.exeを実行すると下記の画面が開きます・・・


下の方の「Options…」ボタンを押して下記ダイアログを開き、Setting1タグにて・・・
・Positioning Mode をKinematicに。
 ※2026-9-8追記:アンテナ位置が固定なのでKinematicよりもStaticを選ぶ方がバラツキが少なくて良いです。実際やってみると一桁違いました。
・Filter Typeは一番厳密そうなCombinedを選び・・・。
・Elevation Mask(°) を30°程度に設定し(この辺りは適当)・・・。
・GPS,GLONASS,Galileo,QZSSにチェックを入れます。


PositionsタブのBaseStationをRINEX Header Positionに設定します。
その他にも細かなパラメーターが色々あって何がベストか分からないのもありますが、このあたりでOKを押してMAIN画面に戻ります。

後は処理するファイルを下記の様に設定していきます。
・RINEX OBS: Rover欄にはRTKNaviでダウンロードしてRTKConvで変換したRINEXファイル(XXX.obs)を指定。
・RINEX OBS: Base Stationには電子基準点からダウンロードして解凍したXXX.oファイルを指定。
・RINEX NAV/CLK,SP3,FCB,IONEX,SBS/EMS or RTCM欄にはXXX.n , XXX.g , XXX.l , XXX.qを指定。
・そして一番下の欄には出力ファイル名が自動的に入っているので・・・
「▶Execute」を押すと解析が始まります。

データー期間が長いと結構時間を要します。
終わったらPlotボタンを押すとこんな感じで分布が見えるはずです。

緑の点がRTKがFixしている(Cm級測位が出来ている)箇所で、黄色の点はFixしておらず精度が悪い点です。

取れたデータからアンテナ座標を求める。

アンテナ座標を求めるにはFixしているデーターだけ使いたいのでxxx.posファイルを以下の様にちょいといじります。

まずxxx.posファイルをテキストエディタで開くと下の様になっています。
この中でQと表示された列が1である行はFIXしたポイントで、その他の2や5になっている個所は精度が悪いのポイントなので、1の行を残して取り除きます。

これはテキストエディタで作業しても良いですが、面倒なのでこのページ末に記載したrubyスクリプトで処理しました。

Q=1の行以外を消してプロットし直すと次の様になりました。


同じスクリプトに-cオプションを指定して実行するとCSVファイルが出ます。
これをExcel等の表計算ソフトで開き、latitude,lognitude,height列を全部平均した座標をアンテナの位置としました(実はExcelは値段が高く持っていないのでLibreOfficeで実行した・・・)。
ついでに標準偏差を出してみるとLatitude≒9.2E-8, Lognitude≒1.67E-7, Hight≒35.07cmとなりました。 3σをmmになおすと30.9mm, 47.0mm, 105.2mmなので、まあセンチメートル単位で測位出来ていると思います。

そして・・・

以上でアンテナ座標を決める事が出来たので引き続き以下の作業を実施していきますが、長くなったので続きは後日投稿します。

・RaspberrypiでF9P受信器に接続してRTCM3データを取得し、同時にNTRIPcasterを実行して自宅内に配信。
・もう一つのF9P受信機をPixhawkに接続してRTK測位。
・ローバーを作成して庭で走らせる。

データー処理スクリプト

#!/usr/bin/env ruby
# coding: utf-8
#
# 2025.12.07 by https://www.hoihoido.com (konchi@hoihoido.com)
#
# rtkpost.exeが吐き出す*.posファイルからFIXしている行を取り出す。
# ※FIXしたらQ列(左から5ブロック目)が1になる。
#
# 引数:
# -c CSV出力(ヘッダなし)
# -q num Q列がnumで示す値である行だけ抜き出す。
# ※Q列はFIXやFLOAT等の状態を示す。1がデフォルトでFIX状態。
#

require 'optparse'

options = {}
opt = OptionParser.new
opt.on("-c", "--CSV", "CSV output") { |v| options[:CSV] = v }
opt.on("-q VAL", "--Q", Integer, "Q num (1=FIX:default)") { |v| options[:Q] = v }

opt.parse!(ARGV)

if ( options[:Q]) then
qval=options[:Q].to_s
else
qval="1"
end

n=0
while (l=gets()) do
if (options[:CSV] and l =~ /^% +GPST +/) then
title=l.split
print "DATA,"
print title[1..-1].join(','),"\n"
end

if l =~ /^\d{4}\/\d{2}\/\d{2} +\S+ +\S+ +\S+ +\S+ +(\d) / then
if $1 == qval then
if ( options[:CSV]) then
l.gsub!(/ +/,",")
end
puts l
n+=1
end
else
if (! options[:CSV]) then
puts l
end
end

end

print(",AVE,")
print("=average(C2:C",n+1,"),")
print("=average(D2:D",n+1,"),")
print("=average(E2:E",n+1,")\n")
print(",σ,")
print("=stdev(C2:C",n+1,"),")
print("=stdev(D2:D",n+1,"),")
print("=stdev(E2:E",n+1,")\n")
print(",3σ,")
print("=3*C",n+3,",")
print("=3*D",n+3,",")
print("=3*E",n+3,"\n")
print(",3σ[mm],")
print("=40000000/360*C",n+4,"*1000,")
print("=40000000/360*D",n+4,"*1000*cos(C",n+2,"/180*pi()),")
print("=E",n+4,"*1000\n")