commit
a2c76acf3b
4 changed files with 301 additions and 1 deletions
@ -1 +1 @@ |
||||
v1.1.5 |
||||
v1.1.6 |
@ -0,0 +1,287 @@ |
||||
// board enforces
|
||||
// in-state
|
||||
// accel set/resume
|
||||
// out-state
|
||||
// cancel button
|
||||
// regen paddle
|
||||
// accel rising edge
|
||||
// brake rising edge
|
||||
// brake > 0mph
|
||||
//
|
||||
int fmax_limit_check(float val, const float MAX, const float MIN) { |
||||
return (val > MAX) || (val < MIN); |
||||
} |
||||
|
||||
// 2m/s are added to be less restrictive
|
||||
const struct lookup_t TESLA_LOOKUP_ANGLE_RATE_UP = { |
||||
{2., 7., 17.}, |
||||
{5., .8, .25}}; |
||||
|
||||
const struct lookup_t TESLA_LOOKUP_ANGLE_RATE_DOWN = { |
||||
{2., 7., 17.}, |
||||
{5., 3.5, .8}}; |
||||
|
||||
const struct lookup_t TESLA_LOOKUP_MAX_ANGLE = { |
||||
{2., 29., 38.}, |
||||
{410., 92., 36.}}; |
||||
|
||||
const int TESLA_RT_INTERVAL = 250000; // 250ms between real time checks
|
||||
|
||||
// state of angle limits
|
||||
float tesla_desired_angle_last = 0; // last desired steer angle
|
||||
float tesla_rt_angle_last = 0.; // last real time angle
|
||||
float tesla_ts_angle_last = 0; |
||||
|
||||
int tesla_controls_allowed_last = 0; |
||||
|
||||
int tesla_brake_prev = 0; |
||||
int tesla_gas_prev = 0; |
||||
int tesla_speed = 0; |
||||
int eac_status = 0; |
||||
|
||||
int tesla_ignition_started = 0; |
||||
|
||||
|
||||
void set_gmlan_digital_output(int to_set); |
||||
void reset_gmlan_switch_timeout(void); |
||||
void gmlan_switch_init(int timeout_enable); |
||||
|
||||
|
||||
static void tesla_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) |
||||
{ |
||||
set_gmlan_digital_output(0); // #define GMLAN_HIGH 0
|
||||
reset_gmlan_switch_timeout(); //we're still in tesla safety mode, reset the timeout counter and make sure our output is enabled
|
||||
|
||||
//int bus_number = (to_push->RDTR >> 4) & 0xFF;
|
||||
uint32_t addr; |
||||
if (to_push->RIR & 4) |
||||
{ |
||||
// Extended
|
||||
// Not looked at, but have to be separated
|
||||
// to avoid address collision
|
||||
addr = to_push->RIR >> 3; |
||||
} |
||||
else |
||||
{ |
||||
// Normal
|
||||
addr = to_push->RIR >> 21; |
||||
} |
||||
|
||||
if (addr == 0x45) |
||||
{ |
||||
// 6 bits starting at position 0
|
||||
int lever_position = (to_push->RDLR & 0x3F); |
||||
if (lever_position == 2) |
||||
{ // pull forward
|
||||
// activate openpilot
|
||||
controls_allowed = 1; |
||||
//}
|
||||
} |
||||
else if (lever_position == 1) |
||||
{ // push towards the back
|
||||
// deactivate openpilot
|
||||
controls_allowed = 0; |
||||
} |
||||
} |
||||
|
||||
// Detect drive rail on (ignition) (start recording)
|
||||
if (addr == 0x348) |
||||
{ |
||||
// GTW_status
|
||||
int drive_rail_on = (to_push->RDLR & 0x0001); |
||||
tesla_ignition_started = drive_rail_on == 1; |
||||
} |
||||
|
||||
// exit controls on brake press
|
||||
// DI_torque2::DI_brakePedal 0x118
|
||||
if (addr == 0x118) |
||||
{ |
||||
// 1 bit at position 16
|
||||
if (((to_push->RDLR & 0x8000)) >> 15 == 1) |
||||
{ |
||||
//disable break cancel by commenting line below
|
||||
controls_allowed = 0; |
||||
} |
||||
//get vehicle speed in m/s. Tesla gives MPH
|
||||
tesla_speed = ((((((to_push->RDLR >> 24) & 0x0F) << 8) + ((to_push->RDLR >> 16) & 0xFF)) * 0.05 - 25) * 1.609 / 3.6); |
||||
if (tesla_speed < 0) |
||||
{ |
||||
tesla_speed = 0; |
||||
} |
||||
} |
||||
|
||||
// exit controls on EPAS error
|
||||
// EPAS_sysStatus::EPAS_eacStatus 0x370
|
||||
if (addr == 0x370) |
||||
{ |
||||
// if EPAS_eacStatus is not 1 or 2, disable control
|
||||
eac_status = ((to_push->RDHR >> 21)) & 0x7; |
||||
// For human steering override we must not disable controls when eac_status == 0
|
||||
// Additional safety: we could only allow eac_status == 0 when we have human steering allowed
|
||||
if ((controls_allowed == 1) && (eac_status != 0) && (eac_status != 1) && (eac_status != 2)) |
||||
{ |
||||
controls_allowed = 0; |
||||
//puts("EPAS error! \n");
|
||||
} |
||||
} |
||||
//get latest steering wheel angle
|
||||
if (addr == 0x00E) |
||||
{ |
||||
float angle_meas_now = (int)((((to_push->RDLR & 0x3F) << 8) + ((to_push->RDLR >> 8) & 0xFF)) * 0.1 - 819.2); |
||||
uint32_t ts = TIM2->CNT; |
||||
uint32_t ts_elapsed = get_ts_elapsed(ts, tesla_ts_angle_last); |
||||
|
||||
// *** angle real time check
|
||||
// add 1 to not false trigger the violation and multiply by 25 since the check is done every 250 ms and steer angle is updated at 100Hz
|
||||
float rt_delta_angle_up = interpolate(TESLA_LOOKUP_ANGLE_RATE_UP, tesla_speed) * 25. + 1.; |
||||
float rt_delta_angle_down = interpolate(TESLA_LOOKUP_ANGLE_RATE_DOWN, tesla_speed) * 25. + 1.; |
||||
float highest_rt_angle = tesla_rt_angle_last + (tesla_rt_angle_last > 0 ? rt_delta_angle_up : rt_delta_angle_down); |
||||
float lowest_rt_angle = tesla_rt_angle_last - (tesla_rt_angle_last > 0 ? rt_delta_angle_down : rt_delta_angle_up); |
||||
|
||||
if ((ts_elapsed > TESLA_RT_INTERVAL) || (controls_allowed && !tesla_controls_allowed_last)) |
||||
{ |
||||
tesla_rt_angle_last = angle_meas_now; |
||||
tesla_ts_angle_last = ts; |
||||
} |
||||
|
||||
// check for violation;
|
||||
if (fmax_limit_check(angle_meas_now, highest_rt_angle, lowest_rt_angle)) |
||||
{ |
||||
// We should not be able to STEER under these conditions
|
||||
// Other sending is fine (to allow human override)
|
||||
controls_allowed = 0; |
||||
//puts("WARN: RT Angle - No steer allowed! \n");
|
||||
} |
||||
else |
||||
{ |
||||
controls_allowed = 1; |
||||
} |
||||
|
||||
tesla_controls_allowed_last = controls_allowed; |
||||
} |
||||
} |
||||
|
||||
// all commands: gas/regen, friction brake and steering
|
||||
// if controls_allowed and no pedals pressed
|
||||
// allow all commands up to limit
|
||||
// else
|
||||
// block all commands that produce actuation
|
||||
|
||||
static int tesla_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) |
||||
{ |
||||
|
||||
uint32_t addr; |
||||
float angle_raw; |
||||
float desired_angle; |
||||
|
||||
addr = to_send->RIR >> 21; |
||||
|
||||
// do not transmit CAN message if steering angle too high
|
||||
// DAS_steeringControl::DAS_steeringAngleRequest
|
||||
if (addr == 0x488) |
||||
{ |
||||
angle_raw = ((to_send->RDLR & 0x7F) << 8) + ((to_send->RDLR & 0xFF00) >> 8); |
||||
desired_angle = angle_raw * 0.1 - 1638.35; |
||||
int16_t violation = 0; |
||||
int st_enabled = (to_send->RDLR & 0x400000) >> 22; |
||||
|
||||
if (st_enabled == 0) { |
||||
//steering is not enabled, do not check angles and do send
|
||||
tesla_desired_angle_last = desired_angle; |
||||
return true; |
||||
} |
||||
|
||||
if (controls_allowed) |
||||
{ |
||||
// add 1 to not false trigger the violation
|
||||
float delta_angle_up = interpolate(TESLA_LOOKUP_ANGLE_RATE_UP, tesla_speed) + 1.; |
||||
float delta_angle_down = interpolate(TESLA_LOOKUP_ANGLE_RATE_DOWN, tesla_speed) + 1.; |
||||
float highest_desired_angle = tesla_desired_angle_last + (tesla_desired_angle_last > 0 ? delta_angle_up : delta_angle_down); |
||||
float lowest_desired_angle = tesla_desired_angle_last - (tesla_desired_angle_last > 0 ? delta_angle_down : delta_angle_up); |
||||
float TESLA_MAX_ANGLE = interpolate(TESLA_LOOKUP_MAX_ANGLE, tesla_speed) + 1.; |
||||
|
||||
//check for max angles
|
||||
violation |= fmax_limit_check(desired_angle, TESLA_MAX_ANGLE, -TESLA_MAX_ANGLE); |
||||
|
||||
//check for angle delta changes
|
||||
violation |= fmax_limit_check(desired_angle, highest_desired_angle, lowest_desired_angle); |
||||
|
||||
if (violation) |
||||
{ |
||||
controls_allowed = 0; |
||||
return false; |
||||
} |
||||
tesla_desired_angle_last = desired_angle; |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static int tesla_tx_lin_hook(int lin_num, uint8_t *data, int len) |
||||
{ |
||||
// LIN is not used on the Tesla
|
||||
return false; |
||||
} |
||||
|
||||
static void tesla_init(int16_t param) |
||||
{ |
||||
controls_allowed = 0; |
||||
tesla_ignition_started = 0; |
||||
gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled
|
||||
} |
||||
|
||||
static int tesla_ign_hook() |
||||
{ |
||||
return tesla_ignition_started; |
||||
} |
||||
|
||||
static int tesla_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) |
||||
{ |
||||
|
||||
int32_t addr = to_fwd->RIR >> 21; |
||||
|
||||
if (bus_num == 0) |
||||
{ |
||||
|
||||
// change inhibit of GTW_epasControl
|
||||
if (addr == 0x101) |
||||
{ |
||||
to_fwd->RDLR = to_fwd->RDLR | 0x4000; // 0x4000: WITH_ANGLE, 0xC000: WITH_BOTH (angle and torque)
|
||||
int checksum = (((to_fwd->RDLR & 0xFF00) >> 8) + (to_fwd->RDLR & 0xFF) + 2) & 0xFF; |
||||
to_fwd->RDLR = to_fwd->RDLR & 0xFFFF; |
||||
to_fwd->RDLR = to_fwd->RDLR + (checksum << 16); |
||||
return 2; |
||||
} |
||||
|
||||
// remove EPB_epasControl
|
||||
if (addr == 0x214) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return 2; // Custom EPAS bus
|
||||
} |
||||
if (bus_num == 2) |
||||
{ |
||||
|
||||
// remove GTW_epasControl in forwards
|
||||
if (addr == 0x101) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return 0; // Chassis CAN
|
||||
} |
||||
return false; |
||||
} |
||||
|
||||
const safety_hooks tesla_hooks = { |
||||
.init = tesla_init, |
||||
.rx = tesla_rx_hook, |
||||
.tx = tesla_tx_hook, |
||||
.tx_lin = tesla_tx_lin_hook, |
||||
.ignition = tesla_ign_hook, |
||||
.fwd = tesla_fwd_hook, |
||||
}; |
Loading…
Reference in new issue