Hello all,
My project consists of a Due board using a CAN shield from copperfield tech. I am using it to control a tachometer in a vehicle with an engine swap.
The actual engine speed is queried through CAN (donor motor system) and converted to decimal.
The original engine ECU is still in the vehicle and is used to monitor certain signals (engine speed, coolant temp, engine oil pressure), and uses those signals to send messages over the original vehicle CAN system to the gauge cluster for driver feedback.
The easiest way to achieve this seems to be putting a decoder wheel on the front of the motor and making the stock ecu "think" that the motor is turning.
The decoder wheel is essentially and magnetic pickup that cycles between high and low. So, I figured the Due should easily be able to handle that, but how to convert values to achieve the right timing?
I wrote an initial program that outputs this sequence, and depending on the delay (in mS) between switching to the next 'bit' in the sequence. By trying different speeds in this initial program I was able to create a slope formula for converting the decimal value acquired via CAN and convert it into delay in mS.
The formula is y = 879415x^-1.01
The theory of operation is true, it works.
Here's the code
#include <OBD2.h>
#include <DueTimer.h>
cAcquireCAN CANport0(CAN_PORT_0);
/***** DEFINITIONS FOR OBD MESSAGES ON CAN PORT 0, see https://en.wikipedia.org/wiki/OBD-II_PIDs to add your own ***************/
//char _name[10], char _units[10], OBD_PID pid, uint8_t OBD_PID_SIZE size, bool _signed, OBD_MODE_REQ mode, float32 slope, float32 offset, cAcquireCAN *, extended ID;
cOBDParameter OBD_Speed( "Speed " , " KPH" , SPEED , _8BITS, false, CURRENT, 1, 0, &CANport0, false);
cOBDParameter OBD_EngineSpeed("Engine Speed " , " RPM" , ENGINE_RPM , _16BITS, false, CURRENT, 0.25, 0, &CANport0, false);
const int outputPin = 12;
const int EOP = 2; // Output pins
const int OxygenAB = 3;
const int OxygenBB = 4;
const int AC = 7;
double delayTimePre = 0;
// Define the sequence (1: high, 0: low)
int sequence[] = {0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,}; // Modify this sequence as needed
int sequenceLength = sizeof(sequence) / sizeof(sequence[0]);
void setup() {
// Begin serial communication and show that the system has reset
Serial.begin(115200);
Serial.println("System Reset");
// Set up pins for engine oil pressure and oxygen sensors and analogWrite the voltage
// Engine Oil Pressure
pinMode(EOP, OUTPUT);
analogWrite(EOP, 255);
// Oxygen Sensor 1/2
pinMode(OxygenAB, OUTPUT);
analogWrite(OxygenAB, 230);
// Oxygen Sensor 2/2
pinMode(OxygenBB, OUTPUT);
analogWrite(OxygenBB, 230);
// Set up digital pin for crank position
pinMode(outputPin, OUTPUT);
//start CAN ports, set the baud rate
CANport0.initialize(_500K);
// Timer frequency for upadating timing in the output sequence
Timer3.attachInterrupt(PrintScreen).setFrequency(300).start();
}
UINT8 i;
UINT32 maxTime;
void loop() {
SequenceTimer();
delayTimePre = pow(OBD_EngineSpeed.getData(), -1.01);
}
void PrintScreen()
{
CANport0.run(POLLING);
Serial.print(OBD_EngineSpeed.getName());
Serial.print(OBD_EngineSpeed.getData());
Serial.println(OBD_EngineSpeed.getUnits());
Serial.println();
Serial.println(delayTimePre * 879415);
}
void SequenceTimer()
{
for (int i = 0; i < sequenceLength; i++) {
digitalWrite(outputPin, sequence[i]);
delayMicroseconds(delayTimePre * 879415);
}
}
The problem I am running into is latency in the program. While watching the data via serial monitor, it updates frequently enough to be useful at all times (engine speed changes quickly!). But on the dash board/over live data from the vehicle system, it is about 2 seconds latent. And if the vehicle revs over ~3500 RPM the whole program bricks and the board has to be reset. As soon as it boots back up and initializes CAN, engine speed comes back on the dash/live data/serial monitor.
Any ideas on how to remedy this or at least make it better? If you're accelerating quickly, you could go through an entire gear within the time it updates on the dash. So effectively it's only useful at idle and cruising RPM.