Track ME: Arduino Mega 2560で作るGPS/GPRSカー・パーソナルトラッカー試作機
部品と材料
| 部品 | 数量 | 備考 |
|---|---|---|
| Arduino Mega 2560 | 1 | 複数のハードウェアシリアルポート必須 |
| NEO-6M GPSモジュール | 1 | シリアル接続、eBay等で安価入手可能 |
| Adafruit SDカードシールド | 1 | ログ記録用(SPIピン変更要) |
| Seeedstudio GPRSシールド V2.0 | 1 | SIM900搭載、SMS送受信用 |
| ジャンパーワイヤー | 1セット | |
| 9V電池 | 1 | 動作確認用(実用時は大容量バッテリー必須) |
| プラスチックケース | 1 | 防水・防塵対策済みのもの推奨 |
プロジェクト概要
車両や個人の位置追跡デバイスを自作するプロジェクトです。Arduino Mega、GPS、GPRSシールド、SDカードで構成されるシンプルなシステムです。SDカードはオプションですが、位置情報履歴の記録と「最後の既知位置」機能のために搭載しています。
システム動作
- 常時GPSで現在位置を取得・更新
- SIMカードへ着信があると自動的に着信拒否し、発信者へSMSで位置情報を返信
- GPS受信良好(衛星数≥3、有効な座標あり)の場合: 現在位置をGoogle Mapsリンク付きで送信
- GPS受信不良の場合: SDカードに保存された「最後に取得できた有効な位置」を送信
- 日時、位置、SMS送信成否をSDカードにログ記録
SMSメッセージ例
// 現在位置取得成功時
Hugo location is now: Lat: 54.315010, Log: 10.130997. https://maps.google.com/maps?q=54.315010,+10.130997
// GPS受信失敗時(最後の既知位置)
I can not seem to find Hugo. Last time that I've saw him, was in: Lat: 54.315010, Log: 10.130997. https://maps.google.com/maps?q=54.315010,+10.130997
配線詳細(Arduino Mega特有のピン配置対応)
SDカードシールド(Uno用→Mega用にSPIピンを配線し直し)
| Uno SPIピン | Mega SPIピン |
|---|---|
| MOSI (11) | 51 |
| MISO (12) | 50 |
| SCK (13) | 52 |
| SS (10) | 53 |
GPRSシールド (Seeedstudio V2.0)
- J7ジャンパーを「Software Serial」側に設定
- シールドのピン7,8 → Arduino Mega Serial1 (ピン18=TX, ピン19=RX)
GPSモジュール (NEO-6M)
- Arduino Mega Serial2 (ピン16=TX2, ピン17=RX2) に接続
- 電源はSDカードシールドの5V/GNDから供給
電源
- 9V電池をVinピンまたはDCジャックに接続
- ※実用時はスリープモード実装と大容量バッテリーが必須(現状は約1時間で電池切れ)
ライブラリ設定(Arduino Mega対応)
- GSMライブラリ(GPRSシールド用)の
GSM.hで//#define UNOをコメントアウトし、#define MEGAを有効化 HWSerial.hでも同様に#define MEGAを有効化- GPS用に
TinyGPS++ライブラリを使用
プログラムフロー
- 起動時: GPRS、GPS、SDカードを初期化
- GPSが衛星を捕捉し有効な座標を得るまで待機(この期間の着信は拒否のみ)
- 衛星数≥3かつ有効座標取得後は、着信時に現在位置SMS送信
- 衛星数<3または無効座標の場合、着信時に最後の既知位置SMS送信
- 全データをSDカードに追記保存
課題と今後の改善点
- 電池持続時間約1時間 - スリープモード未実装。ディープスリープと間欠動作の実装が必須
- サイズが大きい - 専用基板を設計中(写真参照)
- GPRSシールドの電源管理、アンテナ配置の最適化
ソースコード
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "sms.h"
#include "call.h"
#include <TinyGPS++.h>
// GSM.cppの27,28行でシリアルピン変更可
// GSM.hでMEGA定義必須
#include <SPI.h>
#include <SD.h>
const int chipSelect = 53; // MegaのCSピン
CallGSM call;
SMSGSM sms;
char number[20];
byte stat = 0;
int value = 0;
char value_str[5];
TinyGPSPlus gps;
const char *googlePrefix = "https://maps.google.com/maps?q=";
double Lat, Long;
int day, month, year, hour, minute, second;
int num_sat;
boolean one_point_true = false;
void setup() {
Serial.begin(9600);
Serial.print(F("Starting GSM..."));
if (gsm.begin(9600)) Serial.println(F("READY"));
else Serial.println(F("IDLE"));
Serial.println(F("Starting GPS"));
Serial2.begin(9600); // GPS用ハードウェアシリアル
Serial.print(F("Initializing SD card..."));
pinMode(53, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println(F("Card failed, or not present"));
return;
}
Serial.println(F("card initialized."));
}
void loop() {
Get_GPS();
Check_call();
}
// GPSデータ取得・解析
void Get_GPS() {
while (Serial2.available() > 0)
if (gps.encode(Serial2.read()))
num_sat = gps.satellites.value();
if (gps.location.isValid()) {
Lat = gps.location.lat();
Long = gps.location.lng();
if (Lat != 0 && Long != 0) one_point_true = true;
}
if (gps.date.isValid()) {
day = gps.date.day(); month = gps.date.month(); year = gps.date.year();
}
if (gps.time.isValid()) {
hour = gps.time.hour(); minute = gps.time.minute(); second = gps.time.second();
}
smartDelay(500);
if (millis() > 5000 && gps.charsProcessed() < 10) {
Serial.println(F("No GPS detected: check wiring."));
while (true);
}
}
// GPSオブジェクトを継続的にfeedする遅延関数
static void smartDelay(unsigned long ms) {
unsigned long start = millis();
do {
while (Serial2.available()) gps.encode(Serial2.read());
} while (millis() - start < ms);
}
// 着信チェック・処理
void Check_call() {
stat = call.CallStatusWithAuth(number, 0, 0);
if (stat == CALL_INCOM_VOICE_AUTH) {
delay(100);
call.HangUp(); // 着信拒否
Send_SMS(); // SMS返信
}
}
// SMS送信(現在位置または最後の既知位置)
void Send_SMS() {
int error;
char Date[13]; sprintf(Date, "%02d/%02d/%04d ", day, month, year);
char time1[10]; sprintf(time1, "%02d:%02d:%02d ", hour, minute, second);
delay(100);
char lat_print[10], Long_print[10];
dtostrf(Lat, 5, 6, lat_print);
dtostrf(Long, 5, 6, Long_print);
if (num_sat >= 3 && one_point_true) {
char sms_OK[160];
sprintf(sms_OK, "Hugo location is now: Lat: %s, Log: %s. %s%s,+%s\n",
lat_print, Long_print, googlePrefix, lat_print, Long_print);
Serial.println(sms_OK);
error = sms.SendSMS(number, sms_OK);
} else if (num_sat < 3 && one_point_true) {
char sms_NOK[150];
sprintf(sms_NOK, "I can not seem to find Hugo. Last time that i've saw him, was in: Lat: %s, Log: %s. %s%s,+%s\n",
lat_print, Long_print, googlePrefix, lat_print, Long_print);
Serial.println(sms_NOK);
error = sms.SendSMS(number, sms_NOK);
} else {
Serial.println(F("No valid GPS point"));
return;
}
if (error == 0) Serial.println(F("SMS ERROR"));
else Serial.println(F("SMS OK"));
// SDカードにログ記録
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(Date); dataFile.print(" "); dataFile.print(time1);
dataFile.print(" "); dataFile.print(number); dataFile.print(" ");
dataFile.print(lat_print); dataFile.print(", "); dataFile.print(Long_print);
dataFile.print(" "); dataFile.print(error); dataFile.println();
dataFile.close();
} else {
Serial.println(F("error opening datalog.txt"));
}
}
回路図
プロジェクトページのSchematicsセクションに全体配線図とSDカードシールド改造図が掲載されています。
製造プロセス
- Bridge Shield でスマートロボットを構築:Raspberry Pi と Arduino の統合
- Web制御DMX照明システム:Arduino Megaマスターコントローラー
- Bluetooth操作のArduinoスパイボットを自作する
- UnifiedWater v1 - 完全なArduino水質センサーキット
- HSVクロック:Arduino愛好家向けの鮮やかでカスタマイズ可能な時計
- 高性能除雪ロボット:効率的な冬の雪かきを実現
- GSM接続対応ポータブル投票システム「Mobile Vote Box」
- Arduino Portenta H7で作る高性能エッジAIカメラ:OpenMV + TensorFlow Lite
- モダンジュークボックス:Raspberry Pi & Arduino LEDミュージックプレーヤー
- DIY Arduino スマートウォッチ — Apple Watch 風腕時計を自作
- 礼儀正しいドライバーに感謝を伝える - Arduino MKR1000で作る車載メッセージ表示システム