<link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=765706261655433101&amp;zx=4ef7098c-ba2f-462d-82db-af61aa742ad9' rel='stylesheet'/>

2016年2月13日土曜日

2000円のGPSとArduino / ESP-WROOM-02

ベランダにて。シャッター速度の関係で表示が途切れてます


せっかくESP-WROOM-02を使っていますが、ほぼArduinoとして使っているのでこういうタイトルとなりました。

■GPS入手■

秋月の新製品をチェックしていたら、なかなか安くて使いやすそうなGPSのキット(GPS受信機キット 1PPS出力付き 「みちびき」対応)が出ていたので、会社帰りに立ち寄って買ってみました。

秋月のサイトから

が。家に帰って見てみたら、買ったのはWebに出ている新製品ではなくて別の新製品でした(GPS-54型GPSレシーバーモジュール)。キットじゃなくてGPS受信ユニットと2mmピッチ10pコネクタ2個がぽろりと入っているだけorz

秋月のサイトから

私が買ってきた方は衛星「みちびき」にも対応していないみたいだし、消費電流も多いし、何のメリットがあるんだろうorz 余計なシリーズレギュレータが入ってないので3.3vで使えるのがメリットかなw 

勿体ないので使います。そういえばGPSモジュールを買ってマイコンにつないで使うって初めてじゃないだろか。

■結線など■

GPSモジュールのコネクタは2x4pなので、付属の2mmピッチ 10pヘッダソケットを真ん中で切断し、ヘッダソケットに1-5番ピンにそれぞれ配線します。反対側には2pと3pのヘッダピンをハンダ付けします。2pはTxとRx用、3pは3v3が2本とGND用です。

秋月のスチロールケースにカッターナイフで穴を開けて、そこにマウント?しました。こういう小学校的工作懐かしい。

Arduinoの場合、SD0は0, RD0は1と接続します。

ESP-WROOM-02では、SD0はRxD、RD0はTxDと接続します。

GndはGnd、BATTとVCCは3.3v電源と接続します。なお、今回仕様なのでVATTにはバックアップ用のバッテリをつながないで電源をそのまま供給していますが、この端子にバッテリを使う場合に関してはいろいろ注意事項があるので、秋月サイトのメーカー資料を参照してください。9/23ページには「動作時やバックアップ電圧投入時には、BATT電流がバックアップ時よりも多く流れます。」って書いてありますので、その辺注意が必要かと思います。まぁ通常のコイン型のアルカリ / リチウム電池で問題ない程度ですが。

■ヒシチューブ/スミチューブ■

余談ですが、結線といえば今までヒシチューブとスミチューブってメーカーが違うだけの同じものだと思っていて、ずっと30年ぐらい前に買ったヒシチューブを使っていました。が、とうとう30年目にして使いきってしまったので秋月で熱収縮チューブを買ってきました。

そしたら、まず感触からして違うんですよね。在庫のヒシチューブは硬質ビニールみたいだったけど、買ってきたものはゴムっぽい。最初「うちのはそんなに劣化してたんかいw」と思ってコミュニティに書いたら、「別物です」と教えていただきました。そうだったのかー(AA略

勉強になりました m(_ _)m

使ってみると、ヒシチューブよりもキレイに仕上がるような気がします。

■ソフト■

ライブラリを探したのですが、特に見つからず。まぁそんなに面倒くさい処理でもないので、仕様書をみながら何十年かぶりにシリアル信号処理プログラムを書きました。昔、PeopleオンラインのMac版クライアントとか書いたっけなー(遠い目

GPSモジュールは、ただ淡々とデータ(NMEA準拠)を送ってくるので、1行ずつ読み込んで目的の$GPRMCで始まる行が来たら、それぞれのカンマ区切りの後が何文字目なのかを数えつつカンマを \0 で潰してc文字列末としていきます。何番目が何の意味かは決まっているので、あとはそれを読みやすい形式に変えてから表示してます。

といいつつ、めんどくさいので時刻はUTCのままです。ちゃんと日本時間で見たい場合には9時間足せばOKです。移動速度もノット単位です。

ソフト開発Tipsを1つ。こういう「お外に出ないとちゃんと受信できない物」のプログラムを組む場合には「ちゃんと受信できたらこうなるはず」の文字列をダミーとして用意しておき、それが机の上でちゃんと処理されることを試してから外に出ましょう。128-131までのコメント部分がソレです。

// ESP_GPS54_SSD1306 by k.kurahashi 2016-02-13
//
// thanks:
// OLED Library
// https://github.com/squix78/esp8266-oled-ssd1306
//
//
//
// OLED / SSD1306
//
#include <Wire.h>
#include "SSD1306.h"
#include "SSD1306Ui.h"
SSD1306 display(0x3c, 4, 5);
//
// GPS read buffer
//
int gpsByte = -1; // read a byte
char gpsLine[100]; // read line
int gpsLength; // length of buffer
//
// initialize
//
void setup() {
// GPS defaut serial speed
Serial.begin(9600);
pinMode(13, OUTPUT);
// OLED init
Wire.begin();
display.init();
display.flipScreenVertically();
display.displayOn();
display.clear();
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, 0, "status");
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.drawString(127, 0, "waiting");
display.display();
gpsLength = 0;
}
//
// process gps data line
//
void processLine(char *line) {
// handle only $GPRMC line
if (strncmp(line, "$GPRMC,", 7) == 0) {
digitalWrite(13, HIGH);
// split line at ','
int pos[20];
int nPos = 0;
for (int i = 6; i < gpsLength; i++) {
if (gpsLine[i] == ',') {
pos[nPos++] = i+1;
gpsLine[i] = 0;
}
}
// make time format
char stime[10];
int p = 0;
for (int i = 0; i < 6; i++) {
stime[p++] = gpsLine[pos[0] + i];
if ((i % 2) == 1) stime[p++] = ':';
}
stime[p-1] = 0;
// make date format
char sdate[10];
p = 0;
for (int i = 0; i < 6; i++) {
sdate[p++] = gpsLine[pos[8] + i];
if ((i % 2) == 1) sdate[p++] = '-';
}
sdate[p-1] = 0;
// show the datas
char buf[100];
display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, 0, "status");
display.drawString(0, 12, "date");
display.drawString(0, 24, "time");
sprintf(buf, "%c %s", gpsLine[pos[3]], gpsLine + pos[2]); // latitude
display.drawString(0, 36, buf);
sprintf(buf, "%c %s", gpsLine[pos[5]], gpsLine + pos[4]); // longitude
display.drawString(0, 48, buf);
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.drawString(127, 0, gpsLine[pos[1]] == 'A' ? "Available" : "invisible");
display.drawString(127, 12, sdate);
display.drawString(127, 24, stime);
display.drawString(127, 36, gpsLine + pos[7]); // hedding vector
display.drawString(127, 48, gpsLine + pos[6]); // speed
// sprintf(buf, "l=%d,n=%d,0=%d,8=%d", gpsLength, nPos, pos[0], pos[8]);
// display.drawString(127, 36, buf);
display.display();
} else {
digitalWrite(13, LOW);
}
}
//
// Loop
//
void loop() {
// strcpy(gpsLine, "$GPRMC,154655,A,4428.1874,N,00440.5185,W,000.7,000.0,050407,,,A*6C"); // test code
// gpsLength = strlen(gpsLine);
// processLine(gpsLine);
//
// read serial, and skip empty or line feed
gpsByte = Serial.read();
if (gpsByte == -1 || gpsByte == '\n') {
delay(100);
return;
}
// if return, it it end of line. process the one line
if (gpsByte == '\r') {
if (gpsLength > 0) {
processLine(gpsLine);
gpsLength = 0;
}
}
else { // else, append it to the line buffer
gpsLine[gpsLength++] = gpsByte;
gpsLine[gpsLength] = 0;
}
}


■使ってみる■

ダメだろうなーと思いつつ南向きベランダに出してみます。

やっぱり測地できません。が、とりあえず日時は表示されているので、受信には成功しているようです。ということで、広い公園に出て撮ってみたのが一番上のビデオです。コールドスタートだと仕様通り1分少々かかりますね。

でも一度捕捉してしまえば、影に入ったあとでも数秒で再捕捉されます。

さて、これで「真のサイクルコンピュータ」でも作りましょうかね。WiFiテザリングでiPhoneと接続する、単三電池3本で4-8時間ぐらいしか電池の持たないサイクルコンピュータをw なお、「iPhoneってGPSも付いてますよね」という疑問を持ってはいけません。

0 件のコメント:

コメントを投稿