いまどきの車では、OBD(OnBoadrdDialog)によりいろんなデータが取得できる。それを利用した各種インジケーターも販売されているが、自分の欲しいデータを数値で取得できれば、いろんな使い道がある、はずなんだよね。「CIVIC(シビック)FL1でのOBD2データ取得(Arduino使用)基礎編」で基本的な動作は確認できたので応用していこう。
ところで、CAN-BUSシールドにはマイクロSDカードスロットが付いている。これを利用しない手はないだろう。スイッチ入切によるデータロギング機能を追加してみよう。
#include <SPI.h>
#include <mcp2515_can.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
//CAN-BUS
const int CAN_CS_PIN = 9;
const int CAN_INT_PIN = 2;
unsigned char stmp[] = {0x02, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char cmnd[] = {0x0B, 0x0C, 0x11, 0x15};
unsigned long trgt[] = {0x18DA10F1, 0x18DAEFF1, 0x18DAEFF1, 0x18DA10F1};
String unit;
float data;
unsigned char fct;
unsigned char len = 0;
unsigned char buf[8];
mcp2515_can CAN(CAN_CS_PIN);
//LCD
int Col;
int Row;
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//SD
const int SWITCH1 = 6; //D6ピンを使用
const int SWITCH2 = 7; //D7ピンを使用
const int chipSelect = 4; //D4ピンがSD制御用(Arduinoの標準的な設定。CAN-BUSシールドもそうなっている)
int LogStat = 0;
int FileNum = 0;
String FileTemp;
File dir;
File LogData;
unsigned long ti;
void setup() {
//SD Init
pinMode(SWITCH1, OUTPUT); //D6ピンを出力で使用
pinMode(SWITCH2, INPUT_PULLUP); //D7ピンを入力で使用。プルアップしておく(スイッチOFFの場合にHIGHになるように)
digitalWrite(SWITCH1, LOW); //D6ピンはLOWにしておく
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
while (1);
}
dir = SD.open("/");
while(1){
File entry = dir.openNextFile();
if(!entry){break;}
if (!entry.isDirectory()) {
FileTemp = entry.name();
}
entry.close();
FileNum = FileTemp.toInt()+1;
}
//LCD Init
lcd.init();
lcd.backlight();
SERIAL_PORT_MONITOR.begin(115200);
while(!Serial);
if (CAN.begin(CAN_500KBPS) != 0) {
lcd.setCursor(1,0);
lcd.print("CAN-BUS init error!");
while(1);
}
lcd.setCursor(1,0);
lcd.print("CAN-BAS init ok!");
CAN.init_Mask(0 , 1 , 0x00000000); //0x1FFFFFFF);
CAN.init_Filt(0 , 1 , 0x18DAF110);
CAN.init_Filt(1 , 1 , 0x18DAF1EF);
CAN.init_Mask(1 , 1 , 0xFFFFFFFF);
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);
lcd.clear();
}
void loop() {
for (int i=0; i<4; i++) {
ti = millis();
unit = "";
stmp[2] = cmnd[i];
CAN.sendMsgBuf(trgt[i], 1,8, stmp);
if(CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf);
switch (buf[2]) {
//Intake Pressure
case 0x0B:
data=buf[3];
fct = 0;
unit = "kPa";
Col = 0; Row=0;
break;
//rpm
case 0x0C:
data=((float)256*buf[3]+buf[4])/4;
fct = 0;
unit = "rpm";
Col = 8;Row=0;
break;
//Throttle
case 0x11:
data=(float)100*buf[3]/255;
fct = 1;
unit = "%";
Col=0;Row=1;
break;
//Air-Fuel
case 0x15:
data=((float)256*buf[3]+buf[4])/32768; //間違っている
fct = 2; //間違っている
unit = "AFR"; //間違っている
Col=8;Row=1; //間違っている
break;
}
//LCD
lcd.setCursor(Col,Row);lcd.print(data,fct);lcd.print(unit);
//Data Logging
if (digitalRead(SWITCH2) == LOW && LogStat == 0) { //ロギングしていないとき(LogStat=0)、スイッチがON(D7がLOW)になったら
Serial.println("Logging...");
LogData = SD.open(String(FileNum), FILE_WRITE); //設定したファイルを作成
LogStat = 1; //ロギング動作中(LogStat=1)に
}
if (LogStat == 1) { //ロギング中ならデータ書き込み
LogData.print(buf[2],HEX);LogData.print(",");LogData.print(ti);LogData.print(",");LogData.println(data,fct);
if (digitalRead(SWITCH2) == 1) { //スイッチOFFになったら終了
LogData.close();
LogStat = 0;
FileNum++;
}
}
}
}
delay(100);
}
早速、データを取ってみよう。取得するのは、上記スケッチにより、時間・アクセル開度・空燃比・インマニ吸気圧力・エンジン回転数、だ。実際に取得したデータでは、ところどころ取得ミス(値がゼロ)があったのでそれを削除してある。
項目 | データの説明 |
---|---|
横軸 | 時間経過[msec] |
縦軸1(左) | アクセル開度[%] |
縦軸2(左) | |
縦軸3(左) | インマニ吸気圧力(絶対圧)[kPa] |
縦軸4(右) | エンジン回転数[rpm] |
一応、解説を。
データが取れればやってみたくなるのはいつものこと(前回参照『CBR1000RR(SC36)フルパワー化:なんちゃって馬力計算』)だ。今回はトルクも計算してみよう。
項目 | 公式 |
---|---|
運動方程式 | F[N]=m[kg]×α[m/s2] |
動力 | P[W]=F[N]×V[m/s] |
トルク | T[Nm]=F[N]×L[m] |
まず、質量mだが、これは、
m=1,440kg=1,340kg(車両重量:6MT@EXグレード、ガソリン満タン)+100kg(運転手+フロアマット等オプション品+デッドニング材料+その他カスタム部品、のおおよそ) |
とする。次に加速度αだが,加速度とは単位時間当たりの速度の増加分なので,データサンプリング毎の計測間隔(Arduinoの時間計測精度による)とそのときの回転数差・減速比・タイヤ径から求めることが可能だ。
α[m/s^2]=(rpm2-rpm1)[rpm]÷60[rpm->1/sec]÷計測間隔[sec]÷4.105[減速比]÷X.XX[計測時のギヤの変速比]×π[円周率]×0.645[235/40R18タイヤ直径 m] ※CVTだとギヤ比可変で計算できないのでOBD2車速データを取って計算する必要あり |
速度Vは、その瞬間のタイヤ回転数×タイヤ円周長で算出する。
V[m/s]=rpm[rpm]÷60[rpm->1/sec]÷4.105[減速比]÷X.XX[計測時のギヤの変速比]×π[円周率]×0.645[235/40R18タイヤの直径:m] ※CVTだとギヤ比可変で計算できないのでOBD2車速データを取って計算する必要あり |
トルク計算に必要な長さLはタイヤ直径より
L[m]=0.3225=0.645[タイヤ直径:m]÷2[半径にする] |
となる。ただし、このLでの計算はタイヤに作用するトルクなので、エンジン単体のトルクにするためには、変速比で割ってやる必要がある。
Te[Nm]=T[Nm]÷4.105[減速比]÷X.XX[計測時のギヤの変速比] |
さて、その計算結果は...おぉっと、結構衝撃的な値となったぞ。
項目 | カタログ値 | 計算結果 |
---|---|---|
出力[kw] | 134(6000rpm) | 97(6000rpm) ※近似曲線 |
トルク[Nm] | 240(1700-4500rpm) | 170(5000rpm) ※近似曲線 |
まぁこの計算は理論的には正しいかもしれないが、データには雑なところ(近似曲線の引き方もそうだ)があるのでやむを得ないところだ。例えば、5400rpmあたりの外れたデータを1個無視するだけでも5kwくらいは増えそうだし。さらには、車両内部で、安全(エコも?)方向の制御が働いている可能性もあるしね。