openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
8.4 KiB

from cereal import car
from openpilot.common.numpy_fast import clip
from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_can_msg
from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.selfdrive.car.toyota import toyotacan
from openpilot.selfdrive.car.toyota.values import CAR, STATIC_DSU_MSGS, NO_STOP_TIMER_CAR, TSS2_CAR, \
CarControllerParams, ToyotaFlags, \
UNSUPPORTED_DSU_CAR
from opendbc.can.packer import CANPacker
SteerControlType = car.CarParams.SteerControlType
VisualAlert = car.CarControl.HUDControl.VisualAlert
# LKA limits
# EPS faults if you apply torque while the steering rate is above 100 deg/s for too long
MAX_STEER_RATE = 100 # deg/s
MAX_STEER_RATE_FRAMES = 18 # tx control frames needed before torque can be cut
# EPS allows user torque above threshold for 50 frames before permanently faulting
MAX_USER_TORQUE = 500
# LTA limits
# EPS ignores commands above this angle and causes PCS to fault
MAX_LTA_ANGLE = 94.9461 # deg
MAX_LTA_DRIVER_TORQUE_ALLOWANCE = 150 # slightly above steering pressed allows some resistance when changing lanes
class CarController(CarControllerBase):
def __init__(self, dbc_name, CP, VM):
self.CP = CP
self.params = CarControllerParams(self.CP)
self.frame = 0
self.last_steer = 0
self.last_angle = 0
self.alert_active = False
self.last_standstill = False
self.standstill_req = False
self.steer_rate_counter = 0
self.distance_button = 0
self.packer = CANPacker(dbc_name)
self.gas = 0
self.accel = 0
def update(self, CC, CS, now_nanos):
actuators = CC.actuators
hud_control = CC.hudControl
pcm_cancel_cmd = CC.cruiseControl.cancel
lat_active = CC.latActive and abs(CS.out.steeringTorque) < MAX_USER_TORQUE
# *** control msgs ***
can_sends = []
# *** steer torque ***
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
apply_steer = apply_meas_steer_torque_limits(new_steer, self.last_steer, CS.out.steeringTorqueEps, self.params)
# >100 degree/sec steering fault prevention
self.steer_rate_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringRateDeg) >= MAX_STEER_RATE, lat_active,
self.steer_rate_counter, MAX_STEER_RATE_FRAMES)
if not lat_active:
apply_steer = 0
# *** steer angle ***
if self.CP.steerControlType == SteerControlType.angle:
# If using LTA control, disable LKA and set steering angle command
Toyota: add 2023 RAV4/RAV4 Hybrid as dashcam (#27609) * test out lta message * correctly send * percentage is percentage driver isn't overriding * closer to stock system * should be able to send LTA at 100hz, counter is the same as LKA * small amount of torque towards desired * Offset commanded torque correctly * Too little torque * use car's SETME's * Revert "use car's SETME's" This reverts commit c88856969995f97cc5ec4e2b24a5cc4e3ef4721a. * try cutting steer every second * Didn't seem to matter This reverts commit 6923498b2a9eed8beb3998f441899f1df4948f6f. * steer to 0 * let packer set counter * add for camry * log steer faults * comments * bump opendbc * add opParams * add lta safety * set safety param * fix torque control bug * bump panda * fix missing signal * [experiment] apply some rate limiting and anti-windup * no faults, clip to 90 deg, decent torque blending * clean up blending * toyota angle rate limits * use std angle limits * assert we only add angle control to TSS2 cars * clean up carcontroller a bit * space space * bump opendbc * clean up toyotacan from opendbc change * bump panda * will tests run? * steer at zero * refactor angle to use LatControlPID with zero gains * stop some faults and tuning * possibly fix integral wind up at max torque * Add 2023 rav4 * limit torque inside EPS when overriding (no huge windup in edge cases when overriding) * fix wind up issue after turns (or prolonged saturation) * this doesn't work that well * try these limits * try this * log the angle! * global variable * Apply suggestions from code review * clip angle to 3 m/s/s * some tolerance for roll * raise limits a bit * bumppanda * fix faults * still not good * offsetting causing hugging? * Revert "offsetting causing hugging?" This reverts commit a42ec0b772ed74a1fd54b7fef2e7c275a3e8333b. * reduce kp * class var not needed * limit up angle delta * fix saturation check * feedforward includes offset * some threshold for roll * bump panda * surely we don't need this * test stuff * Toyota: Add FW for 2023 RAV4 Hybrid (#27494) * Toyota: Add FW for 2023 RAV4 Hybrid * Set RAVH_TSS2_2022 to use angle SteerControlType * bump panda * remove extras * Revert "remove extras" This reverts commit 87378e734915c107f57f99a5feef4dcb2b2a9a37. * no max angle limit for now * add as separate platforms * remove debug scripts * revert to master * remove these FW versions from 2022 * dashcam these cars :( * fix test * interface * add to untested routes * never send torque with LTA cars * fix values * clean up controlsd * reset lat control files * use the car param * add to params * bump panda to master * Update selfdrive/car/toyota/carcontroller.py * don't set torque params if angle control (fixes controlsd bug) * reset controlsd * keyword * in another pr * simplify test * rm line * Update selfdrive/car/toyota/tests/test_toyota.py --------- Co-authored-by: crispbee <84819466+crispbee@users.noreply.github.com> old-commit-hash: 57c4d78869ad197189427ab68c45ac8cc7bbd9d0
2 years ago
apply_steer = 0
apply_steer_req = False
if self.frame % 2 == 0:
# EPS uses the torque sensor angle to control with, offset to compensate
apply_angle = actuators.steeringAngleDeg + CS.out.steeringAngleOffsetDeg
# Angular rate limit based on speed
apply_angle = apply_std_steer_angle_limits(apply_angle, self.last_angle, CS.out.vEgoRaw, self.params)
if not lat_active:
apply_angle = CS.out.steeringAngleDeg + CS.out.steeringAngleOffsetDeg
self.last_angle = clip(apply_angle, -MAX_LTA_ANGLE, MAX_LTA_ANGLE)
Toyota: add 2023 RAV4/RAV4 Hybrid as dashcam (#27609) * test out lta message * correctly send * percentage is percentage driver isn't overriding * closer to stock system * should be able to send LTA at 100hz, counter is the same as LKA * small amount of torque towards desired * Offset commanded torque correctly * Too little torque * use car's SETME's * Revert "use car's SETME's" This reverts commit c88856969995f97cc5ec4e2b24a5cc4e3ef4721a. * try cutting steer every second * Didn't seem to matter This reverts commit 6923498b2a9eed8beb3998f441899f1df4948f6f. * steer to 0 * let packer set counter * add for camry * log steer faults * comments * bump opendbc * add opParams * add lta safety * set safety param * fix torque control bug * bump panda * fix missing signal * [experiment] apply some rate limiting and anti-windup * no faults, clip to 90 deg, decent torque blending * clean up blending * toyota angle rate limits * use std angle limits * assert we only add angle control to TSS2 cars * clean up carcontroller a bit * space space * bump opendbc * clean up toyotacan from opendbc change * bump panda * will tests run? * steer at zero * refactor angle to use LatControlPID with zero gains * stop some faults and tuning * possibly fix integral wind up at max torque * Add 2023 rav4 * limit torque inside EPS when overriding (no huge windup in edge cases when overriding) * fix wind up issue after turns (or prolonged saturation) * this doesn't work that well * try these limits * try this * log the angle! * global variable * Apply suggestions from code review * clip angle to 3 m/s/s * some tolerance for roll * raise limits a bit * bumppanda * fix faults * still not good * offsetting causing hugging? * Revert "offsetting causing hugging?" This reverts commit a42ec0b772ed74a1fd54b7fef2e7c275a3e8333b. * reduce kp * class var not needed * limit up angle delta * fix saturation check * feedforward includes offset * some threshold for roll * bump panda * surely we don't need this * test stuff * Toyota: Add FW for 2023 RAV4 Hybrid (#27494) * Toyota: Add FW for 2023 RAV4 Hybrid * Set RAVH_TSS2_2022 to use angle SteerControlType * bump panda * remove extras * Revert "remove extras" This reverts commit 87378e734915c107f57f99a5feef4dcb2b2a9a37. * no max angle limit for now * add as separate platforms * remove debug scripts * revert to master * remove these FW versions from 2022 * dashcam these cars :( * fix test * interface * add to untested routes * never send torque with LTA cars * fix values * clean up controlsd * reset lat control files * use the car param * add to params * bump panda to master * Update selfdrive/car/toyota/carcontroller.py * don't set torque params if angle control (fixes controlsd bug) * reset controlsd * keyword * in another pr * simplify test * rm line * Update selfdrive/car/toyota/tests/test_toyota.py --------- Co-authored-by: crispbee <84819466+crispbee@users.noreply.github.com> old-commit-hash: 57c4d78869ad197189427ab68c45ac8cc7bbd9d0
2 years ago
self.last_steer = apply_steer
# toyota can trace shows STEERING_LKA at 42Hz, with counter adding alternatively 1 and 2;
# sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed
# on consecutive messages
can_sends.append(toyotacan.create_steer_command(self.packer, apply_steer, apply_steer_req))
# STEERING_LTA does not seem to allow more rate by sending faster, and may wind up easier
if self.frame % 2 == 0 and self.CP.carFingerprint in TSS2_CAR:
lta_active = lat_active and self.CP.steerControlType == SteerControlType.angle
# cut steering torque with TORQUE_WIND_DOWN when either EPS torque or driver torque is above
# the threshold, to limit max lateral acceleration and for driver torque blending respectively.
full_torque_condition = (abs(CS.out.steeringTorqueEps) < self.params.STEER_MAX and
abs(CS.out.steeringTorque) < MAX_LTA_DRIVER_TORQUE_ALLOWANCE)
# TORQUE_WIND_DOWN at 0 ramps down torque at roughly the max down rate of 1500 units/sec
torque_wind_down = 100 if lta_active and full_torque_condition else 0
can_sends.append(toyotacan.create_lta_steer_command(self.packer, self.CP.steerControlType, self.last_angle,
lta_active, self.frame // 2, torque_wind_down))
# *** gas and brake ***
pcm_accel_cmd = clip(actuators.accel, self.params.ACCEL_MIN, self.params.ACCEL_MAX)
# on entering standstill, send standstill request
if CS.out.standstill and not self.last_standstill and (self.CP.carFingerprint not in NO_STOP_TIMER_CAR):
self.standstill_req = True
if CS.pcm_acc_status != 8:
# pcm entered standstill or it's disabled
self.standstill_req = False
self.last_standstill = CS.out.standstill
# handle UI messages
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
steer_alert = hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw)
# we can spam can to cancel the system even if we are using lat only control
if (self.frame % 3 == 0 and self.CP.openpilotLongitudinalControl) or pcm_cancel_cmd:
lead = hud_control.leadVisible or CS.out.vEgo < 12. # at low speed we always assume the lead is present so ACC can be engaged
# Press distance button until we are at the correct bar length. Only change while enabled to avoid skipping startup popup
if self.frame % 6 == 0 and self.CP.openpilotLongitudinalControl:
desired_distance = 4 - hud_control.leadDistanceBars
if CS.out.cruiseState.enabled and CS.pcm_follow_distance != desired_distance:
self.distance_button = not self.distance_button
else:
self.distance_button = 0
# Lexus IS uses a different cancellation message
if pcm_cancel_cmd and self.CP.carFingerprint in UNSUPPORTED_DSU_CAR:
can_sends.append(toyotacan.create_acc_cancel_command(self.packer))
elif self.CP.openpilotLongitudinalControl:
can_sends.append(toyotacan.create_accel_command(self.packer, pcm_accel_cmd, pcm_cancel_cmd, self.standstill_req, lead, CS.acc_type, fcw_alert,
self.distance_button))
self.accel = pcm_accel_cmd
else:
can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, False, lead, CS.acc_type, False, self.distance_button))
# *** hud ui ***
if self.CP.carFingerprint != CAR.TOYOTA_PRIUS_V:
# ui mesg is at 1Hz but we send asap if:
# - there is something to display
# - there is something to stop displaying
send_ui = False
if ((fcw_alert or steer_alert) and not self.alert_active) or \
(not (fcw_alert or steer_alert) and self.alert_active):
send_ui = True
self.alert_active = not self.alert_active
elif pcm_cancel_cmd:
# forcing the pcm to disengage causes a bad fault sound so play a good sound instead
send_ui = True
if self.frame % 20 == 0 or send_ui:
can_sends.append(toyotacan.create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, hud_control.leftLaneVisible,
hud_control.rightLaneVisible, hud_control.leftLaneDepart,
hud_control.rightLaneDepart, CC.enabled, CS.lkas_hud))
if (self.frame % 100 == 0 or send_ui) and (self.CP.enableDsu or self.CP.flags & ToyotaFlags.DISABLE_RADAR.value):
can_sends.append(toyotacan.create_fcw_command(self.packer, fcw_alert))
# *** static msgs ***
for addr, cars, bus, fr_step, vl in STATIC_DSU_MSGS:
if self.frame % fr_step == 0 and self.CP.enableDsu and self.CP.carFingerprint in cars:
can_sends.append(make_can_msg(addr, vl, bus))
# keep radar disabled
if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value:
can_sends.append([0x750, 0, b"\x0F\x02\x3E\x00\x00\x00\x00\x00", 0])
card: process that abstracts car interface and CAN (#32380) * format card * standalone process * no class member CS, there's no point also can be confusing; what else could be using this? * rename CoS * Update selfdrive/controls/controlsd.py * never works first time :D * canRcvTimeout is bool * hack * add cpu * see what testing closet comes up with * first * some clean up * support passable CI, fix test models * fix startup alert * process replay changes * test_fuzzy * gate carOutput valid on carControl valid * we should publish after we update carOutput * controlsd was using actuatorsOutput from 2 frames ago for torque, not the most up to date * check all checks for carControl in case controlsd dies * log more timestamps * more generic latency logger; needs some clean up latency_logger.py was difficult to understand and modify * card polls on can and carControl to get latest carControl possible * temp try to send earlier * add log * remove latencylogger * no mpld3! * old loop * detect first event * normal send * revert "card polls on can and carControl to get latest carControl possible" how it was is best * sheesh! update should be first * first timestamp * temp comment ( timestamp is slow :( ) * more final ordering, and make polling on/off test repeatable * Received can * new plot timestamps * clean up * no poll * add controllers (draft) * Revert "add controllers (draft)" This reverts commit e2c3f01b2fadcff74347bac90c8a5cc1ef4e27b3. * fix that * conventions * just use CS * consider controlsd state machine in card: not fully done * hmm it's just becoming controlsd * rm debugging * Revert "hmm it's just becoming controlsd" This reverts commit 534a357ee95bec4ed070667186af55d59421bbc7. * Revert "just use CS" This reverts commit 9fa7406f30c86200f20457f7b9ff95e731201bf9. * add vCruise * migrate car state * Revert "migrate car state" This reverts commit 4ae86ca163c6920070f410f608f7644ab632850b. * Revert "add vCruise" This reverts commit af247a8da41c3626ada4231b98042da1a1ae4633. * simple state machine in card (doesn't work as is) * Revert "simple state machine in card (doesn't work as is)" This reverts commit b4af8a9b0a2e17fdfc89d344c64678ef51305c24. * poll carState without conflate * bump * remove state transition * fix * update refs * ignore cumLagMs and don't ignore valid * fix controls mismatch; controlsd used to set alt exp * controlsd_config_callback not needed for card * revert ref temp * update refs * no poll * not builder! * test fix * need to migrate initialized * CC will be a reader * more as_reader! * fix None * init after publish like before - no real difference * controlsd clean up * remove redundant check and check passive for init * stash * flip * migrate missing carOutput for controlsd * Update ref_commit * bump cereal * comment * no class params * no class * Revert "no class" This reverts commit 5499b83c2dcb5462070626f8523e3aec6f4c209d. * add todo * regen and update refs * fix * update refs * and fix that * should be controlsstate * remove controlsState migration CoS.initialized isn't needed yet * fix * flip! * bump * fix that * update refs * fix * if canValid goes false, controlsd would still send * bump * rm diff * need to be very careful with initializing * update refs old-commit-hash: 71f5c441fe32184d94a9f26565a36c661e2ccf28
12 months ago
new_actuators = actuators.as_builder()
new_actuators.steer = apply_steer / self.params.STEER_MAX
new_actuators.steerOutputCan = apply_steer
new_actuators.steeringAngleDeg = self.last_angle
new_actuators.accel = self.accel
new_actuators.gas = self.gas
self.frame += 1
return new_actuators, can_sends