車両には、様々なECU(Electronic Control Unit)が搭載されている。これらのECUは互いに、CAN(Controller Area Network)という通信方式で通信を行っている。そこで、ArduinoとCAN-BUS Shield V2.0を用いて、CAN情報の取得に挑戦してみた。
Arduinoの購入と開発環境構築の記事はこちら↓
CANとは
ここではCANの概要のみ説明する。CANの仕組みについて詳細を知りたい方は、Vector社の「はじめてのCAN」(無料ドキュメント)を参考にすると良い。
診断機通信のためのCAN
CAN通信は、ECU同士の通信を想定したプロトコルであるが、そのプロトコルを使って車両の様々なデータを取得することができる。2008年に北米で診断機通信を実施できるOBD2(オン・ボード・ダイアグノーシス)が義務化されたため、ほとんどの車両にはOBD2のデータに対応している。OBD2は診断機通信の規格(ISO 15765)であり、これに則ったリクエストを診断機が行うことで、ECUの診断用のデータを取得することができる。診断機(またはそれに相当する何か)からデータを要求(リクエストメッセージ)し、ECU側がそのリクエストに答えてデータを送り返す(レスポンスメッセージ)手法も規定されている。詳しくは、Vector社「はじめての診断」(無料ドキュメント)を参照
基本的にはOBD2のデータは各社共通(ただし微妙な違いがあったり、リクエストに対してすべて対応しているとは限らないが、速度・回転数・水温などは取得可能なことが殆ど)なので、その原理を利用して以下のような商品が売られている。
車両制御のためのCAN
診断とは別に、それぞれのECUは、ネットワーク全体に車両の制御に必要な情報を流し続けている。CANネットワークはバス型のため、同一ネットワークに存在するECUはプロトコルに則って自由に喋り、ネットワーク上のECUはそれらを受信することができる。
車両制御のCANデータ構成は、以下のようなデータ構成で送信されてくる。
CAN IDとDLC(データの長さ)、実データを解析できれば、必要な情報を取得することができる。上記データ構成からの読み取りはCANドライバーがやってくれるので、受信の際にはそれほど意識しなくても良い。
ただし、このCAN情報は診断機通信とは異なり、各社共通で定義されたメッセージではない。よって、メッセージを受信したとしても、「このメッセージの中身はこういう意味です」というようにデータを変換して正しく読み取るための「対応表」が必要となる(近年は、ADAS(運転支援システム)の発達に伴い、制御に必要なデータは安全上の理由から読み取れないこともある)。
診断機以外のCANはメーカーで独自に定められており、個別の解析が必要となる。S660に流れている車両制御のためのCANデータを読み取ってみる、というのが今回の試み。
CANデータを収集する
今回は、ArduinoにCAN-BUS Shield V2.0を装着して車両と接続し、CANデータを取得するまでの方法を記載する。
用意するもの
Arduino
数年前にArduino Unoでデータロガーを作成したことがあるが、その際はアナログセンサ(Gセンサ)や、ナビ用の車輪速パルス、回転パルスなどを用いていた。今回は、CANで車両のデータを取得するようなデータロガーの作成を試みる。どうせならハイパワーのものを使ってみたいと思い、Arduino Megaを用意した。
CAN-BUS Shield V2.0
車両を流れるCANメッセージを取得するには、CANメッセージを受信してSPI通信でArduinoのCPUに送信するモジュールにより行われる。今回はメジャーなCAN-BUS Shield V2.0を使用した。Arduino UnoでもArduino Megaでも、特に問題なく使えると製造元に書いてあったため、これを利用することにする。
OBDコネクタ
車両のCANデータを受信するためには、車両のCANネットワークに物理的に接続する必要がある。診断機用にOBD2コネクタが車両側についているため、そこに接続することにした。
ピンが付属しているのでカシメるだけ。やり方は、こちらを参考に。
D-SUB9ピン メスコネクタ
CAN-BUS Shield V2.0と車両を接続する際に必要なコネクタ。はんだ付けして使う。
どうしても、はんだ付けするのが嫌だ!って人向けにはこんな商品もあったりするので参考までに。
その他、電線が必要なので適宜用意する。
なお、最終的にSDカードに保存したCANデータから馬力推定などを簡単に行うため、この記事ではSDカードが制御できるCAN Busシールド+Arduino Megaを使っているが、単純にCAN情報を取得するだけであればもっと単純な構成で対応可能だ。こちらの記事では、Arduni NanoとCANバスモジュールを接続してCAN情報を取得している。
CAN-BUS Shieldを利用したCANデータ取得プログラム
ArduinoとCAN-BUS Shieldを組み合わせる
ArduinoにCAN-BUS Shieldをドッキングさせる(上から慎重に差し込むだけ)。Arduino Unoの場合はピッタリと収まると思うが、Arduino Megaは少し大きい。これでArduino側のハードウェアの準備は終了。簡単だ。
CANトランシーバ(MCP2551)とCANコントローラ(MCP2515)
CAN BUS Shield V2.0には、CANコントローラ(MCP2515)とCANトランシーバ(MCP2551)の2つが搭載されている。
CANトランシーバ(MCP2551)の役割
CANトランシーバの役割は、車両上のCAN電気信号を検知したり、送信の際に変化させたりすること。
あまり詳しく知らなくてもプログラムは組むことができるのだが、CANに参加する車両の各ECU(Electric Control Unit)は、CANのHigh/Lowの2本の配線を持っており、High/Lowの電圧差が0.5V以下(レセシブ)か、0.9V以上か(ドミナント)を検知することにより、電気信号でいうところの1,0を表現している。この辺は、こちらのドキュメントを参照。
CANトランシーバは、High/Lowの電圧差の信号からレセシブ状態とドミナント状態を検出してデジタル信号に置き換えるCANを送信する際には、所定のプロトコル(送信手順)に従って電圧をドミナントとレセシブに変化させ送信する。
CANコントローラ(MCP2515)の役割
CANコントローラは、受信の際にはCANトランシーバが1,0で受信したCAN信号をメッセージとして解釈する。送信の際には、送信すべき信号を1,0の信号に変換してCANトランシーバに渡す役割を持っている。
Arduinoのようなマイコンは、CANコントローラからのシグナルを解釈することで、簡単にCANメッセージを受信することができるという仕組み。
CAN-BUS Shiledライブラリをダウンロード
SEEEDの公式に、CAN-BUS Shieldのライブラリへのリンクがあるので、そこからライブラリをダウンロードする。https://github.com/Seeed-Studio/Seeed_Arduino_CAN
Seeed_Arduino_CAN-master.zipをダウンロードしたら、Arduinoを起動。スケッチ→ライブラリをインクルード、.zip形式のライブラリをインストールを選択して、ダウンロードしたzipを追加する。
CANデータフレームの構成
本来のCANデータに含まれる情報は下図の通り。解析に必要な情報であるID、DLC、データフィールドを取得するAPIはArduinoのライブラリ側が提供してくれている。
今回のプログラムでは、ID、DLC、データフィールドの取得結果を変数can_ID、len、buf[8]にそれぞれ格納するとともに、Arduino側でCANのデータ解析に必要なタイムスタンプを追加するようにプログラムしている。
プログラミング
Arduinoのスケッチ例。今回は診断機に成りすましたメッセージの送受信を目的としないため、CANの送信は行わないようにしている。CANの理解が浅い状態でCAN送信すると、思わぬ車両動作となってしまうおそれがあるので、sendMsgBuf()関数は使用せず。CAN-BUS Shiledから受信したデータをシリアルモニターに表示するプログラム。
/*
* File: CanSerialMonitor.c
* Author: 岡本一車
* https://kurumashikou.com/
*/
#include <SPI.h>
#include "string.h"
#include "mcp2515_can.h"
// ピンの設定
// CAN通信用のCSピン(digital 9)
const int SPI_CAN_CS_PIN = 9;
// SS_defaultPin Arduino unoは10, megaは53
const int PSI_SS_defaultPin = 53;
// グローバル変数 ///////////////////////////////////////////
// タイムスタンプ用変数
unsigned long timestamp = 0;
unsigned long timestamp_old = 0;
// 受信メッセージ格納用
unsigned long can_ID = 0;
unsigned char len = 0;
unsigned char buf[8];
// 送信メッセージ格納用
unsigned char sendMsg[8] = {0, 0, 0, 0, 0, 0, 0, 1};
// CANデータ書き込み値を保持する
String logDataStr;
// CANトランシーバにCSピン設定をセットし、CAN通信インスタンスを生成
mcp2515_can CAN(SPI_CAN_CS_PIN);
// 初期設定 ////////////////////////////////////////////////
void setup() {
// シリアルモニタの設定
SERIAL_PORT_MONITOR.begin(115200);
// シリアルポートの準備が整うまで待つ
while(!Serial);
// CANの初期設定 ///////////////////////////////////////////////
if (CAN.begin(CAN_500KBPS) != CAN_OK) {
SERIAL_PORT_MONITOR.println("CAN initialized error ..............");
while(1);
}else{
SERIAL_PORT_MONITOR.println("CAN initialized OK !!");
}
// シリアルポートにヘッダを書き込み
SERIAL_PORT_MONITOR.println("TimeStamp CAN_ID Len Data");
}
// メイン処理 ////////////////////////////////////////////////
void loop() {
// CANメッセージ受信したときの動作
if (CAN_MSGAVAIL == CAN.checkReceive()) {
// 受信したデータをシリアルモニタに送信 ////////////////////////////////////
if(timestamp_old == 0){
timestamp_old = millis();
}
// CANデータを取得
CAN.readMsgBufID(&can_ID, &len, buf);
// タイムスタンプの取得
timestamp = millis() - timestamp_old;
logDataStr = "";
logDataStr += String(timestamp) + ",";
logDataStr += String(can_ID) + ",";
logDataStr += String(len) + ",";
for (int i = 0; i < len-1; i++) {
logDataStr += (String(buf[i]) + String(","));
}
logDataStr += String(buf[len-1]);
logDataStr += "\r\n";
// シリアルモニターに出力
SERIAL_PORT_MONITOR.print(logDataStr);
}
}
動かなかったらゴメン…一応これで動くはず。あとはArduinoへ焼き込み。焼き込み手順はこちらを参照
車両とArduino+CAN-BUS Shieldの接続
CAN-BUS Shield V2.0側のD-SUB9ピンの作成
まずは、CAN-BUS Shield V2.0に接続するD-SUB9ピンコネクタを作成する。ピン配列は、CAN-BUS Shield V2.0のマニュアルに書いてあった。下の絵は、CAN-BUS Shield V2.0側のコネクタ配線なので、こちらに嵌合するメスコネクタを作成する。
はんだ付けしたメスコネクタの背面。結局使用しなかったが、一応GNDとV_OBD(12V)の配線もしておいた(下図)。
はんだ付けしたら、熱収縮チューブで絶縁しておく(ビニールテープでも良い)。CAN-BUS Shield V2.0と接続した。ノイズ対策として、CANの配線を捩じってツイストペアにしている。
車両側につながるOBD2カプラの作成
車両側のOBDコネクタに接続するためのOBDコネクタを作成する。Wikipediaにピン配列が載っていたのでこちらを参考に作成。今回取得したいのは、CANのHighとLow。下図はWikipediaより。車両側のコネクタ(メス)の6番、14番に挿さるようにオス側コネクタを作成する。
コネクタの作成方法はこちらの記事を参照
車両側、Arduino側、それぞれのコネクタが完成。試作品なので長さがよくわからなかったし、必要な他のArduinoを割り込ませるように中継コネクタ(下図の白色のコネクタ)を複数噛ませているが、この辺は好みで。
S660のOBD2コネクタの場所
最近の車両にはOBD2コネクタが搭載されている。S660の場合は運転席左側の足元にある。
ここに先程作成したOBD2コネクタを挿せば接続完了。Arduinoの電源は、適当にUSBから取得する。
実行してみた
ノートPCを車両に持ち込み、USBでArduinoと接続した。ノートPC上でArduinoのIDEが起動した状態で、ツール→シリアルモニタをON。
車両のイグニッションをONすると、、、、出た!CANがズラズラズラっとシリアルモニタ上に表示された。
これで、CAN情報を取得できた!
今回使用したもの
Arduino
CAN-BUS Shield V2.0
OBDコネクタ
D-SUB9ピン メスコネクタ
CAN-BUS Shield V2.0と車両を接続する際に必要なコネクタ。はんだ付けして使う。
まとめ
Arduino MegaとCAN-BUS Shield V2を利用して、車両からCAN情報を取得するモジュールを作成した。CANデータは車種により異なるので、別途解析が必要。車両に流れている膨大なCANデータの中から、必要なデータを抜き出して処理するプログラムの作成をすることで、サーキット走行データ解析など、使えるシーンはたくさんありそうだ。Arduino Megaを使って、最終的にSDカードに保存したCANデータから馬力を推定している。
ArduinoとCAN-BUS ShieldでCANデータを取得しSDカードに保存
SDカードに保存した車両データから馬力を計測
今回作成したCANデータ取得ユニットを使って、S660の馬力を計測してみた記事はこちら
アルトワークスのCAN解析と馬力計測の記事はこちら
コメント