From 05780d0980d9d93f9b3ee2a2147ab76bc95dcfa5 Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Fri, 12 Jan 2024 22:39:30 -0700 Subject: [PATCH] Nudgeless lane change + lane detection Added toggles for nudgeless lane changes, lane detection, and one lane change per signal activation with a lane change delay factor. --- common/params.cc | 4 +++ selfdrive/controls/lib/desire_helper.py | 31 ++++++++++++++++++ .../assets/toggle_icons/icon_lane.png | Bin 0 -> 18310 bytes .../frogpilot/functions/frogpilot_planner.py | 5 +++ selfdrive/frogpilot/ui/control_settings.cc | 23 ++++++++++++- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 selfdrive/frogpilot/assets/toggle_icons/icon_lane.png diff --git a/common/params.cc b/common/params.cc index fb132af..157ffda 100644 --- a/common/params.cc +++ b/common/params.cc @@ -258,6 +258,8 @@ std::unordered_map keys = { {"GoatScream", PERSISTENT}, {"GreenLightAlert", PERSISTENT}, {"HideSpeed", PERSISTENT}, + {"LaneChangeTime", PERSISTENT}, + {"LaneDetection", PERSISTENT}, {"LaneLinesWidth", PERSISTENT}, {"LateralTune", PERSISTENT}, {"LeadInfo", PERSISTENT}, @@ -282,7 +284,9 @@ std::unordered_map keys = { {"NNFFModelFuzzyMatch", PERSISTENT}, {"NNFFModelName", PERSISTENT}, {"NoLogging", PERSISTENT}, + {"NudgelessLaneChange", PERSISTENT}, {"OfflineMode", PERSISTENT}, + {"OneLaneChange", PERSISTENT}, {"PathEdgeWidth", PERSISTENT}, {"PathWidth", PERSISTENT}, {"RelaxedFollow", PERSISTENT}, diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py index 0dc991c..f6f6578 100644 --- a/selfdrive/controls/lib/desire_helper.py +++ b/selfdrive/controls/lib/desire_helper.py @@ -43,6 +43,11 @@ class DesireHelper: self.desire = log.LateralPlan.Desire.none # FrogPilot variables + self.lane_change_completed = False + + self.lane_change_wait_timer = 0 + self.lane_width_left = 0 + self.lane_width_right = 0 def update(self, carstate, modeldata, lateral_active, lane_change_prob, frogpilot_planner): v_ego = carstate.vEgo @@ -59,6 +64,20 @@ class DesireHelper: self.lane_width_left = 0 self.lane_width_right = 0 + # Calculate the desired lane width for nudgeless lane change with lane detection + if not (frogpilot_planner.lane_detection and one_blinker) or below_lane_change_speed or turning: + lane_available = True + else: + # Set the minimum lane threshold to 2.8 meters + min_lane_threshold = 2.8 + # Set the blinker index based on which signal is on + blinker_index = 0 if carstate.leftBlinker else 1 + current_lane = modeldata.laneLines[blinker_index + 1] + desired_lane = modeldata.laneLines[blinker_index if carstate.leftBlinker else blinker_index + 2] + road_edge = modeldata.roadEdges[blinker_index] + # Check if the lane width exceeds the threshold + lane_available = calculate_lane_width(desired_lane, current_lane, road_edge) >= min_lane_threshold + if not lateral_active or self.lane_change_timer > LANE_CHANGE_TIME_MAX: self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none @@ -67,6 +86,7 @@ class DesireHelper: if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed: 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: @@ -81,10 +101,18 @@ class DesireHelper: blindspot_detected = ((carstate.leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or (carstate.rightBlindspot and self.lane_change_direction == LaneChangeDirection.right)) + # Conduct a nudgeless lane change if all the conditions are true + self.lane_change_wait_timer += DT_MDL + if frogpilot_planner.nudgeless and lane_available and not self.lane_change_completed and self.lane_change_wait_timer >= frogpilot_planner.lane_change_delay: + torque_applied = True + self.lane_change_wait_timer = 0 + if not one_blinker or below_lane_change_speed: self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none elif torque_applied and not blindspot_detected: + # Set the "lane_change_completed" flag to prevent any more lane changes if the toggle is on + self.lane_change_completed = frogpilot_planner.one_lane_change self.lane_change_state = LaneChangeState.laneChangeStarting # LaneChangeState.laneChangeStarting @@ -115,6 +143,9 @@ class DesireHelper: self.prev_one_blinker = one_blinker + # Reset the flags + self.lane_change_completed &= one_blinker + self.desire = DESIRES[self.lane_change_direction][self.lane_change_state] # Send keep pulse once per second during LaneChangeStart.preLaneChange diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_lane.png b/selfdrive/frogpilot/assets/toggle_icons/icon_lane.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8e40aab515d565a21760149f0b5d71df13f53d GIT binary patch literal 18310 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[params.getInt("Model")]); addItem(modelSelectorButton); + } else if (param == "NudgelessLaneChange") { + FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(laneChangeKeys.find(key.c_str()) != laneChangeKeys.end()); + } + }); + toggle = laneChangeToggle; + } else if (param == "LaneChangeTime") { + std::map laneChangeTimeLabels; + for (int i = 0; i <= 10; ++i) { + laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, laneChangeTimeLabels, this, false); + } else { toggle = new ParamControl(param, title, desc, icon, this); } @@ -235,7 +256,7 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CESlowerLead", "CENavigation", "CEStopLights", "CESignal"}; fireTheBabysitterKeys = {"NoLogging", "MuteDM", "MuteDoor", "MuteOverheated", "MuteSeatbelt"}; - laneChangeKeys = {}; + laneChangeKeys = {"LaneChangeTime", "LaneDetection", "OneLaneChange"}; lateralTuneKeys = {"AverageCurvature", "NNFF"}; longitudinalTuneKeys = {"AccelerationProfile", "AggressiveAcceleration", "StoppingDistance"}; speedLimitControllerKeys = {};