mirror of
https://gitlvb.teallvbs.xyz/IQ.Lvbs/IQ.Pilot.git
synced 2026-09-27 07:13:53 +08:00
IQ.Pilot Release Commit @ 9b29107
This commit is contained in:
@@ -1 +1 @@
|
||||
076c1d057f97b067222d74180fbb63ba5467254a
|
||||
9953593a65d6759bb84905b47d81bee547c5bc3f
|
||||
|
||||
@@ -21,13 +21,18 @@
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "268267fdfb6ae438f1b3c6f5f2c378a5b878e68357d5560f604f77d5c36a2cea",
|
||||
"size": 402144
|
||||
"sha256": "3e278b710bd3c5ee69b463cfb3025932ddc92e790733d95f8c218d61de769704",
|
||||
"size": 468040
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/angle_tracker.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ef70814b9b380cc0b93041b1ccca50e993336bf13a5a4c23380d99a494727652",
|
||||
"size": 137168
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "b3d33e86493408e5a02f2df753e1b257f003e5028480b5b040aa5a07eeed98be",
|
||||
"size": 69712
|
||||
"sha256": "fc37e89b7a569fb1a50e841a20168fc36a50ad574e2e3fad1a96d3084d6e8f3e",
|
||||
"size": 69608
|
||||
},
|
||||
"runtime": {
|
||||
"entries": {
|
||||
@@ -35,6 +40,10 @@
|
||||
"path": "python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so",
|
||||
"type": "python-module"
|
||||
},
|
||||
"iqpilot_private.konn3kt.iqlvbs.angle_tracker": {
|
||||
"path": "python/iqpilot_private/konn3kt/iqlvbs/angle_tracker.cpython-312-aarch64-linux-gnu.so",
|
||||
"type": "python-module"
|
||||
},
|
||||
"iqpilot_private.konn3kt.iqlvbs.vehicle_state": {
|
||||
"path": "python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so",
|
||||
"type": "python-module"
|
||||
@@ -42,7 +51,8 @@
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": "v0mM7HrM8Ssbm3E/TxIUefAh5aCkzbZIKDQk5yFN6kr4EgqmVyPMNkqu7kCsn4ah0fTzr7xCrhs/gXjGf+6yBQ==",
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so": "5KQhJ61bt8tNmKuegPVMnMiqEHKcnjhqMtCDv2CphlSS54L/GmsOZjieHQEcgpOIDw7n/7qz2k6iFnwJ6clLCg=="
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": "IJTrAoJ08yLAjBt3NBjErXVIoAuNXTBHoUVOCjsPuQhwN+PnkSNEzd5nO1sLxzSG5HfbgiljQ32jPP8VrTDSBQ==",
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/angle_tracker.cpython-312-aarch64-linux-gnu.so": "Z+lFLZtP3bUrcu56YEJ0xUzCt2LakywFMCqYaLFM6G4Q1jYeu7Y2/nEpPDfVOSW5hn0XVCYM4C4sT08FJlrrBg==",
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so": "9uqsRuEGViBybuh0SxrTdw/uBVGeJXLmS4qhajlXKAVl8HllBQeiF7UY95Di7/yJEDTiSTo4mMJbOcz3UjTSDw=="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
Xr+Nn9b/ZoT2/S94B/I16aHVQI5dZZE3hGvpS6elgasC7e4JZouZvln/ue3Lh5Hg/NTJCCEStRmpEtNfgcjbAA==
|
||||
uP+OnBsv67hALUufnDP6Dux48yzqt2D/MRuzB5Kpigvi+6uTRlq4M2564Vqlf/+A8/C4H4YNRVSOK37wTM9sCA==
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -171,8 +171,8 @@
|
||||
},
|
||||
"python/_iqclosure/iqpilot/system/hardware/tici/hardware.py": {
|
||||
"mode": 420,
|
||||
"sha256": "f1ddffa9bdb5071a49fd65eb4b49958b60b1873e1ec70e6f3f2e2b2501abce2f",
|
||||
"size": 25584
|
||||
"sha256": "e8eae4e8a75e1751525471cf54a8555b7bfd7f08ad84bf2e75642b5745f222db",
|
||||
"size": 25601
|
||||
},
|
||||
"python/_iqclosure/iqpilot/system/hardware/tici/iwlist.py": {
|
||||
"mode": 420,
|
||||
@@ -206,37 +206,37 @@
|
||||
},
|
||||
"python/iqpilot_private/context/cot_decode.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ff7516da01c70d14589479e0d9c1f46ceb7ee771e32e7f1d0f198140689f302b",
|
||||
"sha256": "506f732da9133ba5fdf8ffcb5d7557b28de44b8b789a4994fb1bd9a7c2240641",
|
||||
"size": 138936
|
||||
},
|
||||
"python/iqpilot_private/context/drive_profile.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "828c2115f11b201eab218ccfc137dcf311ada4952567effbe4e8fa271bd45d08",
|
||||
"sha256": "33358560c99c961e172a1643fb4a0ac6048f90d85551c0dea595fc1793372199",
|
||||
"size": 202256
|
||||
},
|
||||
"python/iqpilot_private/context/feature_inputs.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ee5eafd557c46b22fada7811f42af9e0e0e008644a03e6f8c531c6e5f26e6197",
|
||||
"sha256": "e23916b1c8ce0dd6fe28e07d381e8545c14ab9851cc3c501cc8f08e2002df6ee",
|
||||
"size": 135368
|
||||
},
|
||||
"python/iqpilot_private/context/model_context.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "2bf15d3d5be83086ca7a2846d9b0ab1fe08c823e6221413b3084b93c47d1f2f9",
|
||||
"sha256": "cf6a559498981b3bebb4e50ef276e8c6f0816db68534c43b3372f2d88fec9f7d",
|
||||
"size": 473440
|
||||
},
|
||||
"python/iqpilot_private/context/reasoning_relay.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "f4bbb478faa8b8fb139235308f978efaf9c6e80ec8cb7f1b0748199811e7aa0b",
|
||||
"size": 137008
|
||||
"sha256": "674bb7de81a76911f536cd684b384f384b4271bdedf0591ff18c574c7378d6c7",
|
||||
"size": 137560
|
||||
},
|
||||
"python/iqpilot_private/context/speed_limit_input.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "f7834b1874f8b8e89d056f9fdf099505ab9e0a4face41d7ed8aa4818efbd4bb0",
|
||||
"sha256": "b6b8c578e98f584ee221d35e08233f4a96afee3d3d765bc8ce5229040626f9c9",
|
||||
"size": 135872
|
||||
},
|
||||
"python/iqpilot_private/context/temporal_state.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "79cf9a03e07dff07152bfb7894ec1e56db2dca582dae0f7d01cb6c089ee85b40",
|
||||
"sha256": "a08e7b38bdd666bf2aa38e7528574f2bb3650cd8439edc9689b1e36b08fcf5c2",
|
||||
"size": 205456
|
||||
},
|
||||
"runtime": {
|
||||
@@ -272,12 +272,12 @@
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/context/cot_decode.cpython-312-aarch64-linux-gnu.so": "fw6fxIll7mblJ8VV/eMCqYvMx3p8jsCQTXpaIQU3icE61Bu9zEiWU1SwW1tB2nU/16RTY/FuFLt8Q2T2fGsZBg==",
|
||||
"python/iqpilot_private/context/drive_profile.cpython-312-aarch64-linux-gnu.so": "zTS46Eqyugv6h2KTmhWVVeDWPMfo6WErUKdtA4yvXjt//l4fMZRISRE2g9SRbUs2MmMuArrsp9oVm7rBBHLIBQ==",
|
||||
"python/iqpilot_private/context/feature_inputs.cpython-312-aarch64-linux-gnu.so": "bmrrXqu2A1t74MWhENmcL84zwsrgFYBdgfIyxH2V+VxglTi9OUssq48JTTDz4cqwo7yaoKXaaZ8n5h5ZkhXgBA==",
|
||||
"python/iqpilot_private/context/model_context.cpython-312-aarch64-linux-gnu.so": "PR0rbQ5bf3N11dc4Og93+FjevF9+yyyTVcKthsYRSvwxR4g13s+VkdDQXznJcMW9RxwEF5VRLpctfdsLjwmSBQ==",
|
||||
"python/iqpilot_private/context/reasoning_relay.cpython-312-aarch64-linux-gnu.so": "ho6NFRhUu1evnLDkaO5Kfy7l6b43+cOmSaS/Hkkyz5jq6ZhoqftK9GL/AGBMtOyN7w6aQHkKfx+VnNu+yU9eBA==",
|
||||
"python/iqpilot_private/context/speed_limit_input.cpython-312-aarch64-linux-gnu.so": "gTatMeGF73ClQvTWSxXwI3xinhAd7R2chOnOkdOmVa8JCGgCBcL11r8agg3kTL52ELrZjBhv1Y1p1SToGhQXDA==",
|
||||
"python/iqpilot_private/context/temporal_state.cpython-312-aarch64-linux-gnu.so": "LWeYZzk5kwmre0K28KHgylbIbfLa2mUnuNXpkU1fNUNf5R2ceUN6VGBHJtFaZ9Kl2m2FaAXI7O7LxrB90NMeBg=="
|
||||
"python/iqpilot_private/context/cot_decode.cpython-312-aarch64-linux-gnu.so": "3XxFsaC/nx8fXtDtpWs+7oPABYmwlIEj1Ex30U8kTDzguB6P5RJVmkFbstAiWOnVCYfLT47sMlvHeU3VTHehDA==",
|
||||
"python/iqpilot_private/context/drive_profile.cpython-312-aarch64-linux-gnu.so": "9SRCLPJAzPMXMJRyxmfzIR3B2uTfpRm4uzUi1UBnSufzR+ppaRxfCtLestlXWDf2nkQiiaHjF3JdPv3VhjjmBg==",
|
||||
"python/iqpilot_private/context/feature_inputs.cpython-312-aarch64-linux-gnu.so": "KdG3SA295ptxX5WcOmdjeHUkE+f+DTRkPGcJFEXgLMPPMWSgo8aVYILT9z46JTUHd+va82ijRIAJZtJHE+wqAg==",
|
||||
"python/iqpilot_private/context/model_context.cpython-312-aarch64-linux-gnu.so": "yNV0YdFkYGTRyiBFwejPolZHv5ueyQ3XwBjKAoDEB5c80ps6dEDDoXzJBi+Pe1PS/hhVZq3rb5NqVzuJEBlPCA==",
|
||||
"python/iqpilot_private/context/reasoning_relay.cpython-312-aarch64-linux-gnu.so": "OD6pPW3nNwopVqsY0UXVyGrAREG7KNCEO59c5j6uIPuKHaSCu2z59tNG9WZ/mgfJCyhLCAN6K9BULmX2kwRTDA==",
|
||||
"python/iqpilot_private/context/speed_limit_input.cpython-312-aarch64-linux-gnu.so": "B4Pc4T9sPIuF9g35pB43YbaEzwX9h4IhPrvLzwf1HUmkPMT7knz2B1lgU0z8atz96F5OUpJSE2mG5usq5BzjAA==",
|
||||
"python/iqpilot_private/context/temporal_state.cpython-312-aarch64-linux-gnu.so": "KYtRL67X5HZ2vVmQfqW8XhnmDVK1vxpo2geVcZ7NXGZ3FFn5vcIweK2ZFVZoIgPfGvK5QMSONnLXPUNSfc9iCw=="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
47AltDKN9D5zvnmHB0hbFM/JvPLfDaYUk5TyXap8B1xJl2WJZvVx8KEwyclnDv9VJ4ozc1nHTGLnbK37B3ciAg==
|
||||
NcjiBJcKitajD4QhhgJZWkc7JRypOIeWKlHvcc0gRMfLAHU7K3ogMd/ZYHUwWPaTZw0JS5zkUIPuZ7hN+chqDA==
|
||||
|
||||
+1
-1
@@ -557,7 +557,7 @@ class Tici(HardwareBase):
|
||||
if self.get_device_type() in ("tici", "tizi"):
|
||||
if initial_eps_apn:
|
||||
subprocess.call(["mmcli", "-m", "any", f'--3gpp-set-initial-eps-bearer-settings=apn={initial_eps_apn}'])
|
||||
else:
|
||||
elif is_comma_profile:
|
||||
subprocess.call(["mmcli", "-m", "any", '--3gpp-set-initial-eps-bearer-settings=apn='])
|
||||
|
||||
cmds += [
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -141,8 +141,8 @@
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/controls/lib/desire_helper.py": {
|
||||
"mode": 420,
|
||||
"sha256": "0db179f0df2dd8949493bc49a5cdecb18d11383a20239c759ece59fa9ae874cc",
|
||||
"size": 11398
|
||||
"sha256": "5cae804fc22b0e28988147be19bd3ccf895ade0f5c5041504840695ba83d2e20",
|
||||
"size": 13106
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/controls/lib/drive_helpers.py": {
|
||||
"mode": 420,
|
||||
@@ -161,8 +161,8 @@
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/controls/lib/helpers/lane_turn.py": {
|
||||
"mode": 420,
|
||||
"sha256": "faa6f87b227c805e8890a91139e8d16d7874c4b99b330dda08080392ce3479ec",
|
||||
"size": 4618
|
||||
"sha256": "d27bd9010967dd51dccc18ec005ff446ae965379b8e828ff7173331818723ec8",
|
||||
"size": 4667
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/controls/lib/helpers/lateral_edge_guard.py": {
|
||||
"mode": 420,
|
||||
@@ -211,8 +211,8 @@
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/iqmodeld/daemon.py": {
|
||||
"mode": 420,
|
||||
"sha256": "57f4f87e4db2a8a86859ed0a468413d81791043df926738e518afe5ae3503795",
|
||||
"size": 36288
|
||||
"sha256": "62f51d922f6883bc094590a9d95c2c0849d858bbce30f35c2eba00ec9d3d9bad",
|
||||
"size": 36325
|
||||
},
|
||||
"python/_iqclosure/iqpilot/selfdrive/iqmodeld/drive_profile.py": {
|
||||
"mode": 420,
|
||||
@@ -541,8 +541,8 @@
|
||||
},
|
||||
"python/_iqclosure/iqpilot/system/hardware/tici/usb_storage.py": {
|
||||
"mode": 420,
|
||||
"sha256": "3352f2cf70d38e7158ef8ac20bb736dba55c73239cbdd3ab7f431dbacfb5027e",
|
||||
"size": 2189
|
||||
"sha256": "0026831af4dc730669e91b9c2be5aa62f870b9d8bebfaf783e2c078ef382f4be",
|
||||
"size": 2515
|
||||
},
|
||||
"python/_iqclosure/iqpilot/system/hardware/usb.py": {
|
||||
"mode": 420,
|
||||
@@ -576,38 +576,38 @@
|
||||
},
|
||||
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "bc5e1c99a6efca66a1f7d69ade1bd228870f965117deae86378c32e924432d39",
|
||||
"size": 333944
|
||||
"sha256": "1f4bc57a92e768f4cba01d1a37b22157de2ea1baf1df7a650bc68f66dd33f816",
|
||||
"size": 333976
|
||||
},
|
||||
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "5aa52680f9dd3ad393fabbed20e434168becf285ab5991df35dd8b3758d78419",
|
||||
"size": 68072
|
||||
"sha256": "33d7f6b1957b2bd180320f3ac05c14da2b4ea6e624cd2c526f79690502319c72",
|
||||
"size": 68152
|
||||
},
|
||||
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "0a1048e38176dce88844f20f927be2dbca151e87e05e88e707bb807ff44595cc",
|
||||
"size": 333544
|
||||
"sha256": "8f5ede36c9ff1c05d01bfb95c25a06662ff5ff066224a904d133d7485e4b887b",
|
||||
"size": 333552
|
||||
},
|
||||
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "3bbcf0e311d1fed7a8b7f8e0b995875dc1f70f89a57681fe9a507721ba61452e",
|
||||
"size": 404536
|
||||
"sha256": "86295ba52a1453147fa0f9050e449922bd31860ae1992f4d2bc097ad729b3532",
|
||||
"size": 474592
|
||||
},
|
||||
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "23c9a32a75daab86714e127902cef5c456703838db6e178a502aff3fe6cc50f2",
|
||||
"size": 531776
|
||||
"sha256": "18385b31db8bb771a9d87d0442ab74ae81ace0acd4c335fc81550dae1686eab5",
|
||||
"size": 532088
|
||||
},
|
||||
"python/iqpilot_private/emac/model_context.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "cb4888d0a6d31851e15bbd7d53666d01382252cf5b46f994b4eeff2960ac502c",
|
||||
"sha256": "6e9087336511df69b8478df946fd911e60861081161206c1b834473ca5075f8f",
|
||||
"size": 473440
|
||||
},
|
||||
"python/iqpilot_private/emac/rh_images.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "bb23a72222a72983be8cacbf13972e36c966f8c4e3d844fcf572bb54501ef8be",
|
||||
"size": 205848
|
||||
"sha256": "b3e6018fb5c1ca4c2deab213e53274178b7f07d0f804160960f3c6b740cb8ef7",
|
||||
"size": 206032
|
||||
},
|
||||
"runtime": {
|
||||
"entries": {
|
||||
@@ -618,12 +618,12 @@
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": "nb58JcxhuvZb66ykqx6qtiYcxuMrT9RxYLVPrySBh2c/2lK4YAEPOW3NYXItamo3c77tp5X12OOcTenV+hRFDQ==",
|
||||
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": "SlLArJdgtL4q44jc1iF2qOswWn0JaYKPLHM3WX+/CzkW6s5LLjPJLIP2/X9pT/xd8yb5jrrmNlkh756J0BlwDQ==",
|
||||
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": "XuilHMLAoLU+Uythp7DLZyUSzh5cd+Kd/ppdar60CvfI2ddWzyxUtWzRAj89MXosOg8TZlfvdbR+izFSaQaWCQ==",
|
||||
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": "3kHG7y4co2JjaMyYx+Nc2gti9VXv1EkDqgPuijpjtrUXxo2/z23HzW5OFR2tS5HOdSsoPp0QKxqNSJFU2vo1CQ==",
|
||||
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": "MqqTLheWl49buYG1d/aJk6W23WTEpBc0+BgTUAZHRHlfbrvvJzEZxutjS5EUd36QjOcqujdXns50NVrvbaAmDQ==",
|
||||
"python/iqpilot_private/emac/model_context.cpython-312-aarch64-linux-gnu.so": "JI2Fqs5/uhABjC1TA5nPytJQXCWQLDYlEljLTkak6Dc8chUf2WiwBhWpcwFWhZO+QKwxERJXFdsG1ZTuPlTlDQ==",
|
||||
"python/iqpilot_private/emac/rh_images.cpython-312-aarch64-linux-gnu.so": "BkfWTqw5Ei9EMLGwDNlDabsD/3sIXFJNkk+s/VR3Tm7+EKdkzJs4Ws/dshTDvg5DZjuwKmOdeMYZFxEpHcqvAw=="
|
||||
"python/iqpilot_private/emac/bulk_transport.cpython-312-aarch64-linux-gnu.so": "wMMKjD6k+ZfaYxp05TBlB2NFQTyYYvfMdzvDEX99MdROz6r3TEHONeLOW/N9F70eIj9nttenuc3KgZ5SOTapCw==",
|
||||
"python/iqpilot_private/emac/ffs_holder.cpython-312-aarch64-linux-gnu.so": "F4dXFxTj3Am+rj7muIYQMGV+uBSueo1zydF9tK3edeoG5vFtDefsjR8yiws4+WwCTzylmyz7XICOQMIKYzJYAg==",
|
||||
"python/iqpilot_private/emac/mac_client.cpython-312-aarch64-linux-gnu.so": "v+t4WcMEVDBv7dKdAyYbifzTqLtETnPVQy8EV+nMZ2ZJbFv0cMzGzOEdICUsMxdSz1C3Qiiy3Rxo+dxs1j4hDg==",
|
||||
"python/iqpilot_private/emac/mac_protocol.cpython-312-aarch64-linux-gnu.so": "Q9x3nM2BOXiHe6czjbQh3lMVdn+4BqfavTiwxWZt567TpOAUq7aD3Mm5ApDPk2mSd1A5m6hQqve+HGO9nIpCBQ==",
|
||||
"python/iqpilot_private/emac/maciqmodeld.cpython-312-aarch64-linux-gnu.so": "iY14YK0HANnh+RCyxnB0FMqog4a+WPRPLpMkxPaCuep+DSNE9kJuYgiRYk7Cvbfkuml1DzAMoXWWQKlu09sODw==",
|
||||
"python/iqpilot_private/emac/model_context.cpython-312-aarch64-linux-gnu.so": "OieufgDbIEweRN0FZCZSObUcv3t46RO2WobU2AmLM7orh8Y8biZxUOj1EhvZfmjAwscauU25wiVuvjOLDqn7Cg==",
|
||||
"python/iqpilot_private/emac/rh_images.cpython-312-aarch64-linux-gnu.so": "e8iJw1fAkd+pCgLjkH3NGnys7ZNjjP6+M39Aii/xWsVZHzEXT0sENxkQlkPByOOlVyrJe/QE9sZbbUL0Btu9Aw=="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
WG1x9JR+nNQKjx6iHX9H9cBQWxWpHVCMn3NHirf7IDe/MnGX/Xsdv1tHKunzhleUga6DF9uhIsxThBewBFNfAQ==
|
||||
IOy/sKa0AiLLkaZKisGB1drIhqeng32bTisZn568tz5DFMDXVYRAfLhs5BTEK54fqnCJ1V0MaGv8Y5ywh1g2Cw==
|
||||
|
||||
+44
-4
@@ -4,6 +4,8 @@ Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from iqpilot.cereal import car, custom, log
|
||||
|
||||
from iqpilot.common.constants import CV
|
||||
@@ -25,9 +27,12 @@ NavManeuverPhase = custom.IQNavState.ManeuverPhase
|
||||
|
||||
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
||||
LANE_CHANGE_TIME_MAX = 10.0
|
||||
# the model desire history spans 5 s, so one rising edge per 5 s keeps exactly one turn pulse visible
|
||||
TURN_DESIRE_PULSE_HOLD_FRAMES = round(5.0 / DT_MDL) - 1
|
||||
TURN_DESIRE_PULSE_CYCLE_FRAMES = TURN_DESIRE_PULSE_HOLD_FRAMES + 1
|
||||
# only the rising edge reaches the model and it stays visible for the 5 s the history spans, so one
|
||||
# edge per 5 s keeps the turn alive through the maneuver without stacking edges that cut the corner
|
||||
TURN_DESIRE_PULSE_CYCLE_FRAMES = round(5.0 / DT_MDL)
|
||||
TURN_DESIRE_PULSE_HOLD_FRAMES = TURN_DESIRE_PULSE_CYCLE_FRAMES - 1
|
||||
TURN_RECOIL_HEADING_RAD = math.radians(55.0)
|
||||
TURN_DESIRE_MAX_SECONDS = 25.0
|
||||
|
||||
_LANE_CHANGE_DESIRES = {
|
||||
(LaneChangeDirection.none, LaneChangeState.off): log.Desire.none,
|
||||
@@ -111,6 +116,9 @@ class DesireHelper:
|
||||
self.nav_turn_direction = TurnDirection.none
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = log.Desire.none
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
|
||||
@staticmethod
|
||||
def get_lane_change_direction(carstate):
|
||||
@@ -221,19 +229,50 @@ class DesireHelper:
|
||||
def _clear_turn_desire_pulse(self) -> None:
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = log.Desire.none
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
|
||||
def _measured_yaw_rate(self) -> float:
|
||||
# carState.yawRate is left unpopulated by many ports, so the model pose is the primary source
|
||||
rate = getattr(getattr(getattr(self, "_last_modeldata", None), "orientationRate", None), "z", None)
|
||||
try:
|
||||
if rate is not None and len(rate) and math.isfinite(rate[0]):
|
||||
return float(rate[0])
|
||||
except (TypeError, IndexError):
|
||||
pass
|
||||
try:
|
||||
return float(getattr(self._last_carstate, "yawRate", 0.0) or 0.0)
|
||||
except (TypeError, ValueError):
|
||||
return 0.0
|
||||
|
||||
def _turn_recoiled(self, desired_output: log.Desire) -> bool:
|
||||
# blinkers keep running well past the apex, so the executed heading change has to end the
|
||||
# desire: one that outlives the turn keeps steering the plan into the far side of the road
|
||||
if desired_output != self.turn_desire_cycle_input:
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
self.turn_heading_rad += abs(self._measured_yaw_rate()) * DT_MDL
|
||||
self.turn_desire_seconds += DT_MDL
|
||||
if self.turn_heading_rad >= TURN_RECOIL_HEADING_RAD or self.turn_desire_seconds >= TURN_DESIRE_MAX_SECONDS:
|
||||
self.turn_recoiled = True
|
||||
return self.turn_recoiled
|
||||
|
||||
def _pulse_turn_desire(self, desired_output: log.Desire) -> log.Desire:
|
||||
if desired_output not in _PULSED_TURN_DESIRES:
|
||||
self._clear_turn_desire_pulse()
|
||||
return desired_output
|
||||
|
||||
recoiled = self._turn_recoiled(desired_output)
|
||||
|
||||
if desired_output != self.turn_desire_cycle_input:
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = desired_output
|
||||
|
||||
cycle_frame = self.turn_desire_frames % TURN_DESIRE_PULSE_CYCLE_FRAMES
|
||||
self.turn_desire_frames += 1
|
||||
if cycle_frame >= TURN_DESIRE_PULSE_HOLD_FRAMES:
|
||||
if recoiled or cycle_frame >= TURN_DESIRE_PULSE_HOLD_FRAMES:
|
||||
return log.Desire.none
|
||||
return desired_output
|
||||
|
||||
@@ -250,6 +289,7 @@ class DesireHelper:
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob, nav_state=None, modeldata=None, radar_state=None):
|
||||
self._last_carstate = carstate
|
||||
self._last_modeldata = modeldata
|
||||
self.lateral_edge_guard.update(modeldata, carstate.vEgo, DT_MDL)
|
||||
self.lateral_edge_block = LateralEdgeBlock.none
|
||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ TurnDirection = custom.IQTurnSignalDirection
|
||||
TURN_TRIGGER_MPS = 20 * CV.MPH_TO_MS
|
||||
TURN_SPEED_GATE_MPS = TURN_TRIGGER_MPS
|
||||
LANE_CHANGE_SPEED_MIN = TURN_SPEED_GATE_MPS
|
||||
TURN_SPEED_CEILING_MPS = 35 * CV.MPH_TO_MS
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -60,7 +61,7 @@ class TurnSignalPlanner:
|
||||
def _refresh_from_params(self) -> None:
|
||||
requested_gate = _mph_param_to_mps(self._params.get("IQLaneTurnValue", return_default=True))
|
||||
self._state.active = self._params.get_bool("IQLaneTurnDesire")
|
||||
self._state.speed_limit_mps = min(TURN_TRIGGER_MPS, requested_gate)
|
||||
self._state.speed_limit_mps = min(TURN_SPEED_CEILING_MPS, requested_gate)
|
||||
|
||||
def _consume_legacy_kwargs(self, **legacy) -> tuple[bool, bool, bool, bool, float]:
|
||||
return (
|
||||
|
||||
@@ -705,6 +705,7 @@ class InferenceDaemon:
|
||||
populate_iq_model_reasoning(
|
||||
iq_msg.iqDriveModelData, outputs, self._reasoning_wire, main_stamp.frame_id, main_stamp.timestamp_eof
|
||||
)
|
||||
iq_msg.valid = driving_msg.valid
|
||||
|
||||
populate_odometry_message(
|
||||
pose_msg,
|
||||
|
||||
+12
-1
@@ -3,7 +3,18 @@ import subprocess
|
||||
|
||||
from iqpilot.common.params import Params
|
||||
|
||||
SCRIPT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "set_usb_storage.sh")
|
||||
SCRIPT_NAME = "set_usb_storage.sh"
|
||||
|
||||
|
||||
def _script_path() -> str:
|
||||
# signed bundles vendor this module without the shell script beside it
|
||||
sibling = os.path.join(os.path.dirname(os.path.abspath(__file__)), SCRIPT_NAME)
|
||||
if os.path.isfile(sibling):
|
||||
return sibling
|
||||
return os.path.join(os.environ.get("BASEDIR", "/data/iqpilot"), "iqpilot", "system", "hardware", "tici", SCRIPT_NAME)
|
||||
|
||||
|
||||
SCRIPT_PATH = _script_path()
|
||||
|
||||
|
||||
def apply_usb_storage_state(state: bool):
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -239,6 +239,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"ModelManager_ModelsCache", {PERSISTENT, JSON}},
|
||||
|
||||
{"IQEmacEnabled", {PERSISTENT, BOOL, "0"}},
|
||||
{"IQEmacSerial", {PERSISTENT, STRING}},
|
||||
{"IQEmacHost", {PERSISTENT, STRING}},
|
||||
{"IQEmacModel", {PERSISTENT, STRING}},
|
||||
{"IQEmacSmallModel", {PERSISTENT, BOOL, "0"}},
|
||||
@@ -318,6 +319,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"iqMqbSteeringLockout", {PERSISTENT, BOOL, "0"}},
|
||||
{"AllowLateralWhenLongUnavailable", {PERSISTENT, BOOL}},
|
||||
{"IQEmacEnabled", {PERSISTENT, BOOL, "0"}},
|
||||
{"IQEmacSerial", {PERSISTENT, STRING}},
|
||||
{"IQEmacHost", {PERSISTENT, STRING}},
|
||||
{"IQEmacModel", {PERSISTENT, STRING}},
|
||||
{"IQEmacSmallModel", {PERSISTENT, BOOL, "0"}},
|
||||
|
||||
@@ -148,6 +148,22 @@ def test_faulted_lateral_mode_does_not_force_disable_guidance():
|
||||
assert not selfdrive.events_iq.has(EventNameIQ.alcDisengaged)
|
||||
|
||||
|
||||
def test_guidance_keeps_steering_when_long_drops_for_faulted_cruise():
|
||||
guidance, selfdrive = make_engaged_guidance(False)
|
||||
selfdrive.enabled_prev = True
|
||||
faulted = make_vw_car_state(cruise_available=False, cruise_fault_lateral=True)
|
||||
|
||||
selfdrive.events.clear()
|
||||
selfdrive.events_iq.clear()
|
||||
selfdrive.events.add(EventName.pcmDisable)
|
||||
guidance.update(faulted)
|
||||
|
||||
assert not selfdrive.events.has(EventName.pcmDisable)
|
||||
assert not selfdrive.events_iq.has(EventNameIQ.alcDisengaged)
|
||||
assert guidance.state_machine.state == GuidanceState.enabled
|
||||
assert guidance.active
|
||||
|
||||
|
||||
def test_main_switch_rising_edge_arms_guidance_during_faulted_cruise():
|
||||
selfdrive = make_selfdrive(0, brand="volkswagen", main_cruise_allowed=True)
|
||||
selfdrive.CS_prev = make_vw_car_state(cruise_available=False, cruise_fault_lateral=False)
|
||||
|
||||
@@ -166,7 +166,7 @@ class CarSpecificEvents:
|
||||
if pcm_enable:
|
||||
if CS.cruiseState.enabled and not CS_prev.cruiseState.enabled and not CS.blockPcmEnable:
|
||||
events.add(EventName.pcmEnable)
|
||||
elif not CS.cruiseState.enabled and not getattr(CS, 'cruiseFaultLateralMode', False):
|
||||
elif not CS.cruiseState.enabled:
|
||||
events.add(EventName.pcmDisable)
|
||||
|
||||
return events
|
||||
|
||||
@@ -43,7 +43,7 @@ def make_car_state(**overrides):
|
||||
return SimpleNamespace(**base)
|
||||
|
||||
|
||||
def test_pcm_disable_suppressed_during_cruise_fault_lateral_mode():
|
||||
def test_pcm_disable_emitted_during_cruise_fault_lateral_mode():
|
||||
cp = SimpleNamespace(
|
||||
brand="volkswagen",
|
||||
openpilotLongitudinalControl=False,
|
||||
@@ -58,7 +58,8 @@ def test_pcm_disable_suppressed_during_cruise_fault_lateral_mode():
|
||||
|
||||
out = events.update(cs, cs_prev, SimpleNamespace(actuators=SimpleNamespace(accel=0.0)))
|
||||
|
||||
assert not out.has(EventName.pcmDisable)
|
||||
assert out.has(EventName.pcmDisable)
|
||||
assert out.has(EventName.cruiseFaultLateralAllowed)
|
||||
|
||||
|
||||
def test_cruise_fault_lateral_mode_replaces_acc_faulted_alert():
|
||||
|
||||
@@ -4,6 +4,8 @@ Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from iqpilot.cereal import car, custom, log
|
||||
|
||||
from iqpilot.common.constants import CV
|
||||
@@ -25,9 +27,12 @@ NavManeuverPhase = custom.IQNavState.ManeuverPhase
|
||||
|
||||
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
|
||||
LANE_CHANGE_TIME_MAX = 10.0
|
||||
# the model desire history spans 5 s, so one rising edge per 5 s keeps exactly one turn pulse visible
|
||||
TURN_DESIRE_PULSE_HOLD_FRAMES = round(5.0 / DT_MDL) - 1
|
||||
TURN_DESIRE_PULSE_CYCLE_FRAMES = TURN_DESIRE_PULSE_HOLD_FRAMES + 1
|
||||
# only the rising edge reaches the model and it stays visible for the 5 s the history spans, so one
|
||||
# edge per 5 s keeps the turn alive through the maneuver without stacking edges that cut the corner
|
||||
TURN_DESIRE_PULSE_CYCLE_FRAMES = round(5.0 / DT_MDL)
|
||||
TURN_DESIRE_PULSE_HOLD_FRAMES = TURN_DESIRE_PULSE_CYCLE_FRAMES - 1
|
||||
TURN_RECOIL_HEADING_RAD = math.radians(55.0)
|
||||
TURN_DESIRE_MAX_SECONDS = 25.0
|
||||
|
||||
_LANE_CHANGE_DESIRES = {
|
||||
(LaneChangeDirection.none, LaneChangeState.off): log.Desire.none,
|
||||
@@ -111,6 +116,9 @@ class DesireHelper:
|
||||
self.nav_turn_direction = TurnDirection.none
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = log.Desire.none
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
|
||||
@staticmethod
|
||||
def get_lane_change_direction(carstate):
|
||||
@@ -221,19 +229,50 @@ class DesireHelper:
|
||||
def _clear_turn_desire_pulse(self) -> None:
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = log.Desire.none
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
|
||||
def _measured_yaw_rate(self) -> float:
|
||||
# carState.yawRate is left unpopulated by many ports, so the model pose is the primary source
|
||||
rate = getattr(getattr(getattr(self, "_last_modeldata", None), "orientationRate", None), "z", None)
|
||||
try:
|
||||
if rate is not None and len(rate) and math.isfinite(rate[0]):
|
||||
return float(rate[0])
|
||||
except (TypeError, IndexError):
|
||||
pass
|
||||
try:
|
||||
return float(getattr(self._last_carstate, "yawRate", 0.0) or 0.0)
|
||||
except (TypeError, ValueError):
|
||||
return 0.0
|
||||
|
||||
def _turn_recoiled(self, desired_output: log.Desire) -> bool:
|
||||
# blinkers keep running well past the apex, so the executed heading change has to end the
|
||||
# desire: one that outlives the turn keeps steering the plan into the far side of the road
|
||||
if desired_output != self.turn_desire_cycle_input:
|
||||
self.turn_heading_rad = 0.0
|
||||
self.turn_desire_seconds = 0.0
|
||||
self.turn_recoiled = False
|
||||
self.turn_heading_rad += abs(self._measured_yaw_rate()) * DT_MDL
|
||||
self.turn_desire_seconds += DT_MDL
|
||||
if self.turn_heading_rad >= TURN_RECOIL_HEADING_RAD or self.turn_desire_seconds >= TURN_DESIRE_MAX_SECONDS:
|
||||
self.turn_recoiled = True
|
||||
return self.turn_recoiled
|
||||
|
||||
def _pulse_turn_desire(self, desired_output: log.Desire) -> log.Desire:
|
||||
if desired_output not in _PULSED_TURN_DESIRES:
|
||||
self._clear_turn_desire_pulse()
|
||||
return desired_output
|
||||
|
||||
recoiled = self._turn_recoiled(desired_output)
|
||||
|
||||
if desired_output != self.turn_desire_cycle_input:
|
||||
self.turn_desire_frames = 0
|
||||
self.turn_desire_cycle_input = desired_output
|
||||
|
||||
cycle_frame = self.turn_desire_frames % TURN_DESIRE_PULSE_CYCLE_FRAMES
|
||||
self.turn_desire_frames += 1
|
||||
if cycle_frame >= TURN_DESIRE_PULSE_HOLD_FRAMES:
|
||||
if recoiled or cycle_frame >= TURN_DESIRE_PULSE_HOLD_FRAMES:
|
||||
return log.Desire.none
|
||||
return desired_output
|
||||
|
||||
@@ -250,6 +289,7 @@ class DesireHelper:
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob, nav_state=None, modeldata=None, radar_state=None):
|
||||
self._last_carstate = carstate
|
||||
self._last_modeldata = modeldata
|
||||
self.lateral_edge_guard.update(modeldata, carstate.vEgo, DT_MDL)
|
||||
self.lateral_edge_block = LateralEdgeBlock.none
|
||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||
|
||||
@@ -16,6 +16,7 @@ TurnDirection = custom.IQTurnSignalDirection
|
||||
TURN_TRIGGER_MPS = 20 * CV.MPH_TO_MS
|
||||
TURN_SPEED_GATE_MPS = TURN_TRIGGER_MPS
|
||||
LANE_CHANGE_SPEED_MIN = TURN_SPEED_GATE_MPS
|
||||
TURN_SPEED_CEILING_MPS = 35 * CV.MPH_TO_MS
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -60,7 +61,7 @@ class TurnSignalPlanner:
|
||||
def _refresh_from_params(self) -> None:
|
||||
requested_gate = _mph_param_to_mps(self._params.get("IQLaneTurnValue", return_default=True))
|
||||
self._state.active = self._params.get_bool("IQLaneTurnDesire")
|
||||
self._state.speed_limit_mps = min(TURN_TRIGGER_MPS, requested_gate)
|
||||
self._state.speed_limit_mps = min(TURN_SPEED_CEILING_MPS, requested_gate)
|
||||
|
||||
def _consume_legacy_kwargs(self, **legacy) -> tuple[bool, bool, bool, bool, float]:
|
||||
return (
|
||||
|
||||
@@ -104,45 +104,49 @@ class IQFilterEngine:
|
||||
|
||||
|
||||
class IQModeEngine:
|
||||
ENTER_EVIDENCE: dict[str, float] = {'blended': 6.0, 'acc': 40.0}
|
||||
MIN_DWELL_FRAMES: dict[str, int] = {'blended': 40, 'acc': 10}
|
||||
EMERGENCY_HOLD_FRAMES = 40
|
||||
|
||||
def __init__(self):
|
||||
self._state: ModeType = 'acc'
|
||||
self._scores = {'acc': 1.0, 'blended': 0.0}
|
||||
self._switching_timer = 0
|
||||
self._pending: ModeType | None = None
|
||||
self._evidence = 0.0
|
||||
self._mode_age = 0
|
||||
self._forced_takeover = False
|
||||
self._emergency_hold = 0
|
||||
|
||||
def _switch(self, mode: ModeType) -> None:
|
||||
self._state = mode
|
||||
self._mode_age = 0
|
||||
self._pending = None
|
||||
self._evidence = 0.0
|
||||
|
||||
def request(self, mode: ModeType, urgency: float = 1.0, emergency: bool = False) -> None:
|
||||
if emergency:
|
||||
self._forced_takeover = True
|
||||
self._state = mode
|
||||
self._switching_timer = 15
|
||||
self._mode_age = 0
|
||||
self._emergency_hold = self.EMERGENCY_HOLD_FRAMES
|
||||
if mode != self._state:
|
||||
self._switch(mode)
|
||||
return
|
||||
|
||||
self._scores[mode] = min(1.0, self._scores[mode] + 0.1 * urgency)
|
||||
for key in self._scores:
|
||||
if key != mode:
|
||||
self._scores[key] = max(0.0, self._scores[key] - 0.05)
|
||||
|
||||
if self._mode_age < 10 and not self._forced_takeover:
|
||||
if mode == self._state:
|
||||
self._pending = None
|
||||
self._evidence = 0.0
|
||||
return
|
||||
|
||||
threshold = 0.6 if mode != self._state else 0.3
|
||||
if self._scores[mode] > threshold and mode != self._state and self._switching_timer == 0:
|
||||
self._switching_timer = 15
|
||||
self._state = mode
|
||||
self._mode_age = 0
|
||||
if mode != self._pending:
|
||||
self._pending = mode
|
||||
self._evidence = 0.0
|
||||
self._evidence += urgency
|
||||
|
||||
if self._emergency_hold > 0 or self._mode_age < self.MIN_DWELL_FRAMES[self._state]:
|
||||
return
|
||||
if self._evidence >= self.ENTER_EVIDENCE[mode]:
|
||||
self._switch(mode)
|
||||
|
||||
def update(self) -> None:
|
||||
if self._switching_timer > 0:
|
||||
self._switching_timer -= 1
|
||||
|
||||
self._mode_age += 1
|
||||
if self._forced_takeover and self._mode_age > 20:
|
||||
self._forced_takeover = False
|
||||
|
||||
for key in self._scores:
|
||||
self._scores[key] *= 0.98
|
||||
if self._emergency_hold > 0:
|
||||
self._emergency_hold -= 1
|
||||
|
||||
def get_mode(self) -> ModeType:
|
||||
return self._state
|
||||
|
||||
@@ -42,6 +42,11 @@ E2E_MODEL_SPEED_INTENT_BP = [-0.5, 0.0]
|
||||
_A_TOTAL_MAX_V = [1.7, 3.2]
|
||||
_A_TOTAL_MAX_BP = [20., 40.]
|
||||
|
||||
MODE_BLEND_MAX_TIME = 3.0
|
||||
MODE_BLEND_JERK_UP = 1.0
|
||||
MODE_BLEND_JERK_DOWN = 2.5
|
||||
MODE_BLEND_BRAKE_PASS = -1.0
|
||||
|
||||
def get_max_accel(v_ego):
|
||||
return np.interp(v_ego, A_CRUISE_MAX_BP, A_CRUISE_MAX_VALS)
|
||||
|
||||
@@ -88,6 +93,14 @@ def get_e2e_accel(v_ego, v_cruise, model_v, a_target, should_stop):
|
||||
return float(np.interp(min(accel_intent, speed_intent), [0.0, 1.0], [a_target, accel]))
|
||||
|
||||
|
||||
def limit_mode_transition(a_target, a_prev, dt):
|
||||
upper = a_prev + MODE_BLEND_JERK_UP * dt
|
||||
if a_target <= MODE_BLEND_BRAKE_PASS:
|
||||
return min(a_target, upper)
|
||||
lower = a_prev - MODE_BLEND_JERK_DOWN * dt
|
||||
return float(np.clip(a_target, lower, upper))
|
||||
|
||||
|
||||
def get_accel_candidates(e2e, has_lead, mpc_candidate, cruise_candidate, e2e_candidate):
|
||||
candidates = []
|
||||
if not e2e or has_lead:
|
||||
@@ -114,6 +127,8 @@ class LongitudinalPlanner(LongitudinalPlannerIQ):
|
||||
self.output_a_target = 0.0
|
||||
self.output_should_stop = False
|
||||
self.launch_armed = False
|
||||
self.prev_e2e = False
|
||||
self.mode_blend_timer = 0.0
|
||||
try:
|
||||
self.exp_speed_conv = Params().get_bool("expSpeedConv")
|
||||
except UnknownKeyName:
|
||||
@@ -248,6 +263,17 @@ class LongitudinalPlanner(LongitudinalPlannerIQ):
|
||||
self.output_should_stop = any(should_stop for _, _, should_stop in candidates)
|
||||
|
||||
self.output_should_stop = self.output_should_stop or self.forcing_stop
|
||||
|
||||
if e2e != self.prev_e2e:
|
||||
self.mode_blend_timer = MODE_BLEND_MAX_TIME
|
||||
self.prev_e2e = e2e
|
||||
if reset_state or self.fcw or self.output_should_stop:
|
||||
self.mode_blend_timer = 0.0
|
||||
if self.mode_blend_timer > 0.0:
|
||||
limited_a_target = limit_mode_transition(output_a_target, a_prev, self.dt)
|
||||
self.mode_blend_timer = 0.0 if limited_a_target == output_a_target else max(self.mode_blend_timer - self.dt, 0.0)
|
||||
output_a_target = limited_a_target
|
||||
|
||||
self.output_a_target = np.clip(output_a_target, ACCEL_MIN, ACCEL_MAX)
|
||||
|
||||
self.a_desired = float(self.output_a_target)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from iqpilot.selfdrive.controls.lib.iq_dynamic.imahelper import IQModeEngine
|
||||
from iqpilot.selfdrive.controls.lib.longitudinal_planner import (
|
||||
MODE_BLEND_BRAKE_PASS, MODE_BLEND_JERK_DOWN, MODE_BLEND_JERK_UP, limit_mode_transition,
|
||||
)
|
||||
from iqpilot.selfdrive.controls.lib.tests.test_longitudinal_planner_accel_state import CRUISE, build_planner, build_sm
|
||||
|
||||
DT = 0.05
|
||||
|
||||
|
||||
def drive(engine, requests):
|
||||
modes = []
|
||||
for mode, urgency, emergency in requests:
|
||||
engine.request(mode, urgency, emergency)
|
||||
engine.update()
|
||||
modes.append(engine.get_mode())
|
||||
return modes
|
||||
|
||||
|
||||
def count_switches(modes):
|
||||
return sum(1 for prev, cur in zip(modes, modes[1:], strict=False) if prev != cur)
|
||||
|
||||
|
||||
def test_flickering_requests_do_not_chatter():
|
||||
pattern = [('blended', 0.95, False)] * 15 + [('acc', 1.0, False)] * 15
|
||||
modes = drive(IQModeEngine(), pattern * 20)
|
||||
|
||||
assert modes[-1] == 'blended'
|
||||
assert count_switches(modes) == 1
|
||||
|
||||
|
||||
def test_sustained_acc_request_leaves_blended_after_dwell():
|
||||
engine = IQModeEngine()
|
||||
drive(engine, [('blended', 1.0, False)] * 20)
|
||||
assert engine.get_mode() == 'blended'
|
||||
|
||||
modes = drive(engine, [('acc', 0.7, False)] * 100)
|
||||
first_acc = modes.index('acc')
|
||||
|
||||
assert first_acc * DT >= 2.0
|
||||
assert modes[-1] == 'acc'
|
||||
|
||||
|
||||
def test_blended_entry_is_prompt():
|
||||
modes = drive(IQModeEngine(), [('acc', 0.7, False)] * 20 + [('blended', 0.9, False)] * 20)
|
||||
|
||||
assert modes[20:].index('blended') * DT <= 0.5
|
||||
|
||||
|
||||
def test_emergency_switches_immediately_and_holds():
|
||||
engine = IQModeEngine()
|
||||
drive(engine, [('acc', 0.7, False)] * 20)
|
||||
modes = drive(engine, [('blended', 1.0, True)] + [('acc', 1.0, False)] * 30)
|
||||
|
||||
assert modes[0] == 'blended'
|
||||
assert all(mode == 'blended' for mode in modes)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("a_prev,a_target,expected", [
|
||||
(0.0, 1.5, MODE_BLEND_JERK_UP * DT),
|
||||
(1.5, 0.0, 1.5 - MODE_BLEND_JERK_DOWN * DT),
|
||||
(0.2, MODE_BLEND_BRAKE_PASS - 0.5, MODE_BLEND_BRAKE_PASS - 0.5),
|
||||
(0.3, 0.31, 0.31),
|
||||
])
|
||||
def test_limit_mode_transition(a_prev, a_target, expected):
|
||||
assert limit_mode_transition(a_target, a_prev, DT) == pytest.approx(expected)
|
||||
|
||||
|
||||
def test_planner_output_does_not_step_on_mode_switch():
|
||||
v_ego = 12.0
|
||||
planner = build_planner(init_v=v_ego)
|
||||
e2e = {'active': True}
|
||||
planner.is_e2e = lambda sm: e2e['active']
|
||||
sm = build_sm(v_ego, 150.0, v_ego + 5.0, CRUISE)
|
||||
|
||||
for _ in range(100):
|
||||
planner.update(sm)
|
||||
blended_output = float(planner.output_a_target)
|
||||
|
||||
e2e['active'] = False
|
||||
outputs = [blended_output]
|
||||
for _ in range(60):
|
||||
planner.update(sm)
|
||||
outputs.append(float(planner.output_a_target))
|
||||
|
||||
steps = [cur - prev for prev, cur in zip(outputs, outputs[1:], strict=False)]
|
||||
assert max(steps) <= MODE_BLEND_JERK_UP * planner.dt + 1e-6
|
||||
assert outputs[-1] > blended_output + 0.5
|
||||
@@ -6,20 +6,29 @@ import pytest
|
||||
from iqpilot.cereal import custom, log
|
||||
from iqpilot.selfdrive.controls.lib.desire_helper import (
|
||||
DesireHelper,
|
||||
TURN_DESIRE_MAX_SECONDS,
|
||||
TURN_DESIRE_PULSE_CYCLE_FRAMES,
|
||||
TURN_DESIRE_PULSE_HOLD_FRAMES,
|
||||
TURN_RECOIL_HEADING_RAD,
|
||||
)
|
||||
from iqpilot.common.constants import CV
|
||||
from iqpilot.common.realtime import DT_MDL
|
||||
|
||||
|
||||
TurnDirection = custom.IQTurnSignalDirection
|
||||
MODEL_HISTORY_FRAMES = 100
|
||||
|
||||
|
||||
def helper(v_ego=0.0, yaw_rate=0.0):
|
||||
def helper(v_ego=0.0, yaw_rate=0.0, model_yaw_rate=None):
|
||||
result = DesireHelper.__new__(DesireHelper)
|
||||
result._last_carstate = SimpleNamespace(vEgo=v_ego, yawRate=yaw_rate)
|
||||
result._last_modeldata = (None if model_yaw_rate is None
|
||||
else SimpleNamespace(orientationRate=SimpleNamespace(z=[model_yaw_rate])))
|
||||
result.turn_desire_frames = 0
|
||||
result.turn_desire_cycle_input = log.Desire.none
|
||||
result.turn_heading_rad = 0.0
|
||||
result.turn_desire_seconds = 0.0
|
||||
result.turn_recoiled = False
|
||||
result.nav_turn_direction = TurnDirection.none
|
||||
result.lane_turn_direction = TurnDirection.none
|
||||
result.lane_change_direction = log.LaneChangeDirection.none
|
||||
@@ -39,7 +48,7 @@ def visible_pulses(outputs):
|
||||
|
||||
|
||||
@pytest.mark.parametrize("source", ["manual", "nav"])
|
||||
@pytest.mark.parametrize("v_ego,yaw_rate", [(0.0, 0.0), (6.0, 0.0), (4.0, 0.3)])
|
||||
@pytest.mark.parametrize("v_ego,yaw_rate", [(0.0, 0.0), (6.0, 0.0), (4.0, 0.02)])
|
||||
def test_turn_desire_keeps_exactly_one_pulse_in_model_history(source, v_ego, yaw_rate):
|
||||
h = helper(v_ego, yaw_rate)
|
||||
if source == "manual":
|
||||
@@ -58,6 +67,64 @@ def test_turn_desire_keeps_exactly_one_pulse_in_model_history(source, v_ego, yaw
|
||||
assert set(visible_pulses(outputs)[MODEL_HISTORY_FRAMES:].tolist()) == {1}
|
||||
|
||||
|
||||
def test_turn_desire_recoils_once_the_turn_has_been_driven():
|
||||
yaw_rate = 0.4
|
||||
h = helper(v_ego=6.0, yaw_rate=yaw_rate)
|
||||
h.lane_turn_direction = TurnDirection.turnLeft
|
||||
|
||||
frames_to_recoil = int(TURN_RECOIL_HEADING_RAD / (yaw_rate * DT_MDL))
|
||||
outputs = []
|
||||
for _ in range(frames_to_recoil + 4 * TURN_DESIRE_PULSE_CYCLE_FRAMES):
|
||||
h._pick_desire_output()
|
||||
outputs.append(h.desire)
|
||||
|
||||
assert log.Desire.turnLeft in outputs[:TURN_DESIRE_PULSE_HOLD_FRAMES]
|
||||
assert h.turn_recoiled
|
||||
assert all(output == log.Desire.none for output in outputs[frames_to_recoil + 1:])
|
||||
|
||||
|
||||
def test_recoil_holds_through_a_blinker_that_stays_on():
|
||||
h = helper(v_ego=6.0, yaw_rate=0.6)
|
||||
h.lane_turn_direction = TurnDirection.turnRight
|
||||
for _ in range(TURN_DESIRE_PULSE_CYCLE_FRAMES):
|
||||
h._pick_desire_output()
|
||||
assert h.turn_recoiled
|
||||
|
||||
h._last_carstate = SimpleNamespace(vEgo=6.0, yawRate=0.0)
|
||||
outputs = []
|
||||
for _ in range(3 * TURN_DESIRE_PULSE_CYCLE_FRAMES):
|
||||
h._pick_desire_output()
|
||||
outputs.append(h.desire)
|
||||
assert all(output == log.Desire.none for output in outputs)
|
||||
|
||||
|
||||
def test_recoil_clears_when_the_turn_request_drops():
|
||||
h = helper(v_ego=6.0, yaw_rate=0.6)
|
||||
h.lane_turn_direction = TurnDirection.turnRight
|
||||
for _ in range(TURN_DESIRE_PULSE_CYCLE_FRAMES):
|
||||
h._pick_desire_output()
|
||||
assert h.turn_recoiled
|
||||
|
||||
h.lane_turn_direction = TurnDirection.none
|
||||
h._pick_desire_output()
|
||||
assert not h.turn_recoiled
|
||||
assert h.turn_heading_rad == 0.0
|
||||
|
||||
h.lane_turn_direction = TurnDirection.turnRight
|
||||
h._last_carstate = SimpleNamespace(vEgo=6.0, yawRate=0.0)
|
||||
h._pick_desire_output()
|
||||
assert h.desire == log.Desire.turnRight
|
||||
|
||||
|
||||
def test_turn_desire_gives_up_when_the_blinker_outlives_the_maneuver():
|
||||
h = helper(v_ego=6.0, yaw_rate=0.0)
|
||||
h.lane_turn_direction = TurnDirection.turnLeft
|
||||
for _ in range(int(TURN_DESIRE_MAX_SECONDS / DT_MDL) + 1):
|
||||
h._pick_desire_output()
|
||||
assert h.turn_recoiled
|
||||
assert h.desire == log.Desire.none
|
||||
|
||||
|
||||
def test_new_turn_direction_restarts_pulse_immediately():
|
||||
h = helper()
|
||||
for _ in range(TURN_DESIRE_PULSE_HOLD_FRAMES // 2):
|
||||
@@ -73,3 +140,70 @@ def test_lane_change_desires_pass_through_and_reset_pulse():
|
||||
assert h._pulse_turn_desire(log.Desire.laneChangeLeft) == log.Desire.laneChangeLeft
|
||||
assert h.turn_desire_frames == 0
|
||||
assert h.turn_desire_cycle_input == log.Desire.none
|
||||
assert not h.turn_recoiled
|
||||
|
||||
|
||||
def test_turn_speed_gate_follows_the_param_past_the_old_ceiling(monkeypatch):
|
||||
from iqpilot.selfdrive.controls.lib.helpers import lane_turn
|
||||
|
||||
class FakeParams:
|
||||
def get(self, *_a, **_k):
|
||||
return "30.0"
|
||||
|
||||
def get_bool(self, *_a, **_k):
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(lane_turn, "Params", FakeParams)
|
||||
planner = lane_turn.TurnSignalPlanner(None)
|
||||
assert planner.speed_gate == pytest.approx(30.0 * CV.MPH_TO_MS)
|
||||
|
||||
planner.sample(blink_l=True, speed_mps=28.0 * CV.MPH_TO_MS)
|
||||
assert planner.output() == TurnDirection.turnLeft
|
||||
|
||||
planner.sample(blink_l=True, speed_mps=31.0 * CV.MPH_TO_MS)
|
||||
assert planner.output() == TurnDirection.none
|
||||
|
||||
|
||||
def test_turn_speed_gate_is_capped_at_the_ceiling(monkeypatch):
|
||||
from iqpilot.selfdrive.controls.lib.helpers import lane_turn
|
||||
|
||||
class FakeParams:
|
||||
def get(self, *_a, **_k):
|
||||
return "90.0"
|
||||
|
||||
def get_bool(self, *_a, **_k):
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(lane_turn, "Params", FakeParams)
|
||||
planner = lane_turn.TurnSignalPlanner(None)
|
||||
assert planner.speed_gate == pytest.approx(lane_turn.TURN_SPEED_CEILING_MPS)
|
||||
|
||||
|
||||
def test_the_turn_intent_stays_alive_through_the_maneuver():
|
||||
h = helper(v_ego=6.0, yaw_rate=0.15)
|
||||
h.lane_turn_direction = TurnDirection.turnLeft
|
||||
outputs = []
|
||||
for _ in range(int(TURN_RECOIL_HEADING_RAD / (0.15 * DT_MDL)) - 1):
|
||||
h._pick_desire_output()
|
||||
outputs.append(h.desire)
|
||||
|
||||
assert not h.turn_recoiled
|
||||
assert set(visible_pulses(outputs)[MODEL_HISTORY_FRAMES:].tolist()) == {1}
|
||||
|
||||
|
||||
def test_recoil_uses_the_model_pose_when_the_car_reports_no_yaw_rate():
|
||||
# every frame of 00000007--1984111bdd carries yawRate 0.0; the port never fills it in
|
||||
h = helper(v_ego=6.0, yaw_rate=0.0, model_yaw_rate=0.5)
|
||||
h.lane_turn_direction = TurnDirection.turnLeft
|
||||
for _ in range(int(TURN_RECOIL_HEADING_RAD / (0.5 * DT_MDL)) + 2):
|
||||
h._pick_desire_output()
|
||||
assert h.turn_recoiled
|
||||
assert h.desire == log.Desire.none
|
||||
|
||||
|
||||
def test_recoil_falls_back_to_carstate_yaw_rate():
|
||||
h = helper(v_ego=6.0, yaw_rate=0.5)
|
||||
h.lane_turn_direction = TurnDirection.turnLeft
|
||||
for _ in range(int(TURN_RECOIL_HEADING_RAD / (0.5 * DT_MDL)) + 2):
|
||||
h._pick_desire_output()
|
||||
assert h.turn_recoiled
|
||||
|
||||
@@ -705,6 +705,7 @@ class InferenceDaemon:
|
||||
populate_iq_model_reasoning(
|
||||
iq_msg.iqDriveModelData, outputs, self._reasoning_wire, main_stamp.frame_id, main_stamp.timestamp_eof
|
||||
)
|
||||
iq_msg.valid = driving_msg.valid
|
||||
|
||||
populate_odometry_message(
|
||||
pose_msg,
|
||||
|
||||
@@ -63,7 +63,7 @@ THERMAL_BANDS = OrderedDict({
|
||||
OFFROAD_DANGER_TEMP = 75
|
||||
|
||||
prev_offroad_states: dict[str, tuple[bool, str | None]] = {}
|
||||
ALLOWED_TICI_BRANCHES = {"release-new", "release-tici", "master-mici", "beta", "beta-pq", "release-prebuilt"}
|
||||
ALLOWED_TICI_BRANCHES = {"release-new", "release-tici", "release-candidate", "master-mici", "beta", "beta-pq", "release-prebuilt"}
|
||||
|
||||
|
||||
class CanStartupRecovery:
|
||||
|
||||
@@ -16,6 +16,12 @@ def test_beta_pq_allowed_for_tici():
|
||||
assert is_supported_tici_branch(metadata)
|
||||
|
||||
|
||||
def test_release_candidate_allowed_for_tici():
|
||||
metadata = SimpleNamespace(channel="release-candidate", channel_type="release")
|
||||
assert "release-candidate" in ALLOWED_TICI_BRANCHES
|
||||
assert is_supported_tici_branch(metadata)
|
||||
|
||||
|
||||
def test_tici_channel_type_allowed():
|
||||
metadata = SimpleNamespace(channel="random-branch", channel_type="tici")
|
||||
assert is_supported_tici_branch(metadata)
|
||||
|
||||
@@ -98,6 +98,18 @@ ensure_base() {
|
||||
set_attr strings/0x409/product "IQ.Pilot"
|
||||
set_attr configs/c.1/MaxPower 250
|
||||
set_attr configs/c.1/strings/0x409/configuration "IQ.Pilot"
|
||||
enable_os_desc
|
||||
}
|
||||
|
||||
# MS OS descriptors let Windows bind WinUSB to the NutCracker bulk interface with no driver install.
|
||||
# Windows caches a "no OS descriptors" answer per VID/PID/bcdDevice, so bcdDevice changes with this.
|
||||
enable_os_desc() {
|
||||
[ -d "$GADGET/os_desc" ] || return 0
|
||||
set_attr bcdDevice 0x0501
|
||||
set_attr os_desc/b_vendor_code 0xcd
|
||||
set_attr os_desc/qw_sign MSFT100
|
||||
set_attr os_desc/use 1
|
||||
[ -L "$GADGET/os_desc/c.1" ] || sudo ln -s "$GADGET/configs/c.1" "$GADGET/os_desc/c.1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
add_adb() {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import importlib.util
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
SOURCE = Path(__file__).parents[1] / "usb_storage.py"
|
||||
|
||||
|
||||
def load_from(directory: Path):
|
||||
target = directory / "usb_storage.py"
|
||||
shutil.copy(SOURCE, target)
|
||||
spec = importlib.util.spec_from_file_location(f"usb_storage_{directory.name}", target)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_script_beside_the_module_is_used(tmp_path):
|
||||
(tmp_path / "set_usb_storage.sh").write_text("")
|
||||
assert load_from(tmp_path).SCRIPT_PATH == str(tmp_path / "set_usb_storage.sh")
|
||||
|
||||
|
||||
def test_bundled_module_without_the_script_uses_the_install_tree(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("BASEDIR", "/data/iqpilot")
|
||||
assert load_from(tmp_path).SCRIPT_PATH == "/data/iqpilot/iqpilot/system/hardware/tici/set_usb_storage.sh"
|
||||
@@ -3,7 +3,18 @@ import subprocess
|
||||
|
||||
from iqpilot.common.params import Params
|
||||
|
||||
SCRIPT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "set_usb_storage.sh")
|
||||
SCRIPT_NAME = "set_usb_storage.sh"
|
||||
|
||||
|
||||
def _script_path() -> str:
|
||||
# signed bundles vendor this module without the shell script beside it
|
||||
sibling = os.path.join(os.path.dirname(os.path.abspath(__file__)), SCRIPT_NAME)
|
||||
if os.path.isfile(sibling):
|
||||
return sibling
|
||||
return os.path.join(os.environ.get("BASEDIR", "/data/iqpilot"), "iqpilot", "system", "hardware", "tici", SCRIPT_NAME)
|
||||
|
||||
|
||||
SCRIPT_PATH = _script_path()
|
||||
|
||||
|
||||
def apply_usb_storage_state(state: bool):
|
||||
|
||||
Reference in New Issue
Block a user