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

IoT4Car: Arduino MKR1000で車両テレメトリー取得・クラウド可視化 – OBD-II対応

必要な部品と材料

Arduino MKR WiFi 1000 (SAMD21, 3.3V動作) × 1
SparkFun Logic Level Converter (双方向, 5V⇔3.3V) × 1
SparkFun OBD-II UART ボード (STN1110チップ搭載, ELM327コマンドセット対応) × 1
SparkFun OBD-II - DB9 ケーブル × 1
LCD 1602 (I2Cモジュール付き推奨) × 1 (車内リアルタイム表示用)
ブレッドボード、ジャンパーワイヤー × 1式
スマートフォン (テザリング用 Wi-Fi ホットスポット) × 1

使用クラウドサービス

プロジェクト概要

車両の OBD-II ポート (16ピン) に接続し、エンジン回転数、車速、燃料残量、冷却水温度などのリアルタイムデータを取得。Arduino MKR1000 の Wi-Fi 機能でクラウド (dweet.io → freeboard.io) にアップロードし、どこからでもブラウザで車両状態を監視できるシステムです。MKR1000 は 3.3V 動作のため、5V の OBD-II UART ボードとの間にロジックレベルコンバーターが必須です。

OBD-II とは

ハードウェア接続

MKR1000レベルシフター (HV側)レベルシフター (LV側)OBD-II UART
TX (D14)→ HV1LV1 →RX
RX (D13)← HV2LV2 ←TX
GNDGNDGNDGND
3.3V-LV (VCC)-
5V (USB給電時)HV (VCC)-VCC

※ MKR1000 のハードウェアシリアルは Serial1 (D13/D14) です。Serial は USB-CDC (PC通信用) なので注意。

LCD 1602 (I2C) 接続

OBD-II コマンドとレスポンス解析

サービスモード 0x01 (現在データ) の主要 PID

PID (Hex)名称単位/変換式コマンド
0x0D車速km/h (そのまま)010D
0x0Cエンジン回転数RPM = (A×256 + B) / 4010C
0x2F燃料レベル% = A / 255 × 100012F
0x05冷却水温度°C = A - 400105

レスポンス形式

送信: "010D\r"
応答: ">1 0D 00\r"  (">1 " = エコー+モード, "0D" = PID, "00" = データ)
送信: "010C\r"
応答: ">1 0C 09 8C\r" (データ2バイト: 0x098C = 2444 → 2444/4 = 611 RPM)

データ抽出ロジック

受信バッファー rxData に文字列格納。キャリッジリターン \r で終了判定。データ部分は 6文字目以降 (0-indexed) から開始。

完全スケッチ (IoT4Car_code)


/* OBDII-UART-Serial v9
 * Arduino MKR WiFi 1000 + SparkFun OBD-II UART + Level Shifter + LCD1602
 * dweet.io / freeboard.io 連携
 */
#include <SPI.h>
#include <WiFi101.h>
#include <LiquidCrystal.h>

// Wi-Fi設定
char ssid[] = "YOUR_WIFI_SSID";       // スマホテザリングSSID
char pass[] = "YOUR_WIFI_PASSWORD";
char server[] = "www.dweet.io";
unsigned long lastConnectionTime = 0;
const unsigned long postingInterval = 10L * 1000L; // 10秒ごと送信
WiFiClient client;
int wifiStatus = WL_IDLE_STATUS;

// LCD設定 (ピン配置は配線に合わせて)
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// OBD通信バッファ
char rxData[20];
char rxIndex = 0;
char inChar = 0;
String message;

// 車両データ
int vSpeed = 0;   // mph
int vRPM = 0;     // rpm
int vFuel = 0;    // %
int vTemp = 0;    // °C

void setup() {
  lcd.begin(16, 2);
  lcd.clear();
  
  // Wi-Fiシールド確認
  if (WiFi.status() == WL_NO_SHIELD) {
    lcd.println("WiFi shield missing");
    while (true);
  }
  
  // Wi-Fi接続 (テザリング対応)
  while (wifiStatus != WL_CONNECTED) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("Connecting WiFi...");
    wifiStatus = WiFi.begin(ssid, pass);
    delay(5000);
  }
  lcd.setCursor(0, 1);
  lcd.println("Connected!");
  
  // OBD用シリアル (Serial1 = D13/D14)
  Serial1.begin(9600);
  resetBuffer();
}

void loop() {
  // Wi-Fi再接続チェック
  while (wifiStatus != WL_CONNECTED) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("Reconnecting WiFi...");
    wifiStatus = WiFi.begin(ssid, pass);
    delay(5000);
  }
  
  // 4項目順次取得
  getSpeed();      // 010D
  getRPM();        // 010C
  getFuel();       // 012F
  getCoolTemp();   // 0105
  
  // クラウド送信 (10秒間隔)
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
    lastConnectionTime = millis();
  }
}

void getSpeed() {
  message = "010D";
  Serial1.println(message);
  delay(200);
  clearLcdLine(0, 0, 8); // 1行目前半クリア
  lcd.setCursor(0, 0);
  getResponse();
  vSpeed = strtol(&rxData[6], 0, 16); // km/h
  vSpeed = vSpeed * 0.621371;         // mph変換
  lcd.print(vSpeed);
  lcd.print(" mph");
}

void getRPM() {
  message = "010C";
  Serial1.println(message);
  delay(200);
  clearLcdLine(8, 0, 8); // 1行目後半クリア
  lcd.setCursor(8, 0);
  getResponse();
  // 2バイトデータ (rxData[6][7]と[9][10]? 実際はスペース区切りで6,9文字目から)
  int high = strtol(&rxData[6], 0, 16);
  int low = strtol(&rxData[9], 0, 16);
  vRPM = (high * 256 + low) / 4;
  lcd.print(vRPM);
  lcd.print(" rpm");
}

void getFuel() {
  message = "012F";
  Serial1.println(message);
  delay(200);
  clearLcdLine(0, 1, 8); // 2行目前半クリア
  lcd.setCursor(0, 1);
  getResponse();
  vFuel = strtol(&rxData[6], 0, 16);
  vFuel = 1.0 * vFuel / 255 * 100;
  lcd.print(vFuel);
  lcd.print(" %");
}

void getCoolTemp() {
  message = "0105";
  Serial1.println(message);
  delay(200);
  clearLcdLine(8, 1, 8); // 2行目後半クリア
  lcd.setCursor(8, 1);
  getResponse();
  vTemp = strtol(&rxData[6], 0, 16);
  vTemp = vTemp - 40;
  lcd.print(vTemp);
  lcd.write(0xDF); // 度記号 (HD44780キャラコード)
  lcd.print("C");
}

void getResponse() {
  while (Serial1.available() > 0) {
    if (Serial1.peek() == '\r') {
      inChar = Serial1.read();
      rxData[rxIndex] = '\0';
      rxIndex = 0;
    } else {
      inChar = Serial1.read();
      rxData[rxIndex++] = inChar;
    }
  }
}

void resetBuffer() {
  for (int i = 0; i < 20; i++) rxData[i] = 0;
}

void clearLcdLine(int col, int row, int len) {
  lcd.setCursor(col, row);
  for (int i = 0; i < len; i++) lcd.write(' ');
}

void httpRequest() {
  client.stop();
  if (client.connect(server, 80)) {
    String data = "POST /dweet/for/mkr1000?RPM=";
    data.concat(vRPM);
    data.concat("&Speed=");
    data.concat(vSpeed);
    data.concat("&Fuel=");
    data.concat(vFuel);
    data.concat("&Temp=");
    data.concat(vTemp);
    
    client.println(data);
    client.println("Host: www.dweet.io");
    client.println("Connection: close");
    client.println();
  } else {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("Conn failed");
  }
}

freeboard.io ダッシュボード構築手順

  1. freeboard.io でアカウント作成 → 新規ダッシュボード作成
  2. Datasources → Add → Type: dweet.io, Thing Name: mkr1000 (スケッチと一致させる)
  3. Widgets → Add Pane → Add Widget → Type: Gauge 等選択
  4. Value: datasources["mkr1000"]["RPM"] 等を指定
  5. Min/Max/Units 設定 (RPM: 0-8000, Speed: 0-200, Fuel: 0-100%, Temp: -40-150°C)
  6. Save → 公開URLでどこからでも監視可能

実車テストでの注意点

発展・改良アイデア

回路図 (Fritzing)

プロジェクトページの Schematics: frizling_schematics_M8kF26dafQ.fzz

製造プロセス

  1. 車両ナンバープレート総合ガイド:歴史、デザイン、未来
  2. アンチロックブレーキシステム(ABS):滑りやすい路面での車両安全を守る
  3. Arduinoと超音波センサーで作るAI障害物回避ロボット 〜Q学習による強化学習実装〜
  4. DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
  5. DIYクラウドコスチューム: LEDストリップ、Arduino Nano & SparkFunパーツで光る雲に
  6. Pixie: Arduino Pro Miniで作るNeoPixel腕時計 - アナログとデジタル融合のDIY光る時計
  7. 車両シャーシレイアウト:エンジン位置と駆動配置の解説
  8. 車両配線の基礎知識:信頼性の高い自動車性能のためのキーポイント
  9. パワートレインを理解する:車両を動かす仕組み
  10. オルタネーターを理解する:車に電力を供給する仕組みと故障の兆候
  11. シャシ接地(シャシグラウンド)の目的・機能・重要性を解説