前回からのつづき
リアルタイムでエンジン回転数を検出できるようになったので、ここに点火回路を組み込むだけ!と思っていましたがそう楽ではありませんでした。
1.MOSFETを使用したTCI点火回路の自作
これがどうにも上手くいきませんでした。
配線の繋ぎ方が違う?そもそも部品の選定を間違えている??など色々考えましたが、そもそも知識が乏しすぎて何が正しくて何が間違いなのか分からなくなってきました。
AIに2SC3355トランジスタの足の配置を聞いたらデータシートと違う回答が返ってきたりもしたので、AIの言うこともわりと間違えたり正しかったり、、、頭が痛くなります。
2.汎用DC-CDIを使う
そこで思いつきました。点火回路は自作せずに、既存のCDIで置き換えれば良いのでは…??

物価高騰の影響か、数年前から2倍近く値段が上がっていますがこの辺のものを使います。
今回のレッツ4のように点火コイルがない車種の場合(そもそもFI車に点火コイルはありませんが)AC-CDIは使えないのでDC-CDIを使います。
この方法ならArduinoからは点火用の信号を出すだけであとはCDIが点火に必要な工程を担ってくれます。ドエルタイム(IGコイルに電力をチャージする時間)の制御なども省略できるのでコードもかなり短くなります。

3.無事完成!!!
Arduinoから点火信号を出すようにし、クランキングしてきちんと火花が出ることを確認。
ジェミニと少しコードの修正をしながらセルを回すと…エンジンがかかりました!!!
嬉しかったので動画も撮りました。
(レッツ4と言っていましたが実験で使っているのはV50です。エンジンは同じなのでご容赦ください)
少し進角ぎみの感じですが、これはコードの修正でいくらでも改良可能です。
一応Arduinoでクランク角を監視しているのでCDIの点火特性に合わせて任意のタイミングで点火させることが可能です。言い換えれば、直流12Vで動くCDIであれば何でも流用可能という事です。
以下が今回のソースコード。
const int INPUT_PIN = 2; // VRセンサー入力const int IGNITION_PIN = 13; // CDI駆動信号
volatile unsigned long lastPulseTime = 0;volatile unsigned long firstPulseTime = 0;volatile unsigned long pulse4Time = 0;volatile unsigned long pulse5Time = 0;volatile unsigned long rotationPeriod = 0;volatile bool newRotation = false;
volatile bool triggerPulse4 = false;volatile bool triggerPulse5 = false;
volatile int pulseCount = 0;
const int PULSES_PER_ROTATION = 10;const unsigned long DEADBAND_TIME = 400UL;
// ★【超重要パラメータ】パルス5(TDC仮定)から何度遅らせて点火するか// 息が詰まる場合は点火が早すぎるため、遅延度数(DELAY_DEGREES)を大きめ(20〜30)にするか、// 下記のパルス4直接点火を試します。float DELAY_DEGREES = 15.0;
enum SparkState { IDLE, WAITING_FOR_SPARK };SparkState sparkState = IDLE;unsigned long targetSparkTime = 0;
void onPulse() {unsigned long currentTime = micros();unsigned long interval = currentTime - lastPulseTime;if (interval > DEADBAND_TIME) {if (pulseCount == 0) firstPulseTime = currentTime;pulseCount++;// 4個目の突起(TDCの36度手前)if (pulseCount == 4) {pulse4Time = currentTime;triggerPulse4 = true;}
// 5個目の突起(TDC仮定)if (pulseCount == 5) {pulse5Time = currentTime;triggerPulse5 = true;}if (pulseCount >= PULSES_PER_ROTATION) {rotationPeriod = currentTime - firstPulseTime;newRotation = true;pulseCount = 0;}lastPulseTime = currentTime;}}
void setup() {Serial.begin(9600);pinMode(INPUT_PIN, INPUT_PULLUP);pinMode(IGNITION_PIN, OUTPUT);digitalWrite(IGNITION_PIN, LOW);attachInterrupt(digitalPinToInterrupt(INPUT_PIN), onPulse, FALLING);}
void loop() {unsigned long currentTime = micros();static float usPerDegree = 0.0;
if (newRotation) {unsigned long currentPeriod;noInterrupts();newRotation = false;currentPeriod = rotationPeriod;interrupts();if (currentPeriod > 0) {usPerDegree = (float)currentPeriod / 360.0;}}
// ----- テストモードA: パルス5から微小遅延させて点火 -----if (triggerPulse5 && usPerDegree > 0.0) {unsigned long p5;noInterrupts();triggerPulse5 = false;p5 = pulse5Time;interrupts();
// DELAY_DEGREES 分だけ待ってから点火(=点火時期を遅らせる)unsigned long waitTimeUs = (unsigned long)(DELAY_DEGREES * usPerDegree);targetSparkTime = p5 + waitTimeUs;sparkState = WAITING_FOR_SPARK;}
if (sparkState == WAITING_FOR_SPARK && (currentTime - targetSparkTime < 1000000UL)) {if ((long)(currentTime - targetSparkTime) >= 0) {digitalWrite(IGNITION_PIN, HIGH);delayMicroseconds(100);digitalWrite(IGNITION_PIN, LOW);sparkState = IDLE;}}}
完全にAI任せのコードなのでまだまだ改良の余地はあると思いますが、ひとまずこれで。
点火系の回路図は

Arduinoからのピックアップ信号に1kΩの抵抗と保護用のダイオードを付けているだけの簡単なものです。
4.おわりに
無事動いてくれて何よりです。やっぱりAIってすごい…!!!
自作と言いながら汎用CDIを使っちゃってる所は大目に見ていただければと思います。
そして本当なら燃料噴射部分も自作しないとECUとは言えない訳ですが、レッツ4はDCP(ディスチャージポンプ)というちょっと特殊な仕組みなので汎用性もないし…今回は点火だけでおしまいにします。どうしても燃料噴射カットのリミッターを解除したい…という方はキャブ仕様にしてください。
今後いい感じにボロいFI車が入った際にはインジェクターの制御の方も挑戦したいと思います。


























