e:HEVの車ってタコメーター無い割にたまに変なタイミングでエンジン回って気持ち悪い時あるじゃないですか。なのでせめて回転数を数字で理解したいな〜と思って、車両からデータを取ることを考えてみました。
とはいえ偉大なる先駆者の方がいらっしゃるので、基本的にこの流れに沿って進めました。
https://www.takach.net/main.html#CIVIC_FL1
ハードウェアは手元にあったものを使ったので、参照先とは異なります。
・Arduino UNO
・MCP2515ボード(Amazonで売ってる)
・SSD1306 OLED
まずはサクッと配線します。
デフォで付いてる水晶だとダメなので交換しましょう。
さてここからは元の流れに戻って進めます。
まずはこの車がOBD2の何のPIDに対応しているかの一覧を取得します。
Arduinoのスケッチはこんな感じです。
読みづらくてすいません。
みんカラでインデント表示ちゃんとできる方法ご存知の方教えてください。
#include <SPI.h>
#include "mcp2515_can.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
const int CAN_CS_PIN = 10;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(CAN_CS_PIN);
void setup() {
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
while(!Serial);
if (CAN.begin(CAN_500KBPS) != 0) {
Serial.println("CAN-BUS init error!");
while(1);
}
Serial.println("CAN-BAS init ok!");
// フィルターの設定
CAN.init_Mask(0 , 1 , 0x00000000);
CAN.init_Filt(0 , 1 , 0x00000000);
CAN.init_Filt(1 , 1 , 0x00000000);
CAN.init_Mask(1 , 1 , 0x00000000);
CAN.init_Filt(2 , 1 , 0x00000000);
CAN.init_Filt(3 , 1 , 0x00000000);
CAN.init_Filt(4 , 1 , 0x00000000);
CAN.init_Filt(5 , 1 , 0x00000000);
delay(1000);
}
String unit;
float data;
unsigned char yax;
unsigned char fct;
unsigned char len = 0;
uint32_t id;
unsigned char buf[8];
unsigned char stmp[] = {0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char cmnd[] = {0x0C, 0x0D, 0x9A};
unsigned long trgt[] = {0x18DAEFF1, 0x18DAEFF1, 0x18DA01F1};
unsigned long ti;
void loop() {
display.clearDisplay();
//for (int i=0; i<3; i++) {
int i=0;
unsigned long t = millis();
unit = "";
stmp[2] = cmnd[i];
CAN.sendMsgBuf(trgt[i] , 1 , 8 , stmp);
if(CAN.checkReceive()){
CAN.readMsgBuf(&len, buf);
id = CAN.getCanId();
Serial.print(t); Serial.print(":");
Serial.print(id , HEX); Serial.print(":");
for (int i = 0; i < len; i++) {
Serial.print(buf[i] , HEX); Serial.print(" "); //注4
}
Serial.println();
}
//}
delay(100);
}
stmp[2]の値を0x00, 0x20,..., 0xC0まで変えながら実行すると、シリアルモニタに各場合の出力が得られます。
0x00 18DAF1EF:6 41 00 90 18 80 11 55 | 1001 0000 0001 1000 1000 0000 0001 0001
0x20 18DAF1EF:6 41 20 00 00 00 01 55 | 0000 0000 0000 0000 0000 0000 0000 0001
0x40 18DAF1EF:6 41 40 40 00 00 01 55 | 0100 0000 0000 0000 0000 0000 0000 0001
0x60 18DAF1EF:6 41 60 02 00 00 00 55 | 0000 0010 0000 0000 0000 0000 0000 0000
0x80 18DAF101:6 41 80 00 00 00 40 55 | 0000 0000 0000 0000 0000 0000 0100 0000
0x80 18DAF110:6 41 80 00 00 00 02 55 | 0000 0000 0000 0000 0000 0000 0000 0010
0x80 18DAF130:3 7F 01 11 55 55 55 55
0xA0 18DAF130:3 7F 01 11 55 55 55 55
0xC0 18DAF130:3 7F 01 11 55 55 55 55
HEX値をバイナリに直して、ここ
https://en.wikipedia.org/wiki/OBD-II_PIDs
に書いてある読み方で対応PIDをピックアップすると、以下になる。
PID
01 : 18DAF1EF : Monitor status
04 : 18DAF1EF : Calculated engine load [%] : 100A/255
0C : 18DAF1EF : Engine speed [rpm] : (256A+B) / 4
0D : 18DAF1EF : Vehicle speed [km/h] : A
11 : 18DAF1EF : Throttle position [%] : 100A/255
15 : 18DAF1EF : Oxygen Sensor 2 [V or %]
1C : 18DAF1EF : OBD standards this vehicle conforms to
20 : 18DAF1EF : PID supported
40 : 18DAF1EF : PID supported
42 : 18DAF1EF : Control module voltage [V] : (256A+B) / 1000
60 : 18DAF1EF : PID supported
9A : 18DAF101 : Hybrid/EV Vehicle System Data, Battery, Voltage
9F : 18DAF110 : Fuel System Percentage Use
ということで、FL1から増えてるのは0x9Aくらいですかね。
正直あんまり取れる数字ないな・・・という気持ちになっているが、とりあえず表示したら満足できそうな数字として3つピックアップすることにした。
・エンジン回転数
・車速
・HVバッテリー電圧
これまた偉大な参照先のコードを参考にしながら書いてみると、こんな感じになる。
#include <SPI.h>
#include "mcp2515_can.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
const int CAN_CS_PIN = 10;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(CAN_CS_PIN);
void setup() {
Serial.begin(115200);
while(!Serial);
if (CAN.begin(CAN_500KBPS) != 0) {
Serial.println("CAN-BUS init error!");
while(1);
}
Serial.println("CAN-BAS init ok!");
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
// フィルターの設定
CAN.init_Mask(0 , 1 , 0x00000000);
CAN.init_Filt(0 , 1 , 0x00000000);
CAN.init_Filt(1 , 1 , 0x00000000);
CAN.init_Mask(1 , 1 , 0x00000000);
CAN.init_Filt(2 , 1 , 0x00000000);
CAN.init_Filt(3 , 1 , 0x00000000);
CAN.init_Filt(4 , 1 , 0x00000000);
CAN.init_Filt(5 , 1 , 0x00000000);
delay(1000);
}
String unit;
float data;
unsigned char yax;
unsigned char fct;
unsigned char len = 0;
uint32_t id;
unsigned char buf[8];
unsigned char stmp[] = {0x02, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char cmnd[] = {0x0C, 0x0D, 0x9A};
unsigned long trgt[] = {0x18DAEFF1, 0x18DAEFF1, 0x18DA01F1};
unsigned long ti;
void loop() {
display.clearDisplay();
for (int i=0; i<3; i++) {
unsigned long t = millis();
unit = "";
int rpm;
float vbat;
int vsp;
stmp[2] = cmnd[i];
CAN.sendMsgBuf(trgt[i] , 1 , 8 , stmp);
if(CAN.checkReceive()){
CAN.readMsgBuf(&len, buf);
switch(buf[2]){
case 0x0C:
data=((float)256*buf[3]+buf[4])/4;
fct = 0;
unit = "rpm";
yax = 0;
Serial.print(data,fct); Serial.println(unit);
break;
case 0x0D:
data=buf[3];
fct = 0;
unit = "km/h";
yax = 20;
Serial.print(data,fct); Serial.println(unit);
break;
case 0x41:
switch(buf[3]){
case 0x9A:
data=((float)256*buf[6]+buf[7])/
64 .0;
fct = 2;
unit = "V";
yax = 40;
Serial.print(data,fct); Serial.println(unit);
break;
}
break;
}
display.setCursor(0, yax);
display.print(data,fct); display.print(" "); display.println(unit);
}
}
display.display();
delay(100);
}
caseの分岐が増えているが、これはデータ元のECU次第でbufの何バイト目で判別するかが変わっちゃうから。気づくまでけっこう悩んだ。
あとHVバッテリー電圧ですが、PID 0x9Aの末尾2バイトを丸々使っている模様。
(このPIDの使い方は会社によって異なるらしく、ネットにある情報と違った。)
換算式は厳密には不明ですが、
ELM327で取れた値とHEX値とをいくつか並べてChatGPTに相談した結果この式になりました。
5/27 新たにELM327の配線からバイパスして同期して数字見られるようにして比較したところ、係数は70でなく64が正しそうと判明しました。(少なくともELM327+Car scannerの数字とはドンピシャで合う)
それで、最終的にこんな感じの表示になりました。
動画だとこんな感じ。
VIDEO
あとはアクセル開度なり何なり、取りたいやつにPIDとか書き換えればまあ上のリストにある項目は取れそう。
別に持ってるELM327だとHVバッテリーの電流とかエンジン出力とかも出せてるから、どういうリクエスト送ってるのかもうちょっと調べて同じことできないか考えたいな〜というのが今後の展望。
以上です〜。
p.s.
上の動画の背景で流れている曲はこれなので、聴いてください。私の最推しのVtuberです。歌が最高なので他も聴いてください(強欲)
VIDEO