Skip to content

Commit ccf75c4

Browse files
authored
Volkswagen safety updates: Phase 1 (#444)
* Checkpoint Panda refactoring updates * Rename MQB safety tests in preparation for PQ * Refactor MQB tests, add missing torque test * Bring in MQB init without CRC LUT setup * Fix to ACC_06 test case * Fix to ACC_06 test case * Tweak comment for clarity * Drop superfluous return
1 parent 769ade0 commit ccf75c4

File tree

7 files changed

+222
-166
lines changed

7 files changed

+222
-166
lines changed

board/safety.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#define SAFETY_TESLA 10U
3232
#define SAFETY_SUBARU 11U
3333
#define SAFETY_MAZDA 13U
34-
#define SAFETY_VOLKSWAGEN 15U
34+
#define SAFETY_VOLKSWAGEN_MQB 15U
3535
#define SAFETY_TOYOTA_IPAS 16U
3636
#define SAFETY_ALLOUTPUT 17U
3737
#define SAFETY_GM_ASCM 18U
@@ -185,7 +185,7 @@ const safety_hook_config safety_hook_registry[] = {
185185
{SAFETY_CHRYSLER, &chrysler_hooks},
186186
{SAFETY_SUBARU, &subaru_hooks},
187187
{SAFETY_MAZDA, &mazda_hooks},
188-
{SAFETY_VOLKSWAGEN, &volkswagen_hooks},
188+
{SAFETY_VOLKSWAGEN_MQB, &volkswagen_mqb_hooks},
189189
{SAFETY_NOOUTPUT, &nooutput_hooks},
190190
#ifdef ALLOW_DEBUG
191191
{SAFETY_CADILLAC, &cadillac_hooks},

board/safety/safety_volkswagen.h

+124-111
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,156 @@
1-
// Safety-relevant CAN messages for the Volkswagen MQB platform.
2-
#define MSG_EPS_01 0x09F
3-
#define MSG_MOTOR_20 0x121
4-
#define MSG_ACC_06 0x122
5-
#define MSG_HCA_01 0x126
6-
#define MSG_GRA_ACC_01 0x12B
7-
#define MSG_LDW_02 0x397
8-
1+
// Safety-relevant steering constants for Volkswagen
92
const int VOLKSWAGEN_MAX_STEER = 250; // 2.5 Nm (EPS side max of 3.0Nm with fault if violated)
103
const int VOLKSWAGEN_MAX_RT_DELTA = 75; // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75
114
const uint32_t VOLKSWAGEN_RT_INTERVAL = 250000; // 250ms between real time checks
12-
const int VOLKSWAGEN_MAX_RATE_UP = 4; // 2.0 Nm/s available rate of change from the steering rack (EPS side delta-limit of 5.0 Nm/s)
13-
const int VOLKSWAGEN_MAX_RATE_DOWN = 10; // 5.0 Nm/s available rate of change from the steering rack (EPS side delta-limit of 5.0 Nm/s)
5+
const int VOLKSWAGEN_MAX_RATE_UP = 4; // 2.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
6+
const int VOLKSWAGEN_MAX_RATE_DOWN = 10; // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
147
const int VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE = 80;
158
const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3;
169

17-
// MSG_GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
18-
const AddrBus VOLKSWAGEN_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}};
10+
// Safety-relevant CAN messages for the Volkswagen MQB platform
11+
#define MSG_EPS_01 0x09F // RX from EPS, for driver steering torque
12+
#define MSG_MOTOR_20 0x121 // RX from ECU, for driver throttle input
13+
#define MSG_ACC_06 0x122 // RX from ACC radar, for status and engagement
14+
#define MSG_HCA_01 0x126 // TX by OP, Heading Control Assist steering torque
15+
#define MSG_GRA_ACC_01 0x12B // TX by OP, ACC control buttons for cancel/resume
16+
#define MSG_LDW_02 0x397 // TX by OP, Lane line recognition and text alerts
17+
18+
// Transmit of GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration
19+
const AddrBus VOLKSWAGEN_MQB_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}};
20+
const int VOLKSWAGEN_MQB_TX_MSGS_LEN = sizeof(VOLKSWAGEN_MQB_TX_MSGS) / sizeof(VOLKSWAGEN_MQB_TX_MSGS[0]);
1921

2022
// TODO: do checksum and counter checks
21-
AddrCheckStruct volkswagen_rx_checks[] = {
23+
AddrCheckStruct volkswagen_mqb_rx_checks[] = {
2224
{.addr = {MSG_EPS_01}, .bus = 0, .expected_timestep = 10000U},
2325
{.addr = {MSG_ACC_06}, .bus = 0, .expected_timestep = 20000U},
2426
{.addr = {MSG_MOTOR_20}, .bus = 0, .expected_timestep = 20000U},
2527
};
28+
const int VOLKSWAGEN_MQB_RX_CHECKS_LEN = sizeof(volkswagen_mqb_rx_checks) / sizeof(volkswagen_mqb_rx_checks[0]);
2629

27-
const int VOLKSWAGEN_RX_CHECK_LEN = sizeof(volkswagen_rx_checks) / sizeof(volkswagen_rx_checks[0]);
2830

29-
struct sample_t volkswagen_torque_driver; // last few driver torques measured
31+
struct sample_t volkswagen_torque_driver; // Last few driver torques measured
3032
int volkswagen_rt_torque_last = 0;
3133
int volkswagen_desired_torque_last = 0;
3234
uint32_t volkswagen_ts_last = 0;
3335
int volkswagen_gas_prev = 0;
36+
int volkswagen_torque_msg = 0;
37+
int volkswagen_lane_msg = 0;
38+
39+
static void volkswagen_mqb_init(int16_t param) {
40+
UNUSED(param);
3441

35-
static int volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
42+
controls_allowed = false;
43+
relay_malfunction = false;
44+
volkswagen_torque_msg = MSG_HCA_01;
45+
volkswagen_lane_msg = MSG_LDW_02;
46+
}
47+
48+
static int volkswagen_mqb_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) {
3649

37-
bool valid = addr_safety_check(to_push, volkswagen_rx_checks, VOLKSWAGEN_RX_CHECK_LEN,
50+
bool valid = addr_safety_check(to_push, volkswagen_mqb_rx_checks, VOLKSWAGEN_MQB_RX_CHECKS_LEN,
3851
NULL, NULL, NULL);
3952

4053
if (valid) {
41-
int bus = GET_BUS(to_push);
42-
int addr = GET_ADDR(to_push);
43-
44-
// Update driver input torque samples from EPS_01.Driver_Strain for absolute torque, and EPS_01.Driver_Strain_VZ
45-
// for the direction.
46-
if ((bus == 0) && (addr == MSG_EPS_01)) {
47-
int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1F) << 8);
48-
int sign = (GET_BYTE(to_push, 6) & 0x80) >> 7;
49-
if (sign == 1) {
50-
torque_driver_new *= -1;
51-
}
52-
53-
update_sample(&volkswagen_torque_driver, torque_driver_new);
54-
}
55-
56-
// Monitor ACC_06.ACC_Status_ACC for stock ACC status. Because the current MQB port is lateral-only, OP's control
57-
// allowed state is directly driven by stock ACC engagement. Permit the ACC message to come from either bus, in
58-
// order to accommodate future camera-side integrations if needed.
59-
if (addr == MSG_ACC_06) {
60-
int acc_status = (GET_BYTE(to_push, 7) & 0x70) >> 4;
61-
controls_allowed = ((acc_status == 3) || (acc_status == 4) || (acc_status == 5)) ? 1 : 0;
62-
}
63-
64-
// exit controls on rising edge of gas press. Bits [12-20)
65-
if (addr == MSG_MOTOR_20) {
66-
int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF;
67-
if ((gas > 0) && (volkswagen_gas_prev == 0)) {
68-
controls_allowed = 0;
69-
}
70-
volkswagen_gas_prev = gas;
71-
}
72-
73-
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) {
74-
relay_malfunction = true;
75-
}
54+
int bus = GET_BUS(to_push);
55+
int addr = GET_ADDR(to_push);
56+
57+
// Update driver input torque samples
58+
// Signal: EPS_01.Driver_Strain (absolute torque)
59+
// Signal: EPS_01.Driver_Strain_VZ (direction)
60+
if ((bus == 0) && (addr == MSG_EPS_01)) {
61+
int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1F) << 8);
62+
int sign = (GET_BYTE(to_push, 6) & 0x80) >> 7;
63+
if (sign == 1) {
64+
torque_driver_new *= -1;
65+
}
66+
update_sample(&volkswagen_torque_driver, torque_driver_new);
67+
}
68+
69+
// Update ACC status from radar for controls-allowed state
70+
// Signal: ACC_06.ACC_Status_ACC
71+
if ((bus == 0) && (addr == MSG_ACC_06)) {
72+
int acc_status = (GET_BYTE(to_push, 7) & 0x70) >> 4;
73+
controls_allowed = ((acc_status == 3) || (acc_status == 4) || (acc_status == 5)) ? 1 : 0;
74+
}
75+
76+
// Exit controls on rising edge of gas press
77+
// Signal: Motor_20.MO_Fahrpedalrohwert_01
78+
if ((bus == 0) && (addr == MSG_MOTOR_20)) {
79+
int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF;
80+
if ((gas > 0) && (volkswagen_gas_prev == 0)) {
81+
controls_allowed = 0;
82+
}
83+
volkswagen_gas_prev = gas;
84+
}
85+
86+
// If there are HCA messages on bus 0 not sent by OP, there's a relay problem
87+
if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) {
88+
relay_malfunction = true;
89+
}
7690
}
7791
return valid;
7892
}
7993

80-
static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
94+
static bool volkswagen_steering_check(int desired_torque) {
95+
bool violation = false;
96+
uint32_t ts = TIM2->CNT;
97+
98+
if (controls_allowed) {
99+
// *** global torque limit check ***
100+
violation |= max_limit_check(desired_torque, VOLKSWAGEN_MAX_STEER, -VOLKSWAGEN_MAX_STEER);
101+
102+
// *** torque rate limit check ***
103+
violation |= driver_limit_check(desired_torque, volkswagen_desired_torque_last, &volkswagen_torque_driver,
104+
VOLKSWAGEN_MAX_STEER, VOLKSWAGEN_MAX_RATE_UP, VOLKSWAGEN_MAX_RATE_DOWN,
105+
VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE, VOLKSWAGEN_DRIVER_TORQUE_FACTOR);
106+
volkswagen_desired_torque_last = desired_torque;
107+
108+
// *** torque real time rate limit check ***
109+
violation |= rt_rate_limit_check(desired_torque, volkswagen_rt_torque_last, VOLKSWAGEN_MAX_RT_DELTA);
110+
111+
// every RT_INTERVAL set the new limits
112+
uint32_t ts_elapsed = get_ts_elapsed(ts, volkswagen_ts_last);
113+
if (ts_elapsed > VOLKSWAGEN_RT_INTERVAL) {
114+
volkswagen_rt_torque_last = desired_torque;
115+
volkswagen_ts_last = ts;
116+
}
117+
}
118+
119+
// no torque if controls is not allowed
120+
if (!controls_allowed && (desired_torque != 0)) {
121+
violation = true;
122+
}
123+
124+
// reset to 0 if either controls is not allowed or there's a violation
125+
if (violation || !controls_allowed) {
126+
volkswagen_desired_torque_last = 0;
127+
volkswagen_rt_torque_last = 0;
128+
volkswagen_ts_last = ts;
129+
}
130+
131+
return violation;
132+
}
133+
134+
static int volkswagen_mqb_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) {
81135
int addr = GET_ADDR(to_send);
82136
int bus = GET_BUS(to_send);
83137
int tx = 1;
84138

85-
if (!msg_allowed(addr, bus, VOLKSWAGEN_TX_MSGS, sizeof(VOLKSWAGEN_TX_MSGS)/sizeof(VOLKSWAGEN_TX_MSGS[0]))) {
86-
tx = 0;
87-
}
88-
89-
if (relay_malfunction) {
139+
if (!msg_allowed(addr, bus, VOLKSWAGEN_MQB_TX_MSGS, VOLKSWAGEN_MQB_TX_MSGS_LEN) || relay_malfunction) {
90140
tx = 0;
91141
}
92142

93-
// Safety check for HCA_01 Heading Control Assist torque.
143+
// Safety check for HCA_01 Heading Control Assist torque
144+
// Signal: HCA_01.Assist_Torque (absolute torque)
145+
// Signal: HCA_01.Assist_VZ (direction)
94146
if (addr == MSG_HCA_01) {
95-
bool violation = false;
96-
97147
int desired_torque = GET_BYTE(to_send, 2) | ((GET_BYTE(to_send, 3) & 0x3F) << 8);
98148
int sign = (GET_BYTE(to_send, 3) & 0x80) >> 7;
99149
if (sign == 1) {
100150
desired_torque *= -1;
101151
}
102152

103-
uint32_t ts = TIM2->CNT;
104-
105-
if (controls_allowed) {
106-
107-
// *** global torque limit check ***
108-
violation |= max_limit_check(desired_torque, VOLKSWAGEN_MAX_STEER, -VOLKSWAGEN_MAX_STEER);
109-
110-
// *** torque rate limit check ***
111-
violation |= driver_limit_check(desired_torque, volkswagen_desired_torque_last, &volkswagen_torque_driver,
112-
VOLKSWAGEN_MAX_STEER, VOLKSWAGEN_MAX_RATE_UP, VOLKSWAGEN_MAX_RATE_DOWN,
113-
VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE, VOLKSWAGEN_DRIVER_TORQUE_FACTOR);
114-
volkswagen_desired_torque_last = desired_torque;
115-
116-
// *** torque real time rate limit check ***
117-
violation |= rt_rate_limit_check(desired_torque, volkswagen_rt_torque_last, VOLKSWAGEN_MAX_RT_DELTA);
118-
119-
// every RT_INTERVAL set the new limits
120-
uint32_t ts_elapsed = get_ts_elapsed(ts, volkswagen_ts_last);
121-
if (ts_elapsed > VOLKSWAGEN_RT_INTERVAL) {
122-
volkswagen_rt_torque_last = desired_torque;
123-
volkswagen_ts_last = ts;
124-
}
125-
}
126-
127-
// no torque if controls is not allowed
128-
if (!controls_allowed && (desired_torque != 0)) {
129-
violation = true;
130-
}
131-
132-
// reset to 0 if either controls is not allowed or there's a violation
133-
if (violation || !controls_allowed) {
134-
volkswagen_desired_torque_last = 0;
135-
volkswagen_rt_torque_last = 0;
136-
volkswagen_ts_last = ts;
137-
}
138-
139-
if (violation) {
153+
if (volkswagen_steering_check(desired_torque)) {
140154
tx = 0;
141155
}
142156
}
@@ -158,38 +172,37 @@ static int volkswagen_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) {
158172
int addr = GET_ADDR(to_fwd);
159173
int bus_fwd = -1;
160174

161-
// NOTE: Will need refactoring for other bus layouts, such as no-forwarding at camera or J533 running-gear CAN
162-
163175
if (!relay_malfunction) {
164176
switch (bus_num) {
165177
case 0:
166-
// Forward all traffic from J533 gateway to Extended CAN devices.
178+
// Forward all traffic from the Extended CAN onward
167179
bus_fwd = 2;
168180
break;
169181
case 2:
170-
if ((addr == MSG_HCA_01) || (addr == MSG_LDW_02)) {
171-
// OP takes control of the Heading Control Assist and Lane Departure Warning messages from the camera.
182+
if ((addr == volkswagen_torque_msg) || (addr == volkswagen_lane_msg)) {
183+
// OP takes control of the Heading Control Assist and Lane Departure Warning messages from the camera
172184
bus_fwd = -1;
173185
} else {
174-
// Forward all remaining traffic from Extended CAN devices to J533 gateway.
186+
// Forward all remaining traffic from Extended CAN devices to J533 gateway
175187
bus_fwd = 0;
176188
}
177189
break;
178190
default:
179-
// No other buses should be in use; fallback to do-not-forward.
191+
// No other buses should be in use; fallback to do-not-forward
180192
bus_fwd = -1;
181193
break;
182194
}
183195
}
184196
return bus_fwd;
185197
}
186198

187-
const safety_hooks volkswagen_hooks = {
188-
.init = nooutput_init,
189-
.rx = volkswagen_rx_hook,
190-
.tx = volkswagen_tx_hook,
199+
// Volkswagen MQB platform
200+
const safety_hooks volkswagen_mqb_hooks = {
201+
.init = volkswagen_mqb_init,
202+
.rx = volkswagen_mqb_rx_hook,
203+
.tx = volkswagen_mqb_tx_hook,
191204
.tx_lin = nooutput_tx_lin_hook,
192205
.fwd = volkswagen_fwd_hook,
193-
.addr_check = volkswagen_rx_checks,
194-
.addr_check_len = sizeof(volkswagen_rx_checks) / sizeof(volkswagen_rx_checks[0]),
206+
.addr_check = volkswagen_mqb_rx_checks,
207+
.addr_check_len = sizeof(volkswagen_mqb_rx_checks) / sizeof(volkswagen_mqb_rx_checks[0]),
195208
};

python/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class Panda(object):
123123
SAFETY_TESLA = 10
124124
SAFETY_SUBARU = 11
125125
SAFETY_MAZDA = 13
126-
SAFETY_VOLKSWAGEN = 15
126+
SAFETY_VOLKSWAGEN_MQB = 15
127127
SAFETY_TOYOTA_IPAS = 16
128128
SAFETY_ALLOUTPUT = 17
129129
SAFETY_GM_ASCM = 18

tests/safety/libpandasafety_py.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@
9191
void set_subaru_torque_driver(int min, int max);
9292
9393
void init_tests_volkswagen(void);
94+
int get_volkswagen_gas_prev(void);
95+
int get_volkswagen_torque_driver_min(void);
96+
int get_volkswagen_torque_driver_max(void);
9497
void set_volkswagen_desired_torque_last(int t);
9598
void set_volkswagen_rt_torque_last(int t);
9699
void set_volkswagen_torque_driver(int min, int max);
97-
int get_volkswagen_gas_prev(void);
98100
99101
""")
100102

tests/safety/test.c

+8
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ void set_volkswagen_torque_driver(int min, int max){
148148
volkswagen_torque_driver.max = max;
149149
}
150150

151+
int get_volkswagen_torque_driver_min(void){
152+
return volkswagen_torque_driver.min;
153+
}
154+
155+
int get_volkswagen_torque_driver_max(void){
156+
return volkswagen_torque_driver.max;
157+
}
158+
151159
int get_chrysler_torque_meas_min(void){
152160
return chrysler_torque_meas.min;
153161
}

0 commit comments

Comments
 (0)