mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-12 21:02:13 +08:00
BUTTON
This commit is contained in:
@@ -478,6 +478,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"RoadName", CLEAR_ON_MANAGER_START},
|
||||
{"RoadNameUI", PERSISTENT},
|
||||
{"RedPanda", PERSISTENT},
|
||||
{"RemapCancelToDistance", PERSISTENT},
|
||||
{"RemoteStartBootsComma", PERSISTENT},
|
||||
{"RotatingWheel", PERSISTENT},
|
||||
{"ScreenBrightness", PERSISTENT},
|
||||
|
||||
@@ -239,6 +239,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("FullMap", "0", 2, "0"),
|
||||
("GasRegenCmd", "1", 2, "0"),
|
||||
("GMPedalLongitudinal", "1", 2, "1"),
|
||||
("RemapCancelToDistance", "0", 2, "0"),
|
||||
("RedPanda", "0", 3, "0"),
|
||||
("RemoteStartBootsComma", "0", 3, "0"),
|
||||
("GithubSshKeys", "", 0, ""),
|
||||
@@ -828,6 +829,9 @@ class FrogPilotVariables:
|
||||
|
||||
toggle.red_panda = toggle.car_make == "gm" and (params.get_bool("RedPanda") if tuning_level >= level["RedPanda"] else default.get_bool("RedPanda"))
|
||||
toggle.remote_start_boots_comma = toggle.car_make == "gm" and (params.get_bool("RemoteStartBootsComma") if tuning_level >= level["RemoteStartBootsComma"] else default.get_bool("RemoteStartBootsComma"))
|
||||
toggle.remap_cancel_to_distance = toggle.car_make == "gm" and toggle.openpilot_longitudinal and (
|
||||
params.get_bool("RemapCancelToDistance") if tuning_level >= level["RemapCancelToDistance"] else default.get_bool("RemapCancelToDistance")
|
||||
)
|
||||
|
||||
toggle.force_fingerprint = (params.get_bool("ForceFingerprint") if tuning_level >= level["ForceFingerprint"] else default.get_bool("ForceFingerprint")) and toggle.car_model is not None
|
||||
|
||||
|
||||
@@ -171,6 +171,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
|
||||
{"GMToggles", tr("General Motors Settings"), tr("<b>FrogPilot features for General Motors vehicles.</b>"), ""},
|
||||
{"GMPedalLongitudinal", tr("Use Pedal for Longitudinal Control"), tr("<b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available."), ""},
|
||||
{"RemapCancelToDistance", tr("Remap cancel to distance"), tr("<b>Treat CANCEL as distance-button input</b> on supported pedal-long GM platforms. Toggle requires a reboot to take effect."), ""},
|
||||
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
|
||||
{"RedPanda", tr("Red Panda"), tr("<b>Enable Red Panda behavior</b> for GM (alternate safety config and bus numbering). Requires a reboot to take effect."), ""},
|
||||
{"RemoteStartBootsComma", tr("Remote Start Boots Comma"), tr("<b>Use GM C9 SystemPowerMode</b> for ignition detection. Toggle requires a panda firmware update and a reboot to take effect."), ""},
|
||||
@@ -287,7 +288,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
|
||||
static_cast<FrogPilotParamValueControl*>(toggles["LockDoorsTimer"])->setWarning("<b>Warning:</b> openpilot can't detect if keys are still inside the car, so ensure you have a spare key to prevent accidental lockouts!");
|
||||
|
||||
QSet<QString> rebootKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
QSet<QString> rebootKeys = {"NewLongAPI", "RemapCancelToDistance", "TacoTuneHacks"};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(static_cast<ToggleControl*>(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) {
|
||||
if (started) {
|
||||
@@ -430,7 +431,7 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
||||
setVisible &= isHKGCanFd;
|
||||
}
|
||||
|
||||
else if (key == "GMPedalLongitudinal") {
|
||||
else if (key == "GMPedalLongitudinal" || key == "RemapCancelToDistance") {
|
||||
setVisible &= hasPedal;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
QSet<QString> gmKeys = {"GMPedalLongitudinal", "LongPitch", "RedPanda", "RemoteStartBootsComma", "VoltSNG"};
|
||||
QSet<QString> gmKeys = {"GMPedalLongitudinal", "LongPitch", "RedPanda", "RemapCancelToDistance", "RemoteStartBootsComma", "VoltSNG"};
|
||||
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
|
||||
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
|
||||
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
|
||||
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SASCMSupport", "SDSUSupport", "SNGSupport"};
|
||||
|
||||
|
||||
@@ -263,9 +263,13 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
|
||||
// ACC steering wheel buttons (GM_CAM is tied to the PCM)
|
||||
if ((addr == 0x1E1) && (!gm_pcm_cruise || gm_cc_long)) {
|
||||
int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4;
|
||||
bool remap_cancel_to_distance = (alternative_experience & ALT_EXP_GM_REMAP_CANCEL_TO_DISTANCE) != 0;
|
||||
// Malibu Hybrid pedal-long observed format uses byte3 bit0 set (typically 0x01/0x41) on ASCMSteeringButton.
|
||||
// Don't treat that physical CANCEL frame as OP disengage.
|
||||
bool malibu_cancel_passthrough = gm_bolt_2022_pedal && gm_pedal_long && ((GET_BYTE(to_push, 3) & 0x1U) != 0U);
|
||||
bool malibu_cancel_passthrough = remap_cancel_to_distance && gm_bolt_2022_pedal && gm_pedal_long && ((GET_BYTE(to_push, 3) & 0x1U) != 0U);
|
||||
// Gen1 Bolt pedal-long behavior: let wheel CANCEL act as an in-drive aux button (personality cycling),
|
||||
// so safety should not force a controls drop on this RX cancel edge.
|
||||
bool bolt_cancel_passthrough = remap_cancel_to_distance && gm_pedal_long && !gm_has_acc && !gm_bolt_2022_pedal;
|
||||
|
||||
// enter controls on falling edge of set or rising edge of resume (avoids fault)
|
||||
bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET);
|
||||
@@ -275,7 +279,7 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
|
||||
}
|
||||
|
||||
// exit controls on cancel press
|
||||
if ((button == GM_BTN_CANCEL) && !malibu_cancel_passthrough) {
|
||||
if ((button == GM_BTN_CANCEL) && !(malibu_cancel_passthrough || bolt_cancel_passthrough)) {
|
||||
controls_allowed = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -275,3 +275,6 @@ const uint32_t RELAY_TRNS_TIMEOUT = 1U;
|
||||
|
||||
// Always on Lateral
|
||||
#define ALT_EXP_ALWAYS_ON_LATERAL 32
|
||||
|
||||
// GM pedal-long option: interpret wheel CANCEL as an auxiliary distance-style button.
|
||||
#define ALT_EXP_GM_REMAP_CANCEL_TO_DISTANCE 64
|
||||
|
||||
@@ -112,6 +112,7 @@ class ALTERNATIVE_EXPERIENCE:
|
||||
RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX = 8
|
||||
ALLOW_AEB = 16
|
||||
ALWAYS_ON_LATERAL = 32
|
||||
GM_REMAP_CANCEL_TO_DISTANCE = 64
|
||||
|
||||
class Panda:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
from panda import Panda
|
||||
from panda import ALTERNATIVE_EXPERIENCE, Panda
|
||||
from panda.tests.libpanda import libpanda_py
|
||||
import panda.tests.safety.common as common
|
||||
from panda.tests.safety.common import CANPackerPanda
|
||||
@@ -344,6 +344,13 @@ class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafet
|
||||
self._rx(_acc_pcm_msg(False))
|
||||
self.assertEqual(enable, self.safety.get_controls_allowed())
|
||||
|
||||
def test_cancel_button_passthrough(self):
|
||||
# Gen1 Bolt-style pedal-long path: wheel cancel shouldn't force controls off.
|
||||
self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE)
|
||||
self.safety.set_controls_allowed(1)
|
||||
self._rx(self._button_msg(Buttons.CANCEL))
|
||||
self.assertTrue(self.safety.get_controls_allowed())
|
||||
|
||||
def test_buttons(self):
|
||||
self._rx(self._interceptor_user_gas(0))
|
||||
# Only CANCEL button is allowed while cruise is enabled
|
||||
|
||||
@@ -56,8 +56,9 @@ class Car:
|
||||
|
||||
# set alternative experiences from parameters
|
||||
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
||||
self.CP.alternativeExperience = 0
|
||||
if not self.disengage_on_accelerator:
|
||||
if self.disengage_on_accelerator:
|
||||
self.CP.alternativeExperience &= ~ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
else:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
|
||||
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from cereal import car, custom
|
||||
from math import fabs, exp
|
||||
import numpy as np
|
||||
from panda import Panda
|
||||
from panda import ALTERNATIVE_EXPERIENCE, Panda
|
||||
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import interp
|
||||
@@ -48,6 +48,13 @@ BOLT_PEDAL_LONG_CARS = {
|
||||
CAR.CHEVROLET_MALIBU_HYBRID_CC,
|
||||
}
|
||||
|
||||
# Cancel-to-personality mapping target: gen1 Bolt pedal-long paths only.
|
||||
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
|
||||
CAR.CHEVROLET_BOLT_CC_2017,
|
||||
CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
}
|
||||
CANCEL_REMAP_DISTANCE_CARS = BOLT_GEN1_CANCEL_PERSONALITY_CARS | {CAR.CHEVROLET_MALIBU_HYBRID_CC}
|
||||
|
||||
NON_LINEAR_TORQUE_PARAMS = {
|
||||
CAR.CHEVROLET_BOLT_ACC_2022_2023: {
|
||||
"left": [2.6531724862969748, 1.1, 0.1919764879840985, 0.0],
|
||||
@@ -602,29 +609,76 @@ class CarInterface(CarInterfaceBase):
|
||||
if use_panda_paddle_sched:
|
||||
gm_safety_cfg.safetyParam |= Panda.FLAG_GM_PANDA_PADDLE_SCHED
|
||||
|
||||
remap_cancel_to_distance = (
|
||||
getattr(frogpilot_toggles, "remap_cancel_to_distance", False) and
|
||||
ret.openpilotLongitudinalControl and
|
||||
bool(ret.flags & GMFlags.PEDAL_LONG.value) and
|
||||
candidate in CANCEL_REMAP_DISTANCE_CARS
|
||||
)
|
||||
if remap_cancel_to_distance:
|
||||
ret.alternativeExperience |= ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
|
||||
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c, frogpilot_toggles):
|
||||
ret, fp_ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback, frogpilot_toggles)
|
||||
|
||||
remap_cancel_to_distance = bool(self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE)
|
||||
malibu_cancel_passthrough = (
|
||||
remap_cancel_to_distance and
|
||||
self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC and
|
||||
self.CP.openpilotLongitudinalControl
|
||||
)
|
||||
bolt_cancel_personality = (
|
||||
remap_cancel_to_distance and
|
||||
self.CP.carFingerprint in BOLT_GEN1_CANCEL_PERSONALITY_CARS and
|
||||
self.CP.openpilotLongitudinalControl and
|
||||
bool(self.CP.flags & GMFlags.PEDAL_LONG.value)
|
||||
)
|
||||
|
||||
# Don't add event if transitioning from INIT, unless it's to an actual button
|
||||
cruise_button_map = BUTTONS_DICT
|
||||
if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC and self.CP.openpilotLongitudinalControl:
|
||||
# Malibu Hybrid only: keep all wheel-button functionality, but don't map CANCEL
|
||||
# to ButtonType.cancel so OP long isn't disengaged by the physical cancel button.
|
||||
if malibu_cancel_passthrough:
|
||||
# Keep pedal-long cancel presses from creating a buttonCancel disengage event.
|
||||
cruise_button_map = {k: v for k, v in BUTTONS_DICT.items() if k != CruiseButtons.CANCEL}
|
||||
elif bolt_cancel_personality:
|
||||
# Keep pedal-long cancel presses from creating a buttonCancel disengage event.
|
||||
cruise_button_map = {k: v for k, v in BUTTONS_DICT.items() if k != CruiseButtons.CANCEL}
|
||||
|
||||
cruise_events = create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, cruise_button_map,
|
||||
unpressed_btn=CruiseButtons.UNPRESS)
|
||||
cancel_gap_events = []
|
||||
if bolt_cancel_personality:
|
||||
# Gen1 Bolt pedal-long: treat CANCEL as a distance-style button for personality cycling.
|
||||
cancel_gap_events = create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons,
|
||||
{CruiseButtons.CANCEL: ButtonType.gapAdjustCruise},
|
||||
unpressed_btn=CruiseButtons.UNPRESS)
|
||||
|
||||
# Malibu pedal-long cancel can alias wheel-button bits on 0x1E1; ignore those side effects.
|
||||
suppress_malibu_side_buttons = malibu_cancel_passthrough and (
|
||||
self.CS.cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN) or
|
||||
self.CS.prev_cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN)
|
||||
)
|
||||
distance_events = [] if suppress_malibu_side_buttons else create_button_events(
|
||||
self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise}
|
||||
)
|
||||
lkas_events = [] if suppress_malibu_side_buttons else create_button_events(
|
||||
self.CS.lkas_enabled, self.CS.lkas_previously_enabled, {1: FrogPilotButtonType.lkas}
|
||||
)
|
||||
|
||||
if self.CS.cruise_buttons != CruiseButtons.UNPRESS or self.CS.prev_cruise_buttons != CruiseButtons.INIT:
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, cruise_button_map,
|
||||
unpressed_btn=CruiseButtons.UNPRESS),
|
||||
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button,
|
||||
{1: ButtonType.gapAdjustCruise}),
|
||||
*create_button_events(self.CS.lkas_enabled, self.CS.lkas_previously_enabled,
|
||||
{1: FrogPilotButtonType.lkas}),
|
||||
*cruise_events,
|
||||
*cancel_gap_events,
|
||||
*distance_events,
|
||||
*lkas_events,
|
||||
]
|
||||
|
||||
if bolt_cancel_personality and self.CS.cruise_buttons == CruiseButtons.CANCEL:
|
||||
# Feed long-press logic (traffic mode, etc.) as if distance button is being held.
|
||||
fp_ret.distancePressed = True
|
||||
|
||||
# The ECM allows enabling on falling edge of set, but only rising edge of resume
|
||||
events = self.create_common_events(ret, extra_gears=[GearShifter.sport, GearShifter.low,
|
||||
GearShifter.eco, GearShifter.manumatic],
|
||||
|
||||
@@ -9,6 +9,7 @@ from typing import SupportsFloat
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, custom, log
|
||||
from panda import ALTERNATIVE_EXPERIENCE
|
||||
from msgq.visionipc import VisionIpcClient, VisionStreamType
|
||||
|
||||
|
||||
@@ -20,7 +21,7 @@ from openpilot.common.realtime import config_realtime_process, Priority, Ratekee
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event
|
||||
from openpilot.selfdrive.car.gm.values import CC_ONLY_CAR, GMFlags
|
||||
from openpilot.selfdrive.car.gm.values import CAR, CC_ONLY_CAR, GMFlags
|
||||
from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature
|
||||
from openpilot.selfdrive.controls.lib.events import Events, ET
|
||||
@@ -64,6 +65,10 @@ CSID_MAP = {"1": EventName.roadCameraError, "2": EventName.wideRoadCameraError,
|
||||
ACTUATOR_FIELDS = tuple(car.CarControl.Actuators.schema.fields.keys())
|
||||
ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding)
|
||||
ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES)
|
||||
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
|
||||
CAR.CHEVROLET_BOLT_CC_2017,
|
||||
CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
}
|
||||
|
||||
|
||||
class Controls:
|
||||
@@ -773,10 +778,19 @@ class Controls:
|
||||
# decrement personality on distance button press
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
distance_pressed = params_memory.get_bool("OnroadDistanceButtonPressed")
|
||||
bolt_cancel_personality = (
|
||||
self.CP.carName == "gm" and
|
||||
bool(self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE) and
|
||||
bool(self.CP.flags & GMFlags.PEDAL_LONG.value) and
|
||||
self.CP.carFingerprint in BOLT_GEN1_CANCEL_PERSONALITY_CARS
|
||||
)
|
||||
|
||||
if self.frogpilot_toggles.personality_profile_via_distance:
|
||||
distance_pressed |= any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents)
|
||||
distance_pressed &= not (self.sm['frogpilotCarState'].distanceLongPressed or self.sm['frogpilotCarState'].distanceVeryLongPressed)
|
||||
elif bolt_cancel_personality:
|
||||
distance_pressed |= any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents)
|
||||
distance_pressed &= not (self.sm['frogpilotCarState'].distanceLongPressed or self.sm['frogpilotCarState'].distanceVeryLongPressed)
|
||||
if self.frogpilot_toggles.personality_profile_via_distance_long:
|
||||
distance_pressed |= self.sm['frogpilotCarState'].distanceLongPressed
|
||||
if self.frogpilot_toggles.personality_profile_via_distance_very_long:
|
||||
|
||||
Reference in New Issue
Block a user