工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

必要な部品と材料

部品数量備考
Arduino Leonardo1専用ハードウェアシリアル(Serial1)確保のため
SIM900開発ボード1GSM/GPRS通信用、SIM800互換も可
u-blox NEO-6M GPSモジュール1
GPSアンテナ1安物は受信感度が悪いので品質重視
抵抗 220Ω2ステータスLED用
LED(汎用)2電源・GPSロック表示用
ユニバーサル基板 7×5cm1LED回路用、3Dプリントケース適合サイズ
12V→5V ステップダウンモジュール1車バッテリー/シガーソケットから給電
Adafruit microSDカードリーダー15V対応品必須
microSDカード1走行距離保存用

必要な工具

使用ソフトウェア・サービス

このプロジェクトについて

「GPSトラッカーを作りたい」というシンプルなアイデアから始まり、学習曲線は急でしたが「多機能GPSトラッカー」に進化しました。初作品なのでフィードバック・改善提案を歓迎します!

車載想定で以下の機能を実装:

Arduinoのメモリ制約(フラッシュ・RAM)が厳しく、効率的なコードと軽量ライブラリの選定が必須でした。

主要コンポーネント詳細

使用ライブラリ

  1. NeoGPS:GPS解析用。TinyGPS++より軽量・高速。ライブラリマネージャからインストール可。GitHub
  2. Time:UTCタイムゾーン変換用。GitHub
  3. PetitFS:超軽量FATファイルシステム。SDカード読み書き用。GitHub

なぜThinger.io公式ライブラリを使わないのか?

公式ライブラリは使いやすいが、Arduino Leonardoのフラッシュメモリの約80%を消費し、他のコードが入りません。そのためHTTP POSTリクエストを自前で実装しています。

SMSコマンド

全て大文字で送信:

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

NeoGPSの設定

インストール後、ライブラリフォルダ内のGPSPort.hを以下で置き換え:

#ifndef GPSport_h
#define GPSport_h
#define gpsPort Serial1
#define GPS_PORT_NAME "Serial1"
#define DEBUG_PORT Serial
#endif

このファイルでGPS接続シリアルポートを定義します。Mega等の場合はSerial2/Serial3に変更。

精度について: GPSは静止時も位置が微小にドリフトするため、距離積算には誤差があります。本プロジェクトでは「15秒間で10m未満の移動は静止とみなす」「10km超のジャンプは異常値として除外」というフィルタを実装。サンプリング間隔は15秒(短くすれば精度向上、処理負荷増)。

PetitFSの設定

超軽量だが制約多し:ファイル作成不可、サイズ拡張不可、追記不可、タイムスタンプ更新不可、同時オープン1ファイルのみ。標準SDライブラリは約12%大きく、全機能を収められないため採用。

設定変更:

  1. pffArduino.hのSD_CS_PINを10に変更(SPIのSSピン)
  2. pffconf.hで以下を0に無効化:_USE_DIR, _USE_LSEEK, _FS_FAT12, _FS_FAT16
  3. pff.cppの不足戻り値FRESULTを追加(初回コンパイルエラー対策)

SDカード準備

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

SIM900ボードの準備

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
  1. 電源: Arduinoから給電不可。外部5V-9V/2A以上の電源をDCジャックへ。電源セレクターを「外部」側に
  2. シリアル: ソフトウェアシリアル用ジャンパー位置に設定
  3. ソフトウェア電源制御: R13ジャンパーを半田付けし、Arduino D7から制御可能に(コード内SIM900power()使用)。手動電源ボタン運用なら不要
  4. SIMカードPINロック解除: 通常の携帯電話で解除してから使用
  5. ファームウェアバージョン(重要!): B10以降必須。HTTPヘッダーのContent-Type設定コマンドがB10から対応。AT+CGMRで確認。古い場合はファームウェア更新が必要

コードのカスタマイズ項目

Thinger.io連携設定

  1. アカウント作成後、「Bucket(データベース)」を作成
  2. 「HTTP Device」を作成(デバイス名は短く。長いと認証キーが256バイトバッファを超える)
  3. DeviceのCallback設定で作成したBucketを指定
  4. CallbackのOverviewから「Method URL」と「Authorization Header(Bearer除く)」をメモ
  5. コード内のpostDataThinger()のURLと認証キーを置換。https→httpに変更必須
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

送信データ形式:{"longitude":xxx,"latitude":xxx,"date":"DD/MM/YYYY HH:MM:SS"}

成功時シリアル出力:+HTTPACTION: 1,200,0(400エラーならURL/認証キー/ファームウェア確認)

追加データ送信時はsprintfのフォーマット厳守でフィールド追加。

ケース(3Dプリント)

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

車両電源への接続

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー
Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

車のACC連動(シガーソケット回路)から給電する方式を採用。エンジンOFFで装置もOFF。常時電源が必要ならバッテリー直結またはモバイルバッテリー併用。ステップダウンモジュール(12V→5V/2USB出力)でArduinoとSIM900に給電。消費電流はGSM通信時約110mAh(電波状況により変動)。

既知の問題

コード

GPS_tracker_Leonardo_v2.ino(全コードは元記事参照。主要部のみ抜粋)

#include <SoftwareSerial.h>
#include <NMEAGPS.h>
#include <GPSport.h>
#include <TimeLib.h>
#include "PF.h"
#include "PetitSerial.h"

#define UTC_OFFSET 9  // 日本時間(UTC+9)
#define TXPin 8       // SIM900 Tx
#define RXPin 9       // SIM900 Rx
#define PWRPin 7      // SIM900 電源制御
#define DEFAULT_NUMBER "+81XXXXXXXXXX"  // 通知先電話番号

FATFS fs;
String textMessage, number = DEFAULT_NUMBER;
char sms_msg[160];
float Lat = 0, Long = 0;
boolean valid_location = false;
uint8_t num_sat;
NeoGPS::Location_t prevFix;
NMEAGPS gps;
gps_fix fix;
const char *googlePrefix = "https://maps.google.com/maps?q=";
const char *filename = "DIST.TXT";
const char *settings = "SETTINGS.TXT";
NeoGPS::time_t timeFix;
char datePrint[13], timePrint[10];
float totalDistance = 0, triggerDistance = 4000000;
SoftwareSerial SIM900(TXPin, RXPin);

void setup() {
  pinMode(3, OUTPUT); pinMode(4, OUTPUT);
  digitalWrite(3, HIGH);  // 電源LED点灯
  Serial.begin(9600);
  // while (!Serial);  // デバッグ時のみ有効化
  SIM900.begin(9600);
  gpsPort.begin(9600);
  initializeSD();
  SIM900power();
  SIM900.println(F("AT")); delay(500);
  SIM900.println(F("AT+CMGF=1")); delay(500);
  SIM900.println(F("AT+CNMI=1,2,0,0,0")); delay(500);
  connectGPRS();
}

void loop() {
  while (gps.available(gpsPort)) {
    fix = gps.read();
    num_sat = fix.satellites;
    if (fix.valid.location) {
      digitalWrite(4, HIGH);  // GPSロックLED
      Lat = fix.latitude(); Long = fix.longitude();
      if (Lat!=0 && Long!=0 && !valid_location) {
        valid_location = true; prevFix = fix.location;
      }
    }
    if (fix.valid.date && fix.valid.time) {
      timeFix = fix.dateTime; updateTime();
    }
    if (valid_location) {
      // 15秒ごと距離更新
      static const unsigned long REFRESH_INTERVAL_UPD = 15000;
      static unsigned long lastRefreshTime = millis();
      if (millis() - lastRefreshTime >= REFRESH_INTERVAL_UPD) {
        lastRefreshTime += REFRESH_INTERVAL_UPD;
        float distanceDelta = prevFix.DistanceKm(fix.location) * 1000;
        if (distanceDelta > 10 && distanceDelta < 10000) totalDistance += distanceDelta;
        prevFix = fix.location;
      }
      // 2分ごとSD書き込み+Thinger.io送信
      static const unsigned long REFRESH_INTERVAL_WRITE_SD = 120000UL;
      static unsigned long lastRefreshTimeWriteSD = millis();
      if (millis() - lastRefreshTimeWriteSD >= REFRESH_INTERVAL_WRITE_SD) {
        lastRefreshTimeWriteSD += REFRESH_INTERVAL_WRITE_SD;
        char buf[9]; dtostrf(totalDistance, 8, 0, buf);
        if (PF.open(filename)) Serial.println(F("error open file"));
        while (1) {
          UINT nr;
          if (PF.writeFile(buf, sizeof(buf), &nr)) Serial.println(F("error write file"));
          if (nr == sizeof(buf)) { PF.writeFile(0, 0, &nr); break; }
        }
        // Thinger.ioへHTTP POST
        char httpContent[60], tempstrLong[10], tempstrLat[10];
        dtostrf(Lat, 2, 6, tempstrLat); dtostrf(Long, 2, 6, tempstrLong);
        sprintf(httpContent, "{\"longitude\":%s,\"latitude\":%s,\"date\":\"%s %s\"}", tempstrLong, tempstrLat, datePrint, timePrint);
        char httpdataLen[20];
        sprintf(httpdataLen, "AT+HTTPDATA=%i,10000", strlen(httpContent));
        postDataThinger(httpdataLen, httpContent);
      }
    }
  }
  // 走行距離通知
  if (totalDistance > triggerDistance) {
    char distanceTotalMsg[10];
    itoa((totalDistance/1000), distanceTotalMsg, 10);
    sprintf(sms_msg, "Empty catchtank! Current distance: %skm", distanceTotalMsg);
    textMessage = ""; number = DEFAULT_NUMBER; totalDistance = 0;
    sendSMS(sms_msg);
  }
  updateSerial();
}

// 以下、SIM900制御、SMS送受信、GPRS接続、HTTP POST、SDカード初期化、時刻補正等の関数は元コード参照

3Dプリントパーツ

回路図

Thinger.io連携でリアルタイム地図表示する確実な車載GPSトラッカー

製造プロセス

  1. アイロン台の製造:設計、素材、生産プロセス
  2. サーフボードの構造とデザイン:ポリネシアのルーツから現代の革新まで
  3. センサーデータをRaspberry Piに統合:実践ガイド
  4. PSoC 6 Pioneer BoardとIoT Add-On Shieldを極める:開発者向けガイド
  5. エンジン冷却水不足で走行するリスク:最悪の場合エンジン破損も
  6. 社内統合システムを活用した精密製造の実現
  7. Raspberry Pi、自社初MCU「RP2040」と4ドル「Pico」ボードを発表
  8. 屋外GPS資産追跡:トレンド、課題、新興技術
  9. Python map()関数をマスター:構文、例、ベストプラクティス
  10. Java HashMap 完全ガイド:基本から実践まで
  11. BIOVIA Living MapでCOVID-19薬物再配置を加速