mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-06 20:43:46 +08:00
RAV4 torque tuning
This commit is contained in:
@@ -74,6 +74,11 @@ class LatControlTorque(LatControl):
|
||||
if self.starpilot_extension is not None:
|
||||
return self.starpilot_extension.update(active, CS, VM, params, steer_limited_by_safety,
|
||||
desired_curvature, curvature_limited, lat_delay)
|
||||
return self.update_standard(active, CS, VM, params, steer_limited_by_safety,
|
||||
desired_curvature, curvature_limited, lat_delay)
|
||||
|
||||
def update_standard(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, lat_delay,
|
||||
*, friction_policy=None):
|
||||
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
||||
pid_log.version = VERSION
|
||||
measured_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||
@@ -99,6 +104,8 @@ class LatControlTorque(LatControl):
|
||||
ff -= self.torque_params.latAccelOffset
|
||||
threshold = flm.base_threshold(self.flm_surface, CS.vEgo, FRICTION_THRESHOLD)
|
||||
ff, threshold = flm.stages(self.flm_surface, CS, setpoint, desired_lateral_jerk, ff, threshold)
|
||||
if friction_policy is not None:
|
||||
threshold = friction_policy.friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
|
||||
ff += get_friction(error + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone, threshold, self.torque_params)
|
||||
|
||||
if not active:
|
||||
@@ -115,6 +122,9 @@ class LatControlTorque(LatControl):
|
||||
output_torque = apply_turn_assist(self, CS, VM, params, desired_curvature, output_torque)
|
||||
output_torque = flm.angle_assist(self.flm_surface, CS, VM, params, desired_curvature, setpoint, desired_lateral_jerk, output_torque)
|
||||
|
||||
if friction_policy is not None:
|
||||
output_torque *= friction_policy.output_scale(setpoint, CS.vEgo)
|
||||
|
||||
pid_log.active = True
|
||||
pid_log.p = float(self.pid.p)
|
||||
pid_log.i = float(self.pid.i)
|
||||
|
||||
@@ -16,7 +16,7 @@ DOCUMENT_VERSION = 1
|
||||
LEARNING_OFF_KEY = 'ForceAutoTuneOff'
|
||||
MAX_DOCUMENT_BYTES = 4096
|
||||
KNOWN_POLICIES = {'HYUNDAI_IONIQ_6': 'hyundai', 'GENESIS_G70_2020': 'hyundai', 'GENESIS_GV70_ELECTRIFIED_1ST_GEN': 'hyundai', 'TOYOTA_COROLLA_TSS2': 'toyota'}
|
||||
KNOWN_POLICIES.update({'HYUNDAI_SONATA_HYBRID': 'hyundai'})
|
||||
KNOWN_POLICIES.update({'HYUNDAI_SONATA_HYBRID': 'hyundai', 'TOYOTA_RAV4_TSS2': 'toyota'})
|
||||
KNOWN_POLICIES.update(dict.fromkeys(('HYUNDAI_PALISADE', 'HYUNDAI_PALISADE_2023'), 'hyundai'))
|
||||
KNOWN_POLICIES.update(dict.fromkeys((
|
||||
'CHEVROLET_BOLT_CC_2017', 'CHEVROLET_BOLT_CC_2018_2021', 'CHEVROLET_BOLT_CC_2022_2023',
|
||||
@@ -116,6 +116,9 @@ def policy_for(CP) -> str | None:
|
||||
return 'bolt'
|
||||
if corolla_supported(CP):
|
||||
return 'corolla_tss2'
|
||||
from openpilot.starpilot.lateral.rav4_tss2_policy import supported_cp as rav4_supported
|
||||
if rav4_supported(CP):
|
||||
return 'rav4_tss2'
|
||||
from openpilot.starpilot.lateral.palisade_policy import supported_cp as palisade_supported
|
||||
from openpilot.starpilot.lateral.sonata_hybrid_policy import supported_cp as sonata_hybrid_supported
|
||||
if sonata_hybrid_supported(CP):
|
||||
@@ -223,6 +226,11 @@ def read_selection(params, CP) -> ControllerSelection:
|
||||
return ControllerSelection(default.mode, default.policy, 'invalid')
|
||||
|
||||
|
||||
def controller_uses_native_learning(selection: ControllerSelection) -> bool:
|
||||
# RAV4 adds only two shaping stages to the modern native controller.
|
||||
return selection.mode == ControllerMode.STANDARD or selection.policy == "rav4_tss2"
|
||||
|
||||
|
||||
def learning_allowed(params, CP, *, selection: ControllerSelection | None = None) -> bool:
|
||||
"""Latch the exact controller's learning policy at each process startup.
|
||||
|
||||
@@ -241,4 +249,4 @@ def learning_allowed(params, CP, *, selection: ControllerSelection | None = None
|
||||
return False
|
||||
if geometry.force_auto:
|
||||
return selected.source != 'invalid'
|
||||
return selected.mode != ControllerMode.STARPILOT
|
||||
return controller_uses_native_learning(selected) and (selected.policy != "rav4_tss2" or selected.source != "invalid")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""RAV4 TSS2 friction/taper stages on the modern torque controller."""
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.toyota.values import CAR
|
||||
from openpilot.starpilot.lateral.torque_shaping import get_standard_friction_threshold, sigmoid
|
||||
|
||||
|
||||
def supported_cp(cp):
|
||||
if (cp.brand != "toyota" or cp.carFingerprint != CAR.TOYOTA_RAV4_TSS2 or cp.notCar or cp.passive or cp.dashcamOnly or
|
||||
cp.steerControlType != structs.CarParams.SteerControlType.torque or cp.lateralTuning.which() != "torque"):
|
||||
return False
|
||||
tune = cp.lateralTuning.torque
|
||||
return (math.isfinite(tune.latAccelFactor) and tune.latAccelFactor > 0 and
|
||||
math.isfinite(tune.latAccelOffset) and math.isfinite(tune.friction) and tune.friction >= 0)
|
||||
|
||||
|
||||
def center_envelope(setpoint, speed):
|
||||
return sigmoid((13.0 - max(speed, 0.0)) / 3.0) * sigmoid((0.30 - abs(setpoint)) / 0.08)
|
||||
|
||||
|
||||
def friction_threshold(speed, setpoint, jerk):
|
||||
base = get_standard_friction_threshold(speed) * (1.0 + .14 * center_envelope(setpoint, speed))
|
||||
curve = float(np.interp(abs(setpoint), [.30, .85], [1.0, 0.0]))
|
||||
calm = float(np.interp(abs(jerk), [.25, .75], [1.0, 0.0]))
|
||||
increment = float(np.interp(max(speed, 0.0), [0., 2.5, 5., 10., 15., 25.], [0., 0., .04, .065, .05, .025]))
|
||||
return base + increment * curve * calm
|
||||
|
||||
|
||||
def center_output_scale(setpoint, speed):
|
||||
return 1.0 - .12 * center_envelope(setpoint, speed)
|
||||
|
||||
|
||||
class Rav4TSS2TorquePolicy:
|
||||
def __init__(self, parent, cp):
|
||||
if not supported_cp(cp):
|
||||
raise ValueError("Unsupported RAV4 TSS2 torque profile")
|
||||
self.parent = parent
|
||||
|
||||
friction_threshold = staticmethod(friction_threshold)
|
||||
output_scale = staticmethod(center_output_scale)
|
||||
|
||||
def update(self, active, cs, vm, params, safety_limited, curvature, curvature_limited, delay):
|
||||
return self.parent.update_standard(active, cs, vm, params, safety_limited, curvature, curvature_limited, delay,
|
||||
friction_policy=self)
|
||||
@@ -55,7 +55,7 @@ class TestControllerSelection(unittest.TestCase):
|
||||
(TOYOTA.TOYOTA_COROLLA_TSS2, 'corolla_tss2'),
|
||||
(HYUNDAI.KIA_EV6, 'kia_ev6'),
|
||||
(HYUNDAI.HYUNDAI_SONATA, 'sonata'),
|
||||
(TOYOTA.TOYOTA_RAV4_TSS2, None))
|
||||
(TOYOTA.TOYOTA_RAV4_TSS2, 'rav4_tss2'))
|
||||
for vehicle, policy in expected:
|
||||
with self.subTest(vehicle=vehicle):
|
||||
cp = cp_for(vehicle)
|
||||
@@ -96,8 +96,8 @@ class TestControllerSelection(unittest.TestCase):
|
||||
wrong.notCar = True
|
||||
self.assertIsNone(policy_for(wrong))
|
||||
with self.assertRaises(ValueError):
|
||||
unsupported = cp_for(TOYOTA.TOYOTA_RAV4_TSS2)
|
||||
LatControlTorque(unsupported.as_reader(), interfaces[TOYOTA.TOYOTA_RAV4_TSS2](unsupported), DT_CTRL,
|
||||
unsupported = cp_for(TOYOTA.TOYOTA_RAV4_TSS2_2022)
|
||||
LatControlTorque(unsupported.as_reader(), interfaces[TOYOTA.TOYOTA_RAV4_TSS2_2022](unsupported), DT_CTRL,
|
||||
controller_mode=ControllerMode.STARPILOT)
|
||||
|
||||
def test_standard_skips_policy_constructor_and_ioniq_factor_multiplier(self):
|
||||
|
||||
@@ -57,7 +57,7 @@ def test_exact_vehicle_admission_and_upstream_gains():
|
||||
assert native.pid._k_i[1] == [0.15]
|
||||
other_cp, other, _ = controller_for(CAR.TOYOTA_RAV4_TSS2)
|
||||
assert not supported_cp(other_cp)
|
||||
assert selected_policy(other) is None
|
||||
assert type(selected_policy(other)).__name__ == "Rav4TSS2TorquePolicy"
|
||||
assert other.pid._k_i[1] == [0.15]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.lateral import get_friction
|
||||
from opendbc.car.toyota.values import CAR
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.selfdrive.controls.controlsd import Controls
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.starpilot.lateral.controller_selection import (
|
||||
ControllerMode, DOCUMENT_KEY, LEARNING_OFF_KEY, default_selection, policy_for, replace_mode,
|
||||
)
|
||||
from openpilot.starpilot.lateral.rav4_tss2_policy import (
|
||||
supported_cp, friction_threshold, center_output_scale,
|
||||
)
|
||||
from openpilot.starpilot.lateral.tests.test_lane_runtime import feed
|
||||
from openpilot.starpilot.lateral.tests.test_torque_learning import learned_event
|
||||
from openpilot.starpilot.lateral.torque_extension import selected_policy
|
||||
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
|
||||
from openpilot.starpilot.ui.feature_settings_state import row_change
|
||||
|
||||
|
||||
def raw_saved(params, key):
|
||||
try:
|
||||
return Path(params.get_param_path(key)).read_bytes()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def factory(car=CAR.TOYOTA_RAV4_TSS2):
|
||||
return interfaces[car].get_non_essential_params(car)
|
||||
|
||||
|
||||
def publish_rav4_params(params):
|
||||
"""Publish RAV4 CP through Card's real startup configuration and finalization."""
|
||||
from openpilot.selfdrive.car.card import Car
|
||||
from openpilot.starpilot.car.toyota.aol import qualified
|
||||
params.put_bool("OpenpilotEnabledToggle", True, block=True)
|
||||
params.put_bool("SafeMode", False, block=True)
|
||||
cp = factory()
|
||||
|
||||
def discover(*args, pre_create_hook, **kwargs):
|
||||
prepared = pre_create_hook(cp.as_reader().as_builder(), cp.carFingerprint, {}, [])
|
||||
return interfaces[cp.carFingerprint](prepared)
|
||||
|
||||
with patch.dict(os.environ, {"SIMULATION": "1"}), \
|
||||
patch("openpilot.selfdrive.car.card.messaging.recv_one_retry", return_value=SimpleNamespace(can=[1])), \
|
||||
patch("openpilot.selfdrive.car.card.get_car", side_effect=discover):
|
||||
selected = Car()
|
||||
try:
|
||||
final = selected.CP.as_reader().as_builder()
|
||||
assert qualified(final, marked_only=True)
|
||||
assert final.lateralTuning.torque.to_dict() == cp.lateralTuning.torque.to_dict()
|
||||
for field in ("carFingerprint", "steerControlType", "mass", "wheelbase", "centerToFront", "steerRatio",
|
||||
"tireStiffnessFront", "tireStiffnessRear", "steerActuatorDelay"):
|
||||
assert getattr(final, field) == getattr(cp, field)
|
||||
assert raw_saved(params, "CarParams") == final.to_bytes()
|
||||
return final
|
||||
finally:
|
||||
selected.vehicle_startup.close()
|
||||
|
||||
|
||||
def controller(cp, mode=None):
|
||||
return LatControlTorque(cp.as_reader(), interfaces[cp.carFingerprint](cp), .01, controller_mode=mode)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("speed,increment", [(0., 0.), (2.5, 0.), (5., .04), (10., .065), (15., .05), (25., .025)])
|
||||
def test_latest_cleanup_knots_taper_and_left_right_symmetry(speed, increment):
|
||||
# Frozen source-default center envelope, with both taper plateaus independently exercised.
|
||||
envelope = (1 / (1 + math.exp((speed - 13) / 3))) * (1 / (1 + math.exp(-.30 / .08)))
|
||||
assert friction_threshold(speed, 0, 0) == pytest.approx(.30 * (1 + .14 * envelope) + increment)
|
||||
for accel, jerk in ((.10, .10), (.40, .40), (.85, .75)):
|
||||
assert friction_threshold(speed, accel, jerk) == friction_threshold(speed, -accel, -jerk)
|
||||
for accel, jerk in ((.85, 0), (0, .75)):
|
||||
env = (1 / (1 + math.exp((speed - 13) / 3))) * (1 / (1 + math.exp((abs(accel) - .30) / .08)))
|
||||
assert friction_threshold(speed, accel, jerk) == pytest.approx(.30 * (1 + .14 * env))
|
||||
assert .88 <= center_output_scale(0, speed) <= 1
|
||||
|
||||
|
||||
def test_exact_scope_excludes_related_racks_and_bad_tunes():
|
||||
cp = factory()
|
||||
assert supported_cp(cp)
|
||||
assert policy_for(cp) == "rav4_tss2"
|
||||
assert default_selection(cp).mode == ControllerMode.STARPILOT
|
||||
for car in (CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023, CAR.TOYOTA_RAV4_PRIME, CAR.TOYOTA_RAV4H):
|
||||
assert not supported_cp(factory(car))
|
||||
for field, value in (("brand", "hyundai"), ("notCar", True), ("passive", True), ("dashcamOnly", True),
|
||||
("steerControlType", structs.CarParams.SteerControlType.angle)):
|
||||
bad = cp.as_reader().as_builder()
|
||||
setattr(bad, field, value)
|
||||
assert not supported_cp(bad)
|
||||
for field, value in (("latAccelFactor", 0), ("latAccelFactor", float("nan")), ("friction", -.1),
|
||||
("latAccelOffset", float("inf"))):
|
||||
bad = cp.as_reader().as_builder()
|
||||
setattr(bad.lateralTuning.torque, field, value)
|
||||
assert not supported_cp(bad)
|
||||
|
||||
|
||||
def test_actual_modern_owner_reaches_friction_and_final_taper_preserves_tune():
|
||||
cp = factory()
|
||||
shaped = controller(cp)
|
||||
assert type(selected_policy(shaped)).__name__ == "Rav4TSS2TorquePolicy"
|
||||
assert shaped.pid._k_i[1] == [.15] # Modern control gains stay at the existing value.
|
||||
shaped.update_torque_parameters(3.2, .025, .08)
|
||||
assert shaped.torque_params.latAccelFactor == pytest.approx(3.2)
|
||||
assert shaped.torque_params.latAccelOffset == pytest.approx(.025)
|
||||
assert shaped.torque_params.friction == pytest.approx(.08)
|
||||
cs = SimpleNamespace(vEgo=10., steeringAngleDeg=0., steeringPressed=False)
|
||||
params = log.VehicleParameters.new_message(angleOffsetDeg=0., roll=0.)
|
||||
vm = VehicleModel(cp)
|
||||
with patch("openpilot.selfdrive.controls.lib.latcontrol_torque.get_friction", wraps=get_friction) as friction, \
|
||||
patch.object(shaped.pid, "update", return_value=.4):
|
||||
for _ in range(300):
|
||||
result, _, state = shaped.update(True, cs, vm, params, False, .001, False, .14)
|
||||
assert state.desiredLateralAccel == pytest.approx(.1)
|
||||
assert state.desiredLateralJerk == pytest.approx(0., abs=1e-8)
|
||||
assert friction.call_args.args[2] == pytest.approx(friction_threshold(10., .1, 0.), abs=1e-8)
|
||||
raw = shaped.torque_from_lateral_accel(.4, shaped.torque_params)
|
||||
assert result == pytest.approx(-raw * center_output_scale(.1, 10.))
|
||||
standard = controller(cp, ControllerMode.STANDARD)
|
||||
assert selected_policy(standard) is None
|
||||
with patch("openpilot.selfdrive.controls.lib.latcontrol_torque.get_friction", wraps=get_friction) as friction, \
|
||||
patch.object(standard.pid, "update", return_value=.4):
|
||||
standard.update(True, cs, vm, params, False, .001, False, .14)
|
||||
assert friction.call_args.args[2] == .20
|
||||
|
||||
|
||||
def test_actual_controls_saved_optout_and_native_learning_consumer():
|
||||
with OpenpilotPrefix(), patch.dict(os.environ, {"SIMULATION": "0", "REPLAY": "1", "TORQUE_REPLAY_RUNTIME": "0",
|
||||
"AOL_REPLAY_RUNTIME": "0", "LANE_CENTERING_REPLAY_RUNTIME": "0"}), \
|
||||
patch("openpilot.selfdrive.controls.controlsd.messaging.PubMaster"):
|
||||
saved = Params()
|
||||
cp = publish_rav4_params(saved)
|
||||
saved.put_bool("OpenpilotEnabledToggle", True, block=True)
|
||||
saved.put_bool("SafeMode", False, block=True)
|
||||
shaped = Controls()
|
||||
assert shaped.LaC.controller_mode == ControllerMode.STARPILOT
|
||||
assert shaped.torque_learning_allowed
|
||||
for tick in range(2):
|
||||
now = 1_000_000_000 + tick * 250_000_000
|
||||
feed(shaped, now, 0)
|
||||
shaped.sm.update_msgs(now / 1e9, [learned_event(cp, now)])
|
||||
assert shaped.sm.all_checks(["lateralTorqueParameters"])
|
||||
with patch.object(shaped.LaC, "update_torque_parameters") as update:
|
||||
command, _ = shaped.state_control()
|
||||
assert command.latActive
|
||||
update.assert_called_once()
|
||||
raw = replace_mode(None, cp, ControllerMode.STANDARD)
|
||||
saved.put(DOCUMENT_KEY, json.loads(raw), block=True)
|
||||
stored_raw = raw_saved(saved, DOCUMENT_KEY)
|
||||
assert json.loads(stored_raw) == json.loads(raw)
|
||||
assert shaped.LaC.controller_mode == ControllerMode.STARPILOT
|
||||
standard = Controls()
|
||||
assert standard.LaC.controller_mode == ControllerMode.STANDARD
|
||||
assert selected_policy(standard.LaC) is None
|
||||
assert raw_saved(saved, DOCUMENT_KEY) == stored_raw
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", [ControllerMode.STANDARD, ControllerMode.STARPILOT])
|
||||
@pytest.mark.parametrize("saved_raw,allowed,label", [(None, True, "On"), (b"0", True, "On"),
|
||||
(b"1", False, "Off"), (b"bad", False, "Invalid saved preference")])
|
||||
def test_actual_controls_consumer_and_ui_row_honor_learning_choice(mode, saved_raw, allowed, label):
|
||||
with OpenpilotPrefix(), patch.dict(os.environ, {"SIMULATION": "0", "REPLAY": "1", "TORQUE_REPLAY_RUNTIME": "0",
|
||||
"AOL_REPLAY_RUNTIME": "0", "LANE_CENTERING_REPLAY_RUNTIME": "0"}), \
|
||||
patch("openpilot.selfdrive.controls.controlsd.messaging.PubMaster"):
|
||||
saved = Params()
|
||||
cp = publish_rav4_params(saved)
|
||||
saved.put(DOCUMENT_KEY, json.loads(replace_mode(None, cp, mode)), block=True)
|
||||
saved.put_bool("OpenpilotEnabledToggle", True, block=True)
|
||||
saved.put_bool("SafeMode", False, block=True)
|
||||
if saved_raw is not None:
|
||||
Path(saved.get_param_path(LEARNING_OFF_KEY)).write_bytes(saved_raw)
|
||||
controls = Controls()
|
||||
assert controls.LaC.controller_mode == mode
|
||||
assert controls.torque_learning_allowed == allowed
|
||||
owner = FeatureSettingsOwner(saved, lambda group: group == "preferences",
|
||||
vehicle_fingerprint=lambda: str(cp.carFingerprint), vehicle_params=lambda: cp)
|
||||
snapshot = owner.snapshot("torque", parked=False, system_long=False, lateral_context=False, metric=False)
|
||||
row = next(row for row in snapshot.rows if row.key == LEARNING_OFF_KEY)
|
||||
assert row.value == label
|
||||
assert row.available == (saved_raw != b"bad")
|
||||
assert row.choices == (() if saved_raw == b"bad" else ("Off", "On"))
|
||||
for tick in range(2):
|
||||
now = 1_000_000_000 + tick * 250_000_000
|
||||
feed(controls, now, 0)
|
||||
controls.sm.update_msgs(now / 1e9, [learned_event(cp, now)])
|
||||
assert controls.sm.all_checks(["lateralTorqueParameters"])
|
||||
with patch.object(controls.LaC, "update_torque_parameters") as update:
|
||||
command, _ = controls.state_control()
|
||||
assert command.latActive
|
||||
assert update.call_count == int(allowed)
|
||||
assert raw_saved(saved, LEARNING_OFF_KEY) == saved_raw
|
||||
|
||||
|
||||
@pytest.mark.parametrize("initial_mode", [ControllerMode.STANDARD, ControllerMode.STARPILOT])
|
||||
def test_actual_ui_controller_switch_preserves_learning_and_explicit_toggle(initial_mode):
|
||||
with OpenpilotPrefix():
|
||||
cp = factory()
|
||||
saved = Params()
|
||||
saved.put(DOCUMENT_KEY, json.loads(replace_mode(None, cp, initial_mode)), block=True)
|
||||
owner = FeatureSettingsOwner(saved, lambda group: group == "preferences",
|
||||
vehicle_fingerprint=lambda: str(cp.carFingerprint), vehicle_params=lambda: cp)
|
||||
|
||||
def row(key):
|
||||
state = owner.snapshot("torque", parked=False, system_long=False, lateral_context=False, metric=False)
|
||||
return next(row for row in state.rows if row.key == key)
|
||||
|
||||
controller_row = row(DOCUMENT_KEY)
|
||||
request = row_change(controller_row)
|
||||
assert request is not None
|
||||
assert owner.apply(request)
|
||||
# RAV4's native-learning default remains enabled across both controller choices.
|
||||
assert raw_saved(saved, LEARNING_OFF_KEY) is None
|
||||
learning_row = row(LEARNING_OFF_KEY)
|
||||
assert learning_row.available and learning_row.value == "On"
|
||||
request = row_change(learning_row)
|
||||
assert request is not None
|
||||
assert owner.apply(request)
|
||||
assert raw_saved(saved, LEARNING_OFF_KEY) == b"1"
|
||||
learning_row = row(LEARNING_OFF_KEY)
|
||||
assert learning_row.value == "Off" and learning_row.available
|
||||
request = row_change(learning_row)
|
||||
assert request is not None
|
||||
assert owner.apply(request)
|
||||
assert raw_saved(saved, LEARNING_OFF_KEY) == b"0"
|
||||
@@ -66,7 +66,7 @@ class TestTorqueLearning(unittest.TestCase):
|
||||
params.put_bool(LEARNING_OFF_KEY, True, block=True)
|
||||
for vehicle in (HYUNDAI.KIA_EV6, HYUNDAI.HYUNDAI_SONATA):
|
||||
self.assertFalse(learning_allowed(params, cp_for(vehicle)))
|
||||
self.assertTrue(learning_allowed(params, cp_for(TOYOTA.TOYOTA_RAV4_TSS2)))
|
||||
self.assertFalse(learning_allowed(params, cp_for(TOYOTA.TOYOTA_RAV4_TSS2)))
|
||||
|
||||
def test_learner_does_not_restore_collect_estimate_or_overwrite_disabled_cache(self):
|
||||
for vehicle in VEHICLES:
|
||||
|
||||
@@ -43,6 +43,10 @@ def create_extension(parent, cp, mode, selected, *, turn_assist=False):
|
||||
from openpilot.starpilot.lateral.genesis_g70_policy import GenesisG70TorquePolicy, supported_cp
|
||||
if supported_cp(cp):
|
||||
return TorqueExtension(GenesisG70TorquePolicy(parent, cp))
|
||||
if selected == 'rav4_tss2':
|
||||
from openpilot.starpilot.lateral.rav4_tss2_policy import Rav4TSS2TorquePolicy, supported_cp
|
||||
if supported_cp(cp):
|
||||
return TorqueExtension(Rav4TSS2TorquePolicy(parent, cp))
|
||||
if selected == 'corolla_tss2':
|
||||
from openpilot.starpilot.lateral.corolla_tss2_policy import CorollaTSS2TorquePolicy, supported_cp
|
||||
if supported_cp(cp):
|
||||
|
||||
@@ -7,6 +7,7 @@ import json
|
||||
|
||||
from openpilot.starpilot.lateral.controller_selection import (
|
||||
DOCUMENT_KEY, LEARNING_OFF_KEY, MAX_DOCUMENT_BYTES, ControllerMode, policy_for, replace_mode, selection_from_bytes,
|
||||
controller_uses_native_learning,
|
||||
)
|
||||
from openpilot.starpilot.saved_document import commit_exact
|
||||
from openpilot.starpilot.saved_source import read_saved
|
||||
@@ -149,12 +150,12 @@ class ControllerFeature:
|
||||
selection = selection_from_bytes(CP, controller)
|
||||
raw, readable = read_saved(self.params, LEARNING_OFF_KEY, 1)
|
||||
valid = readable and raw in (None, b'0', b'1') and controller_readable and selection.source != 'invalid'
|
||||
starpilot = selection.mode == ControllerMode.STARPILOT
|
||||
value = ('Off' if starpilot or raw == b'1' else 'On') if valid else 'Invalid saved preference'
|
||||
fixed_vehicle_tune = not controller_uses_native_learning(selection)
|
||||
value = ('Off' if fixed_vehicle_tune or raw == b'1' else 'On') if valid else 'Invalid saved preference'
|
||||
reason = ('StarPilot uses the vehicle tune. ' + TUNING_GUIDANCE
|
||||
if starpilot else 'Saved for the next drive. Turn on only if you want Stock Controller to learn torque values.')
|
||||
if fixed_vehicle_tune else 'Saved for the next drive. Turn on if you want this controller to learn torque values.')
|
||||
return FeatureRow(LEARNING_OFF_KEY, 'Automatic Steering Learning', value, raw, ('Off', 'On') if valid else (),
|
||||
available=valid and not starpilot and self.authority('preferences'),
|
||||
available=valid and not fixed_vehicle_tune and self.authority('preferences'),
|
||||
reason=reason if valid else 'Saved controller or learning preference is unreadable or invalid.',
|
||||
capability=capability, dependencies=((DOCUMENT_KEY, controller),), default_value="On")
|
||||
|
||||
@@ -202,7 +203,8 @@ class ControllerFeature:
|
||||
return (self.authority('preferences') and self.vehicle_fingerprint() == request.vehicle_fingerprint and
|
||||
self.capability() == request.capability and readable and current == learning)
|
||||
|
||||
if learning != b'1' and (MODES[request.value] == ControllerMode.STARPILOT or selected.mode == ControllerMode.STARPILOT):
|
||||
if learning != b'1' and (not controller_uses_native_learning(replace(selected, mode=MODES[request.value])) or
|
||||
not controller_uses_native_learning(selected)):
|
||||
def authorize_learning_off() -> bool:
|
||||
current, readable = read_saved(self.params, DOCUMENT_KEY, MAX_DOCUMENT_BYTES)
|
||||
return authorized() and readable and current == request.expected
|
||||
|
||||
Reference in New Issue
Block a user