mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 07:43:48 +08:00
yaas
This commit is contained in:
@@ -412,6 +412,10 @@ def preserve_stock_canfd_lfa_status(car_fingerprint) -> bool:
|
||||
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
|
||||
|
||||
|
||||
def preserve_stock_canfd_lkas_status(car_fingerprint) -> bool:
|
||||
return car_fingerprint not in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN)
|
||||
|
||||
|
||||
def suppress_redundant_gv70_brake_cancel(CP, brake_pressed: bool, lat_active: bool) -> bool:
|
||||
return bool(
|
||||
CP.carFingerprint == CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and
|
||||
@@ -806,7 +810,8 @@ class CarController(CarControllerBase):
|
||||
# payload. Forwarding its stock status bits leaves lane-safety state asserted
|
||||
# while StarPilot is suppressing the stock LFA path.
|
||||
preserve_stock_lkas = bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING) and \
|
||||
not self.long_active_ecu and self.CP.carFingerprint != CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN
|
||||
not self.long_active_ecu and self.CP.carFingerprint != CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN and \
|
||||
preserve_stock_canfd_lkas_status(self.CP.carFingerprint)
|
||||
angle_lkas_alt = bool(self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING and
|
||||
self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR and \
|
||||
|
||||
@@ -183,6 +183,8 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
else:
|
||||
lkas_values = copy.copy(control_values)
|
||||
lkas_values["LKA_AVAILABLE"] = 0
|
||||
if CP.carFingerprint in (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN):
|
||||
lkas_values["DAMP_FACTOR"] = 100
|
||||
|
||||
if lfa_base_values:
|
||||
# Preserve stock UI/status fields and only override the actuation-relevant signals.
|
||||
|
||||
@@ -19,6 +19,7 @@ from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalT
|
||||
should_use_ev6_gt_line_stop_direct_tracking, \
|
||||
should_track_stop_accel_directly_for_car, \
|
||||
preserve_stock_canfd_lfa_status, \
|
||||
preserve_stock_canfd_lkas_status, \
|
||||
suppress_redundant_gv70_brake_cancel
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state, \
|
||||
get_canfd_cruise_available
|
||||
@@ -128,7 +129,9 @@ class TestHyundaiFingerprint:
|
||||
@pytest.mark.parametrize("candidate", (CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN))
|
||||
def test_carnival_uses_clean_canfd_lfa_status(self, candidate):
|
||||
assert not preserve_stock_canfd_lfa_status(candidate)
|
||||
assert not preserve_stock_canfd_lkas_status(candidate)
|
||||
assert preserve_stock_canfd_lfa_status(CAR.HYUNDAI_IONIQ_6)
|
||||
assert preserve_stock_canfd_lkas_status(CAR.HYUNDAI_IONIQ_6)
|
||||
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = candidate
|
||||
@@ -154,6 +157,56 @@ class TestHyundaiFingerprint:
|
||||
active_cluster_msg = hyundaicanfd.create_lfahda_cluster(packer, can_bus, True, None, lfa_icon=2)
|
||||
assert active_cluster_msg[1] == bytes.fromhex("cdfb0180000001000000000000000000")
|
||||
|
||||
@pytest.mark.parametrize("candidate", (CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN))
|
||||
def test_carnival_hda2_clears_stock_lkas_warning_status(self, candidate):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = candidate
|
||||
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CCNC | HyundaiFlags.CANFD_LKA_STEERING |
|
||||
HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
CP.openpilotLongitudinalControl = False
|
||||
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
controller.frame = 1
|
||||
can_bus = CanBus(CP)
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("LKAS_ALT", 0)], can_bus.ACAN)
|
||||
stock_lkas = {
|
||||
"CHECKSUM": 1234,
|
||||
"COUNTER": 42,
|
||||
"LKA_MODE": 0,
|
||||
"LKA_AVAILABLE": 0,
|
||||
"LKA_WARNING": 0,
|
||||
"LKA_ICON": 0,
|
||||
"FCA_SYSWARN": 1,
|
||||
"TORQUE_REQUEST": 0,
|
||||
"STEER_REQ": 0,
|
||||
"LFA_BUTTON": 0,
|
||||
"LKA_ASSIST": 1,
|
||||
"STEER_MODE": 2,
|
||||
"NEW_SIGNAL_2": 3,
|
||||
"HAS_LANE_SAFETY": 0,
|
||||
"DAMP_FACTOR": 100,
|
||||
}
|
||||
cc = SimpleNamespace(enabled=False, latActive=True,
|
||||
actuators=SimpleNamespace(longControlState=LongCtrlState.off),
|
||||
leftBlinker=False, rightBlinker=False,
|
||||
hudControl=SimpleNamespace())
|
||||
cs = SimpleNamespace(stock_lfa_msg=None, stock_lkas_msg=stock_lkas,
|
||||
out=SimpleNamespace(standstill=False, steeringAngleDeg=0.0,
|
||||
gearShifter=structs.CarState.GearShifter.drive))
|
||||
|
||||
msgs = controller.create_canfd_msgs(0, True, 123, 0.0, 0.0, 0.0, False,
|
||||
cc.hudControl, cs, cc, get_test_toggles(), lka_icon=2, lfa_icon=2)
|
||||
lkas_msgs = [msg for msg in msgs if msg[0] == 0x110]
|
||||
assert len(lkas_msgs) == 1
|
||||
|
||||
parser.update([(1, lkas_msgs)])
|
||||
assert parser.can_valid
|
||||
assert parser.vl["LKAS_ALT"]["FCA_SYSWARN"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["LKA_ASSIST"] == 0
|
||||
assert parser.vl["LKAS_ALT"]["DAMP_FACTOR"] == 100
|
||||
assert parser.vl["LKAS_ALT"]["TORQUE_REQUEST"] == 123
|
||||
assert parser.vl["LKAS_ALT"]["STEER_REQ"] == 1
|
||||
|
||||
def test_canfd_torque_bsm_parser_registers_rear_blindspots(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.GENESIS_GV70_ELECTRIFIED_1ST_GEN
|
||||
|
||||
@@ -111,6 +111,7 @@ class Soundd:
|
||||
self.openpilot_crashed_played = False
|
||||
|
||||
self.auto_volume = 0
|
||||
self.pending_stream_status = None
|
||||
|
||||
self.previous_sound_pack = None
|
||||
self.previous_sound_source_signature = None
|
||||
@@ -193,7 +194,7 @@ class Soundd:
|
||||
|
||||
def callback(self, data_out: np.ndarray, frames: int, time, status) -> None:
|
||||
if status:
|
||||
cloudlog.warning(f"soundd stream over/underflow: {status}")
|
||||
self.pending_stream_status = status
|
||||
data_out[:frames, 0] = self.get_sound_data(frames)
|
||||
|
||||
def update_alert(self, new_alert):
|
||||
@@ -256,9 +257,6 @@ class Soundd:
|
||||
|
||||
@retry(attempts=10, delay=3)
|
||||
def get_stream(self, sd):
|
||||
# reload sounddevice to reinitialize portaudio
|
||||
sd._terminate()
|
||||
sd._initialize()
|
||||
return sd.OutputStream(channels=1, samplerate=SAMPLE_RATE, callback=self.callback, blocksize=SAMPLE_BUFFER)
|
||||
|
||||
def start_stream(self, sd):
|
||||
@@ -297,6 +295,11 @@ class Soundd:
|
||||
while True:
|
||||
sm.update(0)
|
||||
|
||||
if self.pending_stream_status is not None:
|
||||
status = self.pending_stream_status
|
||||
self.pending_stream_status = None
|
||||
cloudlog.warning(f"soundd stream over/underflow: {status}")
|
||||
|
||||
if sm.updated['soundPressure'] and self.current_alert == AudibleAlert.none: # only update volume filter when not playing alert
|
||||
self.spl_filter_weighted.update(sm["soundPressure"].soundPressureWeightedDb)
|
||||
self.current_volume = self.calculate_volume(float(self.spl_filter_weighted.x))
|
||||
|
||||
@@ -30,17 +30,20 @@ def _online_cpu_count() -> int | None:
|
||||
return None
|
||||
|
||||
|
||||
def _online_cpu_usage(cpu_usage) -> list[float]:
|
||||
def _online_cpu_usage(cpu_usage, cores=None) -> list[float]:
|
||||
usage = [float(value) for value in cpu_usage]
|
||||
online_count = _online_cpu_count()
|
||||
if online_count is not None and online_count < len(usage):
|
||||
return usage[:online_count]
|
||||
usage = usage[:online_count]
|
||||
|
||||
if cores is not None:
|
||||
usage = [usage[core] for core in cores if 0 <= core < len(usage)]
|
||||
return usage
|
||||
|
||||
|
||||
def device_cpu_throttle_factor(cpu_usage, name="vision"):
|
||||
def device_cpu_throttle_factor(cpu_usage, name="vision", cores=None):
|
||||
"""Return a process-local, low-pass-filtered CPU throttle factor."""
|
||||
usage = _online_cpu_usage(cpu_usage)
|
||||
usage = _online_cpu_usage(cpu_usage, cores=cores)
|
||||
if not usage:
|
||||
return 1.0
|
||||
|
||||
|
||||
@@ -13,6 +13,15 @@ def test_offline_cpu_placeholders_do_not_hide_sustained_load(monkeypatch):
|
||||
assert cpu_throttle._compute_throttle_factor(average, 0) == pytest.approx(1.75)
|
||||
|
||||
|
||||
def test_idle_reserved_cores_do_not_hide_affinity_core_saturation(monkeypatch):
|
||||
monkeypatch.setattr(cpu_throttle, "_online_cpu_count", lambda: 8)
|
||||
|
||||
usage = cpu_throttle._online_cpu_usage([74, 82, 100, 85, 92, 98, 0, 47], cores=[2])
|
||||
|
||||
assert usage == [100.0]
|
||||
assert cpu_throttle._compute_throttle_factor(sum(usage) / len(usage), 1) == 4.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("online_spec", "expected"), (
|
||||
("0-3", 4),
|
||||
("0-3,6-7", 6),
|
||||
|
||||
@@ -151,7 +151,8 @@ class VASMDaemon:
|
||||
in_followup = now < self.followup_until
|
||||
base = FOLLOWUP_INTERVAL if in_followup else BASE_INTERVAL
|
||||
cpu_usage = list(self.sm["deviceState"].cpuUsagePercent) if self.sm.valid.get("deviceState", False) else []
|
||||
factor = device_cpu_throttle_factor(cpu_usage, name="VASM")
|
||||
affinity_cores = V_ASM_AFFINITY_CORES if self._slv_enabled else V_ASM_SOLO_AFFINITY_CORES
|
||||
factor = device_cpu_throttle_factor(cpu_usage, name="VASM", cores=affinity_cores)
|
||||
self._throttle_factor = factor
|
||||
interval = base * factor
|
||||
self._throttle_reason = f"cpu_{factor:.1f}x" if factor > 1.05 else ("followup" if in_followup else "steady")
|
||||
|
||||
@@ -997,7 +997,7 @@ class SpeedLimitVisionDaemon:
|
||||
|
||||
if self.coexistence_mode:
|
||||
cpu_usage = list(self.sm["deviceState"].cpuUsagePercent) if self.sm is not None and self.sm.valid.get("deviceState", False) else []
|
||||
factor = device_cpu_throttle_factor(cpu_usage, name="SpeedLimit")
|
||||
factor = device_cpu_throttle_factor(cpu_usage, name="SpeedLimit", cores=SPEED_LIMIT_VISION_COEXISTENCE_AFFINITY_CORES)
|
||||
if factor > 1.05:
|
||||
self.last_cpu_busy = True
|
||||
interval *= factor
|
||||
@@ -1348,7 +1348,7 @@ class SpeedLimitVisionDaemon:
|
||||
return max(interval, MEMORY_PRESSURE_CLASSIFICATION_INTERVAL)
|
||||
if self.coexistence_mode:
|
||||
cpu_usage = list(self.sm["deviceState"].cpuUsagePercent) if self.sm is not None and self.sm.valid.get("deviceState", False) else []
|
||||
if device_cpu_throttle_factor(cpu_usage, name="SpeedLimit") > 1.05:
|
||||
if device_cpu_throttle_factor(cpu_usage, name="SpeedLimit", cores=SPEED_LIMIT_VISION_COEXISTENCE_AFFINITY_CORES) > 1.05:
|
||||
return max(interval, TRACK_BUSY_CLASSIFICATION_INTERVAL)
|
||||
elif self._device_cpu_busy():
|
||||
return max(interval, TRACK_BUSY_CLASSIFICATION_INTERVAL)
|
||||
|
||||
@@ -97,9 +97,6 @@ class Mic:
|
||||
|
||||
@retry(attempts=10, delay=3)
|
||||
def get_stream(self, sd, device=None):
|
||||
# reload sounddevice to reinitialize portaudio
|
||||
sd._terminate()
|
||||
sd._initialize()
|
||||
kwargs = {
|
||||
"channels": 1,
|
||||
"samplerate": SAMPLE_RATE,
|
||||
|
||||
Reference in New Issue
Block a user