最終更新: 2023/07/28(Fri)22:35
自作と修理を愛するブログ。トイラジ、電子工作、ボルティー、NucleusCMS 、いろいろゴソゴソやってます3Dプリンター / 3Dスキャナーも -kyu-
さて肝心のスケッチです。前に書いた通りライブラリがふたつ必要です。
Arduino-OBD2-Async
https://github.com/vova-ivanyshyn/Arduino-OBD2-Async
Switec X25 library
https://github.com/clearwater/SwitecX25
ライブラリは適当な場所に入れておきます。
スケッチを簡単に説明すると、ステッピングモータの目標値は0.1秒ごとに更新し、モータの動作自体は毎ループごとに行います。文字盤のバックライトは5秒毎に更新。
たぶんもっといいやりかたがあるんでしょうね。シロウトのヘナチョコプログラムだと思って温かい目で見てやってください。何かあったらコメント欄からお知らせいただけると嬉しいです。
#include “SwitecX25.h”
#include “OBD.h”
SwitecX25 motor(315*3, 4, 5, 6, 7);
COBD obd;
// ステップモーター定数
const int PULSE_PER_REV = 315*3; // ステップモータ全体のパルス数
const int MAX_DISP_REV = 8000; // 表示最大回転数(rpm)
const int VIEW_ANGLE = 315; // 使用範囲(deg)
const float CONV = (1 / (float)MAX_DISP_REV) * ((float)VIEW_ANGLE / 315.0) * (float)PULSE_PER_REV;
// 回転数*CONV=ステップ数 : CONV = (1/8000)*(315/315)*315*3 = 0.118125 ->0.12
// エンジン回転数変数
int CurrentRpm = 0; //現在のエンジン回転数
int PreviousRpm = 0; //前回のエンジン回転数
// 更新頻度変数
const int UpdateInterval1 = 100; // 更新間隔(高頻度) ミリ秒
const int UpdateInterval2 = 5000; // 更新間隔(低頻度) ミリ秒
unsigned long PreviousUpdate1 = 0; // 前回の更新時(高頻度)
unsigned long PreviousUpdate2 = 0; // 前回の更新時(低頻度)
// 照明変数
const int LedPin = 9;
const int CdsPin = 0;
int CdsValue = 0;
void setup()
{
for ( int i = 30; i < LedValue(); i += 1 ) {
analogWrite( LedPin, i );
delay( 10 );
}
motor.zero();
delay(200);
motor.setPosition(MAX_DISP_REV * CONV);
motor.updateBlocking();
delay(200);
motor.setPosition(0);
motor.updateBlocking();
delay(200);
obd.begin();
while (!obd.init(PROTO_AUTO));
}
void loop()
{
unsigned long CurrentTime = millis(); // 現在時
motor.update(); //メータを駆動 (1step/Loop)
if (!obd.asyncInProgress()) {
obd.asyncRequest(PID_RPM); //リクエスト送信
}
if (CurrentTime - PreviousUpdate1 >= UpdateInterval1) { //更新(高頻度)
int val = 0;
if (obd.asyncGet(val)) {
CurrentRpm = val % 10000;
if (abs(PreviousRpm - CurrentRpm) > 9){ //前回との差が一桁なら更新しない
motor.setPosition((float)CurrentRpm * (float)CONV); //目標位置設定
PreviousRpm = CurrentRpm;
}
}
PreviousUpdate1 = CurrentTime;
}
if (CurrentTime - PreviousUpdate2 >= UpdateInterval2) { //更新(低頻度)
analogWrite( LedPin, LedValue() );
PreviousUpdate2 = CurrentTime;
}
if (obd.errors >= 2) {
reconnect();
setup();
}
}
void reconnect()
{
for (uint16_t i = 0; !obd.init(PROTO_AUTO); i++) {
delay(3000);
}
}
int LedValue()
{
int result;
CdsValue = analogRead(CdsPin); // だいたい 500-1000
result = -0.3*(float)CdsValue+350;
if (result > 255){
result = 255;
}
return result;
}
ステッピングモータとその駆動方法が決まったので、お待ちかねの 3D モデリングです。あ、お待ちかねなのは自分ですよ念のため。
後づけのメータって、砲弾型のハウジングに入っててダッシュボードの上に無理付けしたりするもんですが、激しく主張するのはどーも好きじゃないので、おや、純正オプションにこんなのあったっけ的な感じにしたいです。
前回ちょっと触れましたが、本当は縦2行程度の LCD を装備して、エンジン回転数以外の情報も表示させる目論見でした。
ちょっとググると、OBD2 スキャナと Arduino を使って同様のことをやっている事例は結構見つかります。
ライブラリに頼らずに、 AT コマンドを発行するところからなにから作り込んでる例もありましたが、大多数は特定のライブラリを利用している模様。あるものは使わなけりゃなぁと。
Arduino の OBD2シールドの販売もしているオーストラリアの Freematics 、この道では超有名です。
ライブラリも含めて自社製品用のスケッチが Gitbub で公開されています。ありがたや。
https://github.com/stanleyhuangyc/ArduinoOBD
一式ダウンロードすると、製品別のスケッチと共用ライブラリが。
libraries\OBD2UART\example フォルダにある rpm_led_uart.ino が一番簡単なサンプルですね。
使い方は簡単。OBD2UART.h をインクルードしておいて、Loop() 内で obd.readPID(PID_RPM, value) とやると、指定した pid に応じて欲しい数値が value に入るわけです。
前回は OBD2 スキャナを改造して信号線を引き出したところまででした。引き続き制御部をこしらえていきます。
クルマとマイコンを OBD2 で接続してゴニョゴニョしている例は Web にたくさん見つかりますが、方向性はだいたい二手に分かれるようです。車載ネットワーク CAN にまで踏み込んですべて自前でやるか、深いところは ELM327 に任せて表層だけすくい取るか。当然、自分は後者です。なのでスキャナの改造から入ったわけで。
さて Arduino です。3D プリンタの制御基板として長いこと使ってはいますが、あちらには Marlin というすばらしいファームウェアがあるので、プログラミングのことは全然わからずとも使えてました。せいぜい自分の環境に合わせてちょっとヘッダファイルを書き換えるくらい。内容は全く理解していません。
なぜかうちには Arduino UNO とその互換機が計3枚あります。純正品は職場の人にもらったもの、中華な互換機は 3D スキャナ Ciclop で使っているもの。やばいところをショートさせて壊してしまい同じものを買い増ししました。その後よくよく調べてみたらシリアル周りが死んでいるだけだったので、シリアル変換基板を入手すれば使えないことはないはず。なので合計3枚です。まあ互換機はともかくとして、せっかく UNO があるのだから、プロトタイプはこれを使って作り込んでいくことにしますかね。最終的にはもっと小さな Arduino に移植すればよいかと。
本プロジェクトで目指すのはこんなかんじのものです。
ホントはタコメータとは別に LCD を装備して、エンジン回転数以外の情報、例えば吸気温度とかトルクとかも表示させる予定でスタートしたのですが、もろもろの事情でひとまずタコメータのみです。このあたりの詳細はいずれ。
サイト内検索
月別アーカイブ