VIVITAの新居 hnii@twitterです。
以前紹介した、「ラズパイとRTK-GPSを使って1m移動する毎に一度ピッと鳴る装置」を改良しました。 良い感じになってきたので「その2」をお送りします。
今回の目標
元々の目標は「海の上で使えるスピードメータを作ってみたい」でした。
前回の「その1」ではゆっくり動かした場合には正しく動くことまでは確認出来ました。しかし、速く動かすと音が一定周期にならず、ピピッピピッと偏ってしまうことが問題でした。
そこで、「その2」では時間遅れが少なく音が途切れないようにすることを目標としました。
GPSモジュールには通信ポートが複数あることが多く、今回のボードもTTLレベルのシリアルポートがあります。 そこでそのポートにArduinoをつないで1mごとに音を出すことにしました。 Arduinoのソフトなら、時間遅れは一定の範囲に抑えられるはずです。
今回追加で準備したもの
ハード
ソフト
- Arduino IDEのインストール
これはサイトが多数有るので別途参照( Arduino - Windows )
- adafruit GPS ライブラリのインストール
つくりかた
ハードウェア
半田付けしたのはArduinoのヘッダー取付とブザー(前回と同じタイプ)をArduinoのA6ポートとGNDの間につなぐところだけでした。あとはGPSモジュールとArduino互換ボードのシリアル1の間を以下の配線でつなぎました。
ピン配線表
*GPS | *JST SH | *ICSP | *Arduino | |
---|---|---|---|---|
GND | 1 | 6 | GND | |
UART1-TX | 3 | 1 | AVR-RX1 | |
UART1-RX | 4 | 4 | AVR-TX1 | |
+5V | 12 | 2 | VCC |
Arduinoの5VをGPSモジュールから与えるつもりでしたが、実験してみるとこの方向には供給されなかったので、別途raspberry-pi -> Arduinoへ5Vの電源をつなぎました。
これらをまとめるとこんなシステムになりました。
GPSモジュールの設定変更
- 精度情報を高いモードに
- UBX-CFG-NMEAのMode FlagsのHigh precision mode -> ON
その結果、今回利用したGPSモジュールにおいては小数点以下の桁数が5桁から7桁になります。
モード | GNGGAメッセージ |
---|---|
普通 | $GNGGA,070511.11,35xx.20429,N,139xx.88722,E,5,12,1.11,13.0,M,39.4,M,1.1,0000*54 |
高精度 | $GNGGA,081551.00,35xx.9479147,N,139xx.1712290,E,1,12,1.06,25.160,M,39.575,M,,*75 |
計測・計算周期
- UBX-CFG-RATE -> 67mS (前回は50mSにしたが、処理落ちしてしまうので)
SERIALポート設定
- UBX-CFG-PRTでUART1を指定し、baudrateを38400に設定。
- GxGGAメッセージをUART1にも出力。
- UBX-CFG-MSGのF0-00 NEMA GxGGA をUART1に出力
浮動小数点から固定小数点へ
その1でつくったpythonスクリプトをArduino用のスケッチに変換します。しかしArduinoではdouble(倍精度浮動小数点形式)が使えないためfloatで演算してみたのですが、1mを正しく計測するには演算精度が足りないようでした。最初は簡単に変換するだけかと思いましたがうまくいきませんでした。
そこでlongで座標がとれるようなライブラリを探してみました。私が見つけたのはadafruitのGPSライブラリで、固定小数点を用いており、10,000,000を緯度経度の1度に割り当てています。この分解能ですと、値が1変わった場合には大体1cm程度となるので今回の用途では十分と考えました。
ライブラリ変更
しかし、ライブラリから出てくる値を確認して見ると変化が連続的ではありません。16おきに変化しているようです。
そこで、ライブラリのソースを見たところ、必要な桁数を取得していなかったので、ソースを2カ所変更します。
Adafruit_GPS::parseLat()と Adafruit_GPS::parseLon()の部分のminutesへ代入しているところを変更します。
< strncpy(degreebuff + 2, p, 4); < degreebuff[6] = '\0'; < long minutes = 50 * atol(degreebuff) / 3; --- > strncpy(degreebuff + 2, p, 7); //add more digit 2019/8/2 > degreebuff[9] = '\0'; > long minutes = atol(degreebuff) / 60;
私の使用しているmacOS上では~/Documents/Arduino/libraries/Adafruit_GPS_Library/Adafruit_GPS.cpp を変更することになりそうです。今回は試験的に直接変更しましたが、他のプロジェクトでもこのライブラリを使う場合にはコピーを取ってから作業を行ってください。
この精度の良くなったライブラリを使ってGPSread2.inoというプログラムをArduinoに焼き込みました。 面倒だったのは、longとfloatを使った式です。 キャストをしっかり入れました。例えば以下の行などが典型的です。
uint32_t oldX; uint32_t x; float l; ... oldX = oldX + (int32_t)(((int32_t)x - (int32_t)oldX) * l);
unsigned longの差分にfloatを掛けたあと、再度longに戻すように指示しました。どのキャストを外しても値が全然違ってきます。
そのソフトウェアは前回同様 GitHub - hnii2006/beepbyONEm におきます。
起動方法は、前回と全く同一です。raspberry-piにloginして、起動スクリプトのstart.shを走らせるだけです。これでRTK-GPSの基地局情報をGPSモジュールに送り込むことができ、Arduinoは電源投入と同時に動き出すので、値が1mずれるごとにピっと音がでるようになります。
実験
今度こそ安定して動くか歩いて実験します。
結果は前よりはとても良くなりました。両側がビルだったり環境が悪いと、RTK出力がfloat解になったり、DGPSになるのが音で分かるのが面白いです。 ビル沿いを歩くとfloat解ですが、道の真ん中を歩くとまたFIX解にもどったりします。
まとめ
初心者がヨットの操船時に手助けできるような海上用スピードメータを再度試作してみました。音の間隔が前回より安定したので、これなら実際に使えそうです。次回体験する時には実際に持って乗り込んでみたいです。
*1:シリアルポートが2個ついているため、片方をGPSに、片方はデバッグポートとして使える, A-Star 328PB Micro - 5V/16MHz - スイッチサイエンス
*2:今回はICSPコネクタにつなぐ
*3:今回はcsgshop販売のF9Pボード用, 日本圧着端子製造株式会社