mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-30 12:43:43 +08:00
9219b7966c
# Conflicts: # panda # release/build_release.sh # selfdrive/car/car_helpers.py # selfdrive/car/chrysler/carcontroller.py # selfdrive/car/chrysler/carstate.py # selfdrive/car/chrysler/interface.py # selfdrive/car/ford/carstate.py # selfdrive/car/ford/interface.py # selfdrive/car/gm/carcontroller.py # selfdrive/car/gm/carstate.py # selfdrive/car/gm/interface.py # selfdrive/car/honda/carcontroller.py # selfdrive/car/honda/interface.py # selfdrive/car/hyundai/carcontroller.py # selfdrive/car/hyundai/carstate.py # selfdrive/car/hyundai/hyundaican.py # selfdrive/car/hyundai/interface.py # selfdrive/car/interfaces.py # selfdrive/car/mazda/carcontroller.py # selfdrive/car/mazda/carstate.py # selfdrive/car/mazda/interface.py # selfdrive/car/nissan/carcontroller.py # selfdrive/car/nissan/interface.py # selfdrive/car/subaru/carstate.py # selfdrive/car/subaru/interface.py # selfdrive/car/subaru/subarucan.py # selfdrive/car/toyota/carcontroller.py # selfdrive/car/toyota/carstate.py # selfdrive/car/toyota/interface.py # selfdrive/car/toyota/toyotacan.py # selfdrive/car/volkswagen/carcontroller.py # selfdrive/car/volkswagen/carstate.py # selfdrive/car/volkswagen/interface.py # selfdrive/controls/controlsd.py # selfdrive/controls/lib/latcontrol_torque.py # selfdrive/controls/lib/lateral_planner.py # selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py # selfdrive/controls/lib/longitudinal_planner.py # selfdrive/locationd/paramsd.py # selfdrive/manager/manager.py # selfdrive/manager/process.py # selfdrive/manager/process_config.py # selfdrive/sentry.py # selfdrive/ui/SConscript # selfdrive/ui/qt/home.cc # selfdrive/ui/qt/maps/map_settings.cc # selfdrive/ui/qt/maps/map_settings.h # selfdrive/ui/qt/offroad/settings.cc # selfdrive/ui/qt/onroad.cc # selfdrive/ui/qt/onroad.h # selfdrive/ui/qt/util.cc # selfdrive/ui/qt/util.h # selfdrive/ui/soundd/sound.h # selfdrive/ui/ui.h # system/version.py
186 lines
8.0 KiB
Python
186 lines
8.0 KiB
Python
import numpy as np
|
|
from cereal import log
|
|
from openpilot.common.conversions import Conversions as CV
|
|
from openpilot.common.params import Params
|
|
from openpilot.common.realtime import DT_MDL
|
|
|
|
LaneChangeState = log.LateralPlan.LaneChangeState
|
|
LaneChangeDirection = log.LateralPlan.LaneChangeDirection
|
|
|
|
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
|
LANE_CHANGE_TIME_MAX = 10.
|
|
|
|
DESIRES = {
|
|
LaneChangeDirection.none: {
|
|
LaneChangeState.off: log.LateralPlan.Desire.none,
|
|
LaneChangeState.preLaneChange: log.LateralPlan.Desire.none,
|
|
LaneChangeState.laneChangeStarting: log.LateralPlan.Desire.none,
|
|
LaneChangeState.laneChangeFinishing: log.LateralPlan.Desire.none,
|
|
},
|
|
LaneChangeDirection.left: {
|
|
LaneChangeState.off: log.LateralPlan.Desire.none,
|
|
LaneChangeState.preLaneChange: log.LateralPlan.Desire.none,
|
|
LaneChangeState.laneChangeStarting: log.LateralPlan.Desire.laneChangeLeft,
|
|
LaneChangeState.laneChangeFinishing: log.LateralPlan.Desire.laneChangeLeft,
|
|
},
|
|
LaneChangeDirection.right: {
|
|
LaneChangeState.off: log.LateralPlan.Desire.none,
|
|
LaneChangeState.preLaneChange: log.LateralPlan.Desire.none,
|
|
LaneChangeState.laneChangeStarting: log.LateralPlan.Desire.laneChangeRight,
|
|
LaneChangeState.laneChangeFinishing: log.LateralPlan.Desire.laneChangeRight,
|
|
},
|
|
}
|
|
|
|
AUTO_LANE_CHANGE_TIMER = {
|
|
0: 0.0,
|
|
1: 0.1,
|
|
2: 0.5,
|
|
3: 1.0,
|
|
4: 1.5,
|
|
}
|
|
|
|
|
|
class DesireHelper:
|
|
def __init__(self):
|
|
self.lane_change_state = LaneChangeState.off
|
|
self.lane_change_direction = LaneChangeDirection.none
|
|
self.lane_change_timer = 0.0
|
|
self.lane_change_ll_prob = 1.0
|
|
self.keep_pulse_timer = 0.0
|
|
self.prev_one_blinker = False
|
|
self.desire = log.LateralPlan.Desire.none
|
|
|
|
self.param_s = Params()
|
|
self.lane_change_wait_timer = 0
|
|
self.prev_lane_change = False
|
|
self.road_edge = False
|
|
self.param_read_counter = 0
|
|
self.read_param()
|
|
self.edge_toggle = self.param_s.get_bool("RoadEdge")
|
|
self.lane_change_set_timer = int(self.param_s.get("AutoLaneChangeTimer", encoding="utf8"))
|
|
self.lane_change_bsm_delay = self.param_s.get_bool("AutoLaneChangeBsmDelay")
|
|
|
|
def read_param(self):
|
|
self.edge_toggle = self.param_s.get_bool("RoadEdge")
|
|
self.lane_change_set_timer = int(self.param_s.get("AutoLaneChangeTimer", encoding="utf8"))
|
|
self.lane_change_bsm_delay = self.param_s.get_bool("AutoLaneChangeBsmDelay")
|
|
|
|
def update(self, carstate, lateral_active, lane_change_prob, model_data):
|
|
if self.param_read_counter % 50 == 0:
|
|
self.read_param()
|
|
self.param_read_counter += 1
|
|
lane_change_auto_timer = AUTO_LANE_CHANGE_TIMER.get(self.lane_change_set_timer, 2.0)
|
|
v_ego = carstate.vEgo
|
|
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
|
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
|
|
|
# Lane detection by FrogAi
|
|
if not self.edge_toggle:
|
|
self.road_edge = False
|
|
elif one_blinker:
|
|
# Set the minimum lane threshold to 3.0 meters
|
|
min_lane_threshold = 3.0
|
|
# Set the blinker index based on which signal is on
|
|
blinker_index = 0 if carstate.leftBlinker else 1
|
|
desired_edge = model_data.roadEdges[blinker_index]
|
|
current_lane = model_data.laneLines[blinker_index + 1]
|
|
# Check if both the desired lane and the current lane have valid x and y values
|
|
if all([desired_edge.x, desired_edge.y, current_lane.x, current_lane.y]) and len(desired_edge.x) == len(current_lane.x):
|
|
# Interpolate the x and y values to the same length
|
|
x = np.linspace(desired_edge.x[0], desired_edge.x[-1], num=len(desired_edge.x))
|
|
lane_y = np.interp(x, current_lane.x, current_lane.y)
|
|
desired_y = np.interp(x, desired_edge.x, desired_edge.y)
|
|
# Calculate the width of the lane we're wanting to change into
|
|
lane_width = np.abs(desired_y - lane_y)
|
|
# Set road_edge to False if the lane width is not larger than the threshold
|
|
self.road_edge = not (np.amax(lane_width) > min_lane_threshold)
|
|
else:
|
|
self.road_edge = True
|
|
else:
|
|
# Default to setting "road_edge" to False
|
|
self.road_edge = False
|
|
|
|
if not carstate.madsEnabled or self.lane_change_timer > LANE_CHANGE_TIME_MAX:
|
|
self.lane_change_state = LaneChangeState.off
|
|
self.lane_change_direction = LaneChangeDirection.none
|
|
self.prev_lane_change = False
|
|
else:
|
|
# LaneChangeState.off
|
|
if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed and not carstate.brakePressed:
|
|
self.lane_change_state = LaneChangeState.preLaneChange
|
|
self.lane_change_ll_prob = 1.0
|
|
self.lane_change_wait_timer = 0
|
|
|
|
# LaneChangeState.preLaneChange
|
|
elif self.lane_change_state == LaneChangeState.preLaneChange and self.road_edge:
|
|
self.lane_change_direction = LaneChangeDirection.none
|
|
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
|
# Set lane change direction
|
|
self.lane_change_direction = LaneChangeDirection.left if \
|
|
carstate.leftBlinker else LaneChangeDirection.right
|
|
|
|
torque_applied = carstate.steeringPressed and \
|
|
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
|
(carstate.steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right))
|
|
|
|
blindspot_detected = ((carstate.leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or
|
|
(carstate.rightBlindspot and self.lane_change_direction == LaneChangeDirection.right))
|
|
|
|
self.lane_change_wait_timer += DT_MDL
|
|
|
|
if self.lane_change_bsm_delay and blindspot_detected and lane_change_auto_timer:
|
|
if lane_change_auto_timer == 0.1:
|
|
self.lane_change_wait_timer = -1
|
|
else:
|
|
self.lane_change_wait_timer = lane_change_auto_timer - 1
|
|
|
|
if not one_blinker or below_lane_change_speed:
|
|
self.lane_change_state = LaneChangeState.off
|
|
self.lane_change_direction = LaneChangeDirection.none
|
|
self.prev_lane_change = False
|
|
elif (torque_applied or ((lane_change_auto_timer and self.lane_change_wait_timer > lane_change_auto_timer) and not self.prev_lane_change)) and \
|
|
not blindspot_detected:
|
|
self.lane_change_state = LaneChangeState.laneChangeStarting
|
|
self.prev_lane_change = True
|
|
|
|
# LaneChangeState.laneChangeStarting
|
|
elif self.lane_change_state == LaneChangeState.laneChangeStarting:
|
|
# fade out over .5s
|
|
self.lane_change_ll_prob = max(self.lane_change_ll_prob - 2 * DT_MDL, 0.0)
|
|
|
|
# 98% certainty
|
|
if lane_change_prob < 0.02 and self.lane_change_ll_prob < 0.01:
|
|
self.lane_change_state = LaneChangeState.laneChangeFinishing
|
|
|
|
# LaneChangeState.laneChangeFinishing
|
|
elif self.lane_change_state == LaneChangeState.laneChangeFinishing:
|
|
# fade in laneline over 1s
|
|
self.lane_change_ll_prob = min(self.lane_change_ll_prob + DT_MDL, 1.0)
|
|
|
|
if self.lane_change_ll_prob > 0.99:
|
|
self.lane_change_direction = LaneChangeDirection.none
|
|
if one_blinker:
|
|
self.lane_change_state = LaneChangeState.preLaneChange
|
|
else:
|
|
self.lane_change_state = LaneChangeState.off
|
|
self.prev_lane_change = False
|
|
|
|
if self.lane_change_state in (LaneChangeState.off, LaneChangeState.preLaneChange):
|
|
self.lane_change_timer = 0.0
|
|
else:
|
|
self.lane_change_timer += DT_MDL
|
|
|
|
self.prev_one_blinker = one_blinker
|
|
|
|
self.desire = DESIRES[self.lane_change_direction][self.lane_change_state]
|
|
|
|
# Send keep pulse once per second during LaneChangeStart.preLaneChange
|
|
if self.lane_change_state in (LaneChangeState.off, LaneChangeState.laneChangeStarting):
|
|
self.keep_pulse_timer = 0.0
|
|
elif self.lane_change_state == LaneChangeState.preLaneChange:
|
|
self.keep_pulse_timer += DT_MDL
|
|
if self.keep_pulse_timer > 1.0:
|
|
self.keep_pulse_timer = 0.0
|
|
elif self.desire in (log.LateralPlan.Desire.keepLeft, log.LateralPlan.Desire.keepRight):
|
|
self.desire = log.LateralPlan.Desire.none
|