u-blox社のNEO-7Mにアクティブアンテナを繋いで測位してみました.
アクティブアンテナを使用するための回路設計がよくわからなかったのですが,他の回路を参考にしつつ組んでみたらちゃんと測位できたので,ここにメモとして残します.
アンテナは秋月電子通商にて販売されているGPS/GLONASS アクティブアンテナを使用しました.
参考資料
- MAX7/NEO-7 HardwareIntegrationManual (PDF)
- GNSS (GPS・GLONASS・QZSS) 受信機キット 取扱説明書 (PDF)
- 筑波大学宇宙技術プロジェクト-STEP日記-:「u-blox NEO-7MとSPI通信」
アクティブアンテナを使うために
アクティブアンテナを使用する際には,受信信号に電源を重畳することでアンテナ内部の増幅回路に電力を供給する必要があります.つまり,アンテナ用の電源ケーブルが別にあるわけではなく,信号が流れている同軸ケーブルを信号と電源で共有しています.
NEO-7Mのハードウェアマニュアル[1]を見ると,アクティブアンテナ用の回路は以下のようにすべしと書いてあります.
アクティブアンテナ専用の電源(VCC_RF)が用意されていたので今回はこれを使いました.コンデンサを直列に挟めば普通の3.3V電源を使うことも出来るようです.
さて,大体の形はわかったものの,肝心のLとCの値がわかりません.
そこで,同じアンテナを使用している[2]の回路を参考に,C=100 pF,L=56 nHとしました.インダクタは丁度よいサイズのものが手元に無かったので,0.2 mmのポリウレタン線を巻いて自作したものを使っています.
ソレノイドのインダクタンスを求める際は以下のサイトを使用しました(長岡係数は0.688422).
比透磁率を1.0としていくつかの条件を試したところr=1.5 mm,N=9,l=9 mmのときにL≒55nHとなったので,この寸法になるように巻いたコイルを使っています(但し,rはコイル半径,Nは巻数,lはコイル長).r=1.5mmとしているのは,直径3.0mmのプラスドライバーを使ってコイルを巻いたためです.
実装
アンテナ周りの設計が終わったので,パパっと実装してしまいましょう.
<回路全体の図>
今回はとりあえずアクティブアンテナが使えることを確認できれば良かったのですが,後々マイコンと繋ぐことを考えるとSPI通信を使えたほうが便利なので,D_SEL端子にジャンパピンを繋いで通信モードを切り替えられるようにしました.SPI通信の仕方については[3]に詳しく書かれています.
<ユニバーサル基板への実装例>
ピンヘッダを逆向きにつけることで変換基板のピンに直接ジャンパワイヤを挿せるようにしました.上の画像ではC2を実装し忘れていますが,お守り程度に付けたものなので余程電源が悪くない限りは無くても大丈夫でしょう.
動作テスト
<動作確認の様子(画像左端のマイコンは3.3V電源として利用)>
<アンテナは天頂が見える位置に設置>
天頂が見えるように,アンテナをベランダに括り付けて動作テストを行いました.電源を入れて測位状態になると,TIMEPULSEピンに繋いだLEDが点滅し始めます.
また,測位状態を確認しやすくするためにublox社が公開しているu-centerを使用しました.衛星の位置や電波状況をグラフに表示してくれるのでとても便利です.
起動から30分程経過した後に,NMEAフォーマットから読み取った緯度・経度をGoogleマップに打ち込んで正しく測位出来ているか確認しました.15m程誤差がありましたが,アパートの屋根が影になって東側の衛星を使えていなかったので,ベランダに設置した状態での精度はこんなものでしょう.
その後も少し測位状態を見ていたところ,衛星の配置によってHDOPは大体0.9〜2.2の範囲で変動しており,使用衛星数は平均して10個程でした.HDOPがもう少し低くなってくれると嬉しいのですが,これは設置場所の問題でしょうか.後で開けた場所に行って実験してみようと思います.
追加実験
後日大学のグラウンド脇で測位してみたところ,HDOPは0.9で安定し,座標のふらつきも大体2.5mの範囲に収まっていました.
もう少しHDOPが下がってくれると嬉しかったのですが,安定しているのでまあ良しとしましょう.750円で買ったモジュールですから,値段的には十分な性能だと思います.
<大学のグラウンド脇にて>
SPIで読み出す際に謎に苦労したので,ちゃんと動作したコードを載せておきます.秋月で販売されている「STM32 Nucleo Board STM32F303K8」にmbed Compiler上で作成した以下のコードを書き込んで動作確認しました.
// SPIはデフォルトでmode0(mode3だと思いっきり文字化けする)
// 通信速度は最大5.5MHz.
// 0xFFが送られてからもデータを読み続けると,50byte以降は無視される.
// 読み出しが無視された後は0xFF以外の値を送ると読み出し再開するらしい.
#include <stdint.h>
#include "mbed.h"
DigitalOut myled(LED1); // 基板上のLED(動作確認用)
DigitalOut CS(PF_1); // NEO-7MのCSピン
SPI spi(PA_7, PA_6, PA_5); // mosi, miso, sclk
Serial uart_usb(USBTX, USBRX); // UART (over USB)
Ticker ticker1; // 一定時間割り込み用タイマ
// NEO-7Mから読み出す際のバッファサイズ[byte]
const uint32_t BUF_SIZE = 600;
// NEO7-Mから読み出したデータをUSB経由でPCに送って表示する.
void data_read() {
uint32_t i;
uint8_t buf[BUF_SIZE];
uint8_t tmp;
uint32_t num = 0; // 読み出したbyte数
CS = 0; // 読み出し開始
for (i=0; i<BUF_SIZE; i++) {
tmp = spi.write(0xFF); // ダミーデータ(0xFF)を送ってデータを読む
if (tmp == 0xFF) {
break;
} else {
buf[i] = tmp;
num++;
}
}
CS = 1; // 読み出し終了
// PC画面に表示
uart_usb.printf("---------------------------\r\n");
uart_usb.printf("read num: %d[byte]\r\n", num);
// ACII形式のNMEAフォーマットデータ(teratermとかで見ると文字列で表示される)
for (i=0; i<num; i++) {
uart_usb.putc( buf[i] ); // 1byteずつ送信
}
}
int main() {
myled = 1;
CS = 1;
// SPI 初期化
spi.format(8, 0); // data size: 8bit, mode0
spi.frequency(5500000); // 5.5MHz
//UART 初期化
uart_usb.baud(115200);
uart_usb.format(8, Serial::None, 1);
// 0.5秒ごとに実行
ticker1.attach(&data_read, 0.5);
while(1) {
myled = !myled; // 点滅
wait(0.5);
}
}