ArduinoとCAN通信で作るレブインジケータ

S660やアルトワークスでサーキットを走行すると、ついついアツくなってしまい、レブリミッターを作動させてしまう事があった。レブリミッターはその通り、上限回転数に達したらそれ以上エンジン回転数が上がらないようにしてエンジンを保護するための機構ではあるものの頻繁に作動させるのもよろしくない。そこで、CANから車両の回転数を取得してLEDを点灯させる機能をArdunino Nanoと互換性のあるELEGOO Nanoで実装した。

目次

レブインジケータとは

S660ではメーターにレブインジケータ機能(回転数がリミット付近であることを表示する機能)が備わっている。取扱説明書によると、

アンビエントメーター

●SPORTモード/SELECTモードにすると、白色から赤色に変化します。

●SPORTモード/SELECTモードで、エンジン回転数が以下に達したとき、中央のリング照明が赤色で点滅します。

マニュアル車

・エンジン回転数が7,000rpm以上になると遅く点滅し、7,200rpm以上になると早く点滅
 ▶6,800rpmまで下がると点灯に戻ります。

無断返送オートマチック車

・エンジン回転数が6,300rpm以上になると遅く点滅し、6,500rpm以上になると早く点滅
 ▶6,100rpmまで下がると点滅に戻ります。

本田技研工業株式会社 S660オーナーズマニュアルより

S660の場合は、SELECTスイッチ(CVTの場合はSPORTモードスイッチ)を押下する必要があるが、このようなメーター演出機能が備わっている。しかしながら、通常のモードではレブインジケータ機能は動作しない。SELECTスイッチは毎回エンジン始動のたびに押下しなければならないので面倒。

アルトワークスの場合はそのような機能はなく、レッドゾーンに入ると燃料カットしてそれ以上回転数が上昇しないような機構のみ。

ということで、Arduino Nanoを使って、CANから回転数情報を取得、指定回転数になったらLEDを点灯させるレブリミッターを作成してみることにした。

今回作成したレブインジケータ

こんな感じ。指定した回転数(公道なので4000rpmに設定)になったら、青色のLEDが点灯するシンプルなやつ。

CANを取得し、その値に応じて何かを動作させる、という事ができたので、色々なものに応用できそう。

使用した機材

Arduni Nano

ユニバーサル基板にハンダ付けできるピッチのピンがついているArduino。そしてめちゃくちゃ小さい。

Arduino
¥4,670 (2024/05/18 14:54:43時点 Amazon調べ-詳細)

ただし少し高いので、試作品の動作確認を行った後は、互換品を使って作成している。そのまま置き換え可能。

Arduni Nano(及び互換品)は、PCとの接続がUSB-TypeBなので、ケーブルを持っていなければ購入しておこう。

Amazonベーシック(Amazon Basics)
¥508 (2024/05/19 01:31:16時点 Amazon調べ-詳細)

ArduinoとCANバスモジュールや、Arduino同士の接続に必要なのがジャンパーケーブル。オス-メス、オス-オス、メス-メスが揃っている。Arduinoのピンにそのまま差せる。

電源

車両にUSBポートがあればそこから電源を取するなら不要だが、今回は12V Accでも接続することもできるように、DC/DCコンバータも実装した。

CAN通信関連

Arduni Nanoと接続がしやすく、安価なCANモジュールを使用。

車両との接続はOBD2コネクタを利用する。

レブインジケータの構想

Arduino NanoとCANバスモジュールを用いて車両から回転数情報を取得。電源はスマホの充電などで用いるUSB電源から供給し、指定回転数になったらLEDを点灯させる。

Arduino NanoとCANバスモジュールを用いて車両OBDコネクタからCANを受信する構成については、こちらの記事で作成済みなので、今回はこの回路を改修して実現する。

あわせて読みたい
ArduinoNanoとMCP2515でCANデータを受信する 以前、Arduino MEGAとCAN-BUS Shieldを用いて車両のCAN情報を取得する事に成功した。→こちら https://kurumashikou.com/gets660can_via_arduino-and-canbus-shield/ Ard...

回路の設計

ということで、以下の回路を設計した。

Arduni Nanoで設計したが、今回は安い互換品のELEGOO Nanoを利用した。CANモジュールはMCP2515。電源供給はLM2596(DC/DCコンバータ)を用いているが、Arduino NanoへUSB経由で電源供給すれば、12Vを接続しなくても動作する。あえてDC/DCコンバータを用いているのは、電源供給を車両のアクセサリから取得する構想だから。なお、今回使用したDC/DCコンバータについては、こちらの記事の後半で紹介している

あわせて読みたい
電装品の動作確認やガジェット開発のための安定化電源 車両の電圧は12V。車両の電装品や、自作の車用ガジェットの動作確認をするために必須と言っても良い「電源」。そこで、車両の電源を入力できる12V(殆どの電装品は14.5V...

車両にUSBポートがあり、それを利用してArduinoに電源取得する場合にはDC/DCコンバータは不要となる。電子部品の小物で必要なのは、NPNトランジスタ(2SC2120-Y)、ダイオード、発光ダイオード、抵抗(100Ω、470Ω)。今回は手持ち部品を使ったが、このあたりの部品を揃えるのは秋月電子の通販が便利。

回路の補足

ちなみに、上記回路は今後の拡張性を考慮して、トランジスタでLEDを駆動するように設計している。LEDだけでなく、例えば「回転数に応じて何か電流がたくさん流れる」機構を搭載することができる。DIODEが配置されている時点で、勘の良いエンジニアなら色々と応用が思いつくかもしれないが、実はこの回路にモーターを搭載する構想があり、その準備のため。

あわせて読みたい
ArduinoとCAN通信で制御する振動アクセルペダル(試作) S660やアルトワークスでサーキットを走行すると、ついついアツくなってしまい、レブリミッターを作動させてしまう事があった。対策として、CANから車両の回転数を取得し...

参考(最小回路)

単純に回転数に応じてLED点灯させるだけで良ければ、トランジスタドライブした点灯用のLEDは不要。Arduino Nanoへの給電もUSB経由で行うのであれば、以下のような最小限の回路で実現可能だ。前述の回路でも、下の回路でも、どちらも後段で紹介するプログラムで動作するように設計したつもりだ(だから余分な100Ωの抵抗が1つある)が、動作確認はしていない。

ユニバーサル基板へのハンダ付け

設計が完了したところで、ユニバーサル基板等にハンダ付けを行う。試作品の動作確認であれば問題ないが、振動・熱など常設して使っていくことを考えるときちんと基板に実装しよう。

ユニバーサル基板の準備と加工

使用した基板はサンハヤト製。この大きさであれば、LM2596(DCDC)、Arduino Nanoの互換機、MCP2515CAN、周辺部品がすべて搭載できる。使っているハンダゴテとかコテ台。安い。ハンダは1kgを10年ほど使っているが一向に減らないので150g程のものを買っておけばよかった。

基板の加工

今回搭載するArduino Nanoはユニバーサル基板に搭載できるピッチで穴が開いているが、LM2596(DCDC)、MCP2515CANはそのままユニバーサル基板に搭載できないので加工が必要。ドリルでちょっと穴あけ。

ハンダ付け

こんな感じでハンダ付け完了。赤黒は12V入力。白線は表示用LED、緑白はCAN配線。

裏面

言い訳しておくと、コテ先が古くハンダの乗りが悪かったので、こんな感じの仕上がりに。まあ、ついているのでヨシ。

続いて、プログラミング

Arduino Nanoプログラムの解説

ポイントのみ解説。全プログラムソースコードこの記事の最後に記載。

コンパイラオプション

今回は、S660用とアルトワークス用の2種類のプログラムをコンパイラオプションで切り替えている。コンパイルする時にs660用かアルトワークス用かを指定する。

// S660用にコンパイルするなら1、アルトワークス用なら0を指定
#define S660 1

#define S660 1 の記載を、#define S660 0 にすればアルトワークス用の設定が適用される。CAN IDや読み込むCANデータが異なるので、処理を分けている。受信部も同様。

// S660の場合の処理
#if S660
    // 回転数を取得(CAN ID 0x1DC)
    if(can_ID==476){
      rpm = buf[1]*256 + buf[2];
      
    // 速度を取得(CAN ID 0x158)
    }else if(can_ID==344){
      vel = buf[4]*256+buf[5];
    }
// アルトワークスの場合の処理
#else
    // 回転数を取得(CAN ID 0x124)
    if(can_ID==292){
      rpm = buf[1]*256 + buf[2];
      rpm = rpm/4;
      
    // 速度を取得(CAN ID 0x314)
    }else if(can_ID==788){
      vel = buf[1]*256+buf[2];
      vel = vel*3/400;
    }
#endif

ヒステリシス

LEDを点灯させる回転数と、消灯させる回転数をそれぞれ設定している。これは、点灯しきい値あたりで回転数が上下したときに点灯と消灯を繰り返すと煩わしいから。

  //#define RPM_LED_ON 7550
  #define RPM_LED_ON 4000
  // LED OFFできる回転数
  //#define RPM_LED_OFF 7100
  #define RPM_LED_OFF 3900

LEDを点灯させるのは最高回転数付近の回転数を狙って7,550rpm。消灯は7,100rpm程度で問題ないだろう。今回は、公道でテストを行うため、レブリミッタ付近まで回すのはちょっと…と思ったのでデバッグ用に4,000rpmでLED点灯、3,900rpmでLED消灯とした(テスト用)。

なお、ある回転数を超えたら点灯、更に回転数を上げると点滅する、などの処理を追加すると、よりREVインジケータ感が増すと思うが今回は省略。

フィルター

車両には大量のCANデータが流れている。それぞれを取得してしまうと、Arduinoの処理が追いつかない。よってフィルターを設定して必要なCAN情報のみを取得するようにフィルターを追加している。

// S660用CANフィルタ設定
  #define MASK0 0x7FF
  // S660 engine_Rev CAN ID 0x1DC
  #define Filter0 0x1DC
  // S660 Transmission_Vel CAN ID 0x158
  #define Filter1 0x158
  #define MASK1 0x7FF
  #define Filter2 0x000
  #define Filter3 0x000
  #define Filter4 0x000
  #define Filter5 0x000
~ 中略 ~
// フィルターとマスクの設定。Mask0/Mask2両方の設定が必要
  CAN.init_Mask(0, 0, MASK0);
  CAN.init_Mask(1, 0, MASK1);
  CAN.init_Filt(0, 0, Filter0);
  CAN.init_Filt(1, 0, Filter1);
  CAN.init_Filt(2, 0, Filter2); 
  CAN.init_Filt(3, 0, Filter3);
  CAN.init_Filt(4, 0, Filter4);
  CAN.init_Filt(5, 0, Filter5);

フィルターの設定についてはこちらの記事を参照

あわせて読みたい
Arduino CAN-BUS Shield V2.0 のフィルター/マスクの設定方法 車両には膨大なCANデータが流れている。これらを解析するに当たり、ArudinoとCAN-BUS Shieldの組み合わせで全て受信して保存しようとすると、データの取りこぼしが発生...

シミュレーションによる確認

プログラム開発にあたっては、こちらで作成したシミュレーション環境を使用してデバッグを行った。車両から送られてくるCAN情報を想定して机上でプログラムの作成~デバッグまでの一連の作業が完了するので、とてもスムーズ。

あわせて読みたい
CAN通信のシミュレーション用の模擬ECUを作成 CAN送信モジュールを作成し、Arduino同士の通信が可能になったので、今回はArduino Megaに、実際の車両ECUのデータを模したものを送信させるようにプログラムの改修を行...

エンジンECUを模擬したArduino MegaのCANから送られてくる回転数信号を受けて、作成した基板のインジケータが点灯することを確認。

シリアルモニタの出力でも確認し、正しく出力できてることを確認できた。

ここまで確認はすべて机上で実施できた。残りは、車両に搭載しての実走テスト。

実走動作確認

基板が完成し、シミュレーションでも思い通りの動作ができたので、S660でテスト走行してみた。

本体は助手席足元に置き、電源は車両のUSBから取得。CANはOBDコネクタ経由。OBDコネクタについては、こちらの記事を参照。

あわせて読みたい
ArduinoNanoとMCP2515でCANデータを受信する 以前、Arduino MEGAとCAN-BUS Shieldを用いて車両のCAN情報を取得する事に成功した。→こちら https://kurumashikou.com/gets660can_via_arduino-and-canbus-shield/ Ard...

表示用LEDはメーター付近に養生テープで固定

概ね想定したどおりの動作となった。指定回転数になったら青色LEDが点灯。ちなみに、アルトワークス用のプログラムでも走行検証して、動作確認している。アルトワークスでもちゃんと動いた。

通常の運転でも使えそう

サーキット用のレブインジケータを作ろうと思っていたが、公道での動作確認テスト用に4000rpmで点灯するようにしてテストしたところ、シフトアップのタイミングをクルマが教えてくれるようで、いい感じ。通常の走行でも「ここでシフトアップ」みたいな好みの回転数を指定しておけば、常用でも使えると思う。もし常用域で使うのなら、

・速度と回転数からシフトポジションを計算し、LED点灯の回転数をシフトポジションにより可変にする
・ヒール&トゥで一時的に回転数が上がる際に点灯すると煩わしいので、クラッチを踏んでいる際にはLED点灯を無効化する

などの改良をすればもっと良いものができそう。その辺はプログラムの改修だけで対応できる。

まとめ

Arduino Nano互換のボードと、MCP2515CANを用いて車両CANを受信して、指定回転数になったらLEDを点灯させるガジェットを作成した。実際に走行して、想定した通りの動作となることを確認できた。サーキットでのレブリミッター動作を防止するために作成したものの、改良を加えることによって普段の運転でも使えそうなことがわかった。

Arduni Nano

ユニバーサル基板にハンダ付けできるピッチのピンがついているArduino。そしてめちゃくちゃ小さい。

Arduino
¥4,670 (2024/05/18 14:54:43時点 Amazon調べ-詳細)

ただし少し高いので、試作品の動作確認を行った後は、互換品を使って作成している。そのまま置き換え可能。

Arduni Nano(及び互換品)は、PCとの接続がUSB-TypeBなので、ケーブルを持っていなければ購入しておこう。

Amazonベーシック(Amazon Basics)
¥508 (2024/05/19 01:31:16時点 Amazon調べ-詳細)

ArduinoとCANバスモジュールや、Arduino同士の接続に必要なのがジャンパーケーブル。オス-メス、オス-オス、メス-メスが揃っている。Arduinoのピンにそのまま差せる。

電源

今回は12V Accに接続することもできるように、DC/DCコンバータも実装した

CAN通信関連

Arduni Nanoと接続がしやすく、安価なCANモジュールを使用。

車両との接続はOBD2コネクタを利用する。

関連リンク

あわせて読みたい
ArduinoNanoとMCP2515でCANデータを受信する 以前、Arduino MEGAとCAN-BUS Shieldを用いて車両のCAN情報を取得する事に成功した。→こちら https://kurumashikou.com/gets660can_via_arduino-and-canbus-shield/ Ard...
あわせて読みたい
ArduinoでCANデータを送信する CANデータを読み取ることができる受信モジュールについてはすでに作成したものの、今後のCANを使った車載ガジェットの開発のために、CANを送信できるプログラムを作成し...
あわせて読みたい
Arduino NanoとArduino Mega間でCAN通信する Arduino Megaに実装したCAN送信プログラムをArduino Nanoに実装したCAN受信プログラムが受信して、PC上のシリアルモニタに表示するテストを行った。ArduinoでCAN通信ガ...
あわせて読みたい
CAN通信のシミュレーション用の模擬ECUを作成 CAN送信モジュールを作成し、Arduino同士の通信が可能になったので、今回はArduino Megaに、実際の車両ECUのデータを模したものを送信させるようにプログラムの改修を行...
あわせて読みたい
ArduinoとCAN通信で制御する振動アクセルペダル(試作) S660やアルトワークスでサーキットを走行すると、ついついアツくなってしまい、レブリミッターを作動させてしまう事があった。対策として、CANから車両の回転数を取得し...

プログラムソースコード

/*
 * File:   LED_REV_Indicator.ino
 * Arduino NANO と MCP2515,TJA1050を用いたCAN通信
 * 必要なライブラリ: MCP_CAN Library ⇒ https://github.com/coryjfowler/MCP_CAN_lib
 * Author: 岡本一車
 * https://kurumashikou.com/
*/
#include <SPI.h>
#include <mcp_can.h>
#include "string.h"
#include "MsTimer2.h"
// S660用にコンパイルするなら1、アルトワークス用なら0を指定
#define S660 1
// S660用の設定 //////////////////////////////////
#if S660
  // S660用LEDを点灯するヒステリシスを設定する
  // LED ONする回転数
  //#define RPM_LED_ON 7550
  #define RPM_LED_ON 4000
  // LED OFFできる回転数
  //#define RPM_LED_OFF 7100
  #define RPM_LED_OFF 3900
  
  // S660用CANフィルタ設定
  #define MASK0 0x7FF
  // S660 engine_Rev CAN ID 0x1DC
  #define Filter0 0x1DC
  // S660 Transmission_Vel CAN ID 0x158
  #define Filter1 0x158
  #define MASK1 0x7FF
  #define Filter2 0x000
  #define Filter3 0x000
  #define Filter4 0x000
  #define Filter5 0x000
// アルトワークス用の設定 ///////////////////////////
#else
  // HA36S用LEDを点灯するヒステリシスを設定する
  // LED ONする回転数
  //#define RPM_LED_ON 7550
  #define RPM_LED_ON 4000
  // LED OFFできる回転数
  //#define RPM_LED_OFF 7100
  #define RPM_LED_OFF 3900
  // HA36Sアルトワークス用CANフィルタ設定
  #define MASK0 0x7FF
  // S660 engine_Rev CAN ID 0x124
  #define Filter0 0x124
  // S660 Transmission_Vel CAN ID 0x314
  #define Filter1 0x314
  #define MASK1 0x7FF
  #define Filter2 0x000
  #define Filter3 0x000
  #define Filter4 0x000
  #define Filter5 0x000
// 車種別設定ここまで
#endif
// ピンの設定 OUT
// SS_defaultPin Arduino unoは10, megaは53
// ここではCAN通信用のCSピンとして、digital 9を使用する
const int SPI_CAN_CS_PIN = 9;
// 表示用LEDピン
const int LED_PIN = 8;
// 外部出力ピン
const int OUTPUT_PIN = 10;
// グローバル変数 ///////////////////////////////////////////
// タイムスタンプ用変数
unsigned long timestamp = 0;
unsigned long timestamp_old = 0;
// 受信メッセージ格納用
unsigned long can_ID = 0;
unsigned char len = 0;
unsigned char buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// 回転数格納用変数
unsigned int rpm = 0;
// 速度格納用変数
unsigned int vel = 0;
// LED点灯フラグ
bool LED_ON = false;
// CANデータ書き込み値を保持する
String logDataStr; 
// CANトランシーバにCSピン設定をセットし、CAN通信インスタンスを生成
MCP_CAN CAN(SPI_CAN_CS_PIN);
// 初期設定 ////////////////////////////////////////////////
void setup() {
  // シリアルモニタの設定
  SERIAL_PORT_MONITOR.begin(115200);
  // シリアルポートの準備が整うまで待つ
  while(!Serial);
  
  // 出力ポート設定
  pinMode(LED_PIN, OUTPUT);
  pinMode(OUTPUT_PIN, OUTPUT);
  // CANの初期設定 ///////////////////////////////////////////////
  if (CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) != CAN_OK) {
    SERIAL_PORT_MONITOR.println("CAN-BUS initiliased error ..............");
    while(1);
  }else{
    CAN.setMode(MCP_NORMAL);
    SERIAL_PORT_MONITOR.println("CAN-BUS initiliased OK !!");
  }
  
  // フィルターとマスクの設定。Mask0/Mask2両方の設定が必要
  CAN.init_Mask(0, 0, MASK0);
  CAN.init_Mask(1, 0, MASK1);
  CAN.init_Filt(0, 0, Filter0);
  CAN.init_Filt(1, 0, Filter1);
  CAN.init_Filt(2, 0, Filter2); 
  CAN.init_Filt(3, 0, Filter3);
  CAN.init_Filt(4, 0, Filter4);
  CAN.init_Filt(5, 0, Filter5);
}
// メイン処理 ////////////////////////////////////////////////
void loop() {
  // CANメッセージ受信したときの動作
  if (CAN_MSGAVAIL == CAN.checkReceive()) {
    
    // 受信したデータをシリアルモニタに送信 ////////////////////////////////////
    if(timestamp_old == 0){
      timestamp_old = millis();
    }
    // CANデータを取得
    //CAN.readMsgBufID(&can_ID, &len, buf);
    CAN.readMsgBuf(&can_ID, &len, buf);
    // タイムスタンプの取得
    timestamp = millis() - timestamp_old;
// S660の場合の処理
#if S660
    // 回転数を取得(CAN ID 0x1DC)
    if(can_ID==476){
      rpm = buf[1]*256 + buf[2];
      
    // 速度を取得(CAN ID 0x158)
    }else if(can_ID==344){
      vel = buf[4]*256+buf[5];
    }
// アルトワークスの場合の処理
#else
    // 回転数を取得(CAN ID 0x124)
    if(can_ID==292){
      rpm = buf[1]*256 + buf[2];
      rpm = rpm/4;
      
    // 速度を取得(CAN ID 0x314)
    }else if(can_ID==788){
      vel = buf[1]*256+buf[2];
      vel = vel*3/400;
    }
#endif
    // デバッグ用出力
    logDataStr  = "";
    logDataStr += String(rpm);
    logDataStr += String("rpm / ");
    logDataStr += String(vel);
    logDataStr += String("kph / ");
    logDataStr += String("LED_flag =");
    logDataStr += String(LED_ON);
    logDataStr += "\r\n";
    SERIAL_PORT_MONITOR.print(logDataStr); 
    
  }
  // ON条件 ////////////////////////////////////////////////////////
  // 回転数を超過し、かつLEDが点灯していない場合
  if(!LED_ON && rpm>=RPM_LED_ON){
    // LEDをONする
    LED_ON = true;
  }
  
  // OFF条件 ////////////////////////////////////////////////////////
  // 指定した回転数以下になり、かつLEDが点灯している場合
  if(LED_ON && rpm<=RPM_LED_OFF){
    // LEDをOFFする
    LED_ON = false;
  }
  
  // 動作フラグが立っているとき、LEDを点灯 /////
  if(LED_ON){
    digitalWrite(LED_PIN, HIGH);
    digitalWrite(OUTPUT_PIN, HIGH);
  }else{
    digitalWrite(LED_PIN, LOW);
    digitalWrite(OUTPUT_PIN, LOW);
  }
}
この記事をSNSでシェアする
  • URLをコピーしました!

コメント

コメントする

目次