Can-bus emulation for cruise control: Difference between revisions
m (→Code example) |
|||
| Line 181: | Line 181: | ||
Regarding the ABS, more CAN message will need to be emulated: | Regarding the ABS, more CAN message will need to be emulated: | ||
{{Note|note-reminder|This section is under development. Feel free to add content.}} | {{Note|note-reminder|This section is under development. Feel free to add content.}} | ||
{| class="wikitable sortable" style="width:100%;" | |||
|+ '''ID 0x1A0, 8 bytes, Sent every 10 ms''' | |||
! Signal!!Byte!! Start bit !!Bits!!Range / Values!!Notes | |||
|- | |||
|ASR request | |||
|1||0||1||0 = no request; 1 = ASR request||Request also present in Byte 5 or 6 | |||
|- | |||
|MSR request|| 1||1||1||0 = no request; 1 = MSR request||Request also present in Byte 7, Byte 6 contains updated info | |||
|- | |||
|ABS braking active||1||2||1||0 = inactive; 1 = ABS braking active|| | |||
|- | |||
|EDS intervention active||1||3||1||0 = inactive; 1 = EDS active||Electronic Differential Lock | |||
|- | |||
|FDR intervention active||1||4||1||0 = inactive; 1 = FDR active|| | |||
|- | |||
|ASR shift influence||1||5||2||00 = no request; 01 = ASR shift map; 02 = downshift request; 03 = shift inhibit||Transmission interaction | |||
|- | |||
|EBV intervention active||1||7||1||0 = inactive; 1 = EBV active||Electronic Brake Force Distribution | |||
|- | |||
|ABS warning lamp||2||0||1||0 = off; 1 = lamp on|| | |||
|- | |||
|ASR/FDR warning lamp||2||1||1||0 = off; 1 = lamp on|| | |||
|- | |||
|Brake warning lamp||2||2||1||0 = off; 1 = lamp on|| | |||
|- | |||
|Brake light switch||2||3||1||0 = brake not applied; 1 = brake applied||Without brake booster this bit transmits the brake light switch | |||
|- | |||
|Brake pressure threshold exceeded||2||3||1||0 = threshold not exceeded; 1 = threshold exceeded||From PQ46 driver brake pressure threshold exceeded | |||
|- | |||
|Brake test switch||2||4||1||0 = brake not applied; 1 = brake applied||RB-ABS systems | |||
|- | |||
|Brake pressure threshold status||2||4||1||0 = status valid; 1 = status unavailable||From PQ46 | |||
|- | |||
|Rough-road suppression||2||5||1||0 = disabled; 1 = active|| | |||
|- | |||
|Rough-road suppression status||2||6||1||0 = valid; 1 = invalid|| | |||
|- | |||
|ABS diagnostic active||2||7||1||0 = no diagnostic; 1 = diagnostic active|| | |||
|- | |||
|Brake booster active||3||0||1|| || | |||
|- | |||
|Vehicle speed low byte||3||1||7||0 – 1.27 km/h||HEX VALUE = speed (km/h) × 100 | |||
|- | |||
|Vehicle speed high byte||4||0||8||0 – 325.12 km/h||HEX VALUE = speed (km/h) / 1.28 | |||
|- | |||
|ASR torque intervention slow||5||0||8||0 – 99.06 %||VALUE = torque intervention / 0.39 | |||
|- | |||
|ASR torque intervention fast||6||0||8||0 – 99.06 %||Bit-inverted MSR torque during MSR request | |||
|- | |||
|MSR torque intervention||7||0||8||0 – 99.06 %|| | |||
|- | |||
|Message counter||8||0||4||0 – 15|| | |||
|- | |||
|ASR controller present||8||4||1||0 = ABS; 1 = ASR|| | |||
|- | |||
|ESP passive button pressed||8||5||1||0 = ESP active; 1 = ESP passive||Driver pressed ESP button | |||
|- | |||
|ESP system status||8||6||1||0 = OK; 1 = fault||ESP disabled due to fault | |||
|- | |||
|Speed substitute value||8||7||1||0 = valid speed; 1 = substitute value|| | |||
|} | |||
== Monitoring the values received by the ECU == | Speed signal constants for the combined value of '''Byte 3 and Byte 4''' | ||
*'''Initial value''' = '''FF88h''' or '''FF89h''' = `1111 1111 1000 100x` (binary) | |||
*'''Supply voltage value''' = '''FFAAh''' or '''FFABh''' = `1111 1111 1010 101x` (binary) | |||
*'''Error value''' = '''FFCCh''' or '''FFCDh''' = `1111 1111 1100 110x` (binary) | |||
<small>These constants correspond to the '''complete 16-bit value composed of Bytes 3 and Byte 4'''</small> | |||
{| class="wikitable sortable" style="width:100%;" | |||
|+'''ID 0x4A0, 8 bytes, Sent every 10 ms''' | |||
!Signal!!Byte!!Start Bit!!Bit Length!!Range / Values!!Notes | |||
|- | |||
|Front left direction||1||0||1||0 = forward; 1 = reverse||Direction detection | |||
|- | |||
|Front left wheel speed||1 & 2||1||15||0..326 km/h||HEX VALUE = vehicle speed (km/h) × 100 | |||
|- | |||
|Front right direction||3||0||1||0 = forward; 1 = reverse|| | |||
|- | |||
|Front right wheel speed||3 & 4||1||15||0..326 km/h|| | |||
|- | |||
|Rear left direction||5||0||1||0 = forward; 1 = reverse|| | |||
|- | |||
|Rear left wheel speed||5 & 6||1||15||0..326 km/h|| | |||
|- | |||
|Rear right direction||7||0||1||0 = forward; 1 = reverse|| | |||
|- | |||
|Rear right wheel speed||7 & 8||0||15||0..326 km/h|| | |||
|} | |||
Speed signal constants for the combined value of '''Byte 1 and Byte 2 (same for 3&4, 5&6, 7&8)''' | |||
*'''Initial value''' = '''FF88h''' or '''FF89h''' = `1111 1111 1000 100x` (binary) | |||
*'''Supply voltage value''' = '''FFAAh''' or '''FFABh''' = `1111 1111 1010 101x` (binary) | |||
*'''Error value''' = '''FFCCh''' or '''FFCDh''' = `1111 1111 1100 110x` (binary) | |||
If you report more than '''327.42km/h (included)''', the ECU will interpret it as an error. | |||
==Monitoring the values received by the ECU== | |||
You can use any suitable scanner, such as VCDS, and monitor the channel '''066''' in the measurement values. | You can use any suitable scanner, such as VCDS, and monitor the channel '''066''' in the measurement values. | ||
This channel lists: | This channel lists: | ||
* Vehicle speed | *Vehicle speed | ||
* Clutch/Brake switch values | *Clutch/Brake switch values | ||
* Cruise control switch values | *Cruise control switch values | ||
* Cruise control status | *Cruise control status | ||
Revision as of 07:58, 8 March 2026
Introduction
This is intended as a reference for those who would like to emulate the can-bus messages for the cruise control.
Application: Any swapped vehicles that do not have can-bus support. It would cover both the Bosch ME7.1.1 and a ME17.5/ME17.5.6
Hardware required
You can use any microcontroller that have CAN-bus capability, such as an Arduino or ESP32. You could also use the SpeedPulser Pro that already has a GPS and CAN-bus capability, you would only need to alter the source code and implement the new CAN-bus message:
- https://forbes-automotive.com/products/speedpulser-pro
- https://github.com/adamforbes92/speedPulserPro
CAN-bus: What is this sorcery?
CAN-bus is a network used by modules to transmit data/information with each other. With only two wires, you can transmit a multitude of messages between modules (multiplexing).
In the past, you would have a single wire for every input. In those instances, every button of your cruise control switch has its own signal wire.
The objective of the CAN-bus emulation is to take all those signals, feed them into your microcontroller and output CAN-bus messages that the ECU will understand, as if it was on a factory MK5/MK6 2.5 chassis.
CAN-bus messages required:
- State of the cruise control switch (Ex.: Main switch, SET, RES, etc.), normally provided by the steering column module
- Vehicle speed, normally provided by the ABS module
Vehicle speed acquisition
The vehicle speed can be retrieved through the following means:
- GPS module
- VSS sensor
- Hall-effect sensor mounted into the instrument cluster to read the speed of the speedometer cable
- There are more ways to gather this information depending on your creativity
Emulating the cruise control switch
The ECU receive the cruise control switch information through the CAN message 0x38A. Here is a detailed description of this CAN message
| Signal | Byte | Start bit | Bits | Range / Values | Notes |
|---|---|---|---|---|---|
| Checksum (See below) | 1 | 0 | 8 | 0..255 (Phys = Hex) | — |
| Main switch | 2 | 0 | 1 | 0 = OFF 1 = ON |
Latching ON/OFF |
| Tip switch OFF | 2 | 1 | 1 | 0 = not pressed 1 = pressed |
— |
| Tip switch DECEL | 2 | 2 | 1 | 0 = not pressed 1 = pressed |
— |
| Tip switch ACCEL | 2 | 3 | 1 | 0 = not pressed 1 = pressed |
— |
| Cruise decelerate (hold) | 2 | 4 | 1 | 0 = not decelerating 1 = decelerating |
— |
| Cruise accelerate (hold) | 2 | 5 | 1 | 0 = not accelerating 1 = accelerating |
— |
| Cruise control stalk error | 2 | 6 | 1 | 0 = OK 1 = stalk error |
— |
| Not used | 2 | 7 | 1 | — | — |
| Tip switch SET | 3 | 0 | 1 | 0 = not pressed 1 = pressed |
— |
| Tip switch RESUME | 3 | 1 | 1 | 0 = not pressed 1 = pressed |
— |
| Sender coding | 3 | 2 | 2 | 00 = Body network 01 = Steering column module 10 = Engine |
Values per spec |
| Message counter | 3 | 4 | 4 | 0..15 (Phys = Hex) | Rolling counter |
| Not used | 4 | 0 | 8 | — | Byte 4 unused |
Checksum
The checksum is a formula used to validate the integrity of the message, and detect possible data corruption during the transmission of the message. If the checksum does not match the data, the ECU might reject the message. (Implausible message)
This checksum is calculated only with Exclusive OR (XOR) operations
Code example
This is a very rough sketch to show a possible implementation. This example would be for an Arduino controller using a MCP2515 shield (hat).
// demo: Cruise control switch, analog to can-bus message for VW PQ35
// Very rough sketch, but should work. Feel free to improve
#include <SPI.h>
#define CAN_2515
// Set SPI CS Pin according to your hardware
#if defined(SEEED_WIO_TERMINAL) && defined(CAN_2518FD)
const int SPI_CS_PIN = BCM8;
const int CAN_INT_PIN = BCM25;
#else
// For Arduino MCP2515 Hat:
// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;
const int CAN_INT_PIN = 2;
#endif
#ifdef CAN_2518FD
#include "mcp2518fd_can.h"
mcp2518fd CAN(SPI_CS_PIN); // Set CS pin
#endif
#ifdef CAN_2515
#include "mcp2515_can.h"
mcp2515_can CAN(SPI_CS_PIN); // Set CS pin
#endif
const int buttonMain = 4;
const int buttonRes = 2;
const int buttonSet = 0;
byte oldSwitchState = 0x0;
byte sequence = 0x0;
void setup() {
SERIAL_PORT_MONITOR.begin(115200);
while(!Serial){};
while (CAN_OK != CAN.begin(CAN_500KBPS)) { // init powertrain can bus : baudrate = 500k
SERIAL_PORT_MONITOR.println("CAN init fail, retry...");
delay(100);
}
SERIAL_PORT_MONITOR.println("CAN init ok!");
pinMode(buttonMain, INPUT_PULLUP);
pinMode(buttonRes, INPUT_PULLUP);
pinMode(buttonSet, INPUT_PULLUP); // default state 12v
}
void loop() {
byte switchState = 0x0;
// Read analog inputs
int stateMain = digitalRead(buttonMain);
int stateRes = digitalRead(buttonRes);
int stateSet = digitalRead(buttonSet);
// You can add more inputs and adjust the logic according the the can-bus chart
if (stateMain == LOW) {
switchState |= (1 << 0); // Set bit 0
}
if (stateSet == LOW) {
switchState |= (1 << 1); // Set bit 1
}
if (stateRes == LOW) {
switchState |= (1 << 2); // Set bit 2
}
// Check if the switch state has changed
if (switchState != oldSwitchState) {
Serial.println(switchState); // Print new state for monitoring purposes
oldSwitchState = switchState; // Update oldSwitchState
}
// Define bytes for can message (0x38A)
byte byteTwo = switchState & 1;
byte byteThree = switchState >> 1;
byteThree = byteThree | 0xC; // Could also be 0x4 (See Sender coding)
byteThree = (sequence << 4) | byteThree;
byte checksum = byteTwo ^ byteThree;
unsigned char payload[4] = {checksum, byteTwo, byteThree, 0x00};
CAN.sendMsgBuf(0x38A, 0, 4, payload);
sequence = (sequence + 1) & 0x0F; // increment for the next frame
delay(20); // Send every 20ms
}
Emulating the ABS module (Vehicle speed)
The ABS module needs to be emulated as the ECU track the vehicle speed for the cruise control.
In practice, it would be possible to do Assembly patches and make the ECU track the engine speed. Although, this extensive work would need to be repeated across multiple firmwares. It makes more sense to emulate the ABS module, especially considered that this requires a skill set out of reach for most readers.
Regarding the ABS, more CAN message will need to be emulated:
| Signal | Byte | Start bit | Bits | Range / Values | Notes |
|---|---|---|---|---|---|
| ASR request | 1 | 0 | 1 | 0 = no request; 1 = ASR request | Request also present in Byte 5 or 6 |
| MSR request | 1 | 1 | 1 | 0 = no request; 1 = MSR request | Request also present in Byte 7, Byte 6 contains updated info |
| ABS braking active | 1 | 2 | 1 | 0 = inactive; 1 = ABS braking active | |
| EDS intervention active | 1 | 3 | 1 | 0 = inactive; 1 = EDS active | Electronic Differential Lock |
| FDR intervention active | 1 | 4 | 1 | 0 = inactive; 1 = FDR active | |
| ASR shift influence | 1 | 5 | 2 | 00 = no request; 01 = ASR shift map; 02 = downshift request; 03 = shift inhibit | Transmission interaction |
| EBV intervention active | 1 | 7 | 1 | 0 = inactive; 1 = EBV active | Electronic Brake Force Distribution |
| ABS warning lamp | 2 | 0 | 1 | 0 = off; 1 = lamp on | |
| ASR/FDR warning lamp | 2 | 1 | 1 | 0 = off; 1 = lamp on | |
| Brake warning lamp | 2 | 2 | 1 | 0 = off; 1 = lamp on | |
| Brake light switch | 2 | 3 | 1 | 0 = brake not applied; 1 = brake applied | Without brake booster this bit transmits the brake light switch |
| Brake pressure threshold exceeded | 2 | 3 | 1 | 0 = threshold not exceeded; 1 = threshold exceeded | From PQ46 driver brake pressure threshold exceeded |
| Brake test switch | 2 | 4 | 1 | 0 = brake not applied; 1 = brake applied | RB-ABS systems |
| Brake pressure threshold status | 2 | 4 | 1 | 0 = status valid; 1 = status unavailable | From PQ46 |
| Rough-road suppression | 2 | 5 | 1 | 0 = disabled; 1 = active | |
| Rough-road suppression status | 2 | 6 | 1 | 0 = valid; 1 = invalid | |
| ABS diagnostic active | 2 | 7 | 1 | 0 = no diagnostic; 1 = diagnostic active | |
| Brake booster active | 3 | 0 | 1 | ||
| Vehicle speed low byte | 3 | 1 | 7 | 0 – 1.27 km/h | HEX VALUE = speed (km/h) × 100 |
| Vehicle speed high byte | 4 | 0 | 8 | 0 – 325.12 km/h | HEX VALUE = speed (km/h) / 1.28 |
| ASR torque intervention slow | 5 | 0 | 8 | 0 – 99.06 % | VALUE = torque intervention / 0.39 |
| ASR torque intervention fast | 6 | 0 | 8 | 0 – 99.06 % | Bit-inverted MSR torque during MSR request |
| MSR torque intervention | 7 | 0 | 8 | 0 – 99.06 % | |
| Message counter | 8 | 0 | 4 | 0 – 15 | |
| ASR controller present | 8 | 4 | 1 | 0 = ABS; 1 = ASR | |
| ESP passive button pressed | 8 | 5 | 1 | 0 = ESP active; 1 = ESP passive | Driver pressed ESP button |
| ESP system status | 8 | 6 | 1 | 0 = OK; 1 = fault | ESP disabled due to fault |
| Speed substitute value | 8 | 7 | 1 | 0 = valid speed; 1 = substitute value |
Speed signal constants for the combined value of Byte 3 and Byte 4
- Initial value = FF88h or FF89h = `1111 1111 1000 100x` (binary)
- Supply voltage value = FFAAh or FFABh = `1111 1111 1010 101x` (binary)
- Error value = FFCCh or FFCDh = `1111 1111 1100 110x` (binary)
These constants correspond to the complete 16-bit value composed of Bytes 3 and Byte 4
| Signal | Byte | Start Bit | Bit Length | Range / Values | Notes |
|---|---|---|---|---|---|
| Front left direction | 1 | 0 | 1 | 0 = forward; 1 = reverse | Direction detection |
| Front left wheel speed | 1 & 2 | 1 | 15 | 0..326 km/h | HEX VALUE = vehicle speed (km/h) × 100 |
| Front right direction | 3 | 0 | 1 | 0 = forward; 1 = reverse | |
| Front right wheel speed | 3 & 4 | 1 | 15 | 0..326 km/h | |
| Rear left direction | 5 | 0 | 1 | 0 = forward; 1 = reverse | |
| Rear left wheel speed | 5 & 6 | 1 | 15 | 0..326 km/h | |
| Rear right direction | 7 | 0 | 1 | 0 = forward; 1 = reverse | |
| Rear right wheel speed | 7 & 8 | 0 | 15 | 0..326 km/h |
Speed signal constants for the combined value of Byte 1 and Byte 2 (same for 3&4, 5&6, 7&8)
- Initial value = FF88h or FF89h = `1111 1111 1000 100x` (binary)
- Supply voltage value = FFAAh or FFABh = `1111 1111 1010 101x` (binary)
- Error value = FFCCh or FFCDh = `1111 1111 1100 110x` (binary)
If you report more than 327.42km/h (included), the ECU will interpret it as an error.
Monitoring the values received by the ECU
You can use any suitable scanner, such as VCDS, and monitor the channel 066 in the measurement values.
This channel lists:
- Vehicle speed
- Clutch/Brake switch values
- Cruise control switch values
- Cruise control status