|
6 | 6 | from selfdrive.car.ford.values import CarControllerParams
|
7 | 7 | from opendbc.can.packer import CANPacker
|
8 | 8 |
|
| 9 | +DEBUG_RAMP_TYPE = False |
| 10 | + |
9 | 11 | VisualAlert = car.CarControl.HUDControl.VisualAlert
|
10 | 12 |
|
| 13 | + |
| 14 | +def apply_steer_angle_limits(apply_steer, apply_steer_last, vEgo, LIMITS): |
| 15 | + steer_up = apply_steer * apply_steer_last > 0. and abs(apply_steer) > abs(apply_steer_last) |
| 16 | + rate_limit = LIMITS.STEER_RATE_LIMIT_UP if steer_up else LIMITS.STEER_RATE_LIMIT_DOWN |
| 17 | + max_angle_diff = interp(vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points) |
| 18 | + return clip(apply_steer, (apply_steer_last - max_angle_diff), (apply_steer_last + max_angle_diff)) |
| 19 | + |
| 20 | + |
11 | 21 | class CarController():
|
12 | 22 | def __init__(self, dbc_name, CP, VM):
|
13 | 23 | self.CP = CP
|
14 | 24 | self.vehicle_model = VM
|
15 | 25 | self.packer = CANPacker(dbc_name)
|
16 | 26 | self.params = CarControllerParams
|
17 | 27 |
|
18 |
| - self.enabled_last = False |
| 28 | + self.apply_steer_last = 0 |
| 29 | + self.steer_rate_limited = False |
19 | 30 | self.main_on_last = False
|
20 |
| - self.generic_toggle_last = False |
| 31 | + self.enabled_last = False |
21 | 32 | self.steer_alert_last = False
|
22 |
| - self.angle_last = 0 |
| 33 | + self.generic_toggle_last = False |
| 34 | + |
| 35 | + self.ramp_type = 0 |
23 | 36 |
|
24 | 37 | def update(self, enabled, CS, frame, actuators, cruise_cancel, visual_alert):
|
25 | 38 | can_sends = []
|
26 |
| - |
27 | 39 | main_on = CS.out.cruiseState.available
|
28 | 40 | steer_alert = visual_alert in [VisualAlert.steerRequired, VisualAlert.ldw]
|
29 | 41 |
|
30 |
| - if cruise_cancel: |
31 |
| - can_sends.append(fordcan.spam_cancel_button(self.packer)) |
| 42 | + apply_steer = 0 |
| 43 | + self.steer_rate_limited = False |
32 | 44 |
|
33 |
| - if (frame % self.params.LKAS_STEER_STEP) == 0: |
34 |
| - angle = actuators.steeringAngleDeg |
| 45 | + if enabled: |
| 46 | + # calculate steer angle, apply angle rate limits |
| 47 | + apply_steer = apply_steer_angle_limits(actuators.steeringAngleDeg, self.apply_steer_last, CS.out.vEgo, CarControllerParams) |
| 48 | + self.steer_rate_limited = actuators.steeringAngleDeg != apply_steer |
35 | 49 |
|
36 |
| - # angle rate limit based on speed |
37 |
| - steer_up = angle * self.angle_last > 0. and abs(angle) > abs(self.angle_last) |
38 |
| - rate_limit = self.params.STEER_RATE_LIMIT_UP if steer_up else self.params.STEER_RATE_LIMIT_DOWN |
39 |
| - max_angle_diff = interp(CS.out.vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points) |
40 |
| - angle = clip(angle, (self.angle_last - max_angle_diff), (self.angle_last + max_angle_diff)) |
| 50 | + if cruise_cancel: |
| 51 | + # cancel stock ACC |
| 52 | + can_sends.append(fordcan.spam_cancel_button(self.packer)) |
41 | 53 |
|
42 |
| - if enabled: |
43 |
| - lca_rq = 1 |
44 |
| - else: |
45 |
| - lca_rq = 0 |
| 54 | + if CS.out.genericToggle and not self.generic_toggle_last: |
| 55 | + # ramp type experiment |
| 56 | + if DEBUG_RAMP_TYPE: |
| 57 | + # TODO: stock varies this with distance from center |
| 58 | + self.ramp_type += 1 |
| 59 | + if self.ramp_type > 3: |
| 60 | + self.ramp_type = 0 |
46 | 61 |
|
47 |
| - angle_rad = angle * CV.DEG_TO_RAD |
| 62 | + if (frame % self.params.LKAS_STEER_STEP) == 0: |
| 63 | + lca_rq = 1 if enabled else 0 |
| 64 | + apply_steer_rad = apply_steer * CV.DEG_TO_RAD |
48 | 65 | curvature = self.vehicle_model.calc_curvature(math.radians(actuators.steeringAngleDeg), CS.out.vEgo, 0.0)
|
49 |
| - ramp_type = 3 |
50 | 66 |
|
51 |
| - can_sends.append(fordcan.create_steer_command(self.packer, angle, curvature)) |
52 |
| - can_sends.append(fordcan.create_steer2_command(self.packer, lca_rq, ramp_type, angle_rad, curvature)) |
| 67 | + self.apply_steer_last = apply_steer |
53 | 68 |
|
54 |
| - self.angle_last = angle |
55 |
| - self.generic_toggle_last = CS.out.genericToggle |
| 69 | + # send steering commands |
| 70 | + can_sends.append(fordcan.create_steer_command(self.packer, apply_steer, curvature)) |
| 71 | + can_sends.append(fordcan.create_steer2_command(self.packer, lca_rq, self.ramp_type, apply_steer_rad, curvature)) |
56 | 72 |
|
57 |
| - # TODO: do we also have to send if CS.ipma_data changed? |
| 73 | + # TODO: do we need to send when values change? is 1hz acceptable? |
58 | 74 | if (frame % self.params.LKAS_UI_STEP) == 0 or (self.main_on_last != main_on) or (self.enabled_last != enabled) or \
|
59 | 75 | (self.steer_alert_last != steer_alert):
|
60 | 76 | can_sends.append(fordcan.create_lkas_ui_command(self.packer, main_on, enabled, steer_alert, CS.ipma_data))
|
61 | 77 |
|
62 | 78 | self.main_on_last = main_on
|
63 | 79 | self.enabled_last = enabled
|
64 | 80 | self.steer_alert_last = steer_alert
|
| 81 | + self.generic_toggle_last = CS.out.genericToggle |
65 | 82 |
|
66 | 83 | return actuators, can_sends
|
0 commit comments