エントリー

2016年04月20日の記事は以下のとおりです。

GPS時計の新作

  • 2016/04/20 11:42
  • カテゴリー:make:

20160420114356.JPG
 先日から取り組んでいたGPS時計ですが,ようやく完成しました。写真はブレッドボードで作った状態ですが,近いうちに基板にハンダ付けして,綺麗にまとめようと思います。

 今回はなかなか大変でした。

 まず,aitendoで買ったNEO6M-ANT-4Pというモジュールですが,これはu-bloxのNEO6Mというなかなか性能のいいGPSモジュールを搭載しているので,基本性能は抜群です。

 ただ,NEO6M-ANT-4Pというモジュールになると,バックアップ電池が死んでいて一晩放置するとCold Startになってしまうという問題がありました。

 ですので,GPS側の設定を変更しないといけないようなプログラムを書くことは出来ません。常に初期状態で立ち上がることを前提にしないといけないので,シリアルポートのボーレートは9600bps,センテンスの更新周期は1秒に1度,1PPSパルスは衛星をつかまえないと出てこないという制約で動くようにする必要があります。

 次の問題は,データが正しくデコード出来ないという問題です。1PPSで更新せず,センテンスをデコードしてそのまま表示した時には,発生しない問題でした。

 GPSからのデータは,テキストによるセンテンスで,UARTから流れてきます。メモリの小さいtiny2313ですので,UARTのバッファは64バイト程度と極めて小さいため,バッファがあふれる前にさっさと処理をしないとダメです。

 そこで,流れてくる情報を最小限の物にしたいところですが,これは前述の通りGPSの設定を変えないといけないですから,今回は出来ません。ログを見れば,かなり大量のデータが流れ込んでいますので,処理に手間取っているとリングバッファが1周して大事なデータが上書きされてしまいます。

 ですが,1PPSで更新をしないように作った場合には問題は出ず,1PPSでの更新を行うとデコード出来ない場合が出てくるというのは,ちょっと解せません。

 調べて見ると,実はLCDの表示に使っていた関数で,ウェイトが極端に長い部分がありました。5usでいいのに,1msも安全のためにとってあったんですね。

 で,1PPSで一気に表示を更新する時に,ここで100ms近くも足止めを食らってしまい,その間にデータが流れてくると,未デコードのデータが上書きされて失われてしまうのでした。

 これが,随時更新という形にすると,時刻と日付が別々に更新されるので,付加が平均化し,なんとか上書きされずに処理が間に合うようでした。

 ということで,ウェイトをぐっと減らして,この問題は解決です。

 そして最後は,1PPSとGPGGAやGPRMCというセンテンスが完全に非同期であるという問題です。先日もちょっと書きましたが,1PPSのパルスが出た段階で受け取っている最新の時刻情報が,1PPSの前の情報なのか後ろの情報なのか,不定なのです。

 1PPSは非常に正確であり,すべての衛星で完全に同期しています。ですから,この1PPSで表示を更新すれば非常に正確な時計が作れることは明白ではあるのですが,更新に使う時刻情報が1PPSよりも過去のものなら1秒加算しないといけませんし,1PPSの未来の情報なら,そのまま更新に使わねばなりません。

 私は,未来の情報が出てくるなんてことはないだろうと思っていましたから,更新時には1秒加算した時刻で更新することにしていました。これで問題がないように思ったのですが,電源を入れて衛星をつかまえた最初のうちは,1秒進んでいる事に気付いてしまったから大変です。

 しばらくすると1秒進むのが解消され,正確な時刻になっているのですが,どこで変わってしまったのかわかりません。じーっと見ていても変化せず,気が付いたら変化しているという苦しい状況で,なかなか尻尾をつかめません。

 対策は,1秒加算するかしないかで条件分岐すればいいんですが,問題はその条件がわからないことです。GPGGAなりGPRMCで出てくる時刻の情報は,最初は未来のものなのですが,しばらくすると過去の物になります。すぐに変化することもあれば,長い間変化しない場合もあり,しかも変わったことがセンテンスからはわかりません。

 そもそも,プログラムにとって,時刻の情報はGPSから出てくる物がすべてですし,これしか時刻情報を持たない以上は比較も出来ず,結局のところGPSから出てくる時刻を信用するほかありません。その時刻が,いつの間にか過去になったり未来になったりするんです。

 ははーん,これはGPGGAやGPGMCの時刻情報のうち,1/10秒や1/100秒に違いがあるんじゃないか?

 そう思って見てみたのですが,どちらも小数点以下は00です。数年前に使ったGPSモジュールでは,ここが.99になったり.00になったりしたので,きっと今回のモジュールもそうだと思っていたのに,ダメでした。これは使えません。

 なら,つかまえた衛星の数と相関があるんじゃないか?

 残念ながら,相関はありませんでした。4個でも11個でも,未来から過去に突然切り替わります。

 なら,1PPSの有無に相関はないか?ありませんでした。

 うーん,じゃステータスがVなら未来,Aなら過去なんじゃない?違いました。

 うむむむ,じゃ,情報の信頼性(DOT)の数値に相関は?

 この数字は,Cold Start直後は99.99で,衛星をつかまえて時間が経過するとどんどん小さな値になります。1.00以下になったら過去になるとか,そういう相関があるのではないかと,シリアルポートに繋いでダラダラと記録したログを頑張って見てみましたが,残念ながら相関はなし。

 このままでは,表示されている時刻のうち,1秒があっているのかあっていないのか,わからないままになってしまいます。せっかく衛星をつかまえている限り狂うことがない正確な時計を作ったのに,1秒が信用出来ないなんて,話になりません。

 これだったら,1PPSで更新しないで,センテンスが出てきた瞬間に表示をした方が,まだ正確です。この方法だと未来かも過去かも知れませんが,ずれは1秒以内のはずですから,1PPSで更新する方が状況は悪いです。

 悔しい。やっぱりGPS時計は無理なのか・・・

 とにかく,頑張ってログをとり続けます。そして,変化したことが分かった時点でログを解析します。

 そうすると,1秒に1回送られているセンテンスに書かれている時刻が,2回続けて同じ時刻になっている箇所が見つかりました。1秒に一度なのに,2回同じ時刻が出てくれば,そりゃ1秒遅れてしまいます。

 よく調べてみると,電源を入れて衛星をつかまえた直後は,やっぱり1秒未来の時刻が出てきます。しばらくすると,ほぼ現在の時刻に一致した周期で,時刻が送られてきます。

 変化するタイミングは不定で,いつ切り替わるかわかりません。また,過去の時刻に切り替わったとしても,ほぼ現在時刻に一致していて,これをそのまま表示しても違和感はないんじゃないんじゃないかと思うくらいです。

 でも,とにかく同じ時刻が2度続いてきたことを検知できれば,時刻が未来なのか過去なのかがわかります。

 そこで,1回前の秒のデータを残して起き,今回の秒と比較をして変化していない場合には,以後の時刻データは未来の物から過去の物に切り替わったと判定し,1秒加算することにしました。

 この対策の問題点は,Hot StartやWarm Startの場合には,電源投入時にすでに過去の時刻に切り替わっているかも知れないので,変化を検知できないということです。

 もちろん,同じ時刻が二度続けば1秒加算することになるのですが,1秒加算しないといけない「過去の時刻」が電源投入時から流れてくると,加算する条件がつかまえられずに,ずっと遅れたままになってしまうわけです。

 これを防ぐ為には,なからずCold Startで起動する必要があります。ん?電池が死んでいるのは,かえって好都合なんじゃないのか?

 ただ,どんな場合でも,同じ時刻が2回続いた時には,これはもう確実に過去の時刻であることがはっきりしますから,1秒加算された状態である事が画面に表示されていれば,その時刻は信用出来るということになります。消えていれば,1秒ずれている可能性があるということですね。

 もう1つの問題は,一度過去の時刻に切り替わったあとは,もう二度と未来の時刻を出すことはないという前提になっていることです。当然,未来の時刻を出すように変化することもありえるとおもいますし,その場合には,時刻が1回前のものと比べて,2秒進んだことを検出出来ればよいだけです。

 このコードを組み込んでみたのですが,実際に動作したことがないので,正しいかどうかはわかりません。

 ということで,問題点がなんとか解決しました。

 基本構造は,センテンスのデコードを行い,得られた情報のうち衛星の個数やステータスは随時,時刻と日付については1PPSで更新を行うというものです。

 1PPSはINT0で割り込みをかけます。UARTでも割り込みを使いますが,AVRの場合は割り込みの優先度は固定で,優先度を変えたければ割り込み要因そのものを見直すということになりますが,今回は1PPSの優先度を上げたので,上位のINT0でいきます。

 Cold Startでは,衛星をつかまえないと1PPSが出てきません。1PPSでしか画面を更新しないと,ずっと画面が固まったままになるので,ステータスがV(つまり1PPSが出てこない)時には,随時更新されるようにしておきます。

 また,立ち上がった直後には時刻情報がでたらめですので,時が24以上になったり,月が13以上になっている場合には不正と見なして,時刻や日付を0でリセットします。

 タイムゾーンは悩みました。メモリサイズの関係もあり,日本標準時に固定してあったのですが,頑張ってあいたポートにスイッチを繋いで,変更出来るようにしようと思ったのです。

 ですが,プラス側の補正はこれまで通りとしても,マイナス側の補正にするとまた日時も調整をし直すコードが必要になったり,調べて見ると時差って1時間単位じゃなく,30分単位だったりして,コードがあふれてしまったのでやめました。

 とりあえずタイムゾーンは+9で固定とし,補正値を画面に出しておくことにとどめました。

 で,かなり不細工でお恥ずかしいのですが,以下がソースです。

続きを読む

ページ移動

  • 前のページ
  • 次のページ
  • ページ
  • 1

ユーティリティ

2016年04月

- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

検索

エントリー検索フォーム
キーワード

ユーザー

新着画像

新着エントリー

過去ログ

Feed