A few days ago a customer asked if we could integrate with the OBD-II interface on pre-2008 ECUs on the Lotus Elise or Exige. Normally we’d say ‘sorry, not out of the box’, as 2008 was the year CAN was mandated on OBD-II. As it turns out from this post on LotusTalk, even the pre-OBDII/CAN Lotus Elise ECUs emit some useful CAN bus data on the OBD-II port, even though they won’t respond to regular OBD-II queries.
Electronic Gauge Cluster
Turns out, the ECU regularly transmits a CAN bus message to the instrument cluster packed full of interesting information. Available in this message is:
- Vehicle Speed
- Engine temperature
- Fuel Level
- Shift light status
The data is constantly broadcast to the instrument cluster, so it should actually be super easy to pick up and transform into virtual channels inside of RaceCapture/Pro. So this weekend, I asked around if I could borrow a Lotus Elise for some CAN bus hacking. My friend David de Regt replied and on Sunday, he and his race-prepped 2006 Elise made their way to our Lab. Excellent!
Lotus Elise CAN bus instrument cluster format
The data to the instrument cluster is broadcast on CAN id 0x400 (1024 decimal) with the following format:
byte - info =============================== 01 - adjusted speed (A - 11) 02 - unused (always 0) 03, 04 - RPM (A * 256 + B) 05 - Fuel Level (0xFF = full, 0x00 = empty) 06 - Engine Temperature (A - 14) 07 - MIL (06 = on, 04 = cranking, 00 = running, 01 = shift light) 08 - unused (always 0)
The OBD-II to RJ45 cable plugs right into RaceCapture/Pro, supplying data and power. In this case, we extended it using a very long network cable extension. We were a bit worried about the cable length, but as it turns out, CAN bus supports 40 meter cable length at the 1 megabit transmission rate used in the Lotus network. Yes, 40 meters – another reason why CAN is so kickass-robust!
Once we hooked it up to the OBD-II port we opened up a Lua scripting console right on the RaceCapture/Pro unit. A quick command immediately yielded a message:
> id, e, d = rxCAN(0, 100) --receive a message from CAN1; 100ms timeout > println(id) 1024
ID 1024 represented the CAN bus ID of the instrument cluster- Excellent!
So we probed further:
> println(d) 0
OK, Speed is zero, that makes sense since the car is stationary. what about RPM?
> println(d) 3 > println(d) 87
Now we’re getting somewhere! So the formula for RPM is A*256 + B, so:
> println(d * 256 + d) 855
855 RPM sounds about right!
So a full script to map all messages to virtual channels would look something like this:
--set the rate of onTick() to 10Hz setTickRate(10) --create the virtual channels speedId = addChannel("GndSpd", 10) --Ground Speed @ 10Hz rpmId = addChannel("RPM",10) --RPM @ 10Hz logging rate fuelId = addChannel("Fuel", 1) -- Fuel % @ 1Hz tempId = addChannel("EngineTemp", 1) --Engine Temp @ 1Hz function onTick() id, e, d = rxCAN(0, 100) --call with 100ms timeout if id == 1024 --did we get a valid CAN message from the cluster? speed = d - 11 --ground speed rpm = d * 256 + d --RPM fuel = d / 256 * 100 -- fuel % temp = d - 14 --engine temperature -- set the virtual channels setChannel(speedId, speed) setChannel(rpmId, rpm) setChannel(fuelId, fuel) setChannel(tempId, temp) end end
A library of mappings (It’s open source, baby!)
Sounds hard? Don’t worry – we’ll add this script and scripts for other systems like Hydra, Megasquirt and more – ready for you to copy and paste into your RaceCapture/Pro configuration. As users contribute scripts you’ll be able to take advantage, tweak and re-submit updated versions for others to use. It’s freedom, baby!