IQ.Pilot Release Commit @ 98a2c61
This commit is contained in:
@@ -91,9 +91,5 @@ class LongControl:
|
||||
freeze_integrator=gas_override)
|
||||
self.smooth.reset()
|
||||
|
||||
if gas_override:
|
||||
# safety blocks braking while the gas is pressed, and a blocked tx drops the whole frame
|
||||
output_accel = max(output_accel, 0.0)
|
||||
|
||||
self.last_output_accel = np.clip(output_accel, accel_limits[0], accel_limits[1])
|
||||
return self.last_output_accel
|
||||
|
||||
@@ -16,17 +16,17 @@ from iqpilot.selfdrive.controls.lib.latcontrol_torque import TORQUE_NN_MODEL_PAT
|
||||
# layers). Used as a fallback so the loader logic is still exercised when no trained
|
||||
# models are shipped (they are removed pending retraining and re-added over time).
|
||||
_SYNTHETIC_MODEL = {
|
||||
"input_size": 4,
|
||||
"input_size": 18,
|
||||
"output_size": 1,
|
||||
"input_mean": [[0.0], [0.0], [0.0], [0.0]],
|
||||
"input_std": [[1.0], [1.0], [1.0], [1.0]],
|
||||
"input_mean": [[0.0]] * 18,
|
||||
"input_std": [[1.0]] * 18,
|
||||
"layers": [
|
||||
{"dense_1_W": [[0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5]], "dense_1_b": [[0.0], [0.0]], "activation": "sigmoid"},
|
||||
{"dense_1_W": [[0.5] * 18, [0.5] * 18], "dense_1_b": [[0.0], [0.0]], "activation": "sigmoid"},
|
||||
{"dense_2_W": [[2.0, 2.0]], "dense_2_b": [[-1.0]], "activation": "identity"},
|
||||
],
|
||||
}
|
||||
|
||||
MODEL_FILES = sorted(f for f in os.listdir(TORQUE_NN_MODEL_PATH) if f.endswith(".json"))
|
||||
MODEL_FILES = sorted(f for f in os.listdir(TORQUE_NN_MODEL_PATH) if f.endswith(".json")) if os.path.isdir(TORQUE_NN_MODEL_PATH) else []
|
||||
if MODEL_FILES:
|
||||
_MODEL_DIR = TORQUE_NN_MODEL_PATH
|
||||
_NAMES = MODEL_FILES
|
||||
|
||||
@@ -15,15 +15,9 @@ from iqpilot.common.params import Params
|
||||
from iqpilot.common.pid import PIDController
|
||||
from iqpilot.selfdrive.iqmodeld.config import ModelConstants
|
||||
from iqpilot.selfdrive.controls.lib.latcontrol_torque import NeuralNetworkFeedForward
|
||||
from iqpilot.selfdrive.controls.lib.latcontrol_torque import TORQUE_NN_MODEL_PATH
|
||||
from iqpilot.selfdrive.controls.lib.neural_network_feed_forward.tests.test_network import _MODEL_DIR, _NAMES
|
||||
|
||||
_REAL_MODEL = next((f for f in sorted(os.listdir(TORQUE_NN_MODEL_PATH))
|
||||
if f.endswith(".json") and f != "MOCK.json"), None)
|
||||
|
||||
# Models are shipped separately and re-added as retrained; with none present,
|
||||
# NNFF is a no-op (falls back to stock torque FF), so the assembly tests skip.
|
||||
pytestmark = pytest.mark.skipif(_REAL_MODEL is None,
|
||||
reason="no NNFF models present (nuked pending retraining)")
|
||||
_REAL_MODEL = next((f for f in _NAMES if f != "MOCK.json"), _NAMES[0])
|
||||
|
||||
|
||||
def _torque_fn():
|
||||
@@ -53,7 +47,7 @@ def _model_v2():
|
||||
|
||||
def _make_controller(model_file):
|
||||
Params().put_bool("NeuralNetworkFeedForward", True)
|
||||
path = os.path.join(TORQUE_NN_MODEL_PATH, model_file)
|
||||
path = os.path.join(_MODEL_DIR, model_file)
|
||||
cp = SimpleNamespace(steerActuatorDelay=0.15)
|
||||
cp_iq = SimpleNamespace(iqLateralNet=SimpleNamespace(
|
||||
model=SimpleNamespace(path=path, name=os.path.splitext(model_file)[0])))
|
||||
@@ -84,7 +78,10 @@ class TestControllerWiring:
|
||||
def test_mock_model_reports_absent(self):
|
||||
nnff = _make_controller("MOCK.json")
|
||||
assert nnff.has_nn_model is False
|
||||
assert nnff.model.input_size >= 2 # MOCK still loads as a valid net
|
||||
if "MOCK.json" in _NAMES:
|
||||
assert nnff.model.input_size >= 2
|
||||
else:
|
||||
assert nnff.model is None
|
||||
|
||||
def test_update_returns_finite_torque(self):
|
||||
nnff = _make_controller(_REAL_MODEL)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from iqpilot.cereal import custom
|
||||
from iqpilot.selfdrive.controls.lib.longcontrol import LongCtrlState, long_control_state_trans
|
||||
from iqpilot.selfdrive.controls.lib.longcontrol import LongControl, LongCtrlState, long_control_state_trans
|
||||
|
||||
|
||||
class TestLongControlStateTransition:
|
||||
@@ -41,3 +43,30 @@ def test_engage():
|
||||
next_state = long_control_state_trans(CP_IQ, active, current_state,
|
||||
should_stop=False, brake_pressed=False, cruise_standstill=False)
|
||||
assert next_state == LongCtrlState.pid
|
||||
|
||||
|
||||
def test_gas_override_preserves_negative_accel_command():
|
||||
pid_calls = []
|
||||
control = object.__new__(LongControl)
|
||||
control.CP = SimpleNamespace(stopAccel=-0.55)
|
||||
control.CP_IQ = SimpleNamespace(enableGasInterceptor=False)
|
||||
control.long_control_state = LongCtrlState.pid
|
||||
control.pid = SimpleNamespace(
|
||||
update=lambda error, **kwargs: pid_calls.append((error, kwargs)) or -0.5,
|
||||
reset=lambda: None,
|
||||
)
|
||||
control.last_output_accel = -0.4
|
||||
control.stopping_decel_rate = 1.0
|
||||
control.smooth = SimpleNamespace(enabled=False, update=lambda: None, reset=lambda: None)
|
||||
car_state = SimpleNamespace(
|
||||
vEgo=15.0,
|
||||
aEgo=0.0,
|
||||
brakePressed=False,
|
||||
standstill=False,
|
||||
cruiseState=SimpleNamespace(standstill=False),
|
||||
)
|
||||
|
||||
output = control.update(True, car_state, -0.5, False, (-3.5, 2.0), gas_override=True)
|
||||
|
||||
assert output == -0.5
|
||||
assert pid_calls == [(-0.5, {"speed": 15.0, "feedforward": -0.5, "freeze_integrator": True})]
|
||||
|
||||
Reference in New Issue
Block a user