Compare commits
179 Commits
FrogPilot
...
oscarpilot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6831761bf | ||
|
|
cd3bd61918 | ||
|
|
649bb4076c | ||
|
|
6e5b300e5e | ||
|
|
105898ba7b | ||
|
|
270d28507a | ||
|
|
b1e8376fe8 | ||
|
|
5d10d44ff5 | ||
|
|
d4e73ccb3a | ||
|
|
532f551963 | ||
|
|
e5b1e616db | ||
|
|
8544b57780 | ||
|
|
1d507de8a7 | ||
|
|
7bc4bfc343 | ||
|
|
b1b4bcb29f | ||
|
|
5081a5d670 | ||
|
|
9de0c5484c | ||
|
|
b5e0895bef | ||
|
|
1d6a60338a | ||
|
|
340961b3d6 | ||
|
|
853a46046c | ||
|
|
0a4599280b | ||
|
|
cf322c6e67 | ||
|
|
a75f80af27 | ||
|
|
f2a6706509 | ||
|
|
b21008c466 | ||
|
|
a72cbe9191 | ||
|
|
faab849d39 | ||
|
|
9b036682a3 | ||
|
|
3d35093c86 | ||
|
|
f6a44879ff | ||
|
|
a24e5e0643 | ||
|
|
361365000b | ||
|
|
4e523dc500 | ||
|
|
5f51f7e3d7 | ||
|
|
89b2a14d05 | ||
|
|
24aa5295c0 | ||
|
|
f78628f919 | ||
|
|
f50ad15347 | ||
|
|
8fe60169a2 | ||
|
|
863e79690f | ||
|
|
c20342dfd0 | ||
|
|
38b37d25b2 | ||
|
|
3bc5e8b792 | ||
|
|
c5af834621 | ||
|
|
090af40dc1 | ||
|
|
28ff6d11e2 | ||
|
|
0f492814f4 | ||
|
|
3ba35357c7 | ||
|
|
5c2c44b780 | ||
|
|
19673dc652 | ||
|
|
915d8a058a | ||
|
|
045fc2d62b | ||
|
|
189f0da0dc | ||
|
|
eefd31d5b5 | ||
|
|
d0ccab85ec | ||
|
|
5e9d7d4776 | ||
|
|
7b92ead535 | ||
|
|
e7657d5007 | ||
|
|
915c7554e3 | ||
|
|
a0af73ebdf | ||
|
|
cca2b14612 | ||
|
|
2b1144ad13 | ||
|
|
53acbd82d0 | ||
|
|
0d8e764b7b | ||
|
|
be57e96588 | ||
|
|
74632d4f51 | ||
|
|
f5f8d0ead2 | ||
|
|
274fb8ca0d | ||
|
|
886ca6bde8 | ||
|
|
c93bda5316 | ||
|
|
8c60f0956b | ||
|
|
a5adf74b23 | ||
|
|
16cba7fca5 | ||
|
|
d561d2a1cd | ||
|
|
19bdca892a | ||
|
|
483f5c0297 | ||
|
|
f2559a0f93 | ||
|
|
a6fd1bfe03 | ||
|
|
0c5da80a05 | ||
|
|
53e8eccf4c | ||
|
|
cb4cb801c9 | ||
|
|
c43a5dac85 | ||
|
|
ae865c80de | ||
|
|
9e994a28af | ||
|
|
b0f82bfb4f | ||
|
|
2f94ff2586 | ||
|
|
f9160f89da | ||
|
|
f08ab420a5 | ||
|
|
638378439e | ||
|
|
f61dfc3321 | ||
|
|
4784743817 | ||
|
|
64acac5f13 | ||
|
|
d1c940a7fa | ||
|
|
9365afc690 | ||
|
|
08d77d9350 | ||
|
|
d766a7d1b2 | ||
|
|
b6ed5a2e25 | ||
|
|
7956d2f3d8 | ||
|
|
0076fc1bd7 | ||
|
|
4ee2476dae | ||
|
|
b09e59e104 | ||
|
|
8b60a60703 | ||
|
|
3682b25f81 | ||
|
|
154eee2f08 | ||
|
|
b3d781ef26 | ||
|
|
9eee0333ec | ||
|
|
dc1ee37053 | ||
|
|
05c45829f8 | ||
|
|
808fc67534 | ||
|
|
ee9802a513 | ||
|
|
dc9dfa03e9 | ||
|
|
17bc9cf1f3 | ||
|
|
b8aecdb78c | ||
|
|
e2ebe7048c | ||
|
|
794b1d8bdd | ||
|
|
fccc1221f6 | ||
|
|
4bbc34c365 | ||
|
|
589c5dfc82 | ||
|
|
ff80bfe06a | ||
|
|
f1c84854ed | ||
|
|
d6404224fa | ||
|
|
9fd53b7ec1 | ||
|
|
a82120e55e | ||
|
|
99006f0f6c | ||
|
|
0f5573f493 | ||
|
|
73315b7009 | ||
|
|
821d9c5807 | ||
|
|
ebad1a29b2 | ||
|
|
00bef387df | ||
|
|
13db24e327 | ||
|
|
7f7d487723 | ||
|
|
50dd50f0a7 | ||
|
|
3fc6fa0b52 | ||
|
|
412553e741 | ||
|
|
0f7641ea39 | ||
|
|
b98b001ceb | ||
|
|
af0fc9daec | ||
|
|
e10db32b69 | ||
|
|
e034f72f3d | ||
|
|
2803846987 | ||
|
|
9634f1b2e6 | ||
|
|
8f817dffd6 | ||
|
|
a380603637 | ||
|
|
9e67df39d3 | ||
|
|
2236323030 | ||
|
|
829b75411b | ||
|
|
da6553c24d | ||
|
|
4948aecc6e | ||
|
|
be628a964e | ||
|
|
52c28f6710 | ||
|
|
8d971f0671 | ||
|
|
88785baa11 | ||
|
|
b5fd185742 | ||
|
|
ad5e06b0ad | ||
|
|
96aa4c3e93 | ||
|
|
5307871310 | ||
|
|
90b8e9f072 | ||
|
|
7853d218a3 | ||
|
|
f931d2982e | ||
|
|
38a3903009 | ||
|
|
2964ede91a | ||
|
|
7949e90b75 | ||
|
|
a7e39e1ccf | ||
|
|
26af5117de | ||
|
|
a8a7c6a20c | ||
|
|
7fb4b58320 | ||
|
|
377c6e3021 | ||
|
|
9213866846 | ||
|
|
67178ebc4b | ||
|
|
746d9fc631 | ||
|
|
e55aa65d18 | ||
|
|
a4f130ba44 | ||
|
|
a81f6285c1 | ||
|
|
072ed7e50f | ||
|
|
425594dd0c | ||
|
|
b7cb5c8893 | ||
|
|
705a30835a | ||
|
|
76f2507503 |
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||||
29
README.md
@@ -1,14 +1,33 @@
|
|||||||
This is oscarpilot. It is a mod of frogpilot.
|
This is oscarpilot. It is a mod of frogpilot.
|
||||||
|
|
||||||
- increased driver monitor timeouts to 30 sec warn / 60 second fatal
|
This is for private use by Brian Hanson. If you come across this you are not intended to use it. Unathorized use of this software
|
||||||
- changed some default settings, notably farmville model default
|
is at your own risk.
|
||||||
|
|
||||||
|
Released under the MIT license. Some parts of the software are released under other licenses as specified.
|
||||||
|
|
||||||
|
Any user of this software shall indemnify and hold harmless Comma.ai, Inc, all developers of openpilot or its forks, and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys’ fees and costs) which arise out of, relate to or result from any use of this software by user.
|
||||||
|
|
||||||
|
THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT. YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS. NO WARRANTY EXPRESSED OR IMPLIED.
|
||||||
|
|
||||||
|
Changes from frogpilot 2024-01-15:
|
||||||
|
|
||||||
|
- changed some default settings, notably defaults: farmville model, disabled turn intentions
|
||||||
- disabled lane change assist
|
- disabled lane change assist
|
||||||
- disabled activation / deactivation sounds in custom sound theme
|
- disabled activation / deactivation sounds in custom sound theme
|
||||||
|
- small edits to theme
|
||||||
|
|
||||||
This is for private use by Brian Hanson. If you come across this you are not intended to use it. Unathorized use of this software
|
- increased driver monitor timeouts to 10 sec warn / 60 second terminate.
|
||||||
is at your own risk. To the greatest extent possible, by using this software, you agree to free Brian Hanson, frogpilot, and openpilot
|
- Justification:
|
||||||
of any liability by your unauthorized choice to use this software, and you use at your own risk.
|
- Many people will turn off the moinitor altogether if given the choice. There has to be a good middle ground.
|
||||||
|
- The monitor's primary responsibility should be to detect when the driver has fallen asleep perhaps, which shouldn't
|
||||||
|
ever happen, but if it does will certainly result in the death of the driver and possibly others. This is critical
|
||||||
|
enough that the car should make very lound angry noises after a threshold which only should happen if the driver
|
||||||
|
has flat out stopped paying attention to driving. The shreeking and continuing to drive is preferable to a car
|
||||||
|
stopping in traffic with its hazards off, as a result the car should keep driving for a reasonable amount of time
|
||||||
|
that the driver would be reawoken.
|
||||||
|
|
||||||
|
Goals:
|
||||||
|
- Conditional experimental mode: override speed on stock ACC, set to experimental mode, revert to last speed when recovered. Last speed updated to car speed limit on change.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
1
commit_and_push
Normal file
@@ -0,0 +1 @@
|
|||||||
|
git add -A; git commit -m "wip"; bash push_private
|
||||||
@@ -244,6 +244,10 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"Compass", PERSISTENT},
|
{"Compass", PERSISTENT},
|
||||||
{"ConditionalExperimental", PERSISTENT},
|
{"ConditionalExperimental", PERSISTENT},
|
||||||
{"CurrentRandomEvent", PERSISTENT},
|
{"CurrentRandomEvent", PERSISTENT},
|
||||||
|
{"CSLCAvailable", PERSISTENT},
|
||||||
|
{"CSLCEnabled", PERSISTENT},
|
||||||
|
{"CSLCSetSpeed", PERSISTENT},
|
||||||
|
{"CSLCTempSpeed", PERSISTENT},
|
||||||
{"CurveSensitivity", PERSISTENT},
|
{"CurveSensitivity", PERSISTENT},
|
||||||
{"CustomColors", PERSISTENT},
|
{"CustomColors", PERSISTENT},
|
||||||
{"CustomIcons", PERSISTENT},
|
{"CustomIcons", PERSISTENT},
|
||||||
@@ -327,6 +331,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
|||||||
{"ReverseCruise", PERSISTENT},
|
{"ReverseCruise", PERSISTENT},
|
||||||
{"RoadEdgesWidth", PERSISTENT},
|
{"RoadEdgesWidth", PERSISTENT},
|
||||||
{"RoadName", PERSISTENT},
|
{"RoadName", PERSISTENT},
|
||||||
|
{"oscar_debug", PERSISTENT},
|
||||||
{"RoadNameUI", PERSISTENT},
|
{"RoadNameUI", PERSISTENT},
|
||||||
{"RotatingWheel", PERSISTENT},
|
{"RotatingWheel", PERSISTENT},
|
||||||
{"SchedulePending", PERSISTENT},
|
{"SchedulePending", PERSISTENT},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optiona
|
||||||
|
|
||||||
from openpilot.common.params import Params
|
from openpilot.common.params import Params
|
||||||
from openpilot.system.hardware.hw import Paths
|
from openpilot.system.hardware.hw import Paths
|
||||||
|
|||||||
33
common/watcher.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import socket
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Initialize the socket without connecting
|
||||||
|
watcher_sock = None
|
||||||
|
|
||||||
|
class Watcher:
|
||||||
|
@staticmethod
|
||||||
|
def ensure_socket_connected():
|
||||||
|
global watcher_sock
|
||||||
|
if watcher_sock is None or watcher_sock.fileno() == -1: # Checks if socket is not initialized or closed
|
||||||
|
try:
|
||||||
|
# Attempt to initialize and connect the socket
|
||||||
|
watcher_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
watcher_sock.connect("/tmp/oscar_watcher.sock")
|
||||||
|
except socket.error:
|
||||||
|
# If connection fails, set sock to None and do nothing
|
||||||
|
watcher_sock = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def log_watch(var_name, message):
|
||||||
|
global watcher_sock
|
||||||
|
Watcher.ensure_socket_connected() # Ensure the socket is connected before attempting to log
|
||||||
|
if watcher_sock: # Proceed only if sock is not None (i.e., is connected)
|
||||||
|
message_json = json.dumps([var_name, message])
|
||||||
|
try:
|
||||||
|
watcher_sock.sendall(message_json.encode('utf-8') + b'\n')
|
||||||
|
except socket.error:
|
||||||
|
# Handle potential error in sending (e.g., if connection was lost)
|
||||||
|
watcher_sock = None # Ensure that the next attempt will try to reconnect
|
||||||
|
finally:
|
||||||
|
watcher_sock.close() # Close the current socket to clean up resources
|
||||||
|
watcher_sock = None # Reset sock to ensure reconnection attempt on next call
|
||||||
2457
hyundai_can_full.dbc
Normal file
719
hyundai_canfd.dbc
Normal file
@@ -0,0 +1,719 @@
|
|||||||
|
VERSION ""
|
||||||
|
|
||||||
|
|
||||||
|
NS_ :
|
||||||
|
NS_DESC_
|
||||||
|
CM_
|
||||||
|
BA_DEF_
|
||||||
|
BA_
|
||||||
|
VAL_
|
||||||
|
CAT_DEF_
|
||||||
|
CAT_
|
||||||
|
FILTER
|
||||||
|
BA_DEF_DEF_
|
||||||
|
EV_DATA_
|
||||||
|
ENVVAR_DATA_
|
||||||
|
SGTYPE_
|
||||||
|
SGTYPE_VAL_
|
||||||
|
BA_DEF_SGTYPE_
|
||||||
|
BA_SGTYPE_
|
||||||
|
SIG_TYPE_REF_
|
||||||
|
VAL_TABLE_
|
||||||
|
SIG_GROUP_
|
||||||
|
SIG_VALTYPE_
|
||||||
|
SIGTYPE_VALTYPE_
|
||||||
|
BO_TX_BU_
|
||||||
|
BA_DEF_REL_
|
||||||
|
BA_REL_
|
||||||
|
BA_DEF_DEF_REL_
|
||||||
|
BU_SG_REL_
|
||||||
|
BU_EV_REL_
|
||||||
|
BU_BO_REL_
|
||||||
|
SG_MUL_VAL_
|
||||||
|
|
||||||
|
BS_:
|
||||||
|
|
||||||
|
BU_: XXX CAMERA FRONT_RADAR ADRV APRK
|
||||||
|
|
||||||
|
|
||||||
|
BO_ 53 ACCELERATOR: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ GEAR : 192|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ ACCELERATOR_PEDAL : 40|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 64 GEAR_ALT: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ GEAR : 32|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
|
||||||
|
BO_ 69 GEAR: 24 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ GEAR : 44|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
|
||||||
|
BO_ 80 LKAS: 16 XXX
|
||||||
|
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
|
||||||
|
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 81 ADRV_0x51: 32 ADRV
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
|
||||||
|
BO_ 96 ESP_STATUS: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ TRACTION_AND_STABILITY_CONTROL : 42|3@1+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ BRAKE_PRESSURE : 128|10@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ BRAKE_PRESSED : 148|1@1+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 101 BRAKE: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BRAKE_POSITION : 40|16@1- (1,0) [0|65535] "" XXX
|
||||||
|
SG_ BRAKE_PRESSED : 57|1@1+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 112 GEAR_ALT_2: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ GEAR : 60|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
|
||||||
|
BO_ 160 WHEEL_SPEEDS: 24 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ MOVING_FORWARD : 56|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ MOVING_BACKWARD : 57|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ MOVING_FORWARD2 : 58|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ MOVING_BACKWARD2 : 59|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ WHEEL_SPEED_1 : 64|16@1+ (0.03125,0) [0|65535] "kph" XXX
|
||||||
|
SG_ WHEEL_SPEED_2 : 80|16@1+ (0.03125,0) [0|65535] "kph" XXX
|
||||||
|
SG_ WHEEL_SPEED_3 : 96|16@1+ (0.03125,0) [0|65535] "kph" XXX
|
||||||
|
SG_ WHEEL_SPEED_4 : 112|16@1+ (0.03125,0) [0|65535] "kph" XXX
|
||||||
|
|
||||||
|
BO_ 234 MDPS: 24 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LKA_ACTIVE : 48|1@0+ (1,0) [0|16777215] "" XXX
|
||||||
|
SG_ LKA_FAULT : 54|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ STEERING_OUT_TORQUE : 64|12@1+ (0.1,-204.8) [0|65535] "" XXX
|
||||||
|
SG_ STEERING_COL_TORQUE : 80|13@1+ (1,-4095) [0|4095] "" XXX
|
||||||
|
SG_ STEERING_ANGLE : 96|16@1- (-0.1,0) [0|255] "deg" XXX
|
||||||
|
SG_ STEERING_ANGLE_2 : 128|16@1- (-0.1,0) [0|65535] "deg" XXX
|
||||||
|
|
||||||
|
BO_ 256 ACCELERATOR_BRAKE_ALT: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BRAKE_PRESSED : 32|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ACCELERATOR_PEDAL_PRESSED : 176|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 261 ACCELERATOR_ALT: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ ACCELERATOR_PEDAL : 103|10@1+ (0.25,0) [0|1022] "" XXX
|
||||||
|
|
||||||
|
BO_ 272 LKAS_ALT: 32 XXX
|
||||||
|
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
|
||||||
|
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 293 STEERING_SENSORS: 16 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ STEERING_RATE : 40|8@1+ (4,0) [0|1016] "deg/s" XXX
|
||||||
|
SG_ STEERING_ANGLE : 24|16@1- (-0.1,0) [0|255] "deg" XXX
|
||||||
|
|
||||||
|
BO_ 298 LFA: 16 ADRV
|
||||||
|
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
|
||||||
|
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 111|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 304 GEAR_SHIFTER: 16 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ PARK_BUTTON : 32|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ GEAR : 64|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ KNOB_POSITION : 40|3@1+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 357 SPAS1: 24 APRK
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|0] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 96|16@1- (0.1,0) [0|0] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 90|3@1+ (1,0) [0|0] "" XXX
|
||||||
|
|
||||||
|
BO_ 362 SPAS2: 32 APRK
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|0] "" XXX
|
||||||
|
SG_ BLINKER_CONTROL : 133|3@1+ (1,0) [0|0] "" XXX
|
||||||
|
|
||||||
|
BO_ 373 TCS: 24 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 80|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 74|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 76|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_4 : 24|7@1+ (1,0) [0|127] "" XXX
|
||||||
|
SG_ aBasis : 32|11@1+ (0.01,-10.23) [0|7] "m/s^2" XXX
|
||||||
|
SG_ NEW_SIGNAL_5 : 72|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_6 : 128|4@1+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_7 : 135|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ PROBABLY_EQUIP : 136|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ AEB_EQUIP_MAYBE : 96|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ EQUIP_MAYBE : 64|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ DriverBraking : 81|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ DriverBrakingLowSens : 84|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ACC_REQ : 68|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ACCEL_REF_ACC : 48|11@1- (1,0) [0|1023] "" XXX
|
||||||
|
SG_ ACCEnable : 67|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 352 ADRV_0x160: 16 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_FF : 64|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_FC : 72|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_2 : 56|8@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ AEB_SETTING : 24|2@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_9 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 384 CAM_0x180: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 385 CAM_0x181: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 386 CAM_0x182: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 387 CAM_0x183: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 388 CAM_0x184: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 389 CAM_0x185: 8 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 416 SCC_CONTROL: 32 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 64|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_8 : 170|4@1+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ ZEROS : 215|48@0+ (1,0) [0|281474976710655] "" XXX
|
||||||
|
SG_ ZEROS_3 : 191|7@0+ (1,0) [0|127] "" XXX
|
||||||
|
SG_ ZEROS_4 : 183|4@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ ZEROS_6 : 119|16@0+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ ZEROS_8 : 95|5@0+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 109|2@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ SET_ME_TMP_64 : 55|8@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ SET_ME_2 : 105|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_6 : 104|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ ZEROS_9 : 71|5@1+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ ZEROS_10 : 111|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_3 : 45|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ ObjValid : 46|1@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 168|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ OBJ_STATUS : 176|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ ACC_ObjDist : 24|11@1+ (0.1,0) [0|204.7] "m" XXX
|
||||||
|
SG_ ZEROS_5 : 77|11@1+ (1,0) [0|2047] "" XXX
|
||||||
|
SG_ DISTANCE_SETTING : 88|3@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ ZEROS_2 : 207|5@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ CRUISE_STANDSTILL : 76|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ aReqRaw : 140|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
|
||||||
|
SG_ aReqValue : 128|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
|
||||||
|
SG_ ZEROS_7 : 63|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ ACCMode : 68|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_12 : 35|9@1+ (0.1,0) [0|255] "" XXX
|
||||||
|
SG_ JerkLowerLimit : 166|7@0+ (0.1,0) [0|12.7] "m/s^3" XXX
|
||||||
|
SG_ StopReq : 184|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_15 : 192|11@1+ (0.1,0) [0|204.7] "m" XXX
|
||||||
|
SG_ VSetDis : 103|8@0+ (1,0) [0|255] "km/h or mph" XXX
|
||||||
|
SG_ MainMode_ACC : 66|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ JerkUpperLimit : 158|7@0+ (0.1,0) [0|0] "" XXX
|
||||||
|
|
||||||
|
BO_ 426 CRUISE_BUTTONS_ALT: 16 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 24|4@1+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ SET_ME_1 : 28|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ DISTANCE_UNIT : 30|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 31|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ ADAPTIVE_CRUISE_MAIN_BTN : 34|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 35|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LFA_BTN : 39|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ CRUISE_BUTTONS : 36|3@1+ (1,0) [0|4] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_4 : 40|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NORMAL_CRUISE_MAIN_BTN : 41|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_5 : 42|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_2 : 44|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_6 : 47|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE7 : 56|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 438 CAM_0x1b6: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 439 CAM_0x1b7: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 440 CAM_0x1b8: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 441 CAM_0x1b9: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 463 CRUISE_BUTTONS: 8 XXX
|
||||||
|
SG_ _CHECKSUM : 0|8@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ LKAS_BTN : 23|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ SET_ME_1 : 29|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ADAPTIVE_CRUISE_MAIN_BTN : 19|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NORMAL_CRUISE_MAIN_BTN : 21|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ COUNTER : 12|4@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CRUISE_BUTTONS : 16|3@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ RIGHT_PADDLE : 25|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LEFT_PADDLE : 27|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 474 ADRV_0x1da: 32 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_22 : 31|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_41 : 47|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 480 LFAHDA_CLUSTER: 16 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ HDA_ICON : 31|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LFA_ICON : 47|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 32|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 30|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 49|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_4 : 24|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 490 ADRV_0x1ea: 32 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_1C : 31|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 32|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 47|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 55|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_4 : 64|6@1+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_5 : 72|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_6 : 75|5@1+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_7 : 80|5@1+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_8 : 88|7@1+ (1,0) [0|127] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_9 : 96|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_10 : 143|5@0+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_11 : 144|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_12 : 152|6@1+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_13 : 160|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_14 : 163|5@1+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_15 : 175|4@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_16 : 168|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_17 : 176|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_18 : 184|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_19 : 208|3@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_20 : 212|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ SET_ME_FF : 120|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_TMP_F : 232|5@1+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ SET_ME_TMP_F_2 : 240|5@1+ (1,0) [0|31] "" XXX
|
||||||
|
|
||||||
|
BO_ 507 CAM_0x1fb: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 512 ADRV_0x200: 8 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_E1 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_3A : 32|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 513 RADAR_0x201: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 528 RADAR_0x210: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 529 RADAR_0x211: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 530 RADAR_0x212: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 531 RADAR_0x213: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 532 RADAR_0x214: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 533 RADAR_0x215: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 534 RADAR_0x216: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 535 RADAR_0x217: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 536 RADAR_0x218: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 537 RADAR_0x219: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 538 RADAR_0x21a: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 539 RADAR_0x21b: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 540 RADAR_0x21c: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 541 RADAR_0x21d: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 542 RADAR_0x21e: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 543 RADAR_0x21f: 32 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 576 RADAR_0x240: 16 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 593 RADAR_0x251: 16 FRONT_RADAR
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 674 CAM_0x2a2: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 675 CAM_0x2a3: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 676 CAM_0x2a4: 24 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 699 CAM_0x2bb: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 700 CAM_0x2bc: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 701 CAM_0x2bd: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 702 CAM_0x2be: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 736 MANUAL_SPEED_LIMIT_ASSIST: 32 XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ MSLA_STATUS : 26|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ MSLA_ENABLED : 38|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ MAX_SPEED : 55|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ MAX_SPEED_COPY : 144|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 837 ADRV_0x345: 8 ADRV
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SET_ME_15 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 866 CAM_0x362: 32 CAMERA
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE24 : 192|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE25 : 200|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE26 : 208|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE27 : 216|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE28 : 224|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE29 : 232|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE30 : 240|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ BYTE31 : 248|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 961 BLINKER_STALKS: 8 XXX
|
||||||
|
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ HIGHBEAM_FORWARD : 18|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ HIGHBEAM_BACKWARD : 26|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RIGHT_BLINKER : 32|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LEFT_BLINKER : 30|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LIGHT_KNOB_POSITION : 21|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 1041 DOORS_SEATBELTS: 8 XXX
|
||||||
|
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ DRIVER_DOOR : 24|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ PASSENGER_DOOR : 34|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ DRIVER_REAR_DOOR : 52|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ PASSENGER_REAR_DOOR : 56|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ DRIVER_SEATBELT : 42|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ PASSENGER_SEATBELT : 36|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 1043 BLINKERS: 8 XXX
|
||||||
|
SG_ LEFT_STALK : 8|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RIGHT_STALK : 10|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
|
||||||
|
SG_ LEFT_LAMP : 20|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RIGHT_LAMP : 22|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LEFT_LAMP_ALT : 59|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RIGHT_LAMP_ALT : 61|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ USE_ALT_LAMP : 62|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 1240 CLUSTER_INFO: 8 XXX
|
||||||
|
SG_ DISTANCE_UNIT : 0|1@1+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 442 BLINDSPOTS_REAR_CORNERS: 24 XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 96|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ COLLISION_AVOIDANCE_ACTIVE : 68|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ LEFT_MB : 30|1@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ LEFT_BLOCKED : 24|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ MORE_LEFT_PROB : 32|1@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ FL_INDICATOR : 46|6@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ FR_INDICATOR : 54|6@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ RIGHT_BLOCKED : 64|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 874 BLINDSPOTS_FRONT_CORNER_2: 16 XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
|
||||||
|
BO_ 485 BLINDSPOTS_FRONT_CORNER_1: 16 XXX
|
||||||
|
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_1 : 108|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_2 : 96|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 88|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_4 : 80|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_5 : 31|2@0+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ REVERSING : 24|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_7 : 32|2@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_8 : 47|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_9 : 55|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
|
||||||
|
BO_ 506 CLUSTER_SPEED_LIMIT: 32 XXX
|
||||||
|
SG_ SPEED_LIMIT_3 : 119|8@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SPEED_LIMIT_2 : 47|7@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SPEED_LIMIT_1 : 39|7@0+ (1,0) [0|255] "" XXX
|
||||||
|
SG_ SPEED_CHANGE_BLINKING : 129|1@1+ (1,0) [0|3] "" XXX
|
||||||
|
SG_ CHIME_2 : 122|2@1+ (1,0) [0|7] "" XXX
|
||||||
|
SG_ CHIME_1 : 133|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ARROW_DOWN : 120|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ ARROW_UP : 121|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ SECONDARY_LIMIT_1 : 79|8@0+ (1,0) [0|127] "" XXX
|
||||||
|
SG_ SECONDARY_LIMIT_2 : 103|8@0+ (1,0) [0|127] "" XXX
|
||||||
|
SG_ SCHOOL_ZONE : 155|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 1144 DRIVE_MODE: 8 XXX
|
||||||
|
SG_ DRIVE_MODE : 0|16@1+ (1,-61611) [0|61611] "" XXX
|
||||||
|
SG_ DRIVE_MODE2 : 28|3@1+ (1,0) [1|3] "" XXX
|
||||||
|
|
||||||
|
BO_ 1151 HVAC_TOUCH_BUTTONS: 8 XXX
|
||||||
|
SG_ AUTO_BUTTON : 8|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ SYNC_BUTTON : 12|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ FR_DEFROST_BUTTON : 20|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RR_DEFROST_BUTTON : 22|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ FAN_SPEED_UP_BUTTON : 24|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ FAN_SPEED_DOWN_BUTTON : 26|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ AIR_DIRECTION_BUTTON : 28|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ AC_BUTTON : 40|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ DRIVER_ONLY_BUTTON : 44|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ RECIRC_BUTTON : 48|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
SG_ HEAT_BUTTON : 52|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 1259 LOCAL_TIME2: 8 XXX
|
||||||
|
SG_ HOURS : 15|5@0+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ SECONDS : 24|6@1+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ NEW_SIGNAL_3 : 39|1@0+ (1,0) [0|1] "" XXX
|
||||||
|
|
||||||
|
BO_ 1264 LOCAL_TIME: 8 XXX
|
||||||
|
SG_ HOURS : 12|5@0+ (1,0) [0|31] "" XXX
|
||||||
|
SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX
|
||||||
|
SG_ SECONDS : 31|8@0+ (1,0) [0|59] "" XXX
|
||||||
|
|
||||||
|
CM_ 272 "Alternative LKAS message, used on cars such as 2023 Ioniq 6, 2nd gen Kona. Matches LKAS except size is 32 bytes";
|
||||||
|
CM_ 676 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA.";
|
||||||
|
CM_ 866 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA. Used on cars that use message 272.";
|
||||||
|
CM_ 1043 "Lamp signals do not seem universal on cars that use LKAS_ALT, but stalk signals do.";
|
||||||
|
|
||||||
|
CM_ SG_ 80 HAS_LANE_SAFETY "If 0, hides LKAS 'Lane Safety' menu from vehicle settings";
|
||||||
|
CM_ SG_ 96 BRAKE_PRESSURE "User applied brake pedal pressure. Ramps from computer applied pressure on falling edge of cruise. Cruise cancels if !=0";
|
||||||
|
CM_ SG_ 101 BRAKE_POSITION "User applied brake pedal position, max is ~700. Signed on some vehicles";
|
||||||
|
CM_ SG_ 373 PROBABLY_EQUIP "aeb equip?";
|
||||||
|
CM_ SG_ 373 ACCEnable "Likely a copy of CAN's TCS13->ACCEnable";
|
||||||
|
CM_ SG_ 373 DriverBraking "Likely derived from BRAKE->BRAKE_POSITION";
|
||||||
|
CM_ SG_ 373 DriverBrakingLowSens "Higher threshold version of DriverBraking";
|
||||||
|
CM_ SG_ 352 SET_ME_9 "has something to do with AEB settings";
|
||||||
|
CM_ SG_ 416 VSetDis "set speed in display units";
|
||||||
|
CM_ SG_ 676 LEFT_LANE_LINE "Left lane line confidence";
|
||||||
|
CM_ SG_ 676 RIGHT_LANE_LINE "Right lane line confidence";
|
||||||
|
CM_ SG_ 736 MAX_SPEED "Display units. Restricts car from driving above this speed unless accelerator pedal is depressed beyond pressure point";
|
||||||
|
CM_ SG_ 866 LEFT_LANE_LINE "Left lane line confidence";
|
||||||
|
CM_ SG_ 866 RIGHT_LANE_LINE "Right lane line confidence";
|
||||||
|
CM_ SG_ 961 COUNTER_ALT "only increments on change";
|
||||||
|
CM_ SG_ 1041 COUNTER_ALT "only increments on change";
|
||||||
|
CM_ SG_ 1043 COUNTER_ALT "only increments on change";
|
||||||
|
CM_ SG_ 1043 USE_ALT_LAMP "likely 1 on cars that use alt lamp signals";
|
||||||
|
VAL_ 53 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
|
||||||
|
VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
|
||||||
|
VAL_ 69 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
|
||||||
|
VAL_ 112 GEAR 0 "P" 5 "D" 6 "N" 7 "R" ;
|
||||||
|
VAL_ 80 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
|
||||||
|
VAL_ 80 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
|
||||||
|
VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off";
|
||||||
|
VAL_ 234 LKA_FAULT 0 "ok" 1 "lka fault" ;
|
||||||
|
VAL_ 272 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
|
||||||
|
VAL_ 272 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
|
||||||
|
VAL_ 298 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green" ;
|
||||||
|
VAL_ 298 LKA_MODE 1 "warning only" 2 "assist" 6 "off" ;
|
||||||
|
VAL_ 304 PARK_BUTTON 1 "Pressed" 2 "Not Pressed";
|
||||||
|
VAL_ 304 KNOB_POSITION 1 "R" 2 "N (on R side)" 3 "Centered" 4 "N (on D side)" 5 "D";
|
||||||
|
VAL_ 304 GEAR 1 "P" 2 "R" 3 "N" 4 "D" ;
|
||||||
|
VAL_ 352 AEB_SETTING 1 "off" 2 "warning only" 3 "active assist" ;
|
||||||
|
VAL_ 362 BLINKER_CONTROL 1 "hazards" 2 "hazards button backlight" 3 "left blinkers" 4 "right blinkers";
|
||||||
|
VAL_ 373 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
|
||||||
|
VAL_ 416 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled" ;
|
||||||
|
VAL_ 426 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume" ;
|
||||||
|
VAL_ 463 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume" ;
|
||||||
|
VAL_ 463 RIGHT_PADDLE 0 "Not Pulled" 1 "Pulled";
|
||||||
|
VAL_ 463 LEFT_PADDLE 0 "Not Pulled" 1 "Pulled";
|
||||||
|
VAL_ 676 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
|
||||||
|
VAL_ 676 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
|
||||||
|
VAL_ 736 MSLA_STATUS 0 "disabled" 1 "active" 2 "paused";
|
||||||
|
VAL_ 866 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
|
||||||
|
VAL_ 866 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
|
||||||
|
VAL_ 1041 DRIVER_DOOR 0 "Closed" 1 "Opened";
|
||||||
|
VAL_ 1041 PASSENGER_DOOR 0 "Closed" 1 "Opened";
|
||||||
|
VAL_ 1041 DRIVER_REAR_DOOR 0 "Closed" 1 "Opened";
|
||||||
|
VAL_ 1041 PASSENGER_REAR_DOOR 0 "Closed" 1 "Opened";
|
||||||
|
VAL_ 1041 DRIVER_SEATBELT 0 "Unlatched" 1 "Latched";
|
||||||
|
VAL_ 1041 PASSENGER_SEATBELT 0 "Unlatched" 1 "Latched";
|
||||||
|
VAL_ 1144 DRIVE_MODE2 3 "Set Sport" 1 "Set Normal" 2 "Set Eco";
|
||||||
|
VAL_ 1240 DISTANCE_UNIT 1 "Miles" 0 "Kilometers";
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
cd /data/openpilot
|
||||||
|
|
||||||
|
bash /data/openpilot/shell/init_shell.sh
|
||||||
|
|
||||||
|
# Blank the UI (assuming framebuffer device is /dev/fb0)
|
||||||
|
# This command clears the framebuffer, effectively blanking the screen
|
||||||
|
|
||||||
export PASSIVE="0"
|
export PASSIVE="0"
|
||||||
exec ./launch_chffrplus.sh
|
exec ./launch_chffrplus.sh
|
||||||
|
|
||||||
|
|||||||
0
logs/blank
Normal file
103
notes
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
hyundai/interface ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
|
||||||
|
|
||||||
|
- The speedometer icons are at:
|
||||||
|
- void AnnotatedCameraWidget::updateState(const UIState &s) {
|
||||||
|
|
||||||
|
- Test: no more wheel or record icons
|
||||||
|
|
||||||
|
- test: 5 minute timeout settings screen
|
||||||
|
- SSH reverse proxy if it is my personal dongle ID
|
||||||
|
- Read all car variables:
|
||||||
|
- Dash speed
|
||||||
|
- Experimental desired speed
|
||||||
|
- engagement
|
||||||
|
- UI updates:
|
||||||
|
- Turn HDA2 icon off if in experimental mode
|
||||||
|
- Show "AUTO" in green if in auto speed mode via wheel icon
|
||||||
|
- Simulated button presses
|
||||||
|
- Down / Up / Resume
|
||||||
|
- CAN data:
|
||||||
|
- Windows down
|
||||||
|
- Lead car distance while in stocklong
|
||||||
|
- Lead car is getting away
|
||||||
|
- Disable all telemetry to comma
|
||||||
|
- Conditional telemetry to me
|
||||||
|
- More than one wifi network - specify set wifi network for dashcam / route uploads and one for basic coms
|
||||||
|
- Implement stocklong on GM cars
|
||||||
|
- settings screen updates
|
||||||
|
- store / restore OP settings on my server
|
||||||
|
- cleanup code / reorganize fork
|
||||||
|
- Info button interception
|
||||||
|
- Set speedometer as main display on car start
|
||||||
|
- Set hvac to standard when car started w/ key (openpilot on)
|
||||||
|
- Store settings on device and on server when possible by dongle id. restore settings on boot.
|
||||||
|
- Bring up wifi before compile. If automatic updates are enabled and a update is available, fetch it and compile.
|
||||||
|
- disable lat turn signal below hwy speeds
|
||||||
|
- setting: disable lane change assist alltogether
|
||||||
|
- setting: auto passive dash cam recorder / uploader
|
||||||
|
- new home screen - weather, radar, location, car status, other fun things
|
||||||
|
- car location tracker automatic upload / api of car location
|
||||||
|
- can i get the cabin temprature from the comma??? display on home screen?
|
||||||
|
- review "BBOTCRASH" - rewrite the crash handler
|
||||||
|
- show map illustration, and drive stats, on route completion
|
||||||
|
https://github.com/pfeiferj/pfeifer-pilot-patches/tree/pfeifer-openpilot-patches/speed-limit-control
|
||||||
|
https://github.com/pfeiferj/pfeifer-pilot-patches/tree/pfeifer-openpilot-patches/disable-dcam-upload
|
||||||
|
https://github.com/pfeiferj/pfeifer-pilot-patches/tree/pfeifer-openpilot-patches/disable-registration
|
||||||
|
https://github.com/pfeiferj/pfeifer-pilot-patches/blob/pfeifer-openpilot-patches/notes/bus%20numbers.md
|
||||||
|
|
||||||
|
- It should do practically everything that opkr fork does
|
||||||
|
- MOST NOTABLY SteerActuatorDelay
|
||||||
|
|
||||||
|
Weather:
|
||||||
|
Ideally we intercept the info buttons on the wheel to control this.
|
||||||
|
UI: https://github.com/jclarke0000/MMM-OpenWeatherForecast/blob/master/README.md
|
||||||
|
Radar: https://github.com/jojoduquartier/MMM-RAIN-RADAR
|
||||||
|
Embed possibility: https://cefview.github.io/QCefView/docs/intros/buiding
|
||||||
|
Openpilot implementation example: https://github.com/twilsonco/openpilot
|
||||||
|
|
||||||
|
Get modem tempratures:
|
||||||
|
gdbus call --system --dest org.freedesktop.ModemManager1 --object-path /org/freedesktop/ModemManager1/Modem/1 --method org.freedesktop.ModemManager1.Modem.Command "AT+QTEMP" 50
|
||||||
|
|
||||||
|
Goals:
|
||||||
|
1 - get current dash speed via calculate_speed_limit_canfd
|
||||||
|
2 - issue set decel button via LFA button (proof of concept)
|
||||||
|
3 - chirp when speed limit changes
|
||||||
|
4 - Use LFA button to set speed of cruise to desired speed - 0-36 speed limit +3, 36-59 + 5, >= 60 +7
|
||||||
|
5 - On experimental mode engage, adjust cruise speed to experimental model speed
|
||||||
|
- Verify pause lateral under 30 is enabled
|
||||||
|
Wishlist:
|
||||||
|
- When car reports seeing lanes, turn lane keep over to car, resume when car can't see lanes or turn signal is activated
|
||||||
|
- Get hyundai speed limit reader merged into frogpilot
|
||||||
|
- Get stock experimental mode controller merged into frogpilot
|
||||||
|
- send canbus messages for current nav instruction / song playing - add my own notices
|
||||||
|
- start car on speedometer display
|
||||||
|
- signal windows are rolled down when turning off car
|
||||||
|
- Setup sentry
|
||||||
|
|
||||||
|
Pie in the sky:
|
||||||
|
- Roll up windows on power off (debug dump canbus)
|
||||||
|
OPKR features:
|
||||||
|
- Auto Resume at Stop
|
||||||
|
- Button Spam CC
|
||||||
|
- auto select speedometer on boot
|
||||||
|
- Accelerated Departure by Cruise Gap: Cruise gap automatically changed to step 1 for faster departure, sets back to orignal gap selection after few second.
|
||||||
|
- Weather radar screen (accessible by wheel)
|
||||||
|
- weather forecast screen (also by wheel)
|
||||||
|
- auto consent to carplay on car start
|
||||||
|
- auto hvac to comfortable on drve mode
|
||||||
|
|
||||||
|
ret.cruiseState.standstill cp_scc.vl["SCC11"]["SCCInfoDisplay"] == 4.
|
||||||
|
|
||||||
|
Interesting can messages
|
||||||
|
|
||||||
|
SG_ C_SunRoofOpenState
|
||||||
|
CR_Datc_DrTempDispF
|
||||||
|
|
||||||
|
2-9 test notes
|
||||||
|
|
||||||
|
- Only the icon with the lane lines is showing after recent lkas mods - can we show amber?
|
||||||
|
- pressing lkas distance does in fact cancel cruise, if only for a second. that means that it response to the cancel button - and possibly resume too?
|
||||||
|
- test: set cluster speed directly
|
||||||
|
- test: simulate down button on wheel
|
||||||
|
- we should put a splash screen of the pacman ghost over the main startup display, and only reveal the interface when we tap on it
|
||||||
|
- Fix: read speed limit from car computer, flicker LKAS button when it is out of range
|
||||||
@@ -273,7 +273,8 @@ static bool hyundai_tx_hook(CANPacket_t *to_send) {
|
|||||||
|
|
||||||
bool allowed_resume = (button == 1) && controls_allowed;
|
bool allowed_resume = (button == 1) && controls_allowed;
|
||||||
bool allowed_cancel = (button == 4) && cruise_engaged_prev;
|
bool allowed_cancel = (button == 4) && cruise_engaged_prev;
|
||||||
if (!(allowed_resume || allowed_cancel)) {
|
bool allowed_cslc = (button == 1 || button == 2) && controls_allowed;
|
||||||
|
if (!(allowed_resume || allowed_cancel || allowed_cslc)) {
|
||||||
tx = false;
|
tx = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,8 +247,9 @@ static bool hyundai_canfd_tx_hook(CANPacket_t *to_send) {
|
|||||||
int button = GET_BYTE(to_send, 2) & 0x7U;
|
int button = GET_BYTE(to_send, 2) & 0x7U;
|
||||||
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
|
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
|
||||||
bool is_resume = (button == HYUNDAI_BTN_RESUME);
|
bool is_resume = (button == HYUNDAI_BTN_RESUME);
|
||||||
|
bool is_cslc = (button == HYUNDAI_BTN_RESUME || button == HYUNDAI_BTN_SET);
|
||||||
|
|
||||||
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed);
|
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed) || (is_cslc && controls_allowed);
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
tx = false;
|
tx = false;
|
||||||
}
|
}
|
||||||
|
|||||||
1
push_github
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_brianhansonxyzgithub -o IdentitiesOnly=yes' git push github oscarpilot
|
||||||
1
push_private
Normal file
@@ -0,0 +1 @@
|
|||||||
|
git push origin oscarpilot
|
||||||
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
selfdrive/assets/oscarpilot_ready.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
0
selfdrive/car/hyundai org/__init__.py
Normal file
210
selfdrive/car/hyundai org/carcontroller.org
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
from cereal import car
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.numpy_fast import clip
|
||||||
|
from openpilot.common.realtime import DT_CTRL
|
||||||
|
from opendbc.can.packer import CANPacker
|
||||||
|
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||||
|
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
|
||||||
|
|
||||||
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
||||||
|
# All slightly below EPS thresholds to avoid fault
|
||||||
|
MAX_ANGLE = 85
|
||||||
|
MAX_ANGLE_FRAMES = 89
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||||
|
|
||||||
|
|
||||||
|
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||||
|
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||||
|
|
||||||
|
# initialize to no line visible
|
||||||
|
# TODO: this is not accurate for all cars
|
||||||
|
sys_state = 1
|
||||||
|
if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
|
||||||
|
sys_state = 3 if enabled or sys_warning else 4
|
||||||
|
elif hud_control.leftLaneVisible:
|
||||||
|
sys_state = 5
|
||||||
|
elif hud_control.rightLaneVisible:
|
||||||
|
sys_state = 6
|
||||||
|
|
||||||
|
# initialize to no warnings
|
||||||
|
left_lane_warning = 0
|
||||||
|
right_lane_warning = 0
|
||||||
|
if hud_control.leftLaneDepart:
|
||||||
|
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
if hud_control.rightLaneDepart:
|
||||||
|
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
|
||||||
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
|
class CarController:
|
||||||
|
def __init__(self, dbc_name, CP, VM):
|
||||||
|
self.CP = CP
|
||||||
|
self.CAN = CanBus(CP)
|
||||||
|
self.params = CarControllerParams(CP)
|
||||||
|
self.packer = CANPacker(dbc_name)
|
||||||
|
self.angle_limit_counter = 0
|
||||||
|
self.frame = 0
|
||||||
|
|
||||||
|
self.accel_last = 0
|
||||||
|
self.apply_steer_last = 0
|
||||||
|
self.car_fingerprint = CP.carFingerprint
|
||||||
|
self.last_button_frame = 0
|
||||||
|
|
||||||
|
def update(self, CC, CS, now_nanos, sport_plus):
|
||||||
|
actuators = CC.actuators
|
||||||
|
hud_control = CC.hudControl
|
||||||
|
|
||||||
|
# steering torque
|
||||||
|
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
||||||
|
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
||||||
|
|
||||||
|
# >90 degree steering fault prevention
|
||||||
|
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
||||||
|
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
||||||
|
|
||||||
|
if not CC.latActive:
|
||||||
|
apply_steer = 0
|
||||||
|
|
||||||
|
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||||
|
torque_fault = CC.latActive and not apply_steer_req
|
||||||
|
|
||||||
|
self.apply_steer_last = apply_steer
|
||||||
|
|
||||||
|
# accel + longitudinal
|
||||||
|
if sport_plus:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
|
||||||
|
else:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
||||||
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||||
|
|
||||||
|
# HUD messages
|
||||||
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||||
|
hud_control)
|
||||||
|
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
# *** common hyundai stuff ***
|
||||||
|
|
||||||
|
# tester present - w/ no response (keeps relevant ECU disabled)
|
||||||
|
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
|
||||||
|
# for longitudinal control, either radar or ADAS driving ECU
|
||||||
|
addr, bus = 0x7d0, 0
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||||
|
addr, bus = 0x730, self.CAN.ECAN
|
||||||
|
can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
|
||||||
|
|
||||||
|
# for blinkers
|
||||||
|
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
|
||||||
|
|
||||||
|
# CAN-FD platforms
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||||
|
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
# steering control
|
||||||
|
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
|
||||||
|
|
||||||
|
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
|
||||||
|
if self.frame % 5 == 0 and hda2:
|
||||||
|
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
|
||||||
|
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
|
||||||
|
|
||||||
|
# LFA and HDA icons
|
||||||
|
if self.frame % 5 == 0 and (not hda2 or hda2_long):
|
||||||
|
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
|
||||||
|
|
||||||
|
# blinkers
|
||||||
|
if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
if hda2:
|
||||||
|
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||||
|
if self.frame % 2 == 0:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||||
|
set_speed_in_units, CS.personality_profile))
|
||||||
|
self.accel_last = accel
|
||||||
|
else:
|
||||||
|
# button presses
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
|
||||||
|
else:
|
||||||
|
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
|
||||||
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
left_lane_warning, right_lane_warning))
|
||||||
|
|
||||||
|
if not self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
|
||||||
|
|
||||||
|
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
# TODO: unclear if this is needed
|
||||||
|
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||||
|
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||||
|
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
||||||
|
hud_control.leadVisible, set_speed_in_units, stopping,
|
||||||
|
CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
|
||||||
|
|
||||||
|
# 20 Hz LFA MFA message
|
||||||
|
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||||
|
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
|
||||||
|
|
||||||
|
# 5 Hz ACC options
|
||||||
|
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(hyundaican.create_acc_opt(self.packer))
|
||||||
|
|
||||||
|
# 2 Hz front radar options
|
||||||
|
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
||||||
|
|
||||||
|
new_actuators = actuators.copy()
|
||||||
|
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
||||||
|
new_actuators.steerOutputCan = apply_steer
|
||||||
|
new_actuators.accel = accel
|
||||||
|
|
||||||
|
self.frame += 1
|
||||||
|
return new_actuators, can_sends
|
||||||
|
|
||||||
|
def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool):
|
||||||
|
can_sends = []
|
||||||
|
if use_clu11:
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
# send resume at a max freq of 10Hz
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
||||||
|
# send 25 messages at a time to increases the likelihood of resume being accepted
|
||||||
|
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
||||||
|
# cruise cancel
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
# cruise standstill resume
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
# TODO: resume for alt button cars
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
return can_sends
|
||||||
500
selfdrive/car/hyundai org/carstate.org
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
from collections import deque
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
|
||||||
|
from cereal import car
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from opendbc.can.parser import CANParser
|
||||||
|
from opendbc.can.can_define import CANDefine
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
|
||||||
|
CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
|
||||||
|
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
|
PREV_BUTTON_SAMPLES = 8
|
||||||
|
CLUSTER_SAMPLE_RATE = 20 # frames
|
||||||
|
STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
|
||||||
|
|
||||||
|
|
||||||
|
class CarState(CarStateBase):
|
||||||
|
def __init__(self, CP):
|
||||||
|
super().__init__(CP)
|
||||||
|
can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
|
||||||
|
|
||||||
|
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
|
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
|
|
||||||
|
self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
|
||||||
|
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
|
||||||
|
"GEAR_SHIFTER"
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
|
||||||
|
else: # preferred and elect gear methods use same definition
|
||||||
|
self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
|
||||||
|
|
||||||
|
self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
|
||||||
|
"ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
|
||||||
|
"ACCELERATOR_BRAKE_ALT"
|
||||||
|
self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
|
||||||
|
"CRUISE_BUTTONS"
|
||||||
|
self.is_metric = False
|
||||||
|
self.buttons_counter = 0
|
||||||
|
|
||||||
|
self.cruise_info = {}
|
||||||
|
|
||||||
|
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
|
||||||
|
self.cluster_speed = 0
|
||||||
|
self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
|
||||||
|
|
||||||
|
self.params = CarControllerParams(CP)
|
||||||
|
|
||||||
|
def update(self, cp, cp_cam):
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp_cam", cp_cam)
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
return self.update_canfd(cp, cp_cam)
|
||||||
|
|
||||||
|
ret = car.CarState.new_message()
|
||||||
|
cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
|
||||||
|
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
|
||||||
|
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||||
|
|
||||||
|
ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
|
||||||
|
cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
|
||||||
|
|
||||||
|
ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
|
||||||
|
|
||||||
|
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
|
||||||
|
)
|
||||||
|
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||||
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||||
|
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||||
|
|
||||||
|
self.cluster_speed_counter += 1
|
||||||
|
if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
|
||||||
|
self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
|
||||||
|
self.cluster_speed_counter = 0
|
||||||
|
|
||||||
|
# Mimic how dash converts to imperial.
|
||||||
|
# Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
|
||||||
|
# TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
|
||||||
|
if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
|
||||||
|
self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
|
||||||
|
|
||||||
|
ret.vEgoCluster = self.cluster_speed * speed_conv
|
||||||
|
|
||||||
|
ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
|
||||||
|
ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
|
||||||
|
ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
|
||||||
|
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
|
||||||
|
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
|
||||||
|
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
|
||||||
|
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
|
||||||
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||||
|
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
||||||
|
|
||||||
|
# cruise state
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||||
|
ret.cruiseState.available = self.main_enabled
|
||||||
|
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
||||||
|
ret.cruiseState.standstill = False
|
||||||
|
ret.cruiseState.nonAdaptive = False
|
||||||
|
else:
|
||||||
|
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
|
||||||
|
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
|
||||||
|
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
|
||||||
|
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
||||||
|
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
|
||||||
|
|
||||||
|
# TODO: Find brake pressure
|
||||||
|
ret.brake = 0
|
||||||
|
ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
|
||||||
|
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
|
||||||
|
ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
|
||||||
|
ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
if self.CP.carFingerprint in HYBRID_CAR:
|
||||||
|
ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
|
||||||
|
else:
|
||||||
|
ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
|
||||||
|
ret.gasPressed = ret.gas > 0
|
||||||
|
else:
|
||||||
|
ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
|
||||||
|
ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
|
||||||
|
|
||||||
|
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
|
||||||
|
# as this seems to be standard over all cars, but is not the preferred method.
|
||||||
|
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
gear = cp.vl["CLU15"]["CF_Clu_Gear"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
gear = cp.vl["TCU12"]["CUR_GR"]
|
||||||
|
else:
|
||||||
|
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
|
||||||
|
|
||||||
|
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||||
|
|
||||||
|
if not self.CP.openpilotLongitudinalControl:
|
||||||
|
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
|
||||||
|
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
|
||||||
|
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
|
||||||
|
scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
|
||||||
|
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
|
||||||
|
ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
|
||||||
|
ret.stockAeb = aeb_warning and aeb_braking
|
||||||
|
|
||||||
|
if self.CP.enableBsm:
|
||||||
|
ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
|
||||||
|
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
||||||
|
|
||||||
|
# save the entire LKAS11 and CLU11
|
||||||
|
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
||||||
|
self.clu11 = copy.copy(cp.vl["CLU11"])
|
||||||
|
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
||||||
|
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
||||||
|
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||||
|
self.prev_main_buttons = self.main_buttons[-1]
|
||||||
|
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||||
|
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
||||||
|
self.main_enabled = not self.main_enabled
|
||||||
|
|
||||||
|
# BBot functions for lfa and gap buttons - test speed up / down
|
||||||
|
self.oscar_lane_center_btn_pressed= False
|
||||||
|
self.oscar_slc_decel = False
|
||||||
|
self.oscar_slc_accel = False
|
||||||
|
|
||||||
|
self.param_memory.put("oscar_debug", "Hello World")
|
||||||
|
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.oscar_lane_center_btn_pressed= True
|
||||||
|
|
||||||
|
# lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# self.custom_speed_up = True
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
# Driving personalities function
|
||||||
|
# if self.personalities_via_wheel and ret.cruiseState.available:
|
||||||
|
# # Sync with the onroad UI button
|
||||||
|
# if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
||||||
|
# self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
||||||
|
|
||||||
|
# # Change personality upon steering wheel button press
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
||||||
|
# self.personality_profile = (self.previous_personality_profile + 2) % 3
|
||||||
|
|
||||||
|
# if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
||||||
|
# self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
||||||
|
# self.previous_personality_profile = self.personality_profile
|
||||||
|
|
||||||
|
# # Toggle Experimental Mode from steering wheel function
|
||||||
|
# if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
||||||
|
# lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# if self.conditional_experimental_mode:
|
||||||
|
# # Set "CEStatus" to work with "Conditional Experimental Mode"
|
||||||
|
# conditional_status = self.param_memory.get_int("CEStatus")
|
||||||
|
# override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
||||||
|
# self.param_memory.put_int("CEStatus", override_value)
|
||||||
|
# else:
|
||||||
|
# experimental_mode = self.param.get_bool("ExperimentalMode")
|
||||||
|
# # Invert the value of "ExperimentalMode"
|
||||||
|
# put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_self", self)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def update_canfd(self, cp, cp_cam):
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
|
||||||
|
|
||||||
|
ret = car.CarState.new_message()
|
||||||
|
|
||||||
|
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
|
||||||
|
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
|
||||||
|
offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
|
||||||
|
ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
|
||||||
|
ret.gasPressed = ret.gas > 1e-5
|
||||||
|
else:
|
||||||
|
ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
|
||||||
|
|
||||||
|
ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
|
||||||
|
|
||||||
|
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
|
||||||
|
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
|
||||||
|
|
||||||
|
gear = cp.vl[self.gear_msg_canfd]["GEAR"]
|
||||||
|
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||||
|
|
||||||
|
# TODO: figure out positions
|
||||||
|
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
|
||||||
|
)
|
||||||
|
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||||
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||||
|
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||||
|
|
||||||
|
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
|
||||||
|
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
|
||||||
|
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
|
||||||
|
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
|
||||||
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||||
|
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
|
||||||
|
|
||||||
|
# TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
|
||||||
|
left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
|
||||||
|
if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
|
||||||
|
left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
|
||||||
|
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
|
||||||
|
cp.vl["BLINKERS"][right_blinker_sig])
|
||||||
|
if self.CP.enableBsm:
|
||||||
|
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
|
||||||
|
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
|
||||||
|
|
||||||
|
# cruise state
|
||||||
|
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
|
||||||
|
ret.cruiseState.available = self.main_enabled
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||||
|
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
|
||||||
|
ret.cruiseState.standstill = False
|
||||||
|
else:
|
||||||
|
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
||||||
|
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
||||||
|
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
||||||
|
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
||||||
|
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
|
||||||
|
|
||||||
|
# Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
|
||||||
|
# It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
|
||||||
|
# The car will brake, but does not respect positive acceleration commands in this mode
|
||||||
|
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
|
||||||
|
if self.CP.carFingerprint in EV_CAR:
|
||||||
|
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
|
||||||
|
|
||||||
|
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
||||||
|
self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
||||||
|
self.prev_main_buttons = self.main_buttons[-1]
|
||||||
|
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
||||||
|
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
||||||
|
self.main_enabled = not self.main_enabled
|
||||||
|
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
||||||
|
ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||||
|
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
|
||||||
|
else cp_cam.vl["CAM_0x2a4"])
|
||||||
|
|
||||||
|
SpeedLimitController.load_state()
|
||||||
|
SpeedLimitController.car_speed_limit = self.calculate_speed_limit_canfd(self.CP, cp, cp_cam) * speed_factor
|
||||||
|
SpeedLimitController.write_car_state()
|
||||||
|
|
||||||
|
# self.custom_speed_up = False
|
||||||
|
self.oscar_lane_center_btn_pressed = False
|
||||||
|
|
||||||
|
if ret.cruiseState.available:
|
||||||
|
|
||||||
|
if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
self.oscar_lane_center_btn_pressed = True
|
||||||
|
|
||||||
|
lkas_pressed = False
|
||||||
|
try:
|
||||||
|
lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
|
||||||
|
except:
|
||||||
|
nothing = 0
|
||||||
|
|
||||||
|
# intentionally cause a failure
|
||||||
|
if lkas_pressed:
|
||||||
|
floog=norpdywoop
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.oscar_lane_center_btn_pressed= True
|
||||||
|
|
||||||
|
# Driving personalities function
|
||||||
|
# if self.personalities_via_wheel and ret.cruiseState.available:
|
||||||
|
# # Sync with the onroad UI button
|
||||||
|
# if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
||||||
|
# self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
||||||
|
|
||||||
|
# # Change personality upon steering wheel button press
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
||||||
|
# self.personality_profile = (self.previous_personality_profile + 2) % 3
|
||||||
|
|
||||||
|
# if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
||||||
|
# self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
||||||
|
# self.previous_personality_profile = self.personality_profile
|
||||||
|
|
||||||
|
# # Toggle Experimental Mode from steering wheel function
|
||||||
|
# if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
||||||
|
# lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# if self.conditional_experimental_mode:
|
||||||
|
# # Set "CEStatus" to work with "Conditional Experimental Mode"
|
||||||
|
# conditional_status = self.param_memory.get_int("CEStatus")
|
||||||
|
# override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
||||||
|
# self.param_memory.put_int("CEStatus", override_value)
|
||||||
|
# else:
|
||||||
|
# experimental_mode = self.param.get_bool("ExperimentalMode")
|
||||||
|
# # Invert the value of "ExperimentalMode"
|
||||||
|
# put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_self", self)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# BBOT does not work
|
||||||
|
def calculate_speed_limit_canfd(self, CP, cp, cp_cam):
|
||||||
|
try:
|
||||||
|
self._speed_limit_clu = cp.vl["CLUSTER_SPEED_LIMIT"]["SPEED_LIMIT_1"]
|
||||||
|
return self._speed_limit_clu if self._speed_limit_clu not in (0, 255) else 0
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_can_parser(self, CP):
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
return self.get_can_parser_canfd(CP)
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
# address, frequency
|
||||||
|
("MDPS12", 50),
|
||||||
|
("TCS13", 50),
|
||||||
|
("TCS15", 10),
|
||||||
|
("CLU11", 50),
|
||||||
|
("CLU15", 5),
|
||||||
|
("ESP12", 100),
|
||||||
|
("CGW1", 10),
|
||||||
|
("CGW2", 5),
|
||||||
|
("CGW4", 5),
|
||||||
|
("WHL_SPD11", 50),
|
||||||
|
("SAS11", 100),
|
||||||
|
]
|
||||||
|
|
||||||
|
if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
|
||||||
|
messages += [
|
||||||
|
("SCC11", 50),
|
||||||
|
("SCC12", 50),
|
||||||
|
]
|
||||||
|
if CP.flags & HyundaiFlags.USE_FCA.value:
|
||||||
|
messages.append(("FCA11", 50))
|
||||||
|
|
||||||
|
if CP.enableBsm:
|
||||||
|
messages.append(("LCA11", 50))
|
||||||
|
|
||||||
|
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
messages.append(("E_EMS11", 50))
|
||||||
|
else:
|
||||||
|
messages += [
|
||||||
|
("EMS12", 100),
|
||||||
|
("EMS16", 100),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
messages.append(("ELECT_GEAR", 20))
|
||||||
|
elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
pass
|
||||||
|
elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
messages.append(("TCU12", 100))
|
||||||
|
else:
|
||||||
|
messages.append(("LVR12", 100))
|
||||||
|
|
||||||
|
messages.append(("BCM_PO_11", 50))
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cam_can_parser(CP):
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
return CarState.get_cam_can_parser_canfd(CP)
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
("LKAS11", 100)
|
||||||
|
]
|
||||||
|
|
||||||
|
if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
|
||||||
|
messages += [
|
||||||
|
("SCC11", 50),
|
||||||
|
("SCC12", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.flags & HyundaiFlags.USE_FCA.value:
|
||||||
|
messages.append(("FCA11", 50))
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
|
||||||
|
|
||||||
|
def get_can_parser_canfd(self, CP):
|
||||||
|
messages = [
|
||||||
|
(self.gear_msg_canfd, 100),
|
||||||
|
(self.accelerator_msg_canfd, 100),
|
||||||
|
("WHEEL_SPEEDS", 100),
|
||||||
|
("STEERING_SENSORS", 100),
|
||||||
|
("MDPS", 100),
|
||||||
|
("TCS", 50),
|
||||||
|
("CRUISE_BUTTONS_ALT", 50),
|
||||||
|
("BLINKERS", 4),
|
||||||
|
("DOORS_SEATBELTS", 4),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.carFingerprint in EV_CAR:
|
||||||
|
messages += [
|
||||||
|
("MANUAL_SPEED_LIMIT_ASSIST", 10),
|
||||||
|
]
|
||||||
|
|
||||||
|
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
|
||||||
|
messages += [
|
||||||
|
("CRUISE_BUTTONS", 50)
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.enableBsm:
|
||||||
|
messages += [
|
||||||
|
("BLINDSPOTS_REAR_CORNERS", 20),
|
||||||
|
]
|
||||||
|
|
||||||
|
# if CP.nav_msg:
|
||||||
|
# messages.append(("CLUSTER_SPEED_LIMIT", 10))
|
||||||
|
|
||||||
|
if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
|
||||||
|
messages += [
|
||||||
|
("SCC_CONTROL", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cam_can_parser_canfd(CP):
|
||||||
|
messages = []
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
|
||||||
|
messages += [(block_lfa_msg, 20)]
|
||||||
|
elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||||
|
messages += [
|
||||||
|
("SCC_CONTROL", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).CAM)
|
||||||
1710
selfdrive/car/hyundai org/fingerprints.org
Normal file
213
selfdrive/car/hyundai org/hyundaican.org
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
import crcmod
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import CAR, CHECKSUM, CAMERA_SCC_CAR
|
||||||
|
|
||||||
|
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
|
||||||
|
|
||||||
|
def create_lkas11(packer, frame, car_fingerprint, apply_steer, steer_req,
|
||||||
|
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||||
|
left_lane, right_lane,
|
||||||
|
left_lane_depart, right_lane_depart):
|
||||||
|
values = {s: lkas11[s] for s in [
|
||||||
|
"CF_Lkas_LdwsActivemode",
|
||||||
|
"CF_Lkas_LdwsSysState",
|
||||||
|
"CF_Lkas_SysWarning",
|
||||||
|
"CF_Lkas_LdwsLHWarning",
|
||||||
|
"CF_Lkas_LdwsRHWarning",
|
||||||
|
"CF_Lkas_HbaLamp",
|
||||||
|
"CF_Lkas_FcwBasReq",
|
||||||
|
"CF_Lkas_HbaSysState",
|
||||||
|
"CF_Lkas_FcwOpt",
|
||||||
|
"CF_Lkas_HbaOpt",
|
||||||
|
"CF_Lkas_FcwSysState",
|
||||||
|
"CF_Lkas_FcwCollisionWarning",
|
||||||
|
"CF_Lkas_FusionState",
|
||||||
|
"CF_Lkas_FcwOpt_USM",
|
||||||
|
"CF_Lkas_LdwsOpt_USM",
|
||||||
|
]}
|
||||||
|
values["CF_Lkas_LdwsSysState"] = sys_state
|
||||||
|
values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0
|
||||||
|
values["CF_Lkas_LdwsLHWarning"] = left_lane_depart
|
||||||
|
values["CF_Lkas_LdwsRHWarning"] = right_lane_depart
|
||||||
|
values["CR_Lkas_StrToqReq"] = apply_steer
|
||||||
|
values["CF_Lkas_ActToi"] = steer_req
|
||||||
|
values["CF_Lkas_ToiFlt"] = torque_fault # seems to allow actuation on CR_Lkas_StrToqReq
|
||||||
|
values["CF_Lkas_MsgCount"] = frame % 0x10
|
||||||
|
|
||||||
|
if car_fingerprint in (CAR.SONATA, CAR.PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.SANTA_FE,
|
||||||
|
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.GENESIS_G70_2020,
|
||||||
|
CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022,
|
||||||
|
CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022,
|
||||||
|
CAR.SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
|
||||||
|
CAR.AZERA_6TH_GEN, CAR.AZERA_HEV_6TH_GEN, CAR.CUSTIN_1ST_GEN):
|
||||||
|
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
|
||||||
|
values["CF_Lkas_LdwsOpt_USM"] = 2
|
||||||
|
|
||||||
|
# FcwOpt_USM 5 = Orange blinking car + lanes
|
||||||
|
# FcwOpt_USM 4 = Orange car + lanes
|
||||||
|
# FcwOpt_USM 3 = Green blinking car + lanes
|
||||||
|
# FcwOpt_USM 2 = Green car + lanes
|
||||||
|
# FcwOpt_USM 1 = White car + lanes
|
||||||
|
# FcwOpt_USM 0 = No car + lanes
|
||||||
|
values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
|
||||||
|
|
||||||
|
# SysWarning 4 = keep hands on wheel
|
||||||
|
# SysWarning 5 = keep hands on wheel (red)
|
||||||
|
# SysWarning 6 = keep hands on wheel (red) + beep
|
||||||
|
# Note: the warning is hidden while the blinkers are on
|
||||||
|
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||||
|
|
||||||
|
# Likely cars lacking the ability to show individual lane lines in the dash
|
||||||
|
elif car_fingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
|
||||||
|
# SysWarning 4 = keep hands on wheel + beep
|
||||||
|
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
|
||||||
|
|
||||||
|
# SysState 0 = no icons
|
||||||
|
# SysState 1-2 = white car + lanes
|
||||||
|
# SysState 3 = green car + lanes, green steering wheel
|
||||||
|
# SysState 4 = green car + lanes
|
||||||
|
values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
|
||||||
|
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
|
||||||
|
|
||||||
|
# these have no effect
|
||||||
|
values["CF_Lkas_LdwsActivemode"] = 0
|
||||||
|
values["CF_Lkas_FcwOpt_USM"] = 0
|
||||||
|
|
||||||
|
elif car_fingerprint == CAR.HYUNDAI_GENESIS:
|
||||||
|
# This field is actually LdwsActivemode
|
||||||
|
# Genesis and Optima fault when forwarding while engaged
|
||||||
|
values["CF_Lkas_LdwsActivemode"] = 2
|
||||||
|
|
||||||
|
dat = packer.make_can_msg("LKAS11", 0, values)[2]
|
||||||
|
|
||||||
|
if car_fingerprint in CHECKSUM["crc8"]:
|
||||||
|
# CRC Checksum as seen on 2019 Hyundai Santa Fe
|
||||||
|
dat = dat[:6] + dat[7:8]
|
||||||
|
checksum = hyundai_checksum(dat)
|
||||||
|
elif car_fingerprint in CHECKSUM["6B"]:
|
||||||
|
# Checksum of first 6 Bytes, as seen on 2018 Kia Sorento
|
||||||
|
checksum = sum(dat[:6]) % 256
|
||||||
|
else:
|
||||||
|
# Checksum of first 6 Bytes and last Byte as seen on 2018 Kia Stinger
|
||||||
|
checksum = (sum(dat[:6]) + dat[7]) % 256
|
||||||
|
|
||||||
|
values["CF_Lkas_Chksum"] = checksum
|
||||||
|
|
||||||
|
return packer.make_can_msg("LKAS11", 0, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_clu11(packer, frame, clu11, button, car_fingerprint):
|
||||||
|
values = {s: clu11[s] for s in [
|
||||||
|
"CF_Clu_CruiseSwState",
|
||||||
|
"CF_Clu_CruiseSwMain",
|
||||||
|
"CF_Clu_SldMainSW",
|
||||||
|
"CF_Clu_ParityBit1",
|
||||||
|
"CF_Clu_VanzDecimal",
|
||||||
|
"CF_Clu_Vanz",
|
||||||
|
"CF_Clu_SPEED_UNIT",
|
||||||
|
"CF_Clu_DetentOut",
|
||||||
|
"CF_Clu_RheostatLevel",
|
||||||
|
"CF_Clu_CluInfo",
|
||||||
|
"CF_Clu_AmpInfo",
|
||||||
|
"CF_Clu_AliveCnt1",
|
||||||
|
]}
|
||||||
|
values["CF_Clu_CruiseSwState"] = button
|
||||||
|
values["CF_Clu_AliveCnt1"] = frame % 0x10
|
||||||
|
# send buttons to camera on camera-scc based cars
|
||||||
|
bus = 2 if car_fingerprint in CAMERA_SCC_CAR else 0
|
||||||
|
return packer.make_can_msg("CLU11", bus, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_lfahda_mfc(packer, enabled, hda_set_speed=0):
|
||||||
|
values = {
|
||||||
|
"LFA_Icon_State": 2 if enabled else 0,
|
||||||
|
"HDA_Active": 1 if hda_set_speed else 0,
|
||||||
|
"HDA_Icon_State": 2 if hda_set_speed else 0,
|
||||||
|
"HDA_VSetReq": hda_set_speed,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("LFAHDA_MFC", 0, values)
|
||||||
|
|
||||||
|
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_visible, set_speed, stopping, long_override, use_fca, cruise_available, personality):
|
||||||
|
commands = []
|
||||||
|
|
||||||
|
scc11_values = {
|
||||||
|
"MainMode_ACC": 1 if cruise_available else 0,
|
||||||
|
"TauGapSet": personality + 1,
|
||||||
|
"VSetDis": set_speed if enabled else 0,
|
||||||
|
"AliveCounterACC": idx % 0x10,
|
||||||
|
"ObjValid": 1, # close lead makes controls tighter
|
||||||
|
"ACC_ObjStatus": 1, # close lead makes controls tighter
|
||||||
|
"ACC_ObjLatPos": 0,
|
||||||
|
"ACC_ObjRelSpd": 0,
|
||||||
|
"ACC_ObjDist": 1, # close lead makes controls tighter
|
||||||
|
}
|
||||||
|
commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
|
||||||
|
|
||||||
|
scc12_values = {
|
||||||
|
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
|
||||||
|
"StopReq": 1 if stopping else 0,
|
||||||
|
"aReqRaw": accel,
|
||||||
|
"aReqValue": accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
|
||||||
|
"CR_VSM_Alive": idx % 0xF,
|
||||||
|
}
|
||||||
|
|
||||||
|
# show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
|
||||||
|
# these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
|
||||||
|
if not use_fca:
|
||||||
|
scc12_values["CF_VSM_ConfMode"] = 1
|
||||||
|
scc12_values["AEB_Status"] = 1 # AEB disabled
|
||||||
|
|
||||||
|
scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[2]
|
||||||
|
scc12_values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
|
||||||
|
|
||||||
|
commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
|
||||||
|
|
||||||
|
scc14_values = {
|
||||||
|
"ComfortBandUpper": 0.0, # stock usually is 0 but sometimes uses higher values
|
||||||
|
"ComfortBandLower": 0.0, # stock usually is 0 but sometimes uses higher values
|
||||||
|
"JerkUpperLimit": upper_jerk, # stock usually is 1.0 but sometimes uses higher values
|
||||||
|
"JerkLowerLimit": 5.0, # stock usually is 0.5 but sometimes uses higher values
|
||||||
|
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||||
|
"ObjGap": 2 if lead_visible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||||
|
}
|
||||||
|
commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
|
||||||
|
|
||||||
|
# Only send FCA11 on cars where it exists on the bus
|
||||||
|
if use_fca:
|
||||||
|
# note that some vehicles most likely have an alternate checksum/counter definition
|
||||||
|
# https://github.com/commaai/opendbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
|
||||||
|
fca11_values = {
|
||||||
|
"CR_FCA_Alive": idx % 0xF,
|
||||||
|
"PAINT1_Status": 1,
|
||||||
|
"FCA_DrvSetStatus": 1,
|
||||||
|
"FCA_Status": 1, # AEB disabled
|
||||||
|
}
|
||||||
|
fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[2]
|
||||||
|
fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
|
||||||
|
commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
|
||||||
|
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def create_acc_opt(packer):
|
||||||
|
commands = []
|
||||||
|
|
||||||
|
scc13_values = {
|
||||||
|
"SCCDrvModeRValue": 2,
|
||||||
|
"SCC_Equip": 1,
|
||||||
|
"Lead_Veh_Dep_Alert_USM": 2,
|
||||||
|
}
|
||||||
|
commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
|
||||||
|
|
||||||
|
# TODO: this needs to be detected and conditionally sent on unsupported long cars
|
||||||
|
fca12_values = {
|
||||||
|
"FCA_DrvSetState": 2,
|
||||||
|
"FCA_USM": 1, # AEB disabled
|
||||||
|
}
|
||||||
|
commands.append(packer.make_can_msg("FCA12", 0, fca12_values))
|
||||||
|
|
||||||
|
return commands
|
||||||
|
|
||||||
|
def create_frt_radar_opt(packer):
|
||||||
|
frt_radar11_values = {
|
||||||
|
"CF_FCA_Equip_Front_Radar": 1,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
|
||||||
224
selfdrive/car/hyundai org/hyundaicanfd.org
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
from openpilot.common.numpy_fast import clip
|
||||||
|
from openpilot.selfdrive.car import CanBusBase
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
|
||||||
|
|
||||||
|
|
||||||
|
class CanBus(CanBusBase):
|
||||||
|
def __init__(self, CP, hda2=None, fingerprint=None) -> None:
|
||||||
|
super().__init__(CP, fingerprint)
|
||||||
|
|
||||||
|
if hda2 is None:
|
||||||
|
assert CP is not None
|
||||||
|
hda2 = CP.flags & HyundaiFlags.CANFD_HDA2.value
|
||||||
|
|
||||||
|
# On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars
|
||||||
|
# have a different harness than the HDA1 and non-HDA variants in order to split
|
||||||
|
# a different bus, since the steering is done by different ECUs.
|
||||||
|
self._a, self._e = 1, 0
|
||||||
|
if hda2:
|
||||||
|
self._a, self._e = 0, 1
|
||||||
|
|
||||||
|
self._a += self.offset
|
||||||
|
self._e += self.offset
|
||||||
|
self._cam = 2 + self.offset
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ECAN(self):
|
||||||
|
return self._e
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ACAN(self):
|
||||||
|
return self._a
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CAM(self):
|
||||||
|
return self._cam
|
||||||
|
|
||||||
|
|
||||||
|
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
"LKA_MODE": 2,
|
||||||
|
"LKA_ICON": 2 if enabled else 1 if lat_active else 0,
|
||||||
|
"TORQUE_REQUEST": apply_steer,
|
||||||
|
"LKA_ASSIST": 0,
|
||||||
|
"STEER_REQ": 1 if lat_active else 0,
|
||||||
|
"STEER_MODE": 0,
|
||||||
|
"HAS_LANE_SAFETY": 0, # hide LKAS settings
|
||||||
|
"NEW_SIGNAL_1": 0,
|
||||||
|
"NEW_SIGNAL_2": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
hda2_lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
|
||||||
|
if CP.openpilotLongitudinalControl:
|
||||||
|
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||||
|
ret.append(packer.make_can_msg(hda2_lkas_msg, CAN.ACAN, values))
|
||||||
|
else:
|
||||||
|
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def create_suppress_lfa(packer, CAN, hda2_lfa_block_msg, hda2_alt_steering):
|
||||||
|
suppress_msg = "CAM_0x362" if hda2_alt_steering else "CAM_0x2a4"
|
||||||
|
msg_bytes = 32 if hda2_alt_steering else 24
|
||||||
|
|
||||||
|
values = {f"BYTE{i}": hda2_lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
|
||||||
|
values["COUNTER"] = hda2_lfa_block_msg["COUNTER"]
|
||||||
|
values["SET_ME_0"] = 0
|
||||||
|
values["SET_ME_0_2"] = 0
|
||||||
|
values["LEFT_LANE_LINE"] = 0
|
||||||
|
values["RIGHT_LANE_LINE"] = 0
|
||||||
|
return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
|
||||||
|
|
||||||
|
def create_buttons(packer, CP, CAN, cnt, btn):
|
||||||
|
values = {
|
||||||
|
"COUNTER": cnt,
|
||||||
|
"SET_ME_1": 1,
|
||||||
|
"CRUISE_BUTTONS": btn,
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
|
||||||
|
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
|
||||||
|
|
||||||
|
def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
|
||||||
|
# TODO: why do we copy different values here?
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
|
||||||
|
values = {s: cruise_info_copy[s] for s in [
|
||||||
|
"COUNTER",
|
||||||
|
"CHECKSUM",
|
||||||
|
"NEW_SIGNAL_1",
|
||||||
|
"MainMode_ACC",
|
||||||
|
"ACCMode",
|
||||||
|
"ZEROS_9",
|
||||||
|
"CRUISE_STANDSTILL",
|
||||||
|
"ZEROS_5",
|
||||||
|
"DISTANCE_SETTING",
|
||||||
|
"VSetDis",
|
||||||
|
]}
|
||||||
|
else:
|
||||||
|
values = {s: cruise_info_copy[s] for s in [
|
||||||
|
"COUNTER",
|
||||||
|
"CHECKSUM",
|
||||||
|
"ACCMode",
|
||||||
|
"VSetDis",
|
||||||
|
"CRUISE_STANDSTILL",
|
||||||
|
]}
|
||||||
|
values.update({
|
||||||
|
"ACCMode": 4,
|
||||||
|
"aReqRaw": 0.0,
|
||||||
|
"aReqValue": 0.0,
|
||||||
|
})
|
||||||
|
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||||
|
|
||||||
|
def create_lfahda_cluster(packer, CAN, enabled):
|
||||||
|
values = {
|
||||||
|
"HDA_ICON": 1 if enabled else 0,
|
||||||
|
# 0 off, 1 gray, 2 green, 3 blinking (wheel icon)
|
||||||
|
"LFA_ICON": 0 if enabled else 0, # was green before i think in 2? 3 should be flashing?
|
||||||
|
# "LFA_ICON": 2 if enabled else 0,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, personality):
|
||||||
|
jerk = 5
|
||||||
|
jn = jerk / 50
|
||||||
|
if not enabled or gas_override:
|
||||||
|
a_val, a_raw = 0, 0
|
||||||
|
else:
|
||||||
|
a_raw = accel
|
||||||
|
a_val = clip(accel, accel_last - jn, accel_last + jn)
|
||||||
|
|
||||||
|
values = {
|
||||||
|
"ACCMode": 0 if not enabled else (2 if gas_override else 1),
|
||||||
|
"MainMode_ACC": 1,
|
||||||
|
"StopReq": 1 if stopping else 0,
|
||||||
|
"aReqValue": a_val,
|
||||||
|
"aReqRaw": a_raw,
|
||||||
|
"VSetDis": set_speed,
|
||||||
|
"JerkLowerLimit": jerk if enabled else 1,
|
||||||
|
"JerkUpperLimit": 3.0,
|
||||||
|
|
||||||
|
"ACC_ObjDist": 1,
|
||||||
|
"ObjValid": 0,
|
||||||
|
"OBJ_STATUS": 2,
|
||||||
|
"SET_ME_2": 0x4,
|
||||||
|
"SET_ME_3": 0x3,
|
||||||
|
"SET_ME_TMP_64": 0x64,
|
||||||
|
"DISTANCE_SETTING": personality + 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||||
|
|
||||||
|
def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("SPAS1", CAN.ECAN, values))
|
||||||
|
|
||||||
|
blink = 0
|
||||||
|
if left_blink:
|
||||||
|
blink = 3
|
||||||
|
elif right_blink:
|
||||||
|
blink = 4
|
||||||
|
values = {
|
||||||
|
"BLINKER_CONTROL": blink,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("SPAS2", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def create_adrv_messages(packer, CAN, frame):
|
||||||
|
# messages needed to car happy after disabling
|
||||||
|
# the ADAS Driving ECU to do longitudinal control
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||||
|
|
||||||
|
if frame % 2 == 0:
|
||||||
|
values = {
|
||||||
|
'AEB_SETTING': 0x1, # show AEB disabled icon
|
||||||
|
'SET_ME_2': 0x2,
|
||||||
|
'SET_ME_FF': 0xff,
|
||||||
|
'SET_ME_FC': 0xfc,
|
||||||
|
'SET_ME_9': 0x9,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 5 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_1C': 0x1c,
|
||||||
|
'SET_ME_FF': 0xff,
|
||||||
|
'SET_ME_TMP_F': 0xf,
|
||||||
|
'SET_ME_TMP_F_2': 0xf,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
|
||||||
|
|
||||||
|
values = {
|
||||||
|
'SET_ME_E1': 0xe1,
|
||||||
|
'SET_ME_3A': 0x3a,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 20 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_15': 0x15,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 100 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_22': 0x22,
|
||||||
|
'SET_ME_41': 0x41,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
375
selfdrive/car/hyundai org/interface.org
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
from cereal import car
|
||||||
|
from panda import Panda
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \
|
||||||
|
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \
|
||||||
|
UNSUPPORTED_LONGITUDINAL_CAR, Buttons
|
||||||
|
from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||||
|
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||||
|
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||||
|
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
params_memory = Params("/dev/shm/params")
|
||||||
|
|
||||||
|
Ecu = car.CarParams.Ecu
|
||||||
|
SafetyModel = car.CarParams.SafetyModel
|
||||||
|
ButtonType = car.CarState.ButtonEvent.Type
|
||||||
|
EventName = car.CarEvent.EventName
|
||||||
|
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
|
||||||
|
BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
|
||||||
|
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
|
||||||
|
|
||||||
|
|
||||||
|
def set_safety_config_hyundai(candidate, CAN, can_fd=False):
|
||||||
|
platform = SafetyModel.hyundaiCanfd if can_fd else \
|
||||||
|
SafetyModel.hyundaiLegacy if candidate in LEGACY_SAFETY_MODE_CAR else \
|
||||||
|
SafetyModel.hyundai
|
||||||
|
cfgs = [get_safety_config(platform), ]
|
||||||
|
if CAN.ECAN >= 4:
|
||||||
|
cfgs.insert(0, get_safety_config(SafetyModel.noOutput))
|
||||||
|
|
||||||
|
return cfgs
|
||||||
|
|
||||||
|
|
||||||
|
class CarInterface(CarInterfaceBase):
|
||||||
|
@staticmethod
|
||||||
|
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||||
|
ret.carName = "hyundai"
|
||||||
|
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
|
||||||
|
params_memory.put_bool("CSLCAvailable", True)
|
||||||
|
|
||||||
|
# These cars have been put into dashcam only due to both a lack of users and test coverage.
|
||||||
|
# These cars likely still work fine. Once a user confirms each car works and a test route is
|
||||||
|
# added to selfdrive/car/tests/routes.py, we can remove it from this list.
|
||||||
|
# FIXME: the Optima Hybrid 2017 uses a different SCC12 checksum
|
||||||
|
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
|
||||||
|
|
||||||
|
hda2 = Ecu.adas in [fw.ecu for fw in car_fw]
|
||||||
|
CAN = CanBus(None, hda2, fingerprint)
|
||||||
|
|
||||||
|
if candidate in CANFD_CAR:
|
||||||
|
# detect HDA2 with ADAS Driving ECU
|
||||||
|
if hda2:
|
||||||
|
if 0x110 in fingerprint[CAN.CAM]:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||||
|
params_memory.put_bool("CSLCAvailable", False)
|
||||||
|
else:
|
||||||
|
# non-HDA2
|
||||||
|
if 0x1cf not in fingerprint[CAN.ECAN]:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
|
||||||
|
# ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
|
||||||
|
if 0x130 not in fingerprint[CAN.ECAN]:
|
||||||
|
if 0x40 not in fingerprint[CAN.ECAN]:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
|
||||||
|
else:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
|
||||||
|
if candidate not in CANFD_RADAR_SCC_CAR:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
|
||||||
|
else:
|
||||||
|
# Send LFA message on cars with HDA
|
||||||
|
if 0x485 in fingerprint[2]:
|
||||||
|
ret.flags |= HyundaiFlags.SEND_LFA.value
|
||||||
|
|
||||||
|
# These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
|
||||||
|
if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]:
|
||||||
|
ret.flags |= HyundaiFlags.USE_FCA.value
|
||||||
|
|
||||||
|
ret.steerActuatorDelay = 0.1 # Default delay
|
||||||
|
ret.steerLimitTimer = 0.4
|
||||||
|
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||||
|
|
||||||
|
if candidate in (CAR.AZERA_6TH_GEN, CAR.AZERA_HEV_6TH_GEN):
|
||||||
|
ret.mass = 1600. if candidate == CAR.AZERA_6TH_GEN else 1675. # ICE is ~average of 2.5L and 3.5L
|
||||||
|
ret.wheelbase = 2.885
|
||||||
|
ret.steerRatio = 14.5
|
||||||
|
elif candidate in (CAR.SANTA_FE, CAR.SANTA_FE_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022):
|
||||||
|
ret.mass = 3982. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.766
|
||||||
|
# Values from optimizer
|
||||||
|
ret.steerRatio = 16.55 # 13.8 is spec end-to-end
|
||||||
|
ret.tireStiffnessFactor = 0.82
|
||||||
|
elif candidate in (CAR.SONATA, CAR.SONATA_HYBRID):
|
||||||
|
ret.mass = 1513.
|
||||||
|
ret.wheelbase = 2.84
|
||||||
|
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
|
||||||
|
ret.tireStiffnessFactor = 0.65
|
||||||
|
elif candidate == CAR.SONATA_LF:
|
||||||
|
ret.mass = 1536.
|
||||||
|
ret.wheelbase = 2.804
|
||||||
|
ret.steerRatio = 13.27 * 1.15 # 15% higher at the center seems reasonable
|
||||||
|
elif candidate == CAR.PALISADE:
|
||||||
|
ret.mass = 1999.
|
||||||
|
ret.wheelbase = 2.90
|
||||||
|
ret.steerRatio = 15.6 * 1.15
|
||||||
|
ret.tireStiffnessFactor = 0.63
|
||||||
|
elif candidate in (CAR.ELANTRA, CAR.ELANTRA_GT_I30):
|
||||||
|
ret.mass = 1275.
|
||||||
|
ret.wheelbase = 2.7
|
||||||
|
ret.steerRatio = 15.4 # 14 is Stock | Settled Params Learner values are steerRatio: 15.401566348670535
|
||||||
|
ret.tireStiffnessFactor = 0.385 # stiffnessFactor settled on 1.0081302973865127
|
||||||
|
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
|
||||||
|
elif candidate == CAR.ELANTRA_2021:
|
||||||
|
ret.mass = 2800. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.72
|
||||||
|
ret.steerRatio = 12.9
|
||||||
|
ret.tireStiffnessFactor = 0.65
|
||||||
|
elif candidate == CAR.ELANTRA_HEV_2021:
|
||||||
|
ret.mass = 3017. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.72
|
||||||
|
ret.steerRatio = 12.9
|
||||||
|
ret.tireStiffnessFactor = 0.65
|
||||||
|
elif candidate == CAR.HYUNDAI_GENESIS:
|
||||||
|
ret.mass = 2060.
|
||||||
|
ret.wheelbase = 3.01
|
||||||
|
ret.steerRatio = 16.5
|
||||||
|
ret.minSteerSpeed = 60 * CV.KPH_TO_MS
|
||||||
|
elif candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022, CAR.KONA_EV_2ND_GEN):
|
||||||
|
ret.mass = {CAR.KONA_EV: 1685., CAR.KONA_HEV: 1425., CAR.KONA_EV_2022: 1743., CAR.KONA_EV_2ND_GEN: 1740.}.get(candidate, 1275.)
|
||||||
|
ret.wheelbase = {CAR.KONA_EV_2ND_GEN: 2.66, }.get(candidate, 2.6)
|
||||||
|
ret.steerRatio = {CAR.KONA_EV_2ND_GEN: 13.6, }.get(candidate, 13.42) # Spec
|
||||||
|
ret.tireStiffnessFactor = 0.385
|
||||||
|
elif candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019, CAR.IONIQ_HEV_2022, CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV):
|
||||||
|
ret.mass = 1490. # weight per hyundai site https://www.hyundaiusa.com/ioniq-electric/specifications.aspx
|
||||||
|
ret.wheelbase = 2.7
|
||||||
|
ret.steerRatio = 13.73 # Spec
|
||||||
|
ret.tireStiffnessFactor = 0.385
|
||||||
|
if candidate in (CAR.IONIQ, CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV_2019):
|
||||||
|
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
|
||||||
|
elif candidate in (CAR.IONIQ_5, CAR.IONIQ_6):
|
||||||
|
ret.mass = 1948
|
||||||
|
ret.wheelbase = 2.97
|
||||||
|
ret.steerRatio = 14.26
|
||||||
|
ret.tireStiffnessFactor = 0.65
|
||||||
|
elif candidate == CAR.VELOSTER:
|
||||||
|
ret.mass = 2917. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.80
|
||||||
|
ret.steerRatio = 13.75 * 1.15
|
||||||
|
ret.tireStiffnessFactor = 0.5
|
||||||
|
elif candidate == CAR.TUCSON:
|
||||||
|
ret.mass = 3520. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.67
|
||||||
|
ret.steerRatio = 14.00 * 1.15
|
||||||
|
ret.tireStiffnessFactor = 0.385
|
||||||
|
elif candidate in (CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN):
|
||||||
|
ret.steerActuatorDelay = 0.1 # Or .15? BBOT test oscarpilot
|
||||||
|
ret.mass = 1630. # average
|
||||||
|
ret.wheelbase = 2.756
|
||||||
|
ret.steerRatio = 16.
|
||||||
|
ret.tireStiffnessFactor = 0.385
|
||||||
|
elif candidate == CAR.SANTA_CRUZ_1ST_GEN:
|
||||||
|
ret.mass = 1870. # weight from Limited trim - the only supported trim
|
||||||
|
ret.wheelbase = 3.000
|
||||||
|
# steering ratio according to Hyundai News https://www.hyundainews.com/assets/documents/original/48035-2022SantaCruzProductGuideSpecsv2081521.pdf
|
||||||
|
ret.steerRatio = 14.2
|
||||||
|
elif candidate == CAR.CUSTIN_1ST_GEN:
|
||||||
|
ret.mass = 1690. # from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0
|
||||||
|
ret.wheelbase = 3.055
|
||||||
|
ret.steerRatio = 17.0 # from learner
|
||||||
|
elif candidate == CAR.STARIA_4TH_GEN:
|
||||||
|
ret.mass = 2205.
|
||||||
|
ret.wheelbase = 3.273
|
||||||
|
ret.steerRatio = 11.94 # https://www.hyundai.com/content/dam/hyundai/au/en/models/staria-load/premium-pip-update-2023/spec-sheet/STARIA_Load_Spec-Table_March_2023_v3.1.pdf
|
||||||
|
|
||||||
|
# Kia
|
||||||
|
elif candidate == CAR.KIA_SORENTO:
|
||||||
|
ret.mass = 1985.
|
||||||
|
ret.wheelbase = 2.78
|
||||||
|
ret.steerRatio = 14.4 * 1.1 # 10% higher at the center seems reasonable
|
||||||
|
elif candidate in (CAR.KIA_NIRO_EV, CAR.KIA_NIRO_EV_2ND_GEN, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_HEV_2ND_GEN, CAR.KIA_NIRO_PHEV_2022):
|
||||||
|
ret.mass = 3543. * CV.LB_TO_KG # average of all the cars
|
||||||
|
ret.wheelbase = 2.7
|
||||||
|
ret.steerRatio = 13.6 # average of all the cars
|
||||||
|
ret.tireStiffnessFactor = 0.385
|
||||||
|
if candidate == CAR.KIA_NIRO_PHEV:
|
||||||
|
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
|
||||||
|
elif candidate == CAR.KIA_SELTOS:
|
||||||
|
ret.mass = 1337.
|
||||||
|
ret.wheelbase = 2.63
|
||||||
|
ret.steerRatio = 14.56
|
||||||
|
elif candidate == CAR.KIA_SPORTAGE_5TH_GEN:
|
||||||
|
ret.mass = 1700. # weight from SX and above trims, average of FWD and AWD versions
|
||||||
|
ret.wheelbase = 2.756
|
||||||
|
ret.steerRatio = 13.6 # steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sportage/2023/specifications
|
||||||
|
elif candidate in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL):
|
||||||
|
ret.mass = 3558. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.80
|
||||||
|
ret.steerRatio = 13.75
|
||||||
|
ret.tireStiffnessFactor = 0.5
|
||||||
|
if candidate == CAR.KIA_OPTIMA_G4:
|
||||||
|
ret.minSteerSpeed = 32 * CV.MPH_TO_MS
|
||||||
|
elif candidate in (CAR.KIA_STINGER, CAR.KIA_STINGER_2022):
|
||||||
|
ret.mass = 1825.
|
||||||
|
ret.wheelbase = 2.78
|
||||||
|
ret.steerRatio = 14.4 * 1.15 # 15% higher at the center seems reasonable
|
||||||
|
elif candidate == CAR.KIA_FORTE:
|
||||||
|
ret.mass = 2878. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.80
|
||||||
|
ret.steerRatio = 13.75
|
||||||
|
ret.tireStiffnessFactor = 0.5
|
||||||
|
elif candidate == CAR.KIA_CEED:
|
||||||
|
ret.mass = 1450.
|
||||||
|
ret.wheelbase = 2.65
|
||||||
|
ret.steerRatio = 13.75
|
||||||
|
ret.tireStiffnessFactor = 0.5
|
||||||
|
elif candidate in (CAR.KIA_K5_2021, CAR.KIA_K5_HEV_2020):
|
||||||
|
ret.mass = 3381. * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.85
|
||||||
|
ret.steerRatio = 13.27 # 2021 Kia K5 Steering Ratio (all trims)
|
||||||
|
ret.tireStiffnessFactor = 0.5
|
||||||
|
elif candidate == CAR.KIA_EV6:
|
||||||
|
ret.mass = 2055
|
||||||
|
ret.wheelbase = 2.9
|
||||||
|
ret.steerRatio = 16.
|
||||||
|
ret.tireStiffnessFactor = 0.65
|
||||||
|
elif candidate == CAR.KIA_SPORTAGE_HYBRID_5TH_GEN:
|
||||||
|
ret.mass = 1767. # SX Prestige trim support only
|
||||||
|
ret.wheelbase = 2.756
|
||||||
|
ret.steerRatio = 13.6
|
||||||
|
elif candidate in (CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN):
|
||||||
|
ret.wheelbase = 2.81
|
||||||
|
ret.steerRatio = 13.5 # average of the platforms
|
||||||
|
if candidate == CAR.KIA_SORENTO_4TH_GEN:
|
||||||
|
ret.mass = 3957 * CV.LB_TO_KG
|
||||||
|
elif candidate == CAR.KIA_SORENTO_HEV_4TH_GEN:
|
||||||
|
ret.mass = 4255 * CV.LB_TO_KG
|
||||||
|
else:
|
||||||
|
ret.mass = 4537 * CV.LB_TO_KG
|
||||||
|
elif candidate == CAR.KIA_CARNIVAL_4TH_GEN:
|
||||||
|
ret.mass = 2087.
|
||||||
|
ret.wheelbase = 3.09
|
||||||
|
ret.steerRatio = 14.23
|
||||||
|
elif candidate == CAR.KIA_K8_HEV_1ST_GEN:
|
||||||
|
ret.mass = 1630. # https://carprices.ae/brands/kia/2023/k8/1.6-turbo-hybrid
|
||||||
|
ret.wheelbase = 2.895
|
||||||
|
ret.steerRatio = 13.27 # guesstimate from K5 platform
|
||||||
|
|
||||||
|
# Genesis
|
||||||
|
elif candidate == CAR.GENESIS_GV60_EV_1ST_GEN:
|
||||||
|
ret.mass = 2205
|
||||||
|
ret.wheelbase = 2.9
|
||||||
|
# https://www.motor1.com/reviews/586376/2023-genesis-gv60-first-drive/#:~:text=Relative%20to%20the%20related%20Ioniq,5%2FEV6%27s%2014.3%3A1.
|
||||||
|
ret.steerRatio = 12.6
|
||||||
|
elif candidate == CAR.GENESIS_G70:
|
||||||
|
ret.steerActuatorDelay = 0.1
|
||||||
|
ret.mass = 1640.0
|
||||||
|
ret.wheelbase = 2.84
|
||||||
|
ret.steerRatio = 13.56
|
||||||
|
elif candidate == CAR.GENESIS_G70_2020:
|
||||||
|
ret.mass = 3673.0 * CV.LB_TO_KG
|
||||||
|
ret.wheelbase = 2.83
|
||||||
|
ret.steerRatio = 12.9
|
||||||
|
elif candidate == CAR.GENESIS_GV70_1ST_GEN:
|
||||||
|
ret.mass = 1950.
|
||||||
|
ret.wheelbase = 2.87
|
||||||
|
ret.steerRatio = 14.6
|
||||||
|
elif candidate == CAR.GENESIS_G80:
|
||||||
|
ret.mass = 2060.
|
||||||
|
ret.wheelbase = 3.01
|
||||||
|
ret.steerRatio = 16.5
|
||||||
|
elif candidate == CAR.GENESIS_G90:
|
||||||
|
ret.mass = 2200.
|
||||||
|
ret.wheelbase = 3.15
|
||||||
|
ret.steerRatio = 12.069
|
||||||
|
elif candidate == CAR.GENESIS_GV80:
|
||||||
|
ret.mass = 2258.
|
||||||
|
ret.wheelbase = 2.95
|
||||||
|
ret.steerRatio = 14.14
|
||||||
|
|
||||||
|
# *** longitudinal control ***
|
||||||
|
if candidate in CANFD_CAR:
|
||||||
|
ret.longitudinalTuning.kpV = [0.1]
|
||||||
|
ret.longitudinalTuning.kiV = [0.0]
|
||||||
|
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
|
||||||
|
else:
|
||||||
|
ret.longitudinalTuning.kpV = [0.5]
|
||||||
|
ret.longitudinalTuning.kiV = [0.0]
|
||||||
|
ret.experimentalLongitudinalAvailable = candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
|
||||||
|
ret.openpilotLongitudinalControl = experimental_long and ret.experimentalLongitudinalAvailable
|
||||||
|
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
ret.stoppingControl = True
|
||||||
|
ret.startingState = True
|
||||||
|
ret.vEgoStarting = 0.1
|
||||||
|
ret.startAccel = 1.0
|
||||||
|
ret.longitudinalActuatorDelayLowerBound = 0.5
|
||||||
|
ret.longitudinalActuatorDelayUpperBound = 0.5
|
||||||
|
|
||||||
|
# *** feature detection ***
|
||||||
|
# if candidate in CANFD_CAR:
|
||||||
|
# ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
|
||||||
|
# ret.nav_msg = 0x544 in fingerprint[0]
|
||||||
|
# else:
|
||||||
|
# ret.enableBsm = 0x58b in fingerprint[0]
|
||||||
|
# ret.nav_msg = False
|
||||||
|
|
||||||
|
# *** panda safety config ***
|
||||||
|
ret.safetyConfigs = set_safety_config_hyundai(candidate, CAN, can_fd=(candidate in CANFD_CAR))
|
||||||
|
|
||||||
|
if hda2:
|
||||||
|
ret.flags |= HyundaiFlags.CANFD_HDA2.value
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2
|
||||||
|
|
||||||
|
if candidate in CANFD_CAR:
|
||||||
|
if hda2 and ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING
|
||||||
|
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CANFD_ALT_BUTTONS
|
||||||
|
|
||||||
|
if ret.flags & HyundaiFlags.CANFD_CAMERA_SCC or candidate in CAMERA_SCC_CAR:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||||
|
if ret.openpilotLongitudinalControl:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
|
||||||
|
params_memory.put_bool("CSLCAvailable", False)
|
||||||
|
if candidate in HYBRID_CAR:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_HYBRID_GAS
|
||||||
|
elif candidate in EV_CAR:
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_EV_GAS
|
||||||
|
|
||||||
|
if candidate in (CAR.KONA, CAR.KONA_EV, CAR.KONA_HEV, CAR.KONA_EV_2022):
|
||||||
|
ret.flags |= HyundaiFlags.ALT_LIMITS.value
|
||||||
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_ALT_LIMITS
|
||||||
|
|
||||||
|
ret.centerToFront = ret.wheelbase * 0.4
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init(CP, logcan, sendcan):
|
||||||
|
if CP.openpilotLongitudinalControl and not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value):
|
||||||
|
addr, bus = 0x7d0, 0
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||||
|
addr, bus = 0x730, CanBus(CP).ECAN
|
||||||
|
disable_ecu(logcan, sendcan, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01')
|
||||||
|
|
||||||
|
# for blinkers
|
||||||
|
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
disable_ecu(logcan, sendcan, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01')
|
||||||
|
|
||||||
|
def _update(self, c):
|
||||||
|
ret = self.CS.update(self.cp, self.cp_cam)
|
||||||
|
|
||||||
|
if self.CS.CP.openpilotLongitudinalControl:
|
||||||
|
ret.buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
|
||||||
|
|
||||||
|
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
|
||||||
|
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
|
||||||
|
# Main button also can trigger an engagement on these cars
|
||||||
|
allow_enable = any(btn in ENABLE_BUTTONS for btn in self.CS.cruise_buttons) or any(self.CS.main_buttons)
|
||||||
|
events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise, allow_enable=allow_enable)
|
||||||
|
|
||||||
|
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
|
||||||
|
if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
|
||||||
|
self.low_speed_alert = True
|
||||||
|
if ret.vEgo > (self.CP.minSteerSpeed + 4.):
|
||||||
|
self.low_speed_alert = False
|
||||||
|
if self.low_speed_alert:
|
||||||
|
events.add(car.CarEvent.EventName.belowSteerSpeed)
|
||||||
|
|
||||||
|
ret.events = events.to_msg()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def apply(self, c, now_nanos, sport_plus):
|
||||||
|
return self.CC.update(c, self.CS, now_nanos, sport_plus)
|
||||||
79
selfdrive/car/hyundai org/radar_interface.org
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
from cereal import car
|
||||||
|
from opendbc.can.parser import CANParser
|
||||||
|
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import DBC
|
||||||
|
|
||||||
|
RADAR_START_ADDR = 0x500
|
||||||
|
RADAR_MSG_COUNT = 32
|
||||||
|
|
||||||
|
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
|
||||||
|
|
||||||
|
def get_radar_can_parser(CP):
|
||||||
|
if DBC[CP.carFingerprint]['radar'] is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)]
|
||||||
|
return CANParser(DBC[CP.carFingerprint]['radar'], messages, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class RadarInterface(RadarInterfaceBase):
|
||||||
|
def __init__(self, CP):
|
||||||
|
super().__init__(CP)
|
||||||
|
self.updated_messages = set()
|
||||||
|
self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
|
||||||
|
self.track_id = 0
|
||||||
|
|
||||||
|
self.radar_off_can = CP.radarUnavailable
|
||||||
|
self.rcp = get_radar_can_parser(CP)
|
||||||
|
|
||||||
|
def update(self, can_strings):
|
||||||
|
if self.radar_off_can or (self.rcp is None):
|
||||||
|
return super().update(None)
|
||||||
|
|
||||||
|
vls = self.rcp.update_strings(can_strings)
|
||||||
|
self.updated_messages.update(vls)
|
||||||
|
|
||||||
|
if self.trigger_msg not in self.updated_messages:
|
||||||
|
return None
|
||||||
|
|
||||||
|
rr = self._update(self.updated_messages)
|
||||||
|
self.updated_messages.clear()
|
||||||
|
|
||||||
|
return rr
|
||||||
|
|
||||||
|
def _update(self, updated_messages):
|
||||||
|
ret = car.RadarData.new_message()
|
||||||
|
if self.rcp is None:
|
||||||
|
return ret
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
if not self.rcp.can_valid:
|
||||||
|
errors.append("canError")
|
||||||
|
ret.errors = errors
|
||||||
|
|
||||||
|
for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT):
|
||||||
|
msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
|
||||||
|
|
||||||
|
if addr not in self.pts:
|
||||||
|
self.pts[addr] = car.RadarData.RadarPoint.new_message()
|
||||||
|
self.pts[addr].trackId = self.track_id
|
||||||
|
self.track_id += 1
|
||||||
|
|
||||||
|
valid = msg['STATE'] in (3, 4)
|
||||||
|
if valid:
|
||||||
|
azimuth = math.radians(msg['AZIMUTH'])
|
||||||
|
self.pts[addr].measured = True
|
||||||
|
self.pts[addr].dRel = math.cos(azimuth) * msg['LONG_DIST']
|
||||||
|
self.pts[addr].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
|
||||||
|
self.pts[addr].vRel = msg['REL_SPEED']
|
||||||
|
self.pts[addr].aRel = msg['REL_ACCEL']
|
||||||
|
self.pts[addr].yvRel = float('nan')
|
||||||
|
|
||||||
|
else:
|
||||||
|
del self.pts[addr]
|
||||||
|
|
||||||
|
ret.points = list(self.pts.values())
|
||||||
|
return ret
|
||||||
591
selfdrive/car/hyundai org/values.org
Normal file
@@ -0,0 +1,591 @@
|
|||||||
|
import re
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum, IntFlag, StrEnum
|
||||||
|
from typing import Dict, List, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
|
from cereal import car
|
||||||
|
from panda.python import uds
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.selfdrive.car import dbc_dict
|
||||||
|
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column
|
||||||
|
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
|
||||||
|
|
||||||
|
Ecu = car.CarParams.Ecu
|
||||||
|
|
||||||
|
|
||||||
|
class CarControllerParams:
|
||||||
|
ACCEL_MIN = -3.5 # m/s
|
||||||
|
ACCEL_MAX = 2.0 # m/s
|
||||||
|
ACCEL_MAX_PLUS = 4.0 # m/s
|
||||||
|
|
||||||
|
def __init__(self, CP):
|
||||||
|
self.STEER_DELTA_UP = 3
|
||||||
|
self.STEER_DELTA_DOWN = 7
|
||||||
|
self.STEER_DRIVER_ALLOWANCE = 50
|
||||||
|
self.STEER_DRIVER_MULTIPLIER = 2
|
||||||
|
self.STEER_DRIVER_FACTOR = 1
|
||||||
|
self.STEER_THRESHOLD = 150
|
||||||
|
self.STEER_STEP = 1 # 100 Hz
|
||||||
|
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
self.STEER_MAX = 270
|
||||||
|
self.STEER_DRIVER_ALLOWANCE = 250
|
||||||
|
self.STEER_DRIVER_MULTIPLIER = 2
|
||||||
|
self.STEER_THRESHOLD = 250
|
||||||
|
self.STEER_DELTA_UP = 2
|
||||||
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
|
||||||
|
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
||||||
|
# If the max stock LKAS request is <384, add your car to this list.
|
||||||
|
elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.IONIQ,
|
||||||
|
CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_PHEV,
|
||||||
|
CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_SORENTO):
|
||||||
|
self.STEER_MAX = 255
|
||||||
|
|
||||||
|
# these cars have significantly more torque than most HKG; limit to 70% of max
|
||||||
|
elif CP.flags & HyundaiFlags.ALT_LIMITS:
|
||||||
|
self.STEER_MAX = 270
|
||||||
|
self.STEER_DELTA_UP = 2
|
||||||
|
self.STEER_DELTA_DOWN = 3
|
||||||
|
|
||||||
|
# Default for most HKG
|
||||||
|
else:
|
||||||
|
self.STEER_MAX = 384
|
||||||
|
|
||||||
|
|
||||||
|
class HyundaiFlags(IntFlag):
|
||||||
|
CANFD_HDA2 = 1
|
||||||
|
CANFD_ALT_BUTTONS = 2
|
||||||
|
CANFD_ALT_GEARS = 4
|
||||||
|
CANFD_CAMERA_SCC = 8
|
||||||
|
|
||||||
|
ALT_LIMITS = 16
|
||||||
|
ENABLE_BLINKERS = 32
|
||||||
|
CANFD_ALT_GEARS_2 = 64
|
||||||
|
SEND_LFA = 128
|
||||||
|
USE_FCA = 256
|
||||||
|
CANFD_HDA2_ALT_STEERING = 512
|
||||||
|
|
||||||
|
|
||||||
|
class CAR(StrEnum):
|
||||||
|
# Hyundai
|
||||||
|
AZERA_6TH_GEN = "HYUNDAI AZERA 6TH GEN"
|
||||||
|
AZERA_HEV_6TH_GEN = "HYUNDAI AZERA HYBRID 6TH GEN"
|
||||||
|
ELANTRA = "HYUNDAI ELANTRA 2017"
|
||||||
|
ELANTRA_GT_I30 = "HYUNDAI I30 N LINE 2019 & GT 2018 DCT"
|
||||||
|
ELANTRA_2021 = "HYUNDAI ELANTRA 2021"
|
||||||
|
ELANTRA_HEV_2021 = "HYUNDAI ELANTRA HYBRID 2021"
|
||||||
|
HYUNDAI_GENESIS = "HYUNDAI GENESIS 2015-2016"
|
||||||
|
IONIQ = "HYUNDAI IONIQ HYBRID 2017-2019"
|
||||||
|
IONIQ_HEV_2022 = "HYUNDAI IONIQ HYBRID 2020-2022"
|
||||||
|
IONIQ_EV_LTD = "HYUNDAI IONIQ ELECTRIC LIMITED 2019"
|
||||||
|
IONIQ_EV_2020 = "HYUNDAI IONIQ ELECTRIC 2020"
|
||||||
|
IONIQ_PHEV_2019 = "HYUNDAI IONIQ PLUG-IN HYBRID 2019"
|
||||||
|
IONIQ_PHEV = "HYUNDAI IONIQ PHEV 2020"
|
||||||
|
KONA = "HYUNDAI KONA 2020"
|
||||||
|
KONA_EV = "HYUNDAI KONA ELECTRIC 2019"
|
||||||
|
KONA_EV_2022 = "HYUNDAI KONA ELECTRIC 2022"
|
||||||
|
KONA_EV_2ND_GEN = "HYUNDAI KONA ELECTRIC 2ND GEN"
|
||||||
|
KONA_HEV = "HYUNDAI KONA HYBRID 2020"
|
||||||
|
SANTA_FE = "HYUNDAI SANTA FE 2019"
|
||||||
|
SANTA_FE_2022 = "HYUNDAI SANTA FE 2022"
|
||||||
|
SANTA_FE_HEV_2022 = "HYUNDAI SANTA FE HYBRID 2022"
|
||||||
|
SANTA_FE_PHEV_2022 = "HYUNDAI SANTA FE PlUG-IN HYBRID 2022"
|
||||||
|
SONATA = "HYUNDAI SONATA 2020"
|
||||||
|
SONATA_LF = "HYUNDAI SONATA 2019"
|
||||||
|
STARIA_4TH_GEN = "HYUNDAI STARIA 4TH GEN"
|
||||||
|
TUCSON = "HYUNDAI TUCSON 2019"
|
||||||
|
PALISADE = "HYUNDAI PALISADE 2020"
|
||||||
|
VELOSTER = "HYUNDAI VELOSTER 2019"
|
||||||
|
SONATA_HYBRID = "HYUNDAI SONATA HYBRID 2021"
|
||||||
|
IONIQ_5 = "HYUNDAI IONIQ 5 2022"
|
||||||
|
IONIQ_6 = "HYUNDAI IONIQ 6 2023"
|
||||||
|
TUCSON_4TH_GEN = "HYUNDAI TUCSON 4TH GEN"
|
||||||
|
TUCSON_HYBRID_4TH_GEN = "HYUNDAI TUCSON HYBRID 4TH GEN"
|
||||||
|
SANTA_CRUZ_1ST_GEN = "HYUNDAI SANTA CRUZ 1ST GEN"
|
||||||
|
CUSTIN_1ST_GEN = "HYUNDAI CUSTIN 1ST GEN"
|
||||||
|
|
||||||
|
# Kia
|
||||||
|
KIA_FORTE = "KIA FORTE E 2018 & GT 2021"
|
||||||
|
KIA_K5_2021 = "KIA K5 2021"
|
||||||
|
KIA_K5_HEV_2020 = "KIA K5 HYBRID 2020"
|
||||||
|
KIA_K8_HEV_1ST_GEN = "KIA K8 HYBRID 1ST GEN"
|
||||||
|
KIA_NIRO_EV = "KIA NIRO EV 2020"
|
||||||
|
KIA_NIRO_EV_2ND_GEN = "KIA NIRO EV 2ND GEN"
|
||||||
|
KIA_NIRO_PHEV = "KIA NIRO HYBRID 2019"
|
||||||
|
KIA_NIRO_PHEV_2022 = "KIA NIRO PLUG-IN HYBRID 2022"
|
||||||
|
KIA_NIRO_HEV_2021 = "KIA NIRO HYBRID 2021"
|
||||||
|
KIA_NIRO_HEV_2ND_GEN = "KIA NIRO HYBRID 2ND GEN"
|
||||||
|
KIA_OPTIMA_G4 = "KIA OPTIMA 4TH GEN"
|
||||||
|
KIA_OPTIMA_G4_FL = "KIA OPTIMA 4TH GEN FACELIFT"
|
||||||
|
KIA_OPTIMA_H = "KIA OPTIMA HYBRID 2017 & SPORTS 2019"
|
||||||
|
KIA_OPTIMA_H_G4_FL = "KIA OPTIMA HYBRID 4TH GEN FACELIFT"
|
||||||
|
KIA_SELTOS = "KIA SELTOS 2021"
|
||||||
|
KIA_SPORTAGE_5TH_GEN = "KIA SPORTAGE 5TH GEN"
|
||||||
|
KIA_SORENTO = "KIA SORENTO GT LINE 2018"
|
||||||
|
KIA_SORENTO_4TH_GEN = "KIA SORENTO 4TH GEN"
|
||||||
|
KIA_SORENTO_HEV_4TH_GEN = "KIA SORENTO HYBRID 4TH GEN"
|
||||||
|
KIA_SORENTO_PHEV_4TH_GEN = "KIA SORENTO PLUG-IN HYBRID 4TH GEN"
|
||||||
|
KIA_SPORTAGE_HYBRID_5TH_GEN = "KIA SPORTAGE HYBRID 5TH GEN"
|
||||||
|
KIA_STINGER = "KIA STINGER GT2 2018"
|
||||||
|
KIA_STINGER_2022 = "KIA STINGER 2022"
|
||||||
|
KIA_CEED = "KIA CEED INTRO ED 2019"
|
||||||
|
KIA_EV6 = "KIA EV6 2022"
|
||||||
|
KIA_CARNIVAL_4TH_GEN = "KIA CARNIVAL 4TH GEN"
|
||||||
|
|
||||||
|
# Genesis
|
||||||
|
GENESIS_GV60_EV_1ST_GEN = "GENESIS GV60 ELECTRIC 1ST GEN"
|
||||||
|
GENESIS_G70 = "GENESIS G70 2018"
|
||||||
|
GENESIS_G70_2020 = "GENESIS G70 2020"
|
||||||
|
GENESIS_GV70_1ST_GEN = "GENESIS GV70 1ST GEN"
|
||||||
|
GENESIS_G80 = "GENESIS G80 2017"
|
||||||
|
GENESIS_G90 = "GENESIS G90 2017"
|
||||||
|
GENESIS_GV80 = "GENESIS GV80 2023"
|
||||||
|
|
||||||
|
|
||||||
|
class Footnote(Enum):
|
||||||
|
CANFD = CarFootnote(
|
||||||
|
"Requires a <a href=\"https://comma.ai/shop/can-fd-panda-kit\" target=\"_blank\">CAN FD panda kit</a> if not using " +
|
||||||
|
"comma 3X for this <a href=\"https://en.wikipedia.org/wiki/CAN_FD\" target=\"_blank\">CAN FD car</a>.",
|
||||||
|
Column.MODEL, shop_footnote=False)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HyundaiCarInfo(CarInfo):
|
||||||
|
package: str = "Smart Cruise Control (SCC)"
|
||||||
|
|
||||||
|
def init_make(self, CP: car.CarParams):
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
self.footnotes.insert(0, Footnote.CANFD)
|
||||||
|
|
||||||
|
|
||||||
|
CAR_INFO: Dict[str, Optional[Union[HyundaiCarInfo, List[HyundaiCarInfo]]]] = {
|
||||||
|
CAR.AZERA_6TH_GEN: HyundaiCarInfo("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.AZERA_HEV_6TH_GEN: [
|
||||||
|
HyundaiCarInfo("Hyundai Azera Hybrid 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
HyundaiCarInfo("Hyundai Azera Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
],
|
||||||
|
CAR.ELANTRA: [
|
||||||
|
# TODO: 2017-18 could be Hyundai G
|
||||||
|
HyundaiCarInfo("Hyundai Elantra 2017-18", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_b])),
|
||||||
|
HyundaiCarInfo("Hyundai Elantra 2019", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_g])),
|
||||||
|
],
|
||||||
|
CAR.ELANTRA_GT_I30: [
|
||||||
|
HyundaiCarInfo("Hyundai Elantra GT 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
HyundaiCarInfo("Hyundai i30 2017-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
],
|
||||||
|
CAR.ELANTRA_2021: HyundaiCarInfo("Hyundai Elantra 2021-23", video_link="https://youtu.be/_EdYQtV52-c", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.ELANTRA_HEV_2021: HyundaiCarInfo("Hyundai Elantra Hybrid 2021-23", video_link="https://youtu.be/_EdYQtV52-c",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.HYUNDAI_GENESIS: [
|
||||||
|
# TODO: check 2015 packages
|
||||||
|
HyundaiCarInfo("Hyundai Genesis 2015-16", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])),
|
||||||
|
HyundaiCarInfo("Genesis G80 2017", "All", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_j])),
|
||||||
|
],
|
||||||
|
CAR.IONIQ: HyundaiCarInfo("Hyundai Ioniq Hybrid 2017-19", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.IONIQ_HEV_2022: HyundaiCarInfo("Hyundai Ioniq Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_h])), # TODO: confirm 2020-21 harness
|
||||||
|
CAR.IONIQ_EV_LTD: HyundaiCarInfo("Hyundai Ioniq Electric 2019", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.IONIQ_EV_2020: HyundaiCarInfo("Hyundai Ioniq Electric 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
CAR.IONIQ_PHEV_2019: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2019", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.IONIQ_PHEV: HyundaiCarInfo("Hyundai Ioniq Plug-in Hybrid 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
CAR.KONA: HyundaiCarInfo("Hyundai Kona 2020", car_parts=CarParts.common([CarHarness.hyundai_b])),
|
||||||
|
CAR.KONA_EV: HyundaiCarInfo("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g])),
|
||||||
|
CAR.KONA_EV_2022: HyundaiCarInfo("Hyundai Kona Electric 2022-23", car_parts=CarParts.common([CarHarness.hyundai_o])),
|
||||||
|
CAR.KONA_HEV: HyundaiCarInfo("Hyundai Kona Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_i])), # TODO: check packages
|
||||||
|
# TODO: this is the 2024 US MY, not yet released
|
||||||
|
CAR.KONA_EV_2ND_GEN: HyundaiCarInfo("Hyundai Kona Electric (with HDA II, Korea only) 2023", video_link="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||||
|
CAR.SANTA_FE: HyundaiCarInfo("Hyundai Santa Fe 2019-20", "All", video_link="https://youtu.be/bjDR0YjM__s",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||||
|
CAR.SANTA_FE_2022: HyundaiCarInfo("Hyundai Santa Fe 2021-23", "All", video_link="https://youtu.be/VnHzSTygTS4",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
CAR.SANTA_FE_HEV_2022: HyundaiCarInfo("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
CAR.SANTA_FE_PHEV_2022: HyundaiCarInfo("Hyundai Santa Fe Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
CAR.SONATA: HyundaiCarInfo("Hyundai Sonata 2020-23", "All", video_link="https://www.youtube.com/watch?v=ix63r9kE3Fw",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.STARIA_4TH_GEN: HyundaiCarInfo("Hyundai Staria 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.SONATA_LF: HyundaiCarInfo("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
CAR.TUCSON: [
|
||||||
|
HyundaiCarInfo("Hyundai Tucson 2021", min_enable_speed=19 * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
HyundaiCarInfo("Hyundai Tucson Diesel 2019", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
],
|
||||||
|
CAR.PALISADE: [
|
||||||
|
HyundaiCarInfo("Hyundai Palisade 2020-22", "All", video_link="https://youtu.be/TAnDqjF4fDY?t=456", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
HyundaiCarInfo("Kia Telluride 2020-22", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
],
|
||||||
|
CAR.VELOSTER: HyundaiCarInfo("Hyundai Veloster 2019-20", min_enable_speed=5. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
CAR.SONATA_HYBRID: HyundaiCarInfo("Hyundai Sonata Hybrid 2020-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.IONIQ_5: [
|
||||||
|
HyundaiCarInfo("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
|
||||||
|
HyundaiCarInfo("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
HyundaiCarInfo("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
|
||||||
|
],
|
||||||
|
CAR.IONIQ_6: [
|
||||||
|
HyundaiCarInfo("Hyundai Ioniq 6 (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||||
|
],
|
||||||
|
CAR.TUCSON_4TH_GEN: [
|
||||||
|
HyundaiCarInfo("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
HyundaiCarInfo("Hyundai Tucson 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
],
|
||||||
|
CAR.TUCSON_HYBRID_4TH_GEN: HyundaiCarInfo("Hyundai Tucson Hybrid 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
CAR.SANTA_CRUZ_1ST_GEN: HyundaiCarInfo("Hyundai Santa Cruz 2022-23", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
CAR.CUSTIN_1ST_GEN: HyundaiCarInfo("Hyundai Custin 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
|
||||||
|
# Kia
|
||||||
|
CAR.KIA_FORTE: [
|
||||||
|
HyundaiCarInfo("Kia Forte 2019-21", car_parts=CarParts.common([CarHarness.hyundai_g])),
|
||||||
|
HyundaiCarInfo("Kia Forte 2023", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
],
|
||||||
|
CAR.KIA_K5_2021: HyundaiCarInfo("Kia K5 2021-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_K5_HEV_2020: HyundaiCarInfo("Kia K5 Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_K8_HEV_1ST_GEN: HyundaiCarInfo("Kia K8 Hybrid (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
|
||||||
|
CAR.KIA_NIRO_EV: [
|
||||||
|
HyundaiCarInfo("Kia Niro EV 2019", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
HyundaiCarInfo("Kia Niro EV 2020", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||||
|
HyundaiCarInfo("Kia Niro EV 2021", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
HyundaiCarInfo("Kia Niro EV 2022", "All", video_link="https://www.youtube.com/watch?v=lT7zcG6ZpGo", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
],
|
||||||
|
CAR.KIA_NIRO_EV_2ND_GEN: HyundaiCarInfo("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_NIRO_PHEV: [
|
||||||
|
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
HyundaiCarInfo("Kia Niro Plug-in Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||||
|
],
|
||||||
|
CAR.KIA_NIRO_PHEV_2022: HyundaiCarInfo("Kia Niro Plug-in Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||||
|
CAR.KIA_NIRO_HEV_2021: [
|
||||||
|
HyundaiCarInfo("Kia Niro Hybrid 2021", car_parts=CarParts.common([CarHarness.hyundai_d])),
|
||||||
|
HyundaiCarInfo("Kia Niro Hybrid 2022", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||||
|
],
|
||||||
|
CAR.KIA_NIRO_HEV_2ND_GEN: HyundaiCarInfo("Kia Niro Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_OPTIMA_G4: HyundaiCarInfo("Kia Optima 2017", "Advanced Smart Cruise Control",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_b])), # TODO: may support 2016, 2018
|
||||||
|
CAR.KIA_OPTIMA_G4_FL: HyundaiCarInfo("Kia Optima 2019-20", car_parts=CarParts.common([CarHarness.hyundai_g])),
|
||||||
|
# TODO: may support adjacent years. may have a non-zero minimum steering speed
|
||||||
|
CAR.KIA_OPTIMA_H: HyundaiCarInfo("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.KIA_OPTIMA_H_G4_FL: HyundaiCarInfo("Kia Optima Hybrid 2019", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
CAR.KIA_SELTOS: HyundaiCarInfo("Kia Seltos 2021", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_SPORTAGE_5TH_GEN: HyundaiCarInfo("Kia Sportage 2023", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
CAR.KIA_SORENTO: [
|
||||||
|
HyundaiCarInfo("Kia Sorento 2018", "Advanced Smart Cruise Control & LKAS", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
HyundaiCarInfo("Kia Sorento 2019", video_link="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
],
|
||||||
|
CAR.KIA_SORENTO_4TH_GEN: HyundaiCarInfo("Kia Sorento 2021-23", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.KIA_SORENTO_HEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Hybrid 2021-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_SORENTO_PHEV_4TH_GEN: HyundaiCarInfo("Kia Sorento Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: HyundaiCarInfo("Kia Sportage Hybrid 2023", car_parts=CarParts.common([CarHarness.hyundai_n])),
|
||||||
|
CAR.KIA_STINGER: HyundaiCarInfo("Kia Stinger 2018-20", video_link="https://www.youtube.com/watch?v=MJ94qoofYw0",
|
||||||
|
car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.KIA_STINGER_2022: HyundaiCarInfo("Kia Stinger 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
CAR.KIA_CEED: HyundaiCarInfo("Kia Ceed 2019", car_parts=CarParts.common([CarHarness.hyundai_e])),
|
||||||
|
CAR.KIA_EV6: [
|
||||||
|
HyundaiCarInfo("Kia EV6 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
|
||||||
|
HyundaiCarInfo("Kia EV6 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
HyundaiCarInfo("Kia EV6 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
|
||||||
|
],
|
||||||
|
CAR.KIA_CARNIVAL_4TH_GEN: [
|
||||||
|
HyundaiCarInfo("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
HyundaiCarInfo("Kia Carnival (China only) 2023", car_parts=CarParts.common([CarHarness.hyundai_k]))
|
||||||
|
],
|
||||||
|
|
||||||
|
# Genesis
|
||||||
|
CAR.GENESIS_GV60_EV_1ST_GEN: [
|
||||||
|
HyundaiCarInfo("Genesis GV60 (Advanced Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||||
|
HyundaiCarInfo("Genesis GV60 (Performance Trim) 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k])),
|
||||||
|
],
|
||||||
|
CAR.GENESIS_G70: HyundaiCarInfo("Genesis G70 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||||
|
CAR.GENESIS_G70_2020: HyundaiCarInfo("Genesis G70 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_f])),
|
||||||
|
CAR.GENESIS_GV70_1ST_GEN: [
|
||||||
|
HyundaiCarInfo("Genesis GV70 (2.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||||
|
HyundaiCarInfo("Genesis GV70 (3.5T Trim) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
|
||||||
|
],
|
||||||
|
CAR.GENESIS_G80: HyundaiCarInfo("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h])),
|
||||||
|
CAR.GENESIS_G90: HyundaiCarInfo("Genesis G90 2017-18", "All", car_parts=CarParts.common([CarHarness.hyundai_c])),
|
||||||
|
CAR.GENESIS_GV80: HyundaiCarInfo("Genesis GV80 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
|
||||||
|
}
|
||||||
|
|
||||||
|
class Buttons:
|
||||||
|
NONE = 0
|
||||||
|
RES_ACCEL = 1
|
||||||
|
SET_DECEL = 2
|
||||||
|
GAP_DIST = 3
|
||||||
|
CANCEL = 4 # on newer models, this is a pause/resume button
|
||||||
|
|
||||||
|
|
||||||
|
def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, Optional[bytes]]]:
|
||||||
|
# Returns unique, platform-specific identification codes for a set of versions
|
||||||
|
codes = set() # (code-Optional[part], date)
|
||||||
|
for fw in fw_versions:
|
||||||
|
code_match = PLATFORM_CODE_FW_PATTERN.search(fw)
|
||||||
|
part_match = PART_NUMBER_FW_PATTERN.search(fw)
|
||||||
|
date_match = DATE_FW_PATTERN.search(fw)
|
||||||
|
if code_match is not None:
|
||||||
|
code: bytes = code_match.group()
|
||||||
|
part = part_match.group() if part_match else None
|
||||||
|
date = date_match.group() if date_match else None
|
||||||
|
if part is not None:
|
||||||
|
# part number starts with generic ECU part type, add what is specific to platform
|
||||||
|
code += b"-" + part[-5:]
|
||||||
|
|
||||||
|
codes.add((code, date))
|
||||||
|
return codes
|
||||||
|
|
||||||
|
|
||||||
|
def match_fw_to_car_fuzzy(live_fw_versions, offline_fw_versions) -> Set[str]:
|
||||||
|
# Non-electric CAN FD platforms often do not have platform code specifiers needed
|
||||||
|
# to distinguish between hybrid and ICE. All EVs so far are either exclusively
|
||||||
|
# electric or specify electric in the platform code.
|
||||||
|
# TODO: whitelist platforms that we've seen hybrid and ICE versions of that have these specifiers
|
||||||
|
fuzzy_platform_blacklist = {str(c) for c in set(CANFD_CAR - EV_CAR)}
|
||||||
|
candidates: Set[str] = set()
|
||||||
|
|
||||||
|
for candidate, fws in offline_fw_versions.items():
|
||||||
|
# Keep track of ECUs which pass all checks (platform codes, within date range)
|
||||||
|
valid_found_ecus = set()
|
||||||
|
valid_expected_ecus = {ecu[1:] for ecu in fws if ecu[0] in PLATFORM_CODE_ECUS}
|
||||||
|
for ecu, expected_versions in fws.items():
|
||||||
|
addr = ecu[1:]
|
||||||
|
# Only check ECUs expected to have platform codes
|
||||||
|
if ecu[0] not in PLATFORM_CODE_ECUS:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Expected platform codes & dates
|
||||||
|
codes = get_platform_codes(expected_versions)
|
||||||
|
expected_platform_codes = {code for code, _ in codes}
|
||||||
|
expected_dates = {date for _, date in codes if date is not None}
|
||||||
|
|
||||||
|
# Found platform codes & dates
|
||||||
|
codes = get_platform_codes(live_fw_versions.get(addr, set()))
|
||||||
|
found_platform_codes = {code for code, _ in codes}
|
||||||
|
found_dates = {date for _, date in codes if date is not None}
|
||||||
|
|
||||||
|
# Check platform code + part number matches for any found versions
|
||||||
|
if not any(found_platform_code in expected_platform_codes for found_platform_code in found_platform_codes):
|
||||||
|
break
|
||||||
|
|
||||||
|
if ecu[0] in DATE_FW_ECUS:
|
||||||
|
# If ECU can have a FW date, require it to exist
|
||||||
|
# (this excludes candidates in the database without dates)
|
||||||
|
if not len(expected_dates) or not len(found_dates):
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check any date within range in the database, format is %y%m%d
|
||||||
|
if not any(min(expected_dates) <= found_date <= max(expected_dates) for found_date in found_dates):
|
||||||
|
break
|
||||||
|
|
||||||
|
valid_found_ecus.add(addr)
|
||||||
|
|
||||||
|
# If all live ECUs pass all checks for candidate, add it as a match
|
||||||
|
if valid_expected_ecus.issubset(valid_found_ecus):
|
||||||
|
candidates.add(candidate)
|
||||||
|
|
||||||
|
return candidates - fuzzy_platform_blacklist
|
||||||
|
|
||||||
|
|
||||||
|
HYUNDAI_VERSION_REQUEST_LONG = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
||||||
|
p16(0xf100) # Long description
|
||||||
|
|
||||||
|
HYUNDAI_VERSION_REQUEST_ALT = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
||||||
|
p16(0xf110) # Alt long description
|
||||||
|
|
||||||
|
HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
|
||||||
|
p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_SPARE_PART_NUMBER) + \
|
||||||
|
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + \
|
||||||
|
p16(0xf100)
|
||||||
|
|
||||||
|
HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40])
|
||||||
|
|
||||||
|
# Regex patterns for parsing platform code, FW date, and part number from FW versions
|
||||||
|
PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] +
|
||||||
|
b')[A-Z]{2}[A-Za-z0-9]{0,2})')
|
||||||
|
DATE_FW_PATTERN = re.compile(b'(?<=[ -])([0-9]{6}$)')
|
||||||
|
PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])')
|
||||||
|
|
||||||
|
# List of ECUs expected to have platform codes, camera and radar should exist on all cars
|
||||||
|
# TODO: use abs, it has the platform code and part number on many platforms
|
||||||
|
PLATFORM_CODE_ECUS = [Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps]
|
||||||
|
# So far we've only seen dates in fwdCamera
|
||||||
|
# TODO: there are date codes in the ABS firmware versions in hex
|
||||||
|
DATE_FW_ECUS = [Ecu.fwdCamera]
|
||||||
|
|
||||||
|
FW_QUERY_CONFIG = FwQueryConfig(
|
||||||
|
requests=[
|
||||||
|
# TODO: minimize shared whitelists for CAN and cornerRadar for CAN-FD
|
||||||
|
# CAN queries (OBD-II port)
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_LONG],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera],
|
||||||
|
),
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_MULTI],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.engine, Ecu.transmission, Ecu.eps, Ecu.abs, Ecu.fwdRadar],
|
||||||
|
),
|
||||||
|
|
||||||
|
# CAN-FD queries (from camera)
|
||||||
|
# TODO: combine shared whitelists with CAN requests
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_LONG],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.fwdCamera, Ecu.fwdRadar, Ecu.cornerRadar, Ecu.hvac],
|
||||||
|
bus=0,
|
||||||
|
auxiliary=True,
|
||||||
|
),
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_LONG],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.fwdCamera, Ecu.adas, Ecu.cornerRadar, Ecu.hvac],
|
||||||
|
bus=1,
|
||||||
|
auxiliary=True,
|
||||||
|
obd_multiplexing=False,
|
||||||
|
),
|
||||||
|
|
||||||
|
# CAN-FD debugging queries
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_ALT],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
|
||||||
|
bus=0,
|
||||||
|
auxiliary=True,
|
||||||
|
),
|
||||||
|
Request(
|
||||||
|
[HYUNDAI_VERSION_REQUEST_ALT],
|
||||||
|
[HYUNDAI_VERSION_RESPONSE],
|
||||||
|
whitelist_ecus=[Ecu.parkingAdas, Ecu.hvac],
|
||||||
|
bus=1,
|
||||||
|
auxiliary=True,
|
||||||
|
obd_multiplexing=False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
extra_ecus=[
|
||||||
|
(Ecu.adas, 0x730, None), # ADAS Driving ECU on HDA2 platforms
|
||||||
|
(Ecu.parkingAdas, 0x7b1, None), # ADAS Parking ECU (may exist on all platforms)
|
||||||
|
(Ecu.hvac, 0x7b3, None), # HVAC Control Assembly
|
||||||
|
(Ecu.cornerRadar, 0x7b7, None),
|
||||||
|
],
|
||||||
|
# Custom fuzzy fingerprinting function using platform codes, part numbers + FW dates:
|
||||||
|
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CHECKSUM = {
|
||||||
|
"crc8": [CAR.SANTA_FE, CAR.SONATA, CAR.PALISADE, CAR.KIA_SELTOS, CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021,
|
||||||
|
CAR.SONATA_HYBRID, CAR.SANTA_FE_2022, CAR.KIA_K5_2021, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022,
|
||||||
|
CAR.KIA_K5_HEV_2020, CAR.CUSTIN_1ST_GEN],
|
||||||
|
"6B": [CAR.KIA_SORENTO, CAR.HYUNDAI_GENESIS],
|
||||||
|
}
|
||||||
|
|
||||||
|
CAN_GEARS = {
|
||||||
|
# which message has the gear. hybrid and EV use ELECT_GEAR
|
||||||
|
"use_cluster_gears": {CAR.ELANTRA, CAR.ELANTRA_GT_I30, CAR.KONA},
|
||||||
|
"use_tcu_gears": {CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.SONATA_LF, CAR.VELOSTER, CAR.TUCSON},
|
||||||
|
}
|
||||||
|
|
||||||
|
CANFD_CAR = {CAR.KIA_EV6, CAR.IONIQ_5, CAR.IONIQ_6, CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN, CAR.KIA_SPORTAGE_HYBRID_5TH_GEN,
|
||||||
|
CAR.SANTA_CRUZ_1ST_GEN, CAR.KIA_SPORTAGE_5TH_GEN, CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN,
|
||||||
|
CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_NIRO_HEV_2ND_GEN, CAR.KIA_NIRO_EV_2ND_GEN,
|
||||||
|
CAR.GENESIS_GV80, CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KONA_EV_2ND_GEN, CAR.KIA_K8_HEV_1ST_GEN,
|
||||||
|
CAR.STARIA_4TH_GEN}
|
||||||
|
|
||||||
|
# The radar does SCC on these cars when HDA I, rather than the camera
|
||||||
|
CANFD_RADAR_SCC_CAR = {CAR.GENESIS_GV70_1ST_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_SORENTO_4TH_GEN, CAR.GENESIS_GV80,
|
||||||
|
CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN}
|
||||||
|
|
||||||
|
# These CAN FD cars do not accept communication control to disable the ADAS ECU,
|
||||||
|
# responds with 0x7F2822 - 'conditions not correct'
|
||||||
|
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = {CAR.IONIQ_6, CAR.KONA_EV_2ND_GEN}
|
||||||
|
|
||||||
|
# The camera does SCC on these cars, rather than the radar
|
||||||
|
CAMERA_SCC_CAR = {CAR.KONA_EV_2022, }
|
||||||
|
|
||||||
|
# these cars use a different gas signal
|
||||||
|
HYBRID_CAR = {CAR.IONIQ_PHEV, CAR.ELANTRA_HEV_2021, CAR.KIA_NIRO_PHEV, CAR.KIA_NIRO_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.IONIQ,
|
||||||
|
CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.SANTA_FE_PHEV_2022, CAR.IONIQ_PHEV_2019, CAR.TUCSON_HYBRID_4TH_GEN,
|
||||||
|
CAR.KIA_SPORTAGE_HYBRID_5TH_GEN, CAR.KIA_SORENTO_PHEV_4TH_GEN, CAR.KIA_K5_HEV_2020, CAR.KIA_NIRO_HEV_2ND_GEN,
|
||||||
|
CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_K8_HEV_1ST_GEN,
|
||||||
|
CAR.AZERA_HEV_6TH_GEN, CAR.KIA_NIRO_PHEV_2022}
|
||||||
|
|
||||||
|
EV_CAR = {CAR.IONIQ_EV_2020, CAR.IONIQ_EV_LTD, CAR.KONA_EV, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_EV_2ND_GEN, CAR.KONA_EV_2022,
|
||||||
|
CAR.KIA_EV6, CAR.IONIQ_5, CAR.IONIQ_6, CAR.GENESIS_GV60_EV_1ST_GEN, CAR.KONA_EV_2ND_GEN}
|
||||||
|
|
||||||
|
# these cars require a special panda safety mode due to missing counters and checksums in the messages
|
||||||
|
LEGACY_SAFETY_MODE_CAR = {CAR.HYUNDAI_GENESIS, CAR.IONIQ_EV_LTD, CAR.KIA_OPTIMA_G4,
|
||||||
|
CAR.VELOSTER, CAR.GENESIS_G70, CAR.GENESIS_G80, CAR.KIA_CEED, CAR.ELANTRA, CAR.IONIQ_HEV_2022,
|
||||||
|
CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30}
|
||||||
|
|
||||||
|
# these cars have not been verified to work with longitudinal yet - radar disable, sending correct messages, etc.
|
||||||
|
UNSUPPORTED_LONGITUDINAL_CAR = LEGACY_SAFETY_MODE_CAR | {CAR.KIA_NIRO_PHEV, CAR.KIA_SORENTO, CAR.SONATA_LF, CAR.KIA_OPTIMA_G4_FL,
|
||||||
|
CAR.KIA_OPTIMA_H_G4_FL}
|
||||||
|
|
||||||
|
# If 0x500 is present on bus 1 it probably has a Mando radar outputting radar points.
|
||||||
|
# If no points are outputted by default it might be possible to turn it on using selfdrive/debug/hyundai_enable_radar_points.py
|
||||||
|
DBC = {
|
||||||
|
CAR.AZERA_6TH_GEN: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.AZERA_HEV_6TH_GEN: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.ELANTRA: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.ELANTRA_GT_I30: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.ELANTRA_2021: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.ELANTRA_HEV_2021: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.GENESIS_G70: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.GENESIS_G70_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.GENESIS_G80: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.GENESIS_G90: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.HYUNDAI_GENESIS: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.IONIQ_PHEV_2019: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.IONIQ_PHEV: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.IONIQ_EV_2020: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.IONIQ_EV_LTD: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.IONIQ: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.IONIQ_HEV_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_FORTE: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_K5_2021: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_K5_HEV_2020: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.KIA_NIRO_EV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.KIA_NIRO_PHEV: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.KIA_NIRO_HEV_2021: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_OPTIMA_G4: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_OPTIMA_G4_FL: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_OPTIMA_H: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_OPTIMA_H_G4_FL: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_SELTOS: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_SORENTO: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
|
||||||
|
CAR.KIA_STINGER: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_STINGER_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KONA: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KONA_EV: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KONA_EV_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KONA_HEV: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.SANTA_FE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.SANTA_FE_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.SANTA_FE_HEV_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.SANTA_FE_PHEV_2022: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.SONATA: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.SONATA_LF: dbc_dict('hyundai_kia_generic', None), # Has 0x5XX messages, but different format
|
||||||
|
CAR.TUCSON: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.PALISADE: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.VELOSTER: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_CEED: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_EV6: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.SONATA_HYBRID: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.TUCSON_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.TUCSON_HYBRID_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.IONIQ_5: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.IONIQ_6: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.SANTA_CRUZ_1ST_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_SPORTAGE_5TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_SPORTAGE_HYBRID_5TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.GENESIS_GV70_1ST_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_SORENTO_PHEV_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.GENESIS_GV60_EV_1ST_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_SORENTO_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_NIRO_HEV_2ND_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_NIRO_EV_2ND_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.GENESIS_GV80: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_CARNIVAL_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_SORENTO_HEV_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KONA_EV_2ND_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.KIA_K8_HEV_1ST_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
CAR.CUSTIN_1ST_GEN: dbc_dict('hyundai_kia_generic', None),
|
||||||
|
CAR.KIA_NIRO_PHEV_2022: dbc_dict('hyundai_kia_generic', 'hyundai_kia_mando_front_radar_generated'),
|
||||||
|
CAR.STARIA_4TH_GEN: dbc_dict('hyundai_canfd', None),
|
||||||
|
}
|
||||||
332
selfdrive/car/hyundai/carcontroller.2
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
from cereal import car
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.numpy_fast import clip
|
||||||
|
from openpilot.common.realtime import DT_CTRL
|
||||||
|
from opendbc.can.packer import CANPacker
|
||||||
|
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||||
|
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR, LEGACY_SAFETY_MODE_CAR
|
||||||
|
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
params_memory = Params("/dev/shm/params")
|
||||||
|
|
||||||
|
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
||||||
|
# All slightly below EPS thresholds to avoid fault
|
||||||
|
MAX_ANGLE = 85
|
||||||
|
MAX_ANGLE_FRAMES = 89
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||||
|
|
||||||
|
|
||||||
|
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||||
|
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||||
|
|
||||||
|
# initialize to no line visible
|
||||||
|
# TODO: this is not accurate for all cars
|
||||||
|
sys_state = 1
|
||||||
|
if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
|
||||||
|
sys_state = 3 if enabled or sys_warning else 4
|
||||||
|
elif hud_control.leftLaneVisible:
|
||||||
|
sys_state = 5
|
||||||
|
elif hud_control.rightLaneVisible:
|
||||||
|
sys_state = 6
|
||||||
|
|
||||||
|
# initialize to no warnings
|
||||||
|
left_lane_warning = 0
|
||||||
|
right_lane_warning = 0
|
||||||
|
if hud_control.leftLaneDepart:
|
||||||
|
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
if hud_control.rightLaneDepart:
|
||||||
|
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
|
||||||
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
|
class CarController:
|
||||||
|
def __init__(self, dbc_name, CP, VM):
|
||||||
|
self.CP = CP
|
||||||
|
self.CAN = CanBus(CP)
|
||||||
|
self.params = CarControllerParams(CP)
|
||||||
|
self.packer = CANPacker(dbc_name)
|
||||||
|
self.angle_limit_counter = 0
|
||||||
|
self.frame = 0
|
||||||
|
|
||||||
|
self.accel_last = 0
|
||||||
|
self.apply_steer_last = 0
|
||||||
|
self.car_fingerprint = CP.carFingerprint
|
||||||
|
self.last_button_frame = 0
|
||||||
|
self.last_resume_frame = 0
|
||||||
|
self.last_debug_frame = 0
|
||||||
|
|
||||||
|
def update(self, CC, CS, now_nanos, sport_plus):
|
||||||
|
actuators = CC.actuators
|
||||||
|
hud_control = CC.hudControl
|
||||||
|
|
||||||
|
# hud_v_cruise = hud_control.setSpeed
|
||||||
|
# if hud_v_cruise > 70:
|
||||||
|
# hud_v_cruise = 0
|
||||||
|
|
||||||
|
# steering torque
|
||||||
|
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
||||||
|
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
||||||
|
|
||||||
|
# >90 degree steering fault prevention
|
||||||
|
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
||||||
|
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
||||||
|
|
||||||
|
if not CC.latActive:
|
||||||
|
apply_steer = 0
|
||||||
|
|
||||||
|
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||||
|
torque_fault = CC.latActive and not apply_steer_req
|
||||||
|
|
||||||
|
self.apply_steer_last = apply_steer
|
||||||
|
|
||||||
|
# accel + longitudinal
|
||||||
|
if sport_plus:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
|
||||||
|
else:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
||||||
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||||
|
|
||||||
|
# HUD messages
|
||||||
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||||
|
hud_control)
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
# *** common hyundai stuff ***
|
||||||
|
|
||||||
|
# tester present - w/ no response (keeps relevant ECU disabled)
|
||||||
|
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
|
||||||
|
# for longitudinal control, either radar or ADAS driving ECU
|
||||||
|
addr, bus = 0x7d0, 0
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||||
|
addr, bus = 0x730, self.CAN.ECAN
|
||||||
|
can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
|
||||||
|
|
||||||
|
# for blinkers
|
||||||
|
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
|
||||||
|
|
||||||
|
# CAN-FD platforms
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||||
|
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
# steering control
|
||||||
|
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
|
||||||
|
|
||||||
|
# MODIFIED BBOT
|
||||||
|
if self.frame % 5 == 0 and hda2:
|
||||||
|
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
|
||||||
|
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
|
||||||
|
|
||||||
|
# MODIFIED BBOT
|
||||||
|
# LFA and HDA icons
|
||||||
|
if self.frame % 5 == 0 and (not hda2 or hda2_long):
|
||||||
|
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
|
||||||
|
|
||||||
|
# blinkers
|
||||||
|
if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
||||||
|
|
||||||
|
# can_sends.append(hyundaicanfd.create_misc_messages(self.packer, self.CAN, self.frame))
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
if hda2:
|
||||||
|
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||||
|
if self.frame % 2 == 0:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||||
|
set_speed_in_units, CS.personality_profile))
|
||||||
|
self.accel_last = accel
|
||||||
|
else:
|
||||||
|
# button presses
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False, set_speed_in_units = None))
|
||||||
|
else:
|
||||||
|
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
|
||||||
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
left_lane_warning, right_lane_warning))
|
||||||
|
|
||||||
|
if not self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
|
||||||
|
|
||||||
|
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
# TODO: unclear if this is needed
|
||||||
|
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||||
|
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||||
|
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
||||||
|
hud_control.leadVisible, set_speed_in_units, stopping,
|
||||||
|
CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
|
||||||
|
|
||||||
|
# 20 Hz LFA MFA message
|
||||||
|
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||||
|
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
|
||||||
|
|
||||||
|
# 5 Hz ACC options
|
||||||
|
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(hyundaican.create_acc_opt(self.packer))
|
||||||
|
|
||||||
|
# 2 Hz front radar options
|
||||||
|
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
||||||
|
|
||||||
|
# CSLC
|
||||||
|
# if not self.CP.openpilotLongitudinalControl and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
|
||||||
|
# if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
|
||||||
|
# # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
|
||||||
|
# cslcSetSpeed = set_speed_in_units
|
||||||
|
# self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
|
||||||
|
# if self.cruise_button != Buttons.NONE:
|
||||||
|
# # if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
|
||||||
|
# # send_freq = 1
|
||||||
|
# # # send resume at a max freq of 10Hz
|
||||||
|
# # if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
|
||||||
|
# # # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
|
||||||
|
# # can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
|
||||||
|
# # if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
|
||||||
|
# # self.last_button_frame = self.frame
|
||||||
|
# if self.frame % 2 == 0:
|
||||||
|
# if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
# can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
|
||||||
|
# else:
|
||||||
|
# can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
|
||||||
|
|
||||||
|
# Test - Works???
|
||||||
|
# if CS.cruise_buttons == Buttons.NONE and CS.cruiseState.enabled:
|
||||||
|
# can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, Buttons.SET_DECEL))
|
||||||
|
|
||||||
|
new_actuators = actuators.copy()
|
||||||
|
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
||||||
|
new_actuators.steerOutputCan = apply_steer
|
||||||
|
new_actuators.accel = accel
|
||||||
|
|
||||||
|
Watcher.log_watch("hyundai_carcontroller_update_CC", CC)
|
||||||
|
Watcher.log_watch("hyundai_carcontroller_update_CS", CS)
|
||||||
|
Watcher.log_watch("hyundai_carcontroller_update_self", self)
|
||||||
|
|
||||||
|
self.frame += 1
|
||||||
|
return new_actuators, can_sends
|
||||||
|
|
||||||
|
def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool, set_speed_in_units = None):
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
# Test me.
|
||||||
|
# can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, 1, Buttons.RES_ACCEL))
|
||||||
|
# if self.CP.openpilotLongitudinalControl:
|
||||||
|
# CC.cruiseControl.resume = True
|
||||||
|
# self.CP.openpilotLongitudinalControl = False
|
||||||
|
# else:
|
||||||
|
# CC.cruiseControl.cancel = True
|
||||||
|
# self.CP.openpilotLongitudinalControl = True
|
||||||
|
|
||||||
|
if use_clu11:
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
# send resume at a max freq of 10Hz
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
||||||
|
# send 25 messages at a time to increases the likeli M,hood of resume being accepted
|
||||||
|
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
||||||
|
# if (self.frame - self.last_button_frame) * DT_CTRL > 3:
|
||||||
|
# if self.last_resume_frame = self.frame
|
||||||
|
|
||||||
|
if CS.oscar_lane_center_btn_pressed:
|
||||||
|
CS.oscar_lane_center_btn_pressed = False
|
||||||
|
# CC.cruiseControl.resume = True
|
||||||
|
CC.cruiseControl.cancel = True
|
||||||
|
# Test this...
|
||||||
|
# Also try create_acc_commands
|
||||||
|
# This attempts to set the speed to
|
||||||
|
# stopping = CC.actuators.longControlState == LongCtrlState.stopping
|
||||||
|
# can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, CC.actuators.accel, stopping, CC.cruiseControl.override,
|
||||||
|
# 40, CS.personality_profile))
|
||||||
|
|
||||||
|
# cruise cancel
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
# cruise standstill resume
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 4:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
# for _ in range(20):
|
||||||
|
nothing = 0
|
||||||
|
# Nothing for now --?
|
||||||
|
# oscar - test me
|
||||||
|
# can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
||||||
|
# can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
self.last_resume_frame = self.frame
|
||||||
|
|
||||||
|
elif set_speed_in_units is not None and not self.CP.openpilotLongitudinalControl and CS.cruiseState.enabled and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
|
||||||
|
# if False and not self.CP.openpilotLongitudinalControl and CC.enabled and CC.experimental_mode and CS.cruiseState.available and not CS.out.gasPressed and CS.cruise_buttons == Buttons.NONE:
|
||||||
|
# # cslcSetSpeed = get_set_speed(self, hud_v_cruise)
|
||||||
|
cslcSetSpeed = set_speed_in_units
|
||||||
|
self.cruise_button = get_cslc_button(self, cslcSetSpeed, CS)
|
||||||
|
if self.cruise_button != Buttons.NONE:
|
||||||
|
# if self.CP.carFingerprint in LEGACY_SAFETY_MODE_CAR:
|
||||||
|
# send_freq = 1
|
||||||
|
# # send resume at a max freq of 10Hz
|
||||||
|
# if (self.frame - self.last_button_frame) * DT_CTRL > 0.1 * send_freq:
|
||||||
|
# # send 25 messages at a time to increases the likelihood of cruise buttons being accepted
|
||||||
|
# can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
|
||||||
|
# if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15 * send_freq:
|
||||||
|
# self.last_button_frame = self.frame
|
||||||
|
if self.frame % 2 == 0:
|
||||||
|
for _ in range(20):
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, ((self.frame // 2) + 1) % 0x10, self.cruise_button))
|
||||||
|
else:
|
||||||
|
can_sends.extend([hyundaican.create_clu11(self.packer, (self.frame // 2) + 1, CS.clu11, self.cruise_button, self.CP.carFingerprint)] * 25)
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
|
||||||
|
# can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.SET_DECEL, self.CP.carFingerprint)] * 25)
|
||||||
|
|
||||||
|
return can_sends
|
||||||
|
|
||||||
|
def get_set_speed(self, hud_v_cruise):
|
||||||
|
v_cruise_kph = min(hud_v_cruise * CV.MS_TO_KPH, V_CRUISE_MAX)
|
||||||
|
v_cruise = int(round(v_cruise_kph * CV.KPH_TO_MPH))
|
||||||
|
|
||||||
|
v_cruise_slc: int = 0
|
||||||
|
# v_cruise_slc = params_memory.get_int("CSLCSpeed")
|
||||||
|
|
||||||
|
if v_cruise_slc > 0:
|
||||||
|
v_cruise = v_cruise_slc
|
||||||
|
return v_cruise
|
||||||
|
|
||||||
|
def get_cslc_button(self, cslcSetSpeed, CS, CC):
|
||||||
|
cruiseBtn = Buttons.NONE
|
||||||
|
speedSetPoint = int(round(CS.out.cruiseState.speed * CV.MS_TO_MPH))
|
||||||
|
|
||||||
|
if cslcSetSpeed < speedSetPoint and speedSetPoint > 25 and CC.enabled and CC.experimental_mode:
|
||||||
|
cruiseBtn = Buttons.SET_DECEL
|
||||||
|
elif cslcSetSpeed > speedSetPoint and speedSetPoint < 85 and CC.enabled:
|
||||||
|
cruiseBtn = Buttons.RES_ACCEL
|
||||||
|
else:
|
||||||
|
cruiseBtn = Buttons.SET_DECEL
|
||||||
|
# cruiseBtn = Buttons.NONE
|
||||||
|
return cruiseBtn
|
||||||
210
selfdrive/car/hyundai/carcontroller.org
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
from cereal import car
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.numpy_fast import clip
|
||||||
|
from openpilot.common.realtime import DT_CTRL
|
||||||
|
from opendbc.can.packer import CANPacker
|
||||||
|
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||||
|
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
|
||||||
|
|
||||||
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
||||||
|
# All slightly below EPS thresholds to avoid fault
|
||||||
|
MAX_ANGLE = 85
|
||||||
|
MAX_ANGLE_FRAMES = 89
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||||
|
|
||||||
|
|
||||||
|
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||||
|
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||||
|
|
||||||
|
# initialize to no line visible
|
||||||
|
# TODO: this is not accurate for all cars
|
||||||
|
sys_state = 1
|
||||||
|
if hud_control.leftLaneVisible and hud_control.rightLaneVisible or sys_warning: # HUD alert only display when LKAS status is active
|
||||||
|
sys_state = 3 if enabled or sys_warning else 4
|
||||||
|
elif hud_control.leftLaneVisible:
|
||||||
|
sys_state = 5
|
||||||
|
elif hud_control.rightLaneVisible:
|
||||||
|
sys_state = 6
|
||||||
|
|
||||||
|
# initialize to no warnings
|
||||||
|
left_lane_warning = 0
|
||||||
|
right_lane_warning = 0
|
||||||
|
if hud_control.leftLaneDepart:
|
||||||
|
left_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
if hud_control.rightLaneDepart:
|
||||||
|
right_lane_warning = 1 if fingerprint in (CAR.GENESIS_G90, CAR.GENESIS_G80) else 2
|
||||||
|
|
||||||
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
|
class CarController:
|
||||||
|
def __init__(self, dbc_name, CP, VM):
|
||||||
|
self.CP = CP
|
||||||
|
self.CAN = CanBus(CP)
|
||||||
|
self.params = CarControllerParams(CP)
|
||||||
|
self.packer = CANPacker(dbc_name)
|
||||||
|
self.angle_limit_counter = 0
|
||||||
|
self.frame = 0
|
||||||
|
|
||||||
|
self.accel_last = 0
|
||||||
|
self.apply_steer_last = 0
|
||||||
|
self.car_fingerprint = CP.carFingerprint
|
||||||
|
self.last_button_frame = 0
|
||||||
|
|
||||||
|
def update(self, CC, CS, now_nanos, sport_plus):
|
||||||
|
actuators = CC.actuators
|
||||||
|
hud_control = CC.hudControl
|
||||||
|
|
||||||
|
# steering torque
|
||||||
|
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
||||||
|
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
||||||
|
|
||||||
|
# >90 degree steering fault prevention
|
||||||
|
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
||||||
|
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
||||||
|
|
||||||
|
if not CC.latActive:
|
||||||
|
apply_steer = 0
|
||||||
|
|
||||||
|
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||||
|
torque_fault = CC.latActive and not apply_steer_req
|
||||||
|
|
||||||
|
self.apply_steer_last = apply_steer
|
||||||
|
|
||||||
|
# accel + longitudinal
|
||||||
|
if sport_plus:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
|
||||||
|
else:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
||||||
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||||
|
|
||||||
|
# HUD messages
|
||||||
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||||
|
hud_control)
|
||||||
|
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
# *** common hyundai stuff ***
|
||||||
|
|
||||||
|
# tester present - w/ no response (keeps relevant ECU disabled)
|
||||||
|
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
|
||||||
|
# for longitudinal control, either radar or ADAS driving ECU
|
||||||
|
addr, bus = 0x7d0, 0
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
||||||
|
addr, bus = 0x730, self.CAN.ECAN
|
||||||
|
can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
|
||||||
|
|
||||||
|
# for blinkers
|
||||||
|
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
|
||||||
|
|
||||||
|
# CAN-FD platforms
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||||
|
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
|
||||||
|
|
||||||
|
# steering control
|
||||||
|
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
|
||||||
|
|
||||||
|
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
|
||||||
|
if self.frame % 5 == 0 and hda2:
|
||||||
|
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
|
||||||
|
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
|
||||||
|
|
||||||
|
# LFA and HDA icons
|
||||||
|
if self.frame % 5 == 0 and (not hda2 or hda2_long):
|
||||||
|
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
|
||||||
|
|
||||||
|
# blinkers
|
||||||
|
if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
||||||
|
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
if hda2:
|
||||||
|
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||||
|
if self.frame % 2 == 0:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||||
|
set_speed_in_units, CS.personality_profile))
|
||||||
|
self.accel_last = accel
|
||||||
|
else:
|
||||||
|
# button presses
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
|
||||||
|
else:
|
||||||
|
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
|
||||||
|
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||||
|
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||||
|
left_lane_warning, right_lane_warning))
|
||||||
|
|
||||||
|
if not self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
|
||||||
|
|
||||||
|
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
# TODO: unclear if this is needed
|
||||||
|
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
||||||
|
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
||||||
|
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
||||||
|
hud_control.leadVisible, set_speed_in_units, stopping,
|
||||||
|
CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
|
||||||
|
|
||||||
|
# 20 Hz LFA MFA message
|
||||||
|
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||||
|
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
|
||||||
|
|
||||||
|
# 5 Hz ACC options
|
||||||
|
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.extend(hyundaican.create_acc_opt(self.packer))
|
||||||
|
|
||||||
|
# 2 Hz front radar options
|
||||||
|
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
|
||||||
|
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
||||||
|
|
||||||
|
new_actuators = actuators.copy()
|
||||||
|
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
||||||
|
new_actuators.steerOutputCan = apply_steer
|
||||||
|
new_actuators.accel = accel
|
||||||
|
|
||||||
|
self.frame += 1
|
||||||
|
return new_actuators, can_sends
|
||||||
|
|
||||||
|
def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool):
|
||||||
|
can_sends = []
|
||||||
|
if use_clu11:
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
# send resume at a max freq of 10Hz
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
||||||
|
# send 25 messages at a time to increases the likelihood of resume being accepted
|
||||||
|
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
||||||
|
# cruise cancel
|
||||||
|
if CC.cruiseControl.cancel:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
# cruise standstill resume
|
||||||
|
elif CC.cruiseControl.resume:
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
||||||
|
# TODO: resume for alt button cars
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
for _ in range(20):
|
||||||
|
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
||||||
|
self.last_button_frame = self.frame
|
||||||
|
|
||||||
|
return can_sends
|
||||||
@@ -6,18 +6,177 @@ from opendbc.can.packer import CANPacker
|
|||||||
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
|
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance
|
||||||
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
|
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
|
||||||
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR, LEGACY_SAFETY_MODE_CAR
|
||||||
|
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
|
# DEVELOPOMENT TODO
|
||||||
|
|
||||||
|
# - Write a loop that runs and does nothing.
|
||||||
|
# - Load as many inputs in possible into state variables.
|
||||||
|
# - Make a state variable tester. It should be a web server running async.
|
||||||
|
# - Make a button tester, also on web server, to test engaging each button.
|
||||||
|
# - Write basic interface refactor
|
||||||
|
# - Write experimental mode speed controller
|
||||||
|
# - Write resume from stop controller
|
||||||
|
# - Implement as many extra features as possible (auto hvac, auto sunroof, suggest a break, remind headlights)
|
||||||
|
|
||||||
|
|
||||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||||
|
|
||||||
|
params_memory = Params("/dev/shm/params")
|
||||||
|
|
||||||
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
|
||||||
# All slightly below EPS thresholds to avoid fault
|
# All slightly below EPS thresholds to avoid fault
|
||||||
MAX_ANGLE = 85
|
MAX_ANGLE = 85
|
||||||
MAX_ANGLE_FRAMES = 89
|
MAX_ANGLE_FRAMES = 89
|
||||||
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||||
|
|
||||||
|
# Constants for state arrays.
|
||||||
|
ENGAGED = 'engaged'
|
||||||
|
STANDBY = 'standby'
|
||||||
|
OFF = 'off'
|
||||||
|
|
||||||
|
# Input
|
||||||
|
# Current state of openpilot and its desired commands
|
||||||
|
openpilot_state = {
|
||||||
|
'openpilot_ready': False, # Openpilot is enabled in settings
|
||||||
|
'lateral_active': False, # Lateral control is engaged either full or always on lateral
|
||||||
|
'openpilot_engaged': False, # Openpilot is full engaged (lateral + cruise control)
|
||||||
|
'always_on_lateral_active': False, # Cruise control disengaged but lateral still engaged
|
||||||
|
'experimental_active': False, # Frogpilot has engaged experimental control, so we need to adjust speed and possibly apply brakes (if this is possible)
|
||||||
|
'experimental_desired_speed': 0, # The speed experimental control wants to set long to
|
||||||
|
'curviture_angle': 0, # Detected current curviture (ideally within the next 3 or 4 seconds) for taking over LKAS and possibly LONG
|
||||||
|
'lane_change_enabled': False, # The lane change assist feature is active
|
||||||
|
'lane_change_active': False, # Executing a lane change assist
|
||||||
|
'connected_to_internet': False,
|
||||||
|
'rate_limited_internet': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input
|
||||||
|
# Esoteric things related to the car that support other features than driving. Will be shown in debugger.
|
||||||
|
car_state = {
|
||||||
|
'location_lat': 0,
|
||||||
|
'location_long': 0,
|
||||||
|
'drive_distance_this_trip': 0,
|
||||||
|
'drive_distance_today': 0,
|
||||||
|
'compass_direction': 'N', # Unclear if I will use this
|
||||||
|
'fuel': 1, # 0-1 fuel tank level
|
||||||
|
'windows_down': False, # True if any windows / sunroof is open
|
||||||
|
'climate_control': False,
|
||||||
|
'climate_control_set_temp': 72,
|
||||||
|
'cabin_temprature': 50,
|
||||||
|
'heated_seat_driver_on': False,
|
||||||
|
'heated_seat_passenger_on': False,
|
||||||
|
'heated_steering_wheel_on': False,
|
||||||
|
'fan_seat_driver_on': False,
|
||||||
|
'fan_seat_passenger_on': False,
|
||||||
|
'info_panel_item_showing': 0, # If we can capture what instrument panel info is showing, we can change it to speed
|
||||||
|
'daytime': False,
|
||||||
|
'headlights': False, # Would be cool to remind to have the headlights turned on if moving
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input
|
||||||
|
# The current status of cruise control activation
|
||||||
|
cruise_control_state = {
|
||||||
|
'set_speed': 0, # Cruise control set speed
|
||||||
|
'actual_speed': 0, # Spedometer reading
|
||||||
|
'speed_limit': 0, # Speed limit as reported by car's dashboard
|
||||||
|
'cruise_control_status': OFF, # or ENGAGED or STANDBY
|
||||||
|
'brake_pressed': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input
|
||||||
|
# The current state of the car in front of us, if cruise control is engaged but the car is not moving
|
||||||
|
stationary_state = {
|
||||||
|
'stationary': False, # When speed reaches 0 we are stationary
|
||||||
|
'stationary_since': 0, # At what time stationary was achieved
|
||||||
|
'stationary_has_lead': False, # At the time of becoming stationary, was there a lead veichele?
|
||||||
|
'stationary_has_lead_distance': 0, # At the time of becoming stationary, what was the distance to the lead veichele?
|
||||||
|
'current_lead_car_distance': 0, # What is the distance to the lead veichele now?
|
||||||
|
'lead_vehicle_moving_away': False, # Has logic decided that the current veichele is moving away?
|
||||||
|
'oem_lanes_detected': False # Is the car reporting it can see lanes? I would like to experiment with engaging stock LKAS.
|
||||||
|
}
|
||||||
|
|
||||||
|
# Input
|
||||||
|
# What buttons the user is pressing. Can be None, BUTTON_SHORT, or BUTTON_LONG (held for 1/2 second)
|
||||||
|
cruise_control_buttons_input = {
|
||||||
|
'engage_cruise_control': None,
|
||||||
|
'cruise_control_speed_up': None,
|
||||||
|
'cruise_control_speed_down': None,
|
||||||
|
'pause_resume_cruise_control': None,
|
||||||
|
'lane_keep_assist_button': None,
|
||||||
|
'lane_follow_assist_button': None
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output
|
||||||
|
# What buttons we wish to simulate pressing.
|
||||||
|
cruise_control_buttons_output = {
|
||||||
|
'engage_cruise_control': False,
|
||||||
|
'cruise_control_speed_up': False,
|
||||||
|
'cruise_control_speed_down': False,
|
||||||
|
'pause_resume_cruise_control': False,
|
||||||
|
'lane_keep_assist_button': False,
|
||||||
|
'lane_follow_assist_button': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output
|
||||||
|
# What buttons we wish to simulate pressing.
|
||||||
|
# I don't know if I will have access to these.
|
||||||
|
other_buttons_output = {
|
||||||
|
'info_category': False,
|
||||||
|
'info_section': False,
|
||||||
|
'heated_seat_driver': False,
|
||||||
|
'heated_seat_passenger': False,
|
||||||
|
'heated_steering_wheel': False,
|
||||||
|
'fan_seat_driver': False,
|
||||||
|
'fan_seat_passenger': False,
|
||||||
|
'sunroof': False,
|
||||||
|
'hvac_power': False,
|
||||||
|
'hvac_sync': False,
|
||||||
|
'hvac_up': False,
|
||||||
|
'hvac_down': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# What to display on the instrument panel. Sent every frame.
|
||||||
|
instrument_panel_outputs = {
|
||||||
|
'lane_keeping_assist_active': False,
|
||||||
|
'forward_collision_warning_active': False,
|
||||||
|
'high_beam_assist_active': False,
|
||||||
|
'forward_collision_avoidance_assist_active': False,
|
||||||
|
'blind_spot_collision_warning_active': False,
|
||||||
|
'lane_following_assist_active': False,
|
||||||
|
'driver_attention_warning_active': False,
|
||||||
|
'lane_departure_warning_active': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# State
|
||||||
|
# Variables to save what oscarpilot is doing - behaviors will change depending
|
||||||
|
# on current state
|
||||||
|
oscarpilot_state = [
|
||||||
|
'set_speed': 0, # Current desired cruise speed
|
||||||
|
'speed_override': False, # Set if moving away from set speed due to experimental
|
||||||
|
'speed_restore': False, # Set if moving twoards set speed due to reengagement or change speed to speed limit
|
||||||
|
'lkas_oem': False, # Set if allowing the car oem software to control LKAS
|
||||||
|
'daytime': False, # Set if it is daytime. Car is more judgmental at night.
|
||||||
|
]
|
||||||
|
|
||||||
|
# Output
|
||||||
|
# These are messages to the user, and get set to false when processed by openpilot
|
||||||
|
# Ideally we can set these in the infotainment area as well, like carplay audio selection
|
||||||
|
oscarpilot_alerts = {
|
||||||
|
'detected_stop_sign_or_light': False, # Openpilot has seen a stoplight or stopsign
|
||||||
|
'very_sharp_curve': False, # The upcoming curve is probably too sharp to be handled automatically
|
||||||
|
'lane_confidence_low': False, # The confidence level that openpilot knows what its doing is low
|
||||||
|
'heavy_traffic_ahead': False, # Mapping data indicates heavy traffic within 2 miles
|
||||||
|
'weather_ahead': False, # Mapping data indicates precipitation within 5 miles
|
||||||
|
'suggest_a_break': False, # Variable will be used to suggest a break (3 hours at day, 1.5 hours at night)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Where is this called? Public? Private? Should we refactor?
|
||||||
def process_hud_alert(enabled, fingerprint, hud_control):
|
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||||
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||||
|
|
||||||
@@ -41,7 +200,6 @@ def process_hud_alert(enabled, fingerprint, hud_control):
|
|||||||
|
|
||||||
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
return sys_warning, sys_state, left_lane_warning, right_lane_warning
|
||||||
|
|
||||||
|
|
||||||
class CarController:
|
class CarController:
|
||||||
def __init__(self, dbc_name, CP, VM):
|
def __init__(self, dbc_name, CP, VM):
|
||||||
self.CP = CP
|
self.CP = CP
|
||||||
@@ -55,115 +213,36 @@ class CarController:
|
|||||||
self.apply_steer_last = 0
|
self.apply_steer_last = 0
|
||||||
self.car_fingerprint = CP.carFingerprint
|
self.car_fingerprint = CP.carFingerprint
|
||||||
self.last_button_frame = 0
|
self.last_button_frame = 0
|
||||||
|
self.last_resume_frame = 0
|
||||||
|
self.last_debug_frame = 0
|
||||||
|
|
||||||
|
self._CC = None
|
||||||
|
# self._CC.actuators
|
||||||
|
# self._CC.hudControl
|
||||||
|
self._CS = None
|
||||||
|
self._now_nanos = None
|
||||||
|
self._sport_plus = None
|
||||||
|
self._actuators = None
|
||||||
|
self._hud_control = None
|
||||||
|
|
||||||
def update(self, CC, CS, now_nanos, sport_plus):
|
def update(self, CC, CS, now_nanos, sport_plus):
|
||||||
actuators = CC.actuators
|
self._CC = CC
|
||||||
hud_control = CC.hudControl
|
self._CS = CS
|
||||||
|
self._now_nanos = now_nanos
|
||||||
|
self._sport_plus = sport_plus
|
||||||
|
|
||||||
# steering torque
|
self._apply_steer = None
|
||||||
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
self._accel = None
|
||||||
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.params)
|
|
||||||
|
|
||||||
# >90 degree steering fault prevention
|
|
||||||
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
|
|
||||||
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
|
||||||
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
|
||||||
|
|
||||||
if not CC.latActive:
|
|
||||||
apply_steer = 0
|
|
||||||
|
|
||||||
# Hold torque with induced temporary fault when cutting the actuation bit
|
|
||||||
torque_fault = CC.latActive and not apply_steer_req
|
|
||||||
|
|
||||||
self.apply_steer_last = apply_steer
|
|
||||||
|
|
||||||
# accel + longitudinal
|
|
||||||
if sport_plus:
|
|
||||||
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
|
|
||||||
else:
|
|
||||||
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
|
||||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
|
||||||
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
|
||||||
|
|
||||||
# HUD messages
|
|
||||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
|
||||||
hud_control)
|
|
||||||
|
|
||||||
can_sends = []
|
can_sends = []
|
||||||
|
|
||||||
# *** common hyundai stuff ***
|
# CAN-FD car logic
|
||||||
|
|
||||||
# tester present - w/ no response (keeps relevant ECU disabled)
|
|
||||||
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and self.CP.openpilotLongitudinalControl:
|
|
||||||
# for longitudinal control, either radar or ADAS driving ECU
|
|
||||||
addr, bus = 0x7d0, 0
|
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
|
|
||||||
addr, bus = 0x730, self.CAN.ECAN
|
|
||||||
can_sends.append([addr, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", bus])
|
|
||||||
|
|
||||||
# for blinkers
|
|
||||||
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
|
||||||
can_sends.append([0x7b1, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", self.CAN.ECAN])
|
|
||||||
|
|
||||||
# CAN-FD platforms
|
|
||||||
if self.CP.carFingerprint in CANFD_CAR:
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
# Steering control for CAN FD
|
||||||
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
|
# can_sends.extend(self._create_common_messages())
|
||||||
|
can_sends.extend(self._create_steering_messages())
|
||||||
# steering control
|
can_sends.extend(self._create_instrument_messages())
|
||||||
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
|
can_sends.extend(self._create_button_messages())
|
||||||
|
|
||||||
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
|
|
||||||
if self.frame % 5 == 0 and hda2:
|
|
||||||
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
|
|
||||||
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
|
|
||||||
|
|
||||||
# LFA and HDA icons
|
|
||||||
if self.frame % 5 == 0 and (not hda2 or hda2_long):
|
|
||||||
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
|
|
||||||
|
|
||||||
# blinkers
|
|
||||||
if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
|
||||||
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
|
||||||
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
|
||||||
if hda2:
|
|
||||||
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
|
||||||
if self.frame % 2 == 0:
|
|
||||||
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
|
||||||
set_speed_in_units, CS.personality_profile))
|
|
||||||
self.accel_last = accel
|
|
||||||
else:
|
|
||||||
# button presses
|
|
||||||
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
|
|
||||||
else:
|
|
||||||
can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.car_fingerprint, apply_steer, apply_steer_req,
|
|
||||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
|
||||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
|
||||||
left_lane_warning, right_lane_warning))
|
|
||||||
|
|
||||||
if not self.CP.openpilotLongitudinalControl:
|
|
||||||
can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
|
|
||||||
|
|
||||||
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
|
|
||||||
# TODO: unclear if this is needed
|
|
||||||
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
|
|
||||||
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
|
|
||||||
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
|
|
||||||
hud_control.leadVisible, set_speed_in_units, stopping,
|
|
||||||
CC.cruiseControl.override, use_fca, CS.out.cruiseState.available, CS.personality_profile))
|
|
||||||
|
|
||||||
# 20 Hz LFA MFA message
|
|
||||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
|
||||||
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
|
|
||||||
|
|
||||||
# 5 Hz ACC options
|
|
||||||
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
|
|
||||||
can_sends.extend(hyundaican.create_acc_opt(self.packer))
|
|
||||||
|
|
||||||
# 2 Hz front radar options
|
|
||||||
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
|
|
||||||
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
|
|
||||||
|
|
||||||
new_actuators = actuators.copy()
|
new_actuators = actuators.copy()
|
||||||
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
new_actuators.steer = apply_steer / self.params.STEER_MAX
|
||||||
@@ -173,38 +252,126 @@ class CarController:
|
|||||||
self.frame += 1
|
self.frame += 1
|
||||||
return new_actuators, can_sends
|
return new_actuators, can_sends
|
||||||
|
|
||||||
def create_button_messages(self, CC: car.CarControl, CS: car.CarState, use_clu11: bool):
|
# def _create_common_messages():
|
||||||
can_sends = []
|
# *** common hyundai stuff ***
|
||||||
if use_clu11:
|
|
||||||
if CC.cruiseControl.cancel:
|
|
||||||
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP.carFingerprint))
|
|
||||||
elif CC.cruiseControl.resume:
|
|
||||||
# send resume at a max freq of 10Hz
|
|
||||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
|
|
||||||
# send 25 messages at a time to increases the likelihood of resume being accepted
|
|
||||||
can_sends.extend([hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.RES_ACCEL, self.CP.carFingerprint)] * 25)
|
|
||||||
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
|
|
||||||
self.last_button_frame = self.frame
|
|
||||||
else:
|
|
||||||
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
|
|
||||||
# cruise cancel
|
|
||||||
if CC.cruiseControl.cancel:
|
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
|
||||||
can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
|
|
||||||
self.last_button_frame = self.frame
|
|
||||||
else:
|
|
||||||
for _ in range(20):
|
|
||||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
|
|
||||||
self.last_button_frame = self.frame
|
|
||||||
|
|
||||||
# cruise standstill resume
|
def _unprocessed():
|
||||||
elif CC.cruiseControl.resume:
|
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
|
# HUD messages
|
||||||
# TODO: resume for alt button cars
|
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||||
pass
|
hud_control)
|
||||||
else:
|
|
||||||
for _ in range(20):
|
can_sends = []
|
||||||
can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
|
|
||||||
self.last_button_frame = self.frame
|
|
||||||
|
# CAN-FD platforms
|
||||||
|
# if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
|
||||||
|
# # LFA and HDA icons
|
||||||
|
# if self.frame % 5 == 0 and (not hda2 or hda2_long):
|
||||||
|
# can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled))
|
||||||
|
|
||||||
|
|
||||||
|
# if self.CP.openpilotLongitudinalControl:
|
||||||
|
# if hda2:
|
||||||
|
# can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
|
||||||
|
# if self.frame % 2 == 0:
|
||||||
|
# can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
|
||||||
|
# set_speed_in_units, CS.personality_profile))
|
||||||
|
# self.accel_last = accel
|
||||||
|
# else:
|
||||||
|
# # button presses
|
||||||
|
# can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
|
||||||
|
|
||||||
|
# Mostly unchanged from frogpilot.
|
||||||
|
def _create_steering_messages():
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
# steering torque
|
||||||
|
new_steer = int(round(actuators.steer * self.params.STEER_MAX))
|
||||||
|
apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, self._CS.out.steeringTorque, self.params)
|
||||||
|
|
||||||
|
# >90 degree steering fault prevention
|
||||||
|
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(self._CS.out.steeringAngleDeg) >= MAX_ANGLE, self._CC.latActive,
|
||||||
|
self.angle_limit_counter, MAX_ANGLE_FRAMES,
|
||||||
|
MAX_ANGLE_CONSECUTIVE_FRAMES)
|
||||||
|
if not CC.latActive:
|
||||||
|
apply_steer = 0
|
||||||
|
|
||||||
|
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||||
|
torque_fault = self._CC.latActive and not apply_steer_req
|
||||||
|
|
||||||
|
self.apply_steer_last = apply_steer
|
||||||
|
|
||||||
|
# accel + longitudinal
|
||||||
|
if sport_plus:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX_PLUS)
|
||||||
|
else:
|
||||||
|
accel = clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX)
|
||||||
|
|
||||||
|
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||||
|
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
|
||||||
|
|
||||||
|
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
|
||||||
|
|
||||||
|
# steering control
|
||||||
|
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_steer))
|
||||||
|
|
||||||
|
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
|
||||||
|
if self.frame % 5 == 0 and hda2:
|
||||||
|
can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.hda2_lfa_block_msg,
|
||||||
|
self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING))
|
||||||
|
# blinkers
|
||||||
|
# if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
|
||||||
|
# can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
|
||||||
|
self._apply_steer = apply_steer
|
||||||
|
self._accel = accel
|
||||||
|
|
||||||
|
return can_sends
|
||||||
|
|
||||||
|
# Placeholder for potential instrument panel processing
|
||||||
|
def _create_instrument_messages(instrument_panel_state):
|
||||||
|
can_sends = []
|
||||||
|
# Assume default values or read the initial state
|
||||||
|
lfa_icon_state = 0
|
||||||
|
hda_active = 0
|
||||||
|
hda_icon_state = 0
|
||||||
|
hda_set_speed = 0 # This would likely need to be more dynamic based on context
|
||||||
|
|
||||||
|
# Assign values based on instrument_panel_outputs states
|
||||||
|
for output in instrument_panel_outputs:
|
||||||
|
if output['name'] == 'lane_keeping_assist_active':
|
||||||
|
lfa_icon_state = 2 if output['value'] else 0
|
||||||
|
elif output['name'] == 'hda_active': # Hypothetical key for example
|
||||||
|
hda_active = 1 if output['value'] else 0
|
||||||
|
elif output['name'] == 'hda_icon_state': # Also hypothetical
|
||||||
|
hda_icon_state = 2 if output['value'] else 0
|
||||||
|
# Add other conditions based on the actual data structure you expect
|
||||||
|
|
||||||
|
# Assume we can bundle all these states into one message as in your example
|
||||||
|
values = {
|
||||||
|
"LFA_Icon_State": lfa_icon_state,
|
||||||
|
"HDA_Active": hda_active,
|
||||||
|
"HDA_Icon_State": hda_icon_state,
|
||||||
|
"HDA_VSetReq": hda_set_speed, # This example assumes static speed; adjust if dynamic
|
||||||
|
}
|
||||||
|
|
||||||
|
can_sends.append(packer.make_can_msg("LFAHDA_MFC", 0, values))
|
||||||
|
|
||||||
|
return can_sends
|
||||||
|
|
||||||
|
# Placeholder for potential button press processing
|
||||||
|
def _create_button_messages(button_presses):
|
||||||
|
can_sends = []
|
||||||
|
|
||||||
|
for button in cruise_control_buttons:
|
||||||
|
if button['value']:
|
||||||
|
# Resetting button state to prevent repeated presses
|
||||||
|
button['value'] = False
|
||||||
|
|
||||||
|
if button['name'] in button_map:
|
||||||
|
# Mapping each button to a specific CAN message
|
||||||
|
btn_value = button_map[button['name']]
|
||||||
|
can_sends.append(create_buttons(packer, CP, CAN, 0, btn_value)) # Counter is example, replace with actual logic if necessary
|
||||||
|
|
||||||
return can_sends
|
return can_sends
|
||||||
500
selfdrive/car/hyundai/carstate.org
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
from collections import deque
|
||||||
|
import copy
|
||||||
|
import math
|
||||||
|
|
||||||
|
from cereal import car
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from opendbc.can.parser import CANParser
|
||||||
|
from opendbc.can.can_define import CANDefine
|
||||||
|
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
|
||||||
|
CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
|
||||||
|
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
|
PREV_BUTTON_SAMPLES = 8
|
||||||
|
CLUSTER_SAMPLE_RATE = 20 # frames
|
||||||
|
STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
|
||||||
|
|
||||||
|
|
||||||
|
class CarState(CarStateBase):
|
||||||
|
def __init__(self, CP):
|
||||||
|
super().__init__(CP)
|
||||||
|
can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
|
||||||
|
|
||||||
|
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
|
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
|
|
||||||
|
self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
|
||||||
|
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
|
||||||
|
"GEAR_SHIFTER"
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
|
||||||
|
else: # preferred and elect gear methods use same definition
|
||||||
|
self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
|
||||||
|
|
||||||
|
self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
|
||||||
|
"ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
|
||||||
|
"ACCELERATOR_BRAKE_ALT"
|
||||||
|
self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
|
||||||
|
"CRUISE_BUTTONS"
|
||||||
|
self.is_metric = False
|
||||||
|
self.buttons_counter = 0
|
||||||
|
|
||||||
|
self.cruise_info = {}
|
||||||
|
|
||||||
|
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
|
||||||
|
self.cluster_speed = 0
|
||||||
|
self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
|
||||||
|
|
||||||
|
self.params = CarControllerParams(CP)
|
||||||
|
|
||||||
|
def update(self, cp, cp_cam):
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp_cam", cp_cam)
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
|
return self.update_canfd(cp, cp_cam)
|
||||||
|
|
||||||
|
ret = car.CarState.new_message()
|
||||||
|
cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
|
||||||
|
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
|
||||||
|
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||||
|
|
||||||
|
ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
|
||||||
|
cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
|
||||||
|
|
||||||
|
ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
|
||||||
|
|
||||||
|
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
|
||||||
|
cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
|
||||||
|
)
|
||||||
|
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||||
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||||
|
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||||
|
|
||||||
|
self.cluster_speed_counter += 1
|
||||||
|
if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
|
||||||
|
self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
|
||||||
|
self.cluster_speed_counter = 0
|
||||||
|
|
||||||
|
# Mimic how dash converts to imperial.
|
||||||
|
# Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
|
||||||
|
# TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
|
||||||
|
if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
|
||||||
|
self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
|
||||||
|
|
||||||
|
ret.vEgoCluster = self.cluster_speed * speed_conv
|
||||||
|
|
||||||
|
ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
|
||||||
|
ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
|
||||||
|
ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
|
||||||
|
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
|
||||||
|
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
|
||||||
|
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
|
||||||
|
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
|
||||||
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||||
|
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
||||||
|
|
||||||
|
# cruise state
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||||
|
ret.cruiseState.available = self.main_enabled
|
||||||
|
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
||||||
|
ret.cruiseState.standstill = False
|
||||||
|
ret.cruiseState.nonAdaptive = False
|
||||||
|
else:
|
||||||
|
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
|
||||||
|
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
|
||||||
|
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
|
||||||
|
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
||||||
|
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
|
||||||
|
|
||||||
|
# TODO: Find brake pressure
|
||||||
|
ret.brake = 0
|
||||||
|
ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
|
||||||
|
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
|
||||||
|
ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
|
||||||
|
ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
if self.CP.carFingerprint in HYBRID_CAR:
|
||||||
|
ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
|
||||||
|
else:
|
||||||
|
ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
|
||||||
|
ret.gasPressed = ret.gas > 0
|
||||||
|
else:
|
||||||
|
ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
|
||||||
|
ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
|
||||||
|
|
||||||
|
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
|
||||||
|
# as this seems to be standard over all cars, but is not the preferred method.
|
||||||
|
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
gear = cp.vl["CLU15"]["CF_Clu_Gear"]
|
||||||
|
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
gear = cp.vl["TCU12"]["CUR_GR"]
|
||||||
|
else:
|
||||||
|
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
|
||||||
|
|
||||||
|
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||||
|
|
||||||
|
if not self.CP.openpilotLongitudinalControl:
|
||||||
|
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
|
||||||
|
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
|
||||||
|
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
|
||||||
|
scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
|
||||||
|
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
|
||||||
|
ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
|
||||||
|
ret.stockAeb = aeb_warning and aeb_braking
|
||||||
|
|
||||||
|
if self.CP.enableBsm:
|
||||||
|
ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
|
||||||
|
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
||||||
|
|
||||||
|
# save the entire LKAS11 and CLU11
|
||||||
|
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
||||||
|
self.clu11 = copy.copy(cp.vl["CLU11"])
|
||||||
|
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
||||||
|
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
||||||
|
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
||||||
|
self.prev_main_buttons = self.main_buttons[-1]
|
||||||
|
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
||||||
|
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
||||||
|
self.main_enabled = not self.main_enabled
|
||||||
|
|
||||||
|
# BBot functions for lfa and gap buttons - test speed up / down
|
||||||
|
self.oscar_lane_center_btn_pressed= False
|
||||||
|
self.oscar_slc_decel = False
|
||||||
|
self.oscar_slc_accel = False
|
||||||
|
|
||||||
|
self.param_memory.put("oscar_debug", "Hello World")
|
||||||
|
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.oscar_lane_center_btn_pressed= True
|
||||||
|
|
||||||
|
# lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# self.custom_speed_up = True
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
# Driving personalities function
|
||||||
|
# if self.personalities_via_wheel and ret.cruiseState.available:
|
||||||
|
# # Sync with the onroad UI button
|
||||||
|
# if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
||||||
|
# self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
||||||
|
|
||||||
|
# # Change personality upon steering wheel button press
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
||||||
|
# self.personality_profile = (self.previous_personality_profile + 2) % 3
|
||||||
|
|
||||||
|
# if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
||||||
|
# self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
||||||
|
# self.previous_personality_profile = self.personality_profile
|
||||||
|
|
||||||
|
# # Toggle Experimental Mode from steering wheel function
|
||||||
|
# if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
||||||
|
# lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# if self.conditional_experimental_mode:
|
||||||
|
# # Set "CEStatus" to work with "Conditional Experimental Mode"
|
||||||
|
# conditional_status = self.param_memory.get_int("CEStatus")
|
||||||
|
# override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
||||||
|
# self.param_memory.put_int("CEStatus", override_value)
|
||||||
|
# else:
|
||||||
|
# experimental_mode = self.param.get_bool("ExperimentalMode")
|
||||||
|
# # Invert the value of "ExperimentalMode"
|
||||||
|
# put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_self", self)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def update_canfd(self, cp, cp_cam):
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
|
||||||
|
|
||||||
|
ret = car.CarState.new_message()
|
||||||
|
|
||||||
|
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
|
||||||
|
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
||||||
|
|
||||||
|
if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
|
||||||
|
offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
|
||||||
|
ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
|
||||||
|
ret.gasPressed = ret.gas > 1e-5
|
||||||
|
else:
|
||||||
|
ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
|
||||||
|
|
||||||
|
ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
|
||||||
|
|
||||||
|
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
|
||||||
|
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
|
||||||
|
|
||||||
|
gear = cp.vl[self.gear_msg_canfd]["GEAR"]
|
||||||
|
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
||||||
|
|
||||||
|
# TODO: figure out positions
|
||||||
|
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
|
||||||
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
|
||||||
|
)
|
||||||
|
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
||||||
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
||||||
|
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
||||||
|
|
||||||
|
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
|
||||||
|
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
|
||||||
|
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
|
||||||
|
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
|
||||||
|
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
||||||
|
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
|
||||||
|
|
||||||
|
# TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
|
||||||
|
left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
|
||||||
|
if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
|
||||||
|
left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
|
||||||
|
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
|
||||||
|
cp.vl["BLINKERS"][right_blinker_sig])
|
||||||
|
if self.CP.enableBsm:
|
||||||
|
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
|
||||||
|
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
|
||||||
|
|
||||||
|
# cruise state
|
||||||
|
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
|
||||||
|
ret.cruiseState.available = self.main_enabled
|
||||||
|
if self.CP.openpilotLongitudinalControl:
|
||||||
|
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
||||||
|
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
|
||||||
|
ret.cruiseState.standstill = False
|
||||||
|
else:
|
||||||
|
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
||||||
|
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
||||||
|
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
||||||
|
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
||||||
|
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
|
||||||
|
|
||||||
|
# Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
|
||||||
|
# It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
|
||||||
|
# The car will brake, but does not respect positive acceleration commands in this mode
|
||||||
|
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
|
||||||
|
if self.CP.carFingerprint in EV_CAR:
|
||||||
|
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
|
||||||
|
|
||||||
|
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
||||||
|
self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
||||||
|
self.prev_main_buttons = self.main_buttons[-1]
|
||||||
|
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
||||||
|
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
||||||
|
self.main_enabled = not self.main_enabled
|
||||||
|
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
||||||
|
ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
||||||
|
|
||||||
|
if self.CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
|
||||||
|
else cp_cam.vl["CAM_0x2a4"])
|
||||||
|
|
||||||
|
SpeedLimitController.load_state()
|
||||||
|
SpeedLimitController.car_speed_limit = self.calculate_speed_limit_canfd(self.CP, cp, cp_cam) * speed_factor
|
||||||
|
SpeedLimitController.write_car_state()
|
||||||
|
|
||||||
|
# self.custom_speed_up = False
|
||||||
|
self.oscar_lane_center_btn_pressed = False
|
||||||
|
|
||||||
|
if ret.cruiseState.available:
|
||||||
|
|
||||||
|
if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
self.oscar_lane_center_btn_pressed = True
|
||||||
|
|
||||||
|
lkas_pressed = False
|
||||||
|
try:
|
||||||
|
lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
|
||||||
|
except:
|
||||||
|
nothing = 0
|
||||||
|
|
||||||
|
# intentionally cause a failure
|
||||||
|
if lkas_pressed:
|
||||||
|
floog=norpdywoop
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.oscar_lane_center_btn_pressed= True
|
||||||
|
|
||||||
|
# Driving personalities function
|
||||||
|
# if self.personalities_via_wheel and ret.cruiseState.available:
|
||||||
|
# # Sync with the onroad UI button
|
||||||
|
# if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
||||||
|
# self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
||||||
|
|
||||||
|
# # Change personality upon steering wheel button press
|
||||||
|
# if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
||||||
|
# self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
||||||
|
# self.personality_profile = (self.previous_personality_profile + 2) % 3
|
||||||
|
|
||||||
|
# if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
||||||
|
# self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
||||||
|
# self.previous_personality_profile = self.personality_profile
|
||||||
|
|
||||||
|
# # Toggle Experimental Mode from steering wheel function
|
||||||
|
# if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
||||||
|
# lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
|
||||||
|
# if lkas_pressed and not self.lkas_previously_pressed:
|
||||||
|
# if self.conditional_experimental_mode:
|
||||||
|
# # Set "CEStatus" to work with "Conditional Experimental Mode"
|
||||||
|
# conditional_status = self.param_memory.get_int("CEStatus")
|
||||||
|
# override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
||||||
|
# self.param_memory.put_int("CEStatus", override_value)
|
||||||
|
# else:
|
||||||
|
# experimental_mode = self.param.get_bool("ExperimentalMode")
|
||||||
|
# # Invert the value of "ExperimentalMode"
|
||||||
|
# put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
||||||
|
# self.lkas_previously_pressed = lkas_pressed
|
||||||
|
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_self", self)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# BBOT does not work
|
||||||
|
def calculate_speed_limit_canfd(self, CP, cp, cp_cam):
|
||||||
|
try:
|
||||||
|
self._speed_limit_clu = cp.vl["CLUSTER_SPEED_LIMIT"]["SPEED_LIMIT_1"]
|
||||||
|
return self._speed_limit_clu if self._speed_limit_clu not in (0, 255) else 0
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_can_parser(self, CP):
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
return self.get_can_parser_canfd(CP)
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
# address, frequency
|
||||||
|
("MDPS12", 50),
|
||||||
|
("TCS13", 50),
|
||||||
|
("TCS15", 10),
|
||||||
|
("CLU11", 50),
|
||||||
|
("CLU15", 5),
|
||||||
|
("ESP12", 100),
|
||||||
|
("CGW1", 10),
|
||||||
|
("CGW2", 5),
|
||||||
|
("CGW4", 5),
|
||||||
|
("WHL_SPD11", 50),
|
||||||
|
("SAS11", 100),
|
||||||
|
]
|
||||||
|
|
||||||
|
if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
|
||||||
|
messages += [
|
||||||
|
("SCC11", 50),
|
||||||
|
("SCC12", 50),
|
||||||
|
]
|
||||||
|
if CP.flags & HyundaiFlags.USE_FCA.value:
|
||||||
|
messages.append(("FCA11", 50))
|
||||||
|
|
||||||
|
if CP.enableBsm:
|
||||||
|
messages.append(("LCA11", 50))
|
||||||
|
|
||||||
|
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
messages.append(("E_EMS11", 50))
|
||||||
|
else:
|
||||||
|
messages += [
|
||||||
|
("EMS12", 100),
|
||||||
|
("EMS16", 100),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
||||||
|
messages.append(("ELECT_GEAR", 20))
|
||||||
|
elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
||||||
|
pass
|
||||||
|
elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
||||||
|
messages.append(("TCU12", 100))
|
||||||
|
else:
|
||||||
|
messages.append(("LVR12", 100))
|
||||||
|
|
||||||
|
messages.append(("BCM_PO_11", 50))
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cam_can_parser(CP):
|
||||||
|
if CP.carFingerprint in CANFD_CAR:
|
||||||
|
return CarState.get_cam_can_parser_canfd(CP)
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
("LKAS11", 100)
|
||||||
|
]
|
||||||
|
|
||||||
|
if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
|
||||||
|
messages += [
|
||||||
|
("SCC11", 50),
|
||||||
|
("SCC12", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.flags & HyundaiFlags.USE_FCA.value:
|
||||||
|
messages.append(("FCA11", 50))
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
|
||||||
|
|
||||||
|
def get_can_parser_canfd(self, CP):
|
||||||
|
messages = [
|
||||||
|
(self.gear_msg_canfd, 100),
|
||||||
|
(self.accelerator_msg_canfd, 100),
|
||||||
|
("WHEEL_SPEEDS", 100),
|
||||||
|
("STEERING_SENSORS", 100),
|
||||||
|
("MDPS", 100),
|
||||||
|
("TCS", 50),
|
||||||
|
("CRUISE_BUTTONS_ALT", 50),
|
||||||
|
("BLINKERS", 4),
|
||||||
|
("DOORS_SEATBELTS", 4),
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.carFingerprint in EV_CAR:
|
||||||
|
messages += [
|
||||||
|
("MANUAL_SPEED_LIMIT_ASSIST", 10),
|
||||||
|
]
|
||||||
|
|
||||||
|
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
|
||||||
|
messages += [
|
||||||
|
("CRUISE_BUTTONS", 50)
|
||||||
|
]
|
||||||
|
|
||||||
|
if CP.enableBsm:
|
||||||
|
messages += [
|
||||||
|
("BLINDSPOTS_REAR_CORNERS", 20),
|
||||||
|
]
|
||||||
|
|
||||||
|
# if CP.nav_msg:
|
||||||
|
# messages.append(("CLUSTER_SPEED_LIMIT", 10))
|
||||||
|
|
||||||
|
if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
|
||||||
|
messages += [
|
||||||
|
("SCC_CONTROL", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_cam_can_parser_canfd(CP):
|
||||||
|
messages = []
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
|
||||||
|
messages += [(block_lfa_msg, 20)]
|
||||||
|
elif CP.flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||||
|
messages += [
|
||||||
|
("SCC_CONTROL", 50),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).CAM)
|
||||||
@@ -10,6 +10,9 @@ from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
|
|||||||
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
|
||||||
CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
|
CANFD_CAR, EV_CAR, HYBRID_CAR, Buttons, CarControllerParams
|
||||||
from openpilot.selfdrive.car.interfaces import CarStateBase
|
from openpilot.selfdrive.car.interfaces import CarStateBase
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
PREV_BUTTON_SAMPLES = 8
|
PREV_BUTTON_SAMPLES = 8
|
||||||
CLUSTER_SAMPLE_RATE = 20 # frames
|
CLUSTER_SAMPLE_RATE = 20 # frames
|
||||||
@@ -24,370 +27,24 @@ class CarState(CarStateBase):
|
|||||||
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
self.cruise_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
self.main_buttons = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
|
||||||
|
|
||||||
self.gear_msg_canfd = "GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
|
|
||||||
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
|
|
||||||
"GEAR_SHIFTER"
|
|
||||||
if CP.carFingerprint in CANFD_CAR:
|
|
||||||
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
|
|
||||||
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
|
||||||
self.shifter_values = can_define.dv["CLU15"]["CF_Clu_Gear"]
|
|
||||||
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
|
||||||
self.shifter_values = can_define.dv["TCU12"]["CUR_GR"]
|
|
||||||
else: # preferred and elect gear methods use same definition
|
|
||||||
self.shifter_values = can_define.dv["LVR12"]["CF_Lvr_Gear"]
|
|
||||||
|
|
||||||
self.accelerator_msg_canfd = "ACCELERATOR" if CP.carFingerprint in EV_CAR else \
|
|
||||||
"ACCELERATOR_ALT" if CP.carFingerprint in HYBRID_CAR else \
|
|
||||||
"ACCELERATOR_BRAKE_ALT"
|
|
||||||
self.cruise_btns_msg_canfd = "CRUISE_BUTTONS_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else \
|
|
||||||
"CRUISE_BUTTONS"
|
|
||||||
self.is_metric = False
|
|
||||||
self.buttons_counter = 0
|
|
||||||
|
|
||||||
self.cruise_info = {}
|
|
||||||
|
|
||||||
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
|
|
||||||
self.cluster_speed = 0
|
|
||||||
self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
|
|
||||||
|
|
||||||
self.params = CarControllerParams(CP)
|
self.params = CarControllerParams(CP)
|
||||||
|
|
||||||
def update(self, cp, cp_cam):
|
def update(self, cp, cp_cam):
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_cp_cam", cp_cam)
|
||||||
|
|
||||||
if self.CP.carFingerprint in CANFD_CAR:
|
if self.CP.carFingerprint in CANFD_CAR:
|
||||||
return self.update_canfd(cp, cp_cam)
|
return self.update_canfd(cp, cp_cam)
|
||||||
|
|
||||||
ret = car.CarState.new_message()
|
Watcher.log_watch("hyundai_carstate_update_self", self)
|
||||||
cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
|
|
||||||
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
|
|
||||||
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
|
||||||
|
|
||||||
ret.doorOpen = any([cp.vl["CGW1"]["CF_Gway_DrvDrSw"], cp.vl["CGW1"]["CF_Gway_AstDrSw"],
|
|
||||||
cp.vl["CGW2"]["CF_Gway_RLDrSw"], cp.vl["CGW2"]["CF_Gway_RRDrSw"]])
|
|
||||||
|
|
||||||
ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
|
|
||||||
|
|
||||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
|
||||||
cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
|
|
||||||
cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
|
|
||||||
cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
|
|
||||||
cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
|
|
||||||
)
|
|
||||||
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
|
||||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
|
||||||
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
|
||||||
|
|
||||||
self.cluster_speed_counter += 1
|
|
||||||
if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
|
|
||||||
self.cluster_speed = cp.vl["CLU15"]["CF_Clu_VehicleSpeed"]
|
|
||||||
self.cluster_speed_counter = 0
|
|
||||||
|
|
||||||
# Mimic how dash converts to imperial.
|
|
||||||
# Sorento is the only platform where CF_Clu_VehicleSpeed is already imperial when not is_metric
|
|
||||||
# TODO: CGW_USM1->CF_Gway_DrLockSoundRValue may describe this
|
|
||||||
if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
|
|
||||||
self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
|
|
||||||
|
|
||||||
ret.vEgoCluster = self.cluster_speed * speed_conv
|
|
||||||
|
|
||||||
ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
|
|
||||||
ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
|
|
||||||
ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
|
|
||||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
|
|
||||||
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
|
|
||||||
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
|
|
||||||
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
|
|
||||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
|
||||||
ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
|
|
||||||
|
|
||||||
# cruise state
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
|
||||||
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
|
||||||
ret.cruiseState.available = self.main_enabled
|
|
||||||
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
|
|
||||||
ret.cruiseState.standstill = False
|
|
||||||
ret.cruiseState.nonAdaptive = False
|
|
||||||
else:
|
|
||||||
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
|
|
||||||
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
|
|
||||||
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
|
|
||||||
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
|
|
||||||
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
|
|
||||||
|
|
||||||
# TODO: Find brake pressure
|
|
||||||
ret.brake = 0
|
|
||||||
ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
|
|
||||||
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
|
|
||||||
ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
|
|
||||||
ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
|
||||||
|
|
||||||
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
|
||||||
if self.CP.carFingerprint in HYBRID_CAR:
|
|
||||||
ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
|
|
||||||
else:
|
|
||||||
ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
|
|
||||||
ret.gasPressed = ret.gas > 0
|
|
||||||
else:
|
|
||||||
ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
|
|
||||||
ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
|
|
||||||
|
|
||||||
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
|
|
||||||
# as this seems to be standard over all cars, but is not the preferred method.
|
|
||||||
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
|
||||||
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
|
|
||||||
elif self.CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
|
||||||
gear = cp.vl["CLU15"]["CF_Clu_Gear"]
|
|
||||||
elif self.CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
|
||||||
gear = cp.vl["TCU12"]["CUR_GR"]
|
|
||||||
else:
|
|
||||||
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
|
|
||||||
|
|
||||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
|
||||||
|
|
||||||
if not self.CP.openpilotLongitudinalControl:
|
|
||||||
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
|
|
||||||
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
|
|
||||||
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
|
|
||||||
scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
|
|
||||||
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
|
|
||||||
ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
|
|
||||||
ret.stockAeb = aeb_warning and aeb_braking
|
|
||||||
|
|
||||||
if self.CP.enableBsm:
|
|
||||||
ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
|
|
||||||
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
|
|
||||||
|
|
||||||
# save the entire LKAS11 and CLU11
|
|
||||||
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
|
|
||||||
self.clu11 = copy.copy(cp.vl["CLU11"])
|
|
||||||
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
|
|
||||||
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
|
||||||
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
|
|
||||||
self.prev_main_buttons = self.main_buttons[-1]
|
|
||||||
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
|
|
||||||
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
|
||||||
self.main_enabled = not self.main_enabled
|
|
||||||
|
|
||||||
# Driving personalities function
|
|
||||||
if self.personalities_via_wheel and ret.cruiseState.available:
|
|
||||||
# Sync with the onroad UI button
|
|
||||||
if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
|
||||||
self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
|
||||||
self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
|
||||||
|
|
||||||
# Change personality upon steering wheel button press
|
|
||||||
if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
|
||||||
self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
|
||||||
self.personality_profile = (self.previous_personality_profile + 2) % 3
|
|
||||||
|
|
||||||
if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
|
||||||
self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
|
||||||
self.previous_personality_profile = self.personality_profile
|
|
||||||
|
|
||||||
# Toggle Experimental Mode from steering wheel function
|
|
||||||
if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
|
||||||
lkas_pressed = cp.vl["BCM_PO_11"]["LFA_Pressed"]
|
|
||||||
if lkas_pressed and not self.lkas_previously_pressed:
|
|
||||||
if self.conditional_experimental_mode:
|
|
||||||
# Set "CEStatus" to work with "Conditional Experimental Mode"
|
|
||||||
conditional_status = self.param_memory.get_int("CEStatus")
|
|
||||||
override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
|
||||||
self.param_memory.put_int("CEStatus", override_value)
|
|
||||||
else:
|
|
||||||
experimental_mode = self.param.get_bool("ExperimentalMode")
|
|
||||||
# Invert the value of "ExperimentalMode"
|
|
||||||
put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
|
||||||
self.lkas_previously_pressed = lkas_pressed
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def update_canfd(self, cp, cp_cam):
|
def update_canfd(self, cp, cp_cam):
|
||||||
ret = car.CarState.new_message()
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp", cp)
|
||||||
|
Watcher.log_watch("hyundai_carstate_update_canfd_cp_cam", cp_cam)
|
||||||
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
|
|
||||||
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
|
|
||||||
|
|
||||||
if self.CP.carFingerprint in (EV_CAR | HYBRID_CAR):
|
|
||||||
offset = 255. if self.CP.carFingerprint in EV_CAR else 1023.
|
|
||||||
ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset
|
|
||||||
ret.gasPressed = ret.gas > 1e-5
|
|
||||||
else:
|
|
||||||
ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
|
|
||||||
|
|
||||||
ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
|
|
||||||
|
|
||||||
ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
|
|
||||||
ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
|
|
||||||
|
|
||||||
gear = cp.vl[self.gear_msg_canfd]["GEAR"]
|
|
||||||
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
|
|
||||||
|
|
||||||
# TODO: figure out positions
|
|
||||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
|
||||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
|
|
||||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
|
|
||||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
|
|
||||||
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
|
|
||||||
)
|
|
||||||
ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
|
|
||||||
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
|
||||||
ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
|
|
||||||
|
|
||||||
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
|
|
||||||
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
|
|
||||||
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
|
|
||||||
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
|
|
||||||
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
|
|
||||||
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
|
|
||||||
|
|
||||||
# TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
|
|
||||||
left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
|
|
||||||
if self.CP.carFingerprint == CAR.KONA_EV_2ND_GEN:
|
|
||||||
left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
|
|
||||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
|
|
||||||
cp.vl["BLINKERS"][right_blinker_sig])
|
|
||||||
if self.CP.enableBsm:
|
|
||||||
ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
|
|
||||||
ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
|
|
||||||
|
|
||||||
# cruise state
|
|
||||||
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
|
|
||||||
ret.cruiseState.available = self.main_enabled
|
|
||||||
if self.CP.openpilotLongitudinalControl:
|
|
||||||
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
|
|
||||||
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
|
|
||||||
ret.cruiseState.standstill = False
|
|
||||||
else:
|
|
||||||
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
|
|
||||||
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
|
|
||||||
ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
|
|
||||||
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
|
|
||||||
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
|
|
||||||
|
|
||||||
# Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
|
|
||||||
# It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
|
|
||||||
# The car will brake, but does not respect positive acceleration commands in this mode
|
|
||||||
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
|
|
||||||
if self.CP.carFingerprint in EV_CAR:
|
|
||||||
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
|
|
||||||
|
|
||||||
self.prev_cruise_buttons = self.cruise_buttons[-1]
|
|
||||||
self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
|
|
||||||
self.prev_main_buttons = self.main_buttons[-1]
|
|
||||||
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
|
|
||||||
if self.prev_main_buttons == 0 and self.main_buttons[-1] != 0:
|
|
||||||
self.main_enabled = not self.main_enabled
|
|
||||||
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
|
|
||||||
ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
|
|
||||||
|
|
||||||
if self.CP.flags & HyundaiFlags.CANFD_HDA2:
|
|
||||||
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
|
|
||||||
else cp_cam.vl["CAM_0x2a4"])
|
|
||||||
|
|
||||||
# Driving personalities function
|
|
||||||
if self.personalities_via_wheel and ret.cruiseState.available:
|
|
||||||
# Sync with the onroad UI button
|
|
||||||
if self.param_memory.get_bool("PersonalityChangedViaUI"):
|
|
||||||
self.personality_profile = self.param.get_int("LongitudinalPersonality")
|
|
||||||
self.param_memory.put_bool("PersonalityChangedViaUI", False)
|
|
||||||
|
|
||||||
# Change personality upon steering wheel button press
|
|
||||||
if self.cruise_buttons[-1] == Buttons.GAP_DIST and self.prev_cruise_buttons == 0:
|
|
||||||
self.param_memory.put_bool("PersonalityChangedViaWheel", True)
|
|
||||||
self.personality_profile = (self.previous_personality_profile + 2) % 3
|
|
||||||
|
|
||||||
if self.personality_profile != self.previous_personality_profile and self.personality_profile >= 0:
|
|
||||||
self.param.put_int("LongitudinalPersonality", self.personality_profile)
|
|
||||||
self.previous_personality_profile = self.personality_profile
|
|
||||||
|
|
||||||
# Toggle Experimental Mode from steering wheel function
|
|
||||||
if self.experimental_mode_via_lkas and ret.cruiseState.available:
|
|
||||||
lkas_pressed = cp.vl[self.cruise_btns_msg_canfd]["LKAS_BTN"]
|
|
||||||
if lkas_pressed and not self.lkas_previously_pressed:
|
|
||||||
if self.conditional_experimental_mode:
|
|
||||||
# Set "CEStatus" to work with "Conditional Experimental Mode"
|
|
||||||
conditional_status = self.param_memory.get_int("CEStatus")
|
|
||||||
override_value = 0 if conditional_status in (1, 2, 3, 4) else 1 if conditional_status >= 5 else 2
|
|
||||||
self.param_memory.put_int("CEStatus", override_value)
|
|
||||||
else:
|
|
||||||
experimental_mode = self.param.get_bool("ExperimentalMode")
|
|
||||||
# Invert the value of "ExperimentalMode"
|
|
||||||
put_bool_nonblocking("ExperimentalMode", not experimental_mode)
|
|
||||||
self.lkas_previously_pressed = lkas_pressed
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_can_parser(self, CP):
|
def get_can_parser(self, CP):
|
||||||
if CP.carFingerprint in CANFD_CAR:
|
|
||||||
return self.get_can_parser_canfd(CP)
|
|
||||||
|
|
||||||
messages = [
|
|
||||||
# address, frequency
|
|
||||||
("MDPS12", 50),
|
|
||||||
("TCS13", 50),
|
|
||||||
("TCS15", 10),
|
|
||||||
("CLU11", 50),
|
|
||||||
("CLU15", 5),
|
|
||||||
("ESP12", 100),
|
|
||||||
("CGW1", 10),
|
|
||||||
("CGW2", 5),
|
|
||||||
("CGW4", 5),
|
|
||||||
("WHL_SPD11", 50),
|
|
||||||
("SAS11", 100),
|
|
||||||
]
|
|
||||||
|
|
||||||
if not CP.openpilotLongitudinalControl and CP.carFingerprint not in CAMERA_SCC_CAR:
|
|
||||||
messages += [
|
|
||||||
("SCC11", 50),
|
|
||||||
("SCC12", 50),
|
|
||||||
]
|
|
||||||
if CP.flags & HyundaiFlags.USE_FCA.value:
|
|
||||||
messages.append(("FCA11", 50))
|
|
||||||
|
|
||||||
if CP.enableBsm:
|
|
||||||
messages.append(("LCA11", 50))
|
|
||||||
|
|
||||||
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
|
||||||
messages.append(("E_EMS11", 50))
|
|
||||||
else:
|
|
||||||
messages += [
|
|
||||||
("EMS12", 100),
|
|
||||||
("EMS16", 100),
|
|
||||||
]
|
|
||||||
|
|
||||||
if CP.carFingerprint in (HYBRID_CAR | EV_CAR):
|
|
||||||
messages.append(("ELECT_GEAR", 20))
|
|
||||||
elif CP.carFingerprint in CAN_GEARS["use_cluster_gears"]:
|
|
||||||
pass
|
|
||||||
elif CP.carFingerprint in CAN_GEARS["use_tcu_gears"]:
|
|
||||||
messages.append(("TCU12", 100))
|
|
||||||
else:
|
|
||||||
messages.append(("LVR12", 100))
|
|
||||||
|
|
||||||
messages.append(("BCM_PO_11", 50))
|
|
||||||
|
|
||||||
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_cam_can_parser(CP):
|
|
||||||
if CP.carFingerprint in CANFD_CAR:
|
|
||||||
return CarState.get_cam_can_parser_canfd(CP)
|
|
||||||
|
|
||||||
messages = [
|
|
||||||
("LKAS11", 100)
|
|
||||||
]
|
|
||||||
|
|
||||||
if not CP.openpilotLongitudinalControl and CP.carFingerprint in CAMERA_SCC_CAR:
|
|
||||||
messages += [
|
|
||||||
("SCC11", 50),
|
|
||||||
("SCC12", 50),
|
|
||||||
]
|
|
||||||
|
|
||||||
if CP.flags & HyundaiFlags.USE_FCA.value:
|
|
||||||
messages.append(("FCA11", 50))
|
|
||||||
|
|
||||||
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2)
|
|
||||||
|
|
||||||
def get_can_parser_canfd(self, CP):
|
|
||||||
messages = [
|
messages = [
|
||||||
(self.gear_msg_canfd, 100),
|
(self.gear_msg_canfd, 100),
|
||||||
(self.accelerator_msg_canfd, 100),
|
(self.accelerator_msg_canfd, 100),
|
||||||
@@ -415,6 +72,9 @@ class CarState(CarStateBase):
|
|||||||
("BLINDSPOTS_REAR_CORNERS", 20),
|
("BLINDSPOTS_REAR_CORNERS", 20),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# if CP.nav_msg:
|
||||||
|
# messages.append(("CLUSTER_SPEED_LIMIT", 10))
|
||||||
|
|
||||||
if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
|
if not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value) and not CP.openpilotLongitudinalControl:
|
||||||
messages += [
|
messages += [
|
||||||
("SCC_CONTROL", 50),
|
("SCC_CONTROL", 50),
|
||||||
@@ -423,7 +83,7 @@ class CarState(CarStateBase):
|
|||||||
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
|
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus(CP).ECAN)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_cam_can_parser_canfd(CP):
|
def get_cam_can_parser(CP):
|
||||||
messages = []
|
messages = []
|
||||||
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
|
block_lfa_msg = "CAM_0x362" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "CAM_0x2a4"
|
||||||
|
|||||||
224
selfdrive/car/hyundai/hyundaicanfd.org
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
from openpilot.common.numpy_fast import clip
|
||||||
|
from openpilot.selfdrive.car import CanBusBase
|
||||||
|
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags
|
||||||
|
|
||||||
|
|
||||||
|
class CanBus(CanBusBase):
|
||||||
|
def __init__(self, CP, hda2=None, fingerprint=None) -> None:
|
||||||
|
super().__init__(CP, fingerprint)
|
||||||
|
|
||||||
|
if hda2 is None:
|
||||||
|
assert CP is not None
|
||||||
|
hda2 = CP.flags & HyundaiFlags.CANFD_HDA2.value
|
||||||
|
|
||||||
|
# On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. HDA2 cars
|
||||||
|
# have a different harness than the HDA1 and non-HDA variants in order to split
|
||||||
|
# a different bus, since the steering is done by different ECUs.
|
||||||
|
self._a, self._e = 1, 0
|
||||||
|
if hda2:
|
||||||
|
self._a, self._e = 0, 1
|
||||||
|
|
||||||
|
self._a += self.offset
|
||||||
|
self._e += self.offset
|
||||||
|
self._cam = 2 + self.offset
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ECAN(self):
|
||||||
|
return self._e
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ACAN(self):
|
||||||
|
return self._a
|
||||||
|
|
||||||
|
@property
|
||||||
|
def CAM(self):
|
||||||
|
return self._cam
|
||||||
|
|
||||||
|
|
||||||
|
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
"LKA_MODE": 2,
|
||||||
|
"LKA_ICON": 2 if enabled else 1 if lat_active else 0,
|
||||||
|
"TORQUE_REQUEST": apply_steer,
|
||||||
|
"LKA_ASSIST": 0,
|
||||||
|
"STEER_REQ": 1 if lat_active else 0,
|
||||||
|
"STEER_MODE": 0,
|
||||||
|
"HAS_LANE_SAFETY": 0, # hide LKAS settings
|
||||||
|
"NEW_SIGNAL_1": 0,
|
||||||
|
"NEW_SIGNAL_2": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_HDA2:
|
||||||
|
hda2_lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
|
||||||
|
if CP.openpilotLongitudinalControl:
|
||||||
|
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||||
|
ret.append(packer.make_can_msg(hda2_lkas_msg, CAN.ACAN, values))
|
||||||
|
else:
|
||||||
|
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def create_suppress_lfa(packer, CAN, hda2_lfa_block_msg, hda2_alt_steering):
|
||||||
|
suppress_msg = "CAM_0x362" if hda2_alt_steering else "CAM_0x2a4"
|
||||||
|
msg_bytes = 32 if hda2_alt_steering else 24
|
||||||
|
|
||||||
|
values = {f"BYTE{i}": hda2_lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
|
||||||
|
values["COUNTER"] = hda2_lfa_block_msg["COUNTER"]
|
||||||
|
values["SET_ME_0"] = 0
|
||||||
|
values["SET_ME_0_2"] = 0
|
||||||
|
values["LEFT_LANE_LINE"] = 0
|
||||||
|
values["RIGHT_LANE_LINE"] = 0
|
||||||
|
return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
|
||||||
|
|
||||||
|
def create_buttons(packer, CP, CAN, cnt, btn):
|
||||||
|
values = {
|
||||||
|
"COUNTER": cnt,
|
||||||
|
"SET_ME_1": 1,
|
||||||
|
"CRUISE_BUTTONS": btn,
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
|
||||||
|
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
|
||||||
|
|
||||||
|
def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
|
||||||
|
# TODO: why do we copy different values here?
|
||||||
|
if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
|
||||||
|
values = {s: cruise_info_copy[s] for s in [
|
||||||
|
"COUNTER",
|
||||||
|
"CHECKSUM",
|
||||||
|
"NEW_SIGNAL_1",
|
||||||
|
"MainMode_ACC",
|
||||||
|
"ACCMode",
|
||||||
|
"ZEROS_9",
|
||||||
|
"CRUISE_STANDSTILL",
|
||||||
|
"ZEROS_5",
|
||||||
|
"DISTANCE_SETTING",
|
||||||
|
"VSetDis",
|
||||||
|
]}
|
||||||
|
else:
|
||||||
|
values = {s: cruise_info_copy[s] for s in [
|
||||||
|
"COUNTER",
|
||||||
|
"CHECKSUM",
|
||||||
|
"ACCMode",
|
||||||
|
"VSetDis",
|
||||||
|
"CRUISE_STANDSTILL",
|
||||||
|
]}
|
||||||
|
values.update({
|
||||||
|
"ACCMode": 4,
|
||||||
|
"aReqRaw": 0.0,
|
||||||
|
"aReqValue": 0.0,
|
||||||
|
})
|
||||||
|
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||||
|
|
||||||
|
def create_lfahda_cluster(packer, CAN, enabled):
|
||||||
|
values = {
|
||||||
|
"HDA_ICON": 1 if enabled else 0,
|
||||||
|
# 0 off, 1 gray, 2 green, 3 blinking (wheel icon)
|
||||||
|
"LFA_ICON": 0 if enabled else 0, # was green before i think in 2? 3 should be flashing?
|
||||||
|
# "LFA_ICON": 2 if enabled else 0,
|
||||||
|
}
|
||||||
|
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
||||||
|
|
||||||
|
|
||||||
|
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, personality):
|
||||||
|
jerk = 5
|
||||||
|
jn = jerk / 50
|
||||||
|
if not enabled or gas_override:
|
||||||
|
a_val, a_raw = 0, 0
|
||||||
|
else:
|
||||||
|
a_raw = accel
|
||||||
|
a_val = clip(accel, accel_last - jn, accel_last + jn)
|
||||||
|
|
||||||
|
values = {
|
||||||
|
"ACCMode": 0 if not enabled else (2 if gas_override else 1),
|
||||||
|
"MainMode_ACC": 1,
|
||||||
|
"StopReq": 1 if stopping else 0,
|
||||||
|
"aReqValue": a_val,
|
||||||
|
"aReqRaw": a_raw,
|
||||||
|
"VSetDis": set_speed,
|
||||||
|
"JerkLowerLimit": jerk if enabled else 1,
|
||||||
|
"JerkUpperLimit": 3.0,
|
||||||
|
|
||||||
|
"ACC_ObjDist": 1,
|
||||||
|
"ObjValid": 0,
|
||||||
|
"OBJ_STATUS": 2,
|
||||||
|
"SET_ME_2": 0x4,
|
||||||
|
"SET_ME_3": 0x3,
|
||||||
|
"SET_ME_TMP_64": 0x64,
|
||||||
|
"DISTANCE_SETTING": personality + 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||||
|
|
||||||
|
def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("SPAS1", CAN.ECAN, values))
|
||||||
|
|
||||||
|
blink = 0
|
||||||
|
if left_blink:
|
||||||
|
blink = 3
|
||||||
|
elif right_blink:
|
||||||
|
blink = 4
|
||||||
|
values = {
|
||||||
|
"BLINKER_CONTROL": blink,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("SPAS2", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def create_adrv_messages(packer, CAN, frame):
|
||||||
|
# messages needed to car happy after disabling
|
||||||
|
# the ADAS Driving ECU to do longitudinal control
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
values = {
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||||
|
|
||||||
|
if frame % 2 == 0:
|
||||||
|
values = {
|
||||||
|
'AEB_SETTING': 0x1, # show AEB disabled icon
|
||||||
|
'SET_ME_2': 0x2,
|
||||||
|
'SET_ME_FF': 0xff,
|
||||||
|
'SET_ME_FC': 0xfc,
|
||||||
|
'SET_ME_9': 0x9,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 5 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_1C': 0x1c,
|
||||||
|
'SET_ME_FF': 0xff,
|
||||||
|
'SET_ME_TMP_F': 0xf,
|
||||||
|
'SET_ME_TMP_F_2': 0xf,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
|
||||||
|
|
||||||
|
values = {
|
||||||
|
'SET_ME_E1': 0xe1,
|
||||||
|
'SET_ME_3A': 0x3a,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 20 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_15': 0x15,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
|
||||||
|
|
||||||
|
if frame % 100 == 0:
|
||||||
|
values = {
|
||||||
|
'SET_ME_22': 0x22,
|
||||||
|
'SET_ME_41': 0x41,
|
||||||
|
}
|
||||||
|
ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
|
||||||
|
|
||||||
|
return ret
|
||||||
@@ -41,7 +41,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer):
|
|||||||
|
|
||||||
values = {
|
values = {
|
||||||
"LKA_MODE": 2,
|
"LKA_MODE": 2,
|
||||||
"LKA_ICON": 2 if enabled else 1,
|
"LKA_ICON": 2 if enabled else 1 if lat_active else 0,
|
||||||
"TORQUE_REQUEST": apply_steer,
|
"TORQUE_REQUEST": apply_steer,
|
||||||
"LKA_ASSIST": 0,
|
"LKA_ASSIST": 0,
|
||||||
"STEER_REQ": 1 if lat_active else 0,
|
"STEER_REQ": 1 if lat_active else 0,
|
||||||
@@ -116,7 +116,9 @@ def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
|
|||||||
def create_lfahda_cluster(packer, CAN, enabled):
|
def create_lfahda_cluster(packer, CAN, enabled):
|
||||||
values = {
|
values = {
|
||||||
"HDA_ICON": 1 if enabled else 0,
|
"HDA_ICON": 1 if enabled else 0,
|
||||||
"LFA_ICON": 2 if enabled else 0,
|
# 0 off, 1 gray, 2 green, 3 blinking (wheel icon)
|
||||||
|
"LFA_ICON": 0 if enabled else 0, # was green before i think in 2? 3 should be flashing?
|
||||||
|
# "LFA_ICON": 2 if enabled else 0,
|
||||||
}
|
}
|
||||||
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
|
||||||
|
|
||||||
@@ -151,7 +153,6 @@ def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_ov
|
|||||||
|
|
||||||
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
|
||||||
|
|
||||||
|
|
||||||
def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
|
||||||
ret = []
|
ret = []
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
|
|||||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||||
|
from openpilot.common.params import Params
|
||||||
|
|
||||||
|
params_memory = Params("/dev/shm/params")
|
||||||
|
|
||||||
Ecu = car.CarParams.Ecu
|
Ecu = car.CarParams.Ecu
|
||||||
SafetyModel = car.CarParams.SafetyModel
|
SafetyModel = car.CarParams.SafetyModel
|
||||||
@@ -35,6 +38,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||||
ret.carName = "hyundai"
|
ret.carName = "hyundai"
|
||||||
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
|
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
|
||||||
|
params_memory.put_bool("CSLCAvailable", True)
|
||||||
|
|
||||||
# These cars have been put into dashcam only due to both a lack of users and test coverage.
|
# These cars have been put into dashcam only due to both a lack of users and test coverage.
|
||||||
# These cars likely still work fine. Once a user confirms each car works and a test route is
|
# These cars likely still work fine. Once a user confirms each car works and a test route is
|
||||||
@@ -50,6 +54,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
if hda2:
|
if hda2:
|
||||||
if 0x110 in fingerprint[CAN.CAM]:
|
if 0x110 in fingerprint[CAN.CAM]:
|
||||||
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
|
||||||
|
params_memory.put_bool("CSLCAvailable", False)
|
||||||
else:
|
else:
|
||||||
# non-HDA2
|
# non-HDA2
|
||||||
if 0x1cf not in fingerprint[CAN.ECAN]:
|
if 0x1cf not in fingerprint[CAN.ECAN]:
|
||||||
@@ -148,6 +153,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.steerRatio = 14.00 * 1.15
|
ret.steerRatio = 14.00 * 1.15
|
||||||
ret.tireStiffnessFactor = 0.385
|
ret.tireStiffnessFactor = 0.385
|
||||||
elif candidate in (CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN):
|
elif candidate in (CAR.TUCSON_4TH_GEN, CAR.TUCSON_HYBRID_4TH_GEN):
|
||||||
|
ret.steerActuatorDelay = 0.1 # Or .15? BBOT test oscarpilot
|
||||||
ret.mass = 1630. # average
|
ret.mass = 1630. # average
|
||||||
ret.wheelbase = 2.756
|
ret.wheelbase = 2.756
|
||||||
ret.steerRatio = 16.
|
ret.steerRatio = 16.
|
||||||
@@ -291,10 +297,12 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.longitudinalActuatorDelayUpperBound = 0.5
|
ret.longitudinalActuatorDelayUpperBound = 0.5
|
||||||
|
|
||||||
# *** feature detection ***
|
# *** feature detection ***
|
||||||
if candidate in CANFD_CAR:
|
# if candidate in CANFD_CAR:
|
||||||
ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
|
# ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
|
||||||
else:
|
# ret.nav_msg = 0x544 in fingerprint[0]
|
||||||
ret.enableBsm = 0x58b in fingerprint[0]
|
# else:
|
||||||
|
# ret.enableBsm = 0x58b in fingerprint[0]
|
||||||
|
# ret.nav_msg = False
|
||||||
|
|
||||||
# *** panda safety config ***
|
# *** panda safety config ***
|
||||||
ret.safetyConfigs = set_safety_config_hyundai(candidate, CAN, can_fd=(candidate in CANFD_CAR))
|
ret.safetyConfigs = set_safety_config_hyundai(candidate, CAN, can_fd=(candidate in CANFD_CAR))
|
||||||
@@ -313,6 +321,7 @@ class CarInterface(CarInterfaceBase):
|
|||||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC
|
||||||
if ret.openpilotLongitudinalControl:
|
if ret.openpilotLongitudinalControl:
|
||||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG
|
||||||
|
params_memory.put_bool("CSLCAvailable", False)
|
||||||
if candidate in HYBRID_CAR:
|
if candidate in HYBRID_CAR:
|
||||||
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_HYBRID_GAS
|
ret.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_HYBRID_GAS
|
||||||
elif candidate in EV_CAR:
|
elif candidate in EV_CAR:
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offr
|
|||||||
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||||
from openpilot.system.hardware import HARDWARE
|
from openpilot.system.hardware import HARDWARE
|
||||||
|
|
||||||
|
from openpilot.common.watcher import Watcher
|
||||||
|
|
||||||
SOFT_DISABLE_TIME = 3 # seconds
|
SOFT_DISABLE_TIME = 3 # seconds
|
||||||
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
|
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
|
||||||
LANE_DEPARTURE_THRESHOLD = 0.1
|
LANE_DEPARTURE_THRESHOLD = 0.1
|
||||||
@@ -131,6 +133,9 @@ class Controls:
|
|||||||
|
|
||||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX
|
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX
|
||||||
|
|
||||||
|
# Test
|
||||||
|
Watcher.log_watch("always_on_lateral", self.always_on_lateral)
|
||||||
|
|
||||||
# read params
|
# read params
|
||||||
self.is_metric = self.params.get_bool("IsMetric")
|
self.is_metric = self.params.get_bool("IsMetric")
|
||||||
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
||||||
@@ -605,6 +610,7 @@ class Controls:
|
|||||||
self.state = State.enabled
|
self.state = State.enabled
|
||||||
self.current_alert_types.append(ET.ENABLE)
|
self.current_alert_types.append(ET.ENABLE)
|
||||||
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode, self.conditional_experimental_mode)
|
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode, self.conditional_experimental_mode)
|
||||||
|
# self.v_cruise_helper.initialize_v_cruise(CS, self.frogpilot_variables, self.experimental_mode, self.conditional_experimental_mode)
|
||||||
|
|
||||||
# Check if openpilot is engaged and actuators are enabled
|
# Check if openpilot is engaged and actuators are enabled
|
||||||
self.enabled = self.state in ENABLED_STATES
|
self.enabled = self.state in ENABLED_STATES
|
||||||
@@ -659,7 +665,7 @@ class Controls:
|
|||||||
self.lateral_allowed |= CS.cruiseState.enabled or (CS.cruiseState.available and self.always_on_lateral_main)
|
self.lateral_allowed |= CS.cruiseState.enabled or (CS.cruiseState.available and self.always_on_lateral_main)
|
||||||
|
|
||||||
self.FPCC.alwaysOnLateral = self.lateral_allowed and driving_gear and signal_check
|
self.FPCC.alwaysOnLateral = self.lateral_allowed and driving_gear and signal_check
|
||||||
if self.FPCC.alwaysOnLateral:/
|
if self.FPCC.alwaysOnLateral:
|
||||||
self.current_alert_types.append(ET.WARNING)
|
self.current_alert_types.append(ET.WARNING)
|
||||||
|
|
||||||
# Check which actuators can be enabled
|
# Check which actuators can be enabled
|
||||||
@@ -1002,6 +1008,8 @@ class Controls:
|
|||||||
|
|
||||||
self.average_desired_curvature = self.params.get_bool("AverageCurvature")
|
self.average_desired_curvature = self.params.get_bool("AverageCurvature")
|
||||||
self.conditional_experimental_mode = self.params.get_bool("ConditionalExperimental")
|
self.conditional_experimental_mode = self.params.get_bool("ConditionalExperimental")
|
||||||
|
# self.frogpilot_variables.CSLC = self.params.get_bool("CSLCEnabled")
|
||||||
|
# self.frogpilot_variables.CSLCA = self.params.get_bool("CSLCAvailable")
|
||||||
|
|
||||||
custom_theme = self.params.get_bool("CustomTheme")
|
custom_theme = self.params.get_bool("CustomTheme")
|
||||||
custom_sounds = self.params.get_int("CustomSounds") if custom_theme else 0
|
custom_sounds = self.params.get_int("CustomSounds") if custom_theme else 0
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ class DesireHelper:
|
|||||||
self.lane_change_state = LaneChangeState.off
|
self.lane_change_state = LaneChangeState.off
|
||||||
self.lane_change_direction = LaneChangeDirection.none
|
self.lane_change_direction = LaneChangeDirection.none
|
||||||
elif one_blinker and below_lane_change_speed and frogpilot_planner.turn_desires:
|
elif one_blinker and below_lane_change_speed and frogpilot_planner.turn_desires:
|
||||||
|
# BBOT
|
||||||
self.turn_direction = TurnDirection.turnLeft if carstate.leftBlinker else TurnDirection.turnRight
|
self.turn_direction = TurnDirection.turnLeft if carstate.leftBlinker else TurnDirection.turnRight
|
||||||
# Set the "turn_completed" flag to prevent lane changes after completing a turn
|
# Set the "turn_completed" flag to prevent lane changes after completing a turn
|
||||||
self.turn_completed = True
|
self.turn_completed = True
|
||||||
|
|||||||
@@ -139,6 +139,11 @@ class VCruiseHelper:
|
|||||||
if self.CP.pcmCruise:
|
if self.CP.pcmCruise:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# if frogpilot_variables.CSLC:
|
||||||
|
# self.v_cruise_kph = CS.cruiseState.speed * CV.MS_TO_KPH
|
||||||
|
# self.v_cruise_cluster_kph = self.v_cruise_kph
|
||||||
|
# return
|
||||||
|
|
||||||
initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode and not conditional_experimental_mode else V_CRUISE_INITIAL
|
initial = V_CRUISE_INITIAL_EXPERIMENTAL_MODE if experimental_mode and not conditional_experimental_mode else V_CRUISE_INITIAL
|
||||||
|
|
||||||
# 250kph or above probably means we never had a set speed
|
# 250kph or above probably means we never had a set speed
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM
|
|||||||
if "REPLAY" in os.environ:
|
if "REPLAY" in os.environ:
|
||||||
branch = "replay"
|
branch = "replay"
|
||||||
|
|
||||||
return StartupAlert("Hippity hoppity this is my property", "so I do what I want 🐸", alert_status=AlertStatus.frogpilot)
|
return StartupAlert("Oscarpilot ready", "Be excellent to eachother", alert_status=AlertStatus.frogpilot)
|
||||||
|
|
||||||
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
|
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
|
||||||
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
|
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
|
||||||
@@ -373,7 +373,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
EventName.startupMaster: {
|
EventName.startupMaster: {
|
||||||
ET.PERMANENT: startup_master_alert,
|
# ET.PERMANENT: startup_master_alert,
|
||||||
|
ET.PERMANENT: StartupAlert("OscarPilot Ready"),
|
||||||
},
|
},
|
||||||
|
|
||||||
# Car is recognized, but marked as dashcam only
|
# Car is recognized, but marked as dashcam only
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -135,7 +135,7 @@ class ConditionalExperimentalMode:
|
|||||||
self.lead_detection(radarState)
|
self.lead_detection(radarState)
|
||||||
self.road_curvature(modelData, v_ego)
|
self.road_curvature(modelData, v_ego)
|
||||||
self.slow_lead(mpc, radarState, v_ego)
|
self.slow_lead(mpc, radarState, v_ego)
|
||||||
self.stop_sign_and_light(modelData, v_ego)
|
# self.stop_sign_and_light(modelData, v_ego)
|
||||||
self.v_ego_slowing_down(v_ego)
|
self.v_ego_slowing_down(v_ego)
|
||||||
self.v_lead_slowing_down(mpc, radarState)
|
self.v_lead_slowing_down(mpc, radarState)
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ def calculate_lane_width(lane, current_lane, road_edge):
|
|||||||
|
|
||||||
class FrogPilotPlanner:
|
class FrogPilotPlanner:
|
||||||
def __init__(self, params, params_memory):
|
def __init__(self, params, params_memory):
|
||||||
|
self.params_memory = params_memory
|
||||||
self.cem = ConditionalExperimentalMode()
|
self.cem = ConditionalExperimentalMode()
|
||||||
self.mtsc = MapTurnSpeedController()
|
self.mtsc = MapTurnSpeedController()
|
||||||
|
|
||||||
@@ -105,6 +106,8 @@ class FrogPilotPlanner:
|
|||||||
self.x_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, mpc.x_solution)
|
self.x_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, mpc.x_solution)
|
||||||
self.x_desired_trajectory = self.x_desired_trajectory_full[:CONTROL_N]
|
self.x_desired_trajectory = self.x_desired_trajectory_full[:CONTROL_N]
|
||||||
|
|
||||||
|
# self.params_memory.put_int("CSLCSpeed", int(round(self.v_cruise * CV.MS_TO_MPH)))
|
||||||
|
|
||||||
def update_v_cruise(self, carState, controlsState, modelData, enabled, v_cruise, v_ego):
|
def update_v_cruise(self, carState, controlsState, modelData, enabled, v_cruise, v_ego):
|
||||||
# Pfeiferj's Map Turn Speed Controller
|
# Pfeiferj's Map Turn Speed Controller
|
||||||
if self.map_turn_speed_controller:
|
if self.map_turn_speed_controller:
|
||||||
@@ -168,7 +171,12 @@ class FrogPilotPlanner:
|
|||||||
else:
|
else:
|
||||||
self.vtsc_target = v_cruise
|
self.vtsc_target = v_cruise
|
||||||
|
|
||||||
|
# if self.CSLC:
|
||||||
|
# v_ego_diff = 0
|
||||||
|
# else:
|
||||||
|
|
||||||
v_ego_diff = max(carState.vEgoRaw - carState.vEgoCluster, 0)
|
v_ego_diff = max(carState.vEgoRaw - carState.vEgoCluster, 0)
|
||||||
|
|
||||||
return min(v_cruise, self.mtsc_target, self.slc_target, self.vtsc_target) - v_ego_diff
|
return min(v_cruise, self.mtsc_target, self.slc_target, self.vtsc_target) - v_ego_diff
|
||||||
|
|
||||||
def publish_lateral(self, sm, pm, DH):
|
def publish_lateral(self, sm, pm, DH):
|
||||||
@@ -206,6 +214,8 @@ class FrogPilotPlanner:
|
|||||||
def update_frogpilot_params(self, params, params_memory):
|
def update_frogpilot_params(self, params, params_memory):
|
||||||
self.is_metric = params.get_bool("IsMetric")
|
self.is_metric = params.get_bool("IsMetric")
|
||||||
|
|
||||||
|
# self.CSLC = params.get_bool("CSLCEnabled")
|
||||||
|
|
||||||
self.blindspot_path = params.get_bool("CustomUI") and params.get_bool("BlindSpotPath")
|
self.blindspot_path = params.get_bool("CustomUI") and params.get_bool("BlindSpotPath")
|
||||||
|
|
||||||
self.conditional_experimental_mode = params.get_bool("ConditionalExperimental")
|
self.conditional_experimental_mode = params.get_bool("ConditionalExperimental")
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ def set_model_list_parameter(params):
|
|||||||
|
|
||||||
if previous_model_list != model_list:
|
if previous_model_list != model_list:
|
||||||
# Reset the selected model if the model list changed
|
# Reset the selected model if the model list changed
|
||||||
params.put_int("Model", 0)
|
params.put_int("Model", 3)
|
||||||
params.put("ModelList", model_list)
|
params.put("ModelList", model_list)
|
||||||
params.remove("CalibrationParams");
|
params.remove("CalibrationParams");
|
||||||
params.remove("LiveTorqueParameters");
|
params.remove("LiveTorqueParameters");
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ private:
|
|||||||
background-color: #4a4a4a;
|
background-color: #4a4a4a;
|
||||||
}
|
}
|
||||||
QPushButton:checked:enabled {
|
QPushButton:checked:enabled {
|
||||||
background-color: #33Ab4C;
|
background-color: #0048FF;
|
||||||
}
|
}
|
||||||
QPushButton:disabled {
|
QPushButton:disabled {
|
||||||
color: #33E4E4E4;
|
color: #33E4E4E4;
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ QString SelectMaps::activeButtonStyle = R"(
|
|||||||
border-width: 0;
|
border-width: 0;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
color: #dddddd;
|
color: #dddddd;
|
||||||
background-color: #33Ab4C;
|
background-color: #0048FF;
|
||||||
)";
|
)";
|
||||||
|
|
||||||
QString SelectMaps::normalButtonStyle = R"(
|
QString SelectMaps::normalButtonStyle = R"(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "selfdrive/frogpilot/ui/control_settings.h"
|
#include "selfdrive/frogpilot/ui/control_settings.h"
|
||||||
#include "selfdrive/ui/ui.h"
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
FrogPilotControlsPanel::FrogPilotControlsPanel(OscarSettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
const std::vector<std::tuple<QString, QString, QString, QString>> controlToggles {
|
const std::vector<std::tuple<QString, QString, QString, QString>> controlToggles {
|
||||||
{"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"},
|
{"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"},
|
||||||
{"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"},
|
{"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"},
|
||||||
@@ -10,9 +10,9 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil
|
|||||||
{"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""},
|
{"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""},
|
||||||
{"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""},
|
{"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""},
|
||||||
{"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""},
|
{"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""},
|
||||||
{"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""},
|
// {"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""},
|
||||||
{"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""},
|
{"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""},
|
||||||
|
{"CSLCEnabled", "Custom Stock Longitudinal Control", "Use cruise control button spamming to adjust cruise set speed based on MTSC, VTSC, and SLC", "../frogpilot/assets/toggle_icons/icon_custom.png"},
|
||||||
{"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"},
|
{"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"},
|
||||||
{"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"},
|
{"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"},
|
||||||
{"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"},
|
{"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"},
|
||||||
@@ -419,11 +419,11 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil
|
|||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles);
|
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles);
|
||||||
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles);
|
QObject::connect(parent, &OscarSettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles);
|
||||||
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric);
|
// QObject::connect(parent, &OscarSettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric);
|
||||||
|
|
||||||
hideSubToggles();
|
hideSubToggles();
|
||||||
updateMetric();
|
// updateMetric();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrogPilotControlsPanel::updateCarToggles() {
|
void FrogPilotControlsPanel::updateCarToggles() {
|
||||||
|
|||||||
559
selfdrive/frogpilot/ui/control_settings.cc.org
Normal file
@@ -0,0 +1,559 @@
|
|||||||
|
#include "selfdrive/frogpilot/ui/control_settings.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
|
const std::vector<std::tuple<QString, QString, QString, QString>> controlToggles {
|
||||||
|
{"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"},
|
||||||
|
{"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"},
|
||||||
|
|
||||||
|
{"ConditionalExperimental", "Conditional Experimental Mode", "Automatically switches to 'Experimental Mode' under predefined conditions.", "../frogpilot/assets/toggle_icons/icon_conditional.png"},
|
||||||
|
{"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""},
|
||||||
|
{"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""},
|
||||||
|
{"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""},
|
||||||
|
// {"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""},
|
||||||
|
{"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""},
|
||||||
|
{"CSLCEnabled", "Custom Stock Longitudinal Control", "Use cruise control button spamming to adjust cruise set speed based on MTSC, VTSC, and SLC", "../frogpilot/assets/toggle_icons/icon_custom.png"},
|
||||||
|
{"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"},
|
||||||
|
{"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"},
|
||||||
|
{"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"},
|
||||||
|
|
||||||
|
{"FireTheBabysitter", "Fire the Babysitter", "Deactivate some of openpilot's 'Babysitter' protocols for more user autonomy.", "../frogpilot/assets/toggle_icons/icon_babysitter.png"},
|
||||||
|
{"NoLogging", "Disable All Logging", "Turn off all data tracking to enhance privacy or reduce thermal load.\n\nWARNING: This action will prevent drive recording and data cannot be recovered!", ""},
|
||||||
|
{"MuteDoor", "Mute Door Open Alert", "Disable alerts for open doors.", ""},
|
||||||
|
{"MuteDM", "Mute Driver Monitoring", "Disable driver monitoring.", ""},
|
||||||
|
{"MuteOverheated", "Mute Overheated System Alert", "Disable alerts for the device being overheated.", ""},
|
||||||
|
{"MuteSeatbelt", "Mute Seatbelt Unlatched Alert", "Disable alerts for unlatched seatbelts.", ""},
|
||||||
|
{"OfflineMode", "Offline Mode", "Allow the device to be offline indefinitely.", ""},
|
||||||
|
|
||||||
|
{"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
|
||||||
|
{"AverageCurvature", "Average Desired Curvature", "Use Pfeiferj's distance-based curvature adjustment for improved curve handling.", ""},
|
||||||
|
{"NNFF", "NNFF - Neural Network Feedforward", "Use Twilsonco's Neural Network Feedforward for enhanced precision in lateral control.", ""},
|
||||||
|
{"SteerRatio", steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : "Steer Ratio", "Set a custom steer ratio for your vehicle controls.", ""},
|
||||||
|
|
||||||
|
{"LongitudinalTune", "Longitudinal Tuning", "Modify openpilot's acceleration and braking behavior.", "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
|
||||||
|
{"AccelerationProfile", "Acceleration Profile", "Change the acceleration rate to be either sporty or eco-friendly.", ""},
|
||||||
|
{"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""},
|
||||||
|
{"StoppingDistance", "Increased Stopping Distance", "Increase the stopping distance for a more comfortable stop.", ""},
|
||||||
|
{"SmoothBraking", "Smoother Braking Behind Lead", "Smoothen out the braking behavior when approaching slower vehicles.", ""},
|
||||||
|
|
||||||
|
{"Model", "Model Selector", "Choose your preferred openpilot model.", "../assets/offroad/icon_calibration.png"},
|
||||||
|
|
||||||
|
{"MTSCEnabled", "Map Turn Speed Control", "Slow down for anticipated curves detected by your downloaded maps.", "../frogpilot/assets/toggle_icons/icon_speed_map.png"},
|
||||||
|
|
||||||
|
{"NudgelessLaneChange", "Nudgeless Lane Change", "Enable lane changes without manual steering input.", "../frogpilot/assets/toggle_icons/icon_lane.png"},
|
||||||
|
{"LaneChangeTime", "Lane Change Timer", "Specify a delay before executing a nudgeless lane change.", ""},
|
||||||
|
{"LaneDetection", "Lane Detection", "Block nudgeless lane changes when a lane isn't detected.", ""},
|
||||||
|
{"OneLaneChange", "One Lane Change Per Signal", "Limit to one nudgeless lane change per turn signal activation.", ""},
|
||||||
|
|
||||||
|
{"QOLControls", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"},
|
||||||
|
{"DisableOnroadUploads", "Disable Onroad Uploads", "Prevent large data uploads when onroad.", ""},
|
||||||
|
{"HigherBitrate", "Higher Bitrate Recording", "Increases the quality of the footage uploaded to comma connect.", ""},
|
||||||
|
{"PauseLateralOnSignal", "Pause Lateral On Turn Signal Below", "Temporarily disable lateral control during turn signal use below the set speed.", ""},
|
||||||
|
{"ReverseCruise", "Reverse Cruise Increase", "Reverses the 'long press' functionality when increasing the max set speed. Useful to increase the max speed quickly.", ""},
|
||||||
|
{"SetSpeedOffset", "Set Speed Offset", "Set an offset for your desired set speed.", ""},
|
||||||
|
|
||||||
|
{"SpeedLimitController", "Speed Limit Controller", "Automatically adjust vehicle speed to match speed limits using 'Open Street Map's, 'Navigate On openpilot', or your car's dashboard (TSS2 Toyotas only).", "../assets/offroad/icon_speed_limit.png"},
|
||||||
|
{"Offset1", "Speed Limit Offset (0-34 mph)", "Speed limit offset for speed limits between 0-34 mph.", ""},
|
||||||
|
{"Offset2", "Speed Limit Offset (35-54 mph)", "Speed limit offset for speed limits between 35-54 mph.", ""},
|
||||||
|
{"Offset3", "Speed Limit Offset (55-64 mph)", "Speed limit offset for speed limits between 55-64 mph.", ""},
|
||||||
|
{"Offset4", "Speed Limit Offset (65-99 mph)", "Speed limit offset for speed limits between 65-99 mph.", ""},
|
||||||
|
{"SLCFallback", "Fallback Method", "Choose your fallback method for when there are no speed limits currently being obtained from Navigation, OSM, and the car's dashboard.", ""},
|
||||||
|
{"SLCOverride", "Override Method", "Choose your preferred method to override the current speed limit.", ""},
|
||||||
|
{"SLCPriority", "Priority Order", "Determine the priority order for what speed limits to use.", ""},
|
||||||
|
|
||||||
|
{"TurnDesires", "Use Turn Desires", "Use turn desires for enhanced precision in turns below the minimum lane change speed.", "../assets/navigation/direction_continue_right.png"},
|
||||||
|
|
||||||
|
{"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"},
|
||||||
|
{"CurveSensitivity", "Curve Detection Sensitivity", "Set curve detection sensitivity. Higher values prompt earlier responses, lower values lead to smoother but later reactions.", ""},
|
||||||
|
{"TurnAggressiveness", "Turn Speed Aggressiveness", "Set turn speed aggressiveness. Higher values result in faster turns, lower values yield gentler turns.", ""},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[param, title, desc, icon] : controlToggles) {
|
||||||
|
ParamControl *toggle;
|
||||||
|
|
||||||
|
if (param == "AdjustablePersonalities") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 3, {{0, "None"}, {1, "Steering Wheel"}, {2, "Onroad UI Button"}, {3, "Wheel + Button"}}, this, true);
|
||||||
|
|
||||||
|
} else if (param == "AlwaysOnLateral") {
|
||||||
|
std::vector<QString> aolToggles{"AlwaysOnLateralMain"};
|
||||||
|
std::vector<QString> aolToggleNames{tr("Enable On Cruise Main")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, aolToggles, aolToggleNames);
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamToggleControl*>(toggle), &FrogPilotParamToggleControl::buttonClicked, [this](const bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
FrogPilotConfirmationDialog::toggleAlert("WARNING: This is very experimental and isn't guaranteed to work. If you run into any issues, please report it in the FrogPilot Discord!",
|
||||||
|
"I understand the risks.", this);
|
||||||
|
}
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (param == "ConditionalExperimental") {
|
||||||
|
FrogPilotParamManageControl *conditionalExperimentalToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(conditionalExperimentalToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
conditionalSpeedsImperial->setVisible(!isMetric);
|
||||||
|
conditionalSpeedsMetric->setVisible(isMetric);
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = conditionalExperimentalToggle;
|
||||||
|
} else if (param == "CECurves") {
|
||||||
|
FrogPilotParamValueControl *CESpeedImperial = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 99,
|
||||||
|
std::map<int, QString>(), this, false, " mph");
|
||||||
|
FrogPilotParamValueControl *CESpeedLeadImperial = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 99,
|
||||||
|
std::map<int, QString>(), this, false, " mph");
|
||||||
|
conditionalSpeedsImperial = new FrogPilotDualParamControl(CESpeedImperial, CESpeedLeadImperial, this);
|
||||||
|
addItem(conditionalSpeedsImperial);
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *CESpeedMetric = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 150,
|
||||||
|
std::map<int, QString>(), this, false, " kph");
|
||||||
|
FrogPilotParamValueControl *CESpeedLeadMetric = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 150,
|
||||||
|
std::map<int, QString>(), this, false, " kph");
|
||||||
|
conditionalSpeedsMetric = new FrogPilotDualParamControl(CESpeedMetric, CESpeedLeadMetric, this);
|
||||||
|
addItem(conditionalSpeedsMetric);
|
||||||
|
|
||||||
|
std::vector<QString> curveToggles{"CECurvesLead"};
|
||||||
|
std::vector<QString> curveToggleNames{tr("With Lead")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, curveToggles, curveToggleNames);
|
||||||
|
} else if (param == "CEStopLights") {
|
||||||
|
std::vector<QString> stopLightToggles{"CEStopLightsLead"};
|
||||||
|
std::vector<QString> stopLightToggleNames{tr("With Lead")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, stopLightToggles, stopLightToggleNames);
|
||||||
|
|
||||||
|
} else if (param == "CustomPersonalities") {
|
||||||
|
FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(false);
|
||||||
|
}
|
||||||
|
aggressiveProfile->setVisible(true);
|
||||||
|
standardProfile->setVisible(true);
|
||||||
|
relaxedProfile->setVisible(true);
|
||||||
|
});
|
||||||
|
toggle = customPersonalitiesToggle;
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *aggressiveFollow = new FrogPilotParamValueControl("AggressiveFollow", "Follow",
|
||||||
|
"Set the 'Aggressive' personality' following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.25 seconds.", "../frogpilot/assets/other_images/aggressive.png",
|
||||||
|
10, 50, std::map<int, QString>(), this, false, " sec", 10);
|
||||||
|
FrogPilotParamValueControl *aggressiveJerk = new FrogPilotParamValueControl("AggressiveJerk", " Jerk",
|
||||||
|
"Configure brake/gas pedal responsiveness for the 'Aggressive' personality. Higher values yield a more 'relaxed' response.\n\nStock: 0.5.", "", 1, 50,
|
||||||
|
std::map<int, QString>(), this, false, "", 10);
|
||||||
|
aggressiveProfile = new FrogPilotDualParamControl(aggressiveFollow, aggressiveJerk, this, true);
|
||||||
|
addItem(aggressiveProfile);
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *standardFollow = new FrogPilotParamValueControl("StandardFollow", "Follow",
|
||||||
|
"Set the 'Standard' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.45 seconds.", "../frogpilot/assets/other_images/standard.png",
|
||||||
|
10, 50, std::map<int, QString>(), this, false, " sec", 10);
|
||||||
|
FrogPilotParamValueControl *standardJerk = new FrogPilotParamValueControl("StandardJerk", " Jerk",
|
||||||
|
"Adjust brake/gas pedal responsiveness for the 'Standard' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50,
|
||||||
|
std::map<int, QString>(), this, false, "", 10);
|
||||||
|
standardProfile = new FrogPilotDualParamControl(standardFollow, standardJerk, this, true);
|
||||||
|
addItem(standardProfile);
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *relaxedFollow = new FrogPilotParamValueControl("RelaxedFollow", "Follow",
|
||||||
|
"Set the 'Relaxed' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.75 seconds.", "../frogpilot/assets/other_images/relaxed.png",
|
||||||
|
10, 50, std::map<int, QString>(), this, false, " sec", 10);
|
||||||
|
FrogPilotParamValueControl *relaxedJerk = new FrogPilotParamValueControl("RelaxedJerk", " Jerk",
|
||||||
|
"Set brake/gas pedal responsiveness for the 'Relaxed' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50,
|
||||||
|
std::map<int, QString>(), this, false, "", 10);
|
||||||
|
relaxedProfile = new FrogPilotDualParamControl(relaxedFollow, relaxedJerk, this, true);
|
||||||
|
addItem(relaxedProfile);
|
||||||
|
|
||||||
|
} else if (param == "DeviceShutdown") {
|
||||||
|
std::map<int, QString> shutdownLabels;
|
||||||
|
for (int i = 0; i <= 33; ++i) {
|
||||||
|
shutdownLabels[i] = i == 0 ? "Instant" : i <= 3 ? QString::number(i * 15) + " mins" : QString::number(i - 3) + (i == 4 ? " hour" : " hours");
|
||||||
|
}
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, shutdownLabels, this, false);
|
||||||
|
|
||||||
|
} else if (param == "ExperimentalModeActivation") {
|
||||||
|
std::vector<QString> experimentalModeToggles{"ExperimentalModeViaLKAS", "ExperimentalModeViaScreen"};
|
||||||
|
std::vector<QString> experimentalModeNames{tr("LKAS Button"), tr("Screen")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, experimentalModeToggles, experimentalModeNames);
|
||||||
|
|
||||||
|
} else if (param == "FireTheBabysitter") {
|
||||||
|
FrogPilotParamManageControl *fireTheBabysitterToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(fireTheBabysitterToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = fireTheBabysitterToggle;
|
||||||
|
|
||||||
|
} else if (param == "LateralTune") {
|
||||||
|
FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = lateralTuneToggle;
|
||||||
|
} else if (param == "SteerRatio") {
|
||||||
|
toggle = new FrogPilotParamValueControlFloat(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, std::map<int, QString>(), this, false, "", 10.0);
|
||||||
|
|
||||||
|
} else if (param == "LongitudinalTune") {
|
||||||
|
FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = longitudinalTuneToggle;
|
||||||
|
} else if (param == "AccelerationProfile") {
|
||||||
|
std::vector<QString> profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")};
|
||||||
|
FrogPilotButtonParamControl *profileSelection = new FrogPilotButtonParamControl(param, title, desc, icon, profileOptions);
|
||||||
|
toggle = profileSelection;
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 3) {
|
||||||
|
FrogPilotConfirmationDialog::toggleAlert("WARNING: This maxes out openpilot's acceleration from 2.0 m/s to 4.0 m/s and may cause oscillations when accelerating!",
|
||||||
|
"I understand the risks.", this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (param == "StoppingDistance") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, std::map<int, QString>(), this, false, " feet");
|
||||||
|
|
||||||
|
} else if (param == "Model") {
|
||||||
|
modelSelectorButton = new FrogPilotButtonIconControl(title, tr("SELECT"), desc, icon);
|
||||||
|
QStringList models = {"New Delhi (Default)", "Blue Diamond V1", "Blue Diamond V2", "Farmville", "New Lemon Pie"};
|
||||||
|
QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models]() {
|
||||||
|
int currentModel = params.getInt("Model");
|
||||||
|
QString currentModelLabel = models[currentModel];
|
||||||
|
|
||||||
|
QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), models, currentModelLabel, this);
|
||||||
|
if (!selection.isEmpty()) {
|
||||||
|
int selectedModel = models.indexOf(selection);
|
||||||
|
params.putInt("Model", selectedModel);
|
||||||
|
params.remove("CalibrationParams");
|
||||||
|
params.remove("LiveTorqueParameters");
|
||||||
|
modelSelectorButton->setValue(selection);
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
modelSelectorButton->setValue(models[params.getInt("Model")]);
|
||||||
|
addItem(modelSelectorButton);
|
||||||
|
|
||||||
|
} else if (param == "NudgelessLaneChange") {
|
||||||
|
FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(laneChangeKeys.find(key.c_str()) != laneChangeKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = laneChangeToggle;
|
||||||
|
} else if (param == "LaneChangeTime") {
|
||||||
|
std::map<int, QString> laneChangeTimeLabels;
|
||||||
|
for (int i = 0; i <= 10; ++i) {
|
||||||
|
laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds";
|
||||||
|
}
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, laneChangeTimeLabels, this, false);
|
||||||
|
|
||||||
|
} else if (param == "QOLControls") {
|
||||||
|
FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = qolToggle;
|
||||||
|
} else if (param == "PauseLateralOnSignal") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map<int, QString>(), this, false, " mph");
|
||||||
|
} else if (param == "SetSpeedOffset") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map<int, QString>(), this, false, " mph");
|
||||||
|
|
||||||
|
} else if (param == "SpeedLimitController") {
|
||||||
|
FrogPilotParamManageControl *speedLimitControllerToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(speedLimitControllerToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end());
|
||||||
|
}
|
||||||
|
slscPriorityButton->setVisible(true);
|
||||||
|
});
|
||||||
|
toggle = speedLimitControllerToggle;
|
||||||
|
} else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map<int, QString>(), this, false, " mph");
|
||||||
|
} else if (param == "SLCFallback") {
|
||||||
|
std::vector<QString> fallbackOptions{tr("None"), tr("Experimental Mode"), tr("Previous Limit")};
|
||||||
|
FrogPilotButtonParamControl *fallbackSelection = new FrogPilotButtonParamControl(param, title, desc, icon, fallbackOptions);
|
||||||
|
toggle = fallbackSelection;
|
||||||
|
} else if (param == "SLCOverride") {
|
||||||
|
std::vector<QString> overrideOptions{tr("None"), tr("Manual Set Speed"), tr("Max Set Speed")};
|
||||||
|
FrogPilotButtonParamControl *overrideSelection = new FrogPilotButtonParamControl(param, title, desc, icon, overrideOptions);
|
||||||
|
toggle = overrideSelection;
|
||||||
|
} else if (param == "SLCPriority") {
|
||||||
|
const QStringList priorities {
|
||||||
|
"Navigation, Dashboard, Offline Maps",
|
||||||
|
"Navigation, Offline Maps, Dashboard",
|
||||||
|
"Navigation, Offline Maps",
|
||||||
|
"Navigation, Dashboard",
|
||||||
|
"Navigation",
|
||||||
|
"Offline Maps, Dashboard, Navigation",
|
||||||
|
"Offline Maps, Navigation, Dashboard",
|
||||||
|
"Offline Maps, Navigation",
|
||||||
|
"Offline Maps, Dashboard",
|
||||||
|
"Offline Maps",
|
||||||
|
"Dashboard, Navigation, Offline Maps",
|
||||||
|
"Dashboard, Offline Maps, Navigation",
|
||||||
|
"Dashboard, Offline Maps",
|
||||||
|
"Dashboard, Navigation",
|
||||||
|
"Dashboard",
|
||||||
|
"Highest",
|
||||||
|
"Lowest",
|
||||||
|
"",
|
||||||
|
};
|
||||||
|
|
||||||
|
slscPriorityButton = new ButtonControl(title, tr("SELECT"), desc);
|
||||||
|
QObject::connect(slscPriorityButton, &ButtonControl::clicked, this, [this, priorities]() {
|
||||||
|
QStringList availablePriorities = {"Dashboard", "Navigation", "Offline Maps", "Highest", "Lowest", "None"};
|
||||||
|
QStringList selectedPriorities;
|
||||||
|
int priorityValue = -1;
|
||||||
|
|
||||||
|
QStringList priorityPrompts = {tr("Select your primary priority"), tr("Select your secondary priority"), tr("Select your tertiary priority")};
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
QString selection = MultiOptionDialog::getSelection(priorityPrompts[i], availablePriorities, "", this);
|
||||||
|
if (selection.isEmpty()) break;
|
||||||
|
|
||||||
|
if (selection == "None") {
|
||||||
|
priorityValue = 17;
|
||||||
|
break;
|
||||||
|
} else if (selection == "Highest") {
|
||||||
|
priorityValue = 15;
|
||||||
|
break;
|
||||||
|
} else if (selection == "Lowest") {
|
||||||
|
priorityValue = 16;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
selectedPriorities.append(selection);
|
||||||
|
availablePriorities.removeAll(selection);
|
||||||
|
availablePriorities.removeAll("Highest");
|
||||||
|
availablePriorities.removeAll("Lowest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priorityValue == -1 && !selectedPriorities.isEmpty()) {
|
||||||
|
QString priorityString = selectedPriorities.join(", ");
|
||||||
|
priorityValue = priorities.indexOf(priorityString);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priorityValue != -1) {
|
||||||
|
slscPriorityButton->setValue(priorities[priorityValue]);
|
||||||
|
params.putInt("SLCPriority", priorityValue);
|
||||||
|
updateToggles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
slscPriorityButton->setValue(priorities[params.getInt("SLCPriority")]);
|
||||||
|
addItem(slscPriorityButton);
|
||||||
|
|
||||||
|
} else if (param == "VisionTurnControl") {
|
||||||
|
FrogPilotParamManageControl *visionTurnControlToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(visionTurnControlToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = visionTurnControlToggle;
|
||||||
|
} else if (param == "CurveSensitivity" || param == "TurnAggressiveness") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 200, std::map<int, QString>(), this, false, "%");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
toggle = new ParamControl(param, title, desc, icon, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem(toggle);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
|
||||||
|
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> rebootKeys = {"AlwaysOnLateral", "FireTheBabysitter", "HigherBitrate", "MuteDM", "NNFF"};
|
||||||
|
for (const std::string &key : rebootKeys) {
|
||||||
|
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CESlowerLead", "CENavigation", "CEStopLights", "CESignal"};
|
||||||
|
fireTheBabysitterKeys = {"NoLogging", "MuteDM", "MuteDoor", "MuteOverheated", "MuteSeatbelt", "OfflineMode"};
|
||||||
|
laneChangeKeys = {"LaneChangeTime", "LaneDetection", "OneLaneChange"};
|
||||||
|
lateralTuneKeys = {"AverageCurvature", "NNFF", "SteerRatio"};
|
||||||
|
longitudinalTuneKeys = {"AccelerationProfile", "AggressiveAcceleration", "SmoothBraking", "StoppingDistance"};
|
||||||
|
mtscKeys = {"MTSCAggressiveness"};
|
||||||
|
qolKeys = {"DisableOnroadUploads", "HigherBitrate", "PauseLateralOnSignal", "ReverseCruise", "SetSpeedOffset"};
|
||||||
|
speedLimitControllerKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "SLCFallback", "SLCOverride", "SLCPriority"};
|
||||||
|
visionTurnControlKeys = {"CurveSensitivity", "TurnAggressiveness"};
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) {
|
||||||
|
if (!offroad) {
|
||||||
|
updateCarToggles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles);
|
||||||
|
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles);
|
||||||
|
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric);
|
||||||
|
|
||||||
|
hideSubToggles();
|
||||||
|
updateMetric();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::updateCarToggles() {
|
||||||
|
FrogPilotParamValueControlFloat *steerRatioToggle = static_cast<FrogPilotParamValueControlFloat*>(toggles["SteerRatio"]);
|
||||||
|
steerRatioStock = params.getFloat("SteerRatioStock");
|
||||||
|
steerRatioToggle->setTitle(steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : QString("Steer Ratio"));
|
||||||
|
steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25, "", 10.0);
|
||||||
|
steerRatioToggle->refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::updateToggles() {
|
||||||
|
std::thread([this]() {
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::updateMetric() {
|
||||||
|
bool previousIsMetric = isMetric;
|
||||||
|
isMetric = params.getBool("IsMetric");
|
||||||
|
|
||||||
|
if (isMetric != previousIsMetric) {
|
||||||
|
double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
|
||||||
|
double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE;
|
||||||
|
params.putInt("CESpeed", std::nearbyint(params.getInt("CESpeed") * speedConversion));
|
||||||
|
params.putInt("CESpeedLead", std::nearbyint(params.getInt("CESpeedLead") * speedConversion));
|
||||||
|
params.putInt("Offset1", std::nearbyint(params.getInt("Offset1") * speedConversion));
|
||||||
|
params.putInt("Offset2", std::nearbyint(params.getInt("Offset2") * speedConversion));
|
||||||
|
params.putInt("Offset3", std::nearbyint(params.getInt("Offset3") * speedConversion));
|
||||||
|
params.putInt("Offset4", std::nearbyint(params.getInt("Offset4") * speedConversion));
|
||||||
|
params.putInt("PauseLateralOnSignal", std::nearbyint(params.getInt("PauseLateralOnSignal") * speedConversion));
|
||||||
|
params.putInt("SetSpeedOffset", std::nearbyint(params.getInt("SetSpeedOffset") * speedConversion));
|
||||||
|
params.putInt("StoppingDistance", std::nearbyint(params.getInt("StoppingDistance") * distanceConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *offset1Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset1"]);
|
||||||
|
FrogPilotParamValueControl *offset2Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset2"]);
|
||||||
|
FrogPilotParamValueControl *offset3Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset3"]);
|
||||||
|
FrogPilotParamValueControl *offset4Toggle = static_cast<FrogPilotParamValueControl*>(toggles["Offset4"]);
|
||||||
|
FrogPilotParamValueControl *pauseLateralToggle = static_cast<FrogPilotParamValueControl*>(toggles["PauseLateralOnSignal"]);
|
||||||
|
FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast<FrogPilotParamValueControl*>(toggles["SetSpeedOffset"]);
|
||||||
|
FrogPilotParamValueControl *stoppingDistanceToggle = static_cast<FrogPilotParamValueControl*>(toggles["StoppingDistance"]);
|
||||||
|
|
||||||
|
if (isMetric) {
|
||||||
|
offset1Toggle->setTitle("Speed Limit Offset (0-34 kph)");
|
||||||
|
offset2Toggle->setTitle("Speed Limit Offset (35-54 kph)");
|
||||||
|
offset3Toggle->setTitle("Speed Limit Offset (55-64 kph)");
|
||||||
|
offset4Toggle->setTitle("Speed Limit Offset (65-99 kph)");
|
||||||
|
|
||||||
|
offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 kph.");
|
||||||
|
offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 kph.");
|
||||||
|
offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 kph.");
|
||||||
|
offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 kph.");
|
||||||
|
|
||||||
|
offset1Toggle->updateControl(0, 150, " kph");
|
||||||
|
offset2Toggle->updateControl(0, 150, " kph");
|
||||||
|
offset3Toggle->updateControl(0, 150, " kph");
|
||||||
|
offset4Toggle->updateControl(0, 150, " kph");
|
||||||
|
pauseLateralToggle->updateControl(0, 150, " kph");
|
||||||
|
setSpeedOffsetToggle->updateControl(0, 150, " kph");
|
||||||
|
stoppingDistanceToggle->updateControl(0, 5, " meters");
|
||||||
|
} else {
|
||||||
|
offset1Toggle->setTitle("Speed Limit Offset (0-34 mph)");
|
||||||
|
offset2Toggle->setTitle("Speed Limit Offset (35-54 mph)");
|
||||||
|
offset3Toggle->setTitle("Speed Limit Offset (55-64 mph)");
|
||||||
|
offset4Toggle->setTitle("Speed Limit Offset (65-99 mph)");
|
||||||
|
|
||||||
|
offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 mph.");
|
||||||
|
offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 mph.");
|
||||||
|
offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 mph.");
|
||||||
|
offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 mph.");
|
||||||
|
|
||||||
|
offset1Toggle->updateControl(0, 99, " mph");
|
||||||
|
offset2Toggle->updateControl(0, 99, " mph");
|
||||||
|
offset3Toggle->updateControl(0, 99, " mph");
|
||||||
|
offset4Toggle->updateControl(0, 99, " mph");
|
||||||
|
pauseLateralToggle->updateControl(0, 99, " mph");
|
||||||
|
setSpeedOffsetToggle->updateControl(0, 99, " mph");
|
||||||
|
stoppingDistanceToggle->updateControl(0, 10, " feet");
|
||||||
|
}
|
||||||
|
|
||||||
|
offset1Toggle->refresh();
|
||||||
|
offset2Toggle->refresh();
|
||||||
|
offset3Toggle->refresh();
|
||||||
|
offset4Toggle->refresh();
|
||||||
|
pauseLateralToggle->refresh();
|
||||||
|
setSpeedOffsetToggle->refresh();
|
||||||
|
stoppingDistanceToggle->refresh();
|
||||||
|
|
||||||
|
previousIsMetric = isMetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::parentToggleClicked() {
|
||||||
|
aggressiveProfile->setVisible(false);
|
||||||
|
conditionalSpeedsImperial->setVisible(false);
|
||||||
|
conditionalSpeedsMetric->setVisible(false);
|
||||||
|
modelSelectorButton->setVisible(false);
|
||||||
|
slscPriorityButton->setVisible(false);
|
||||||
|
standardProfile->setVisible(false);
|
||||||
|
relaxedProfile->setVisible(false);
|
||||||
|
|
||||||
|
this->openParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::hideSubToggles() {
|
||||||
|
aggressiveProfile->setVisible(false);
|
||||||
|
conditionalSpeedsImperial->setVisible(false);
|
||||||
|
conditionalSpeedsMetric->setVisible(false);
|
||||||
|
modelSelectorButton->setVisible(true);
|
||||||
|
slscPriorityButton->setVisible(false);
|
||||||
|
standardProfile->setVisible(false);
|
||||||
|
relaxedProfile->setVisible(false);
|
||||||
|
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
bool subToggles = conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() ||
|
||||||
|
fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end() ||
|
||||||
|
laneChangeKeys.find(key.c_str()) != laneChangeKeys.end() ||
|
||||||
|
lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end() ||
|
||||||
|
longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end() ||
|
||||||
|
mtscKeys.find(key.c_str()) != mtscKeys.end() ||
|
||||||
|
qolKeys.find(key.c_str()) != qolKeys.end() ||
|
||||||
|
speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end() ||
|
||||||
|
visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end();
|
||||||
|
toggle->setVisible(!subToggles);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->closeParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotControlsPanel::hideEvent(QHideEvent *event) {
|
||||||
|
hideSubToggles();
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
#include "selfdrive/oscarpilot/settings/settings.h"
|
||||||
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ class FrogPilotControlsPanel : public FrogPilotListWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FrogPilotControlsPanel(SettingsWindow *parent);
|
explicit FrogPilotControlsPanel(OscarSettingsWindow *parent);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void closeParentToggle();
|
void closeParentToggle();
|
||||||
|
|||||||
53
selfdrive/frogpilot/ui/control_settings.h.org
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
|
|
||||||
|
class FrogPilotControlsPanel : public FrogPilotListWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FrogPilotControlsPanel(SettingsWindow *parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeParentToggle();
|
||||||
|
void openParentToggle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void hideEvent(QHideEvent *event);
|
||||||
|
void hideSubToggles();
|
||||||
|
void parentToggleClicked();
|
||||||
|
void updateCarToggles();
|
||||||
|
void updateMetric();
|
||||||
|
void updateToggles();
|
||||||
|
|
||||||
|
ButtonControl *slscPriorityButton;
|
||||||
|
|
||||||
|
FrogPilotButtonIconControl *modelSelectorButton;
|
||||||
|
|
||||||
|
FrogPilotDualParamControl *aggressiveProfile;
|
||||||
|
FrogPilotDualParamControl *conditionalSpeedsImperial;
|
||||||
|
FrogPilotDualParamControl *conditionalSpeedsMetric;
|
||||||
|
FrogPilotDualParamControl *standardProfile;
|
||||||
|
FrogPilotDualParamControl *relaxedProfile;
|
||||||
|
|
||||||
|
std::set<QString> conditionalExperimentalKeys;
|
||||||
|
std::set<QString> fireTheBabysitterKeys;
|
||||||
|
std::set<QString> laneChangeKeys;
|
||||||
|
std::set<QString> lateralTuneKeys;
|
||||||
|
std::set<QString> longitudinalTuneKeys;
|
||||||
|
std::set<QString> mtscKeys;
|
||||||
|
std::set<QString> qolKeys;
|
||||||
|
std::set<QString> speedLimitControllerKeys;
|
||||||
|
std::set<QString> visionTurnControlKeys;
|
||||||
|
|
||||||
|
std::map<std::string, ParamControl*> toggles;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
Params paramsMemory{"/dev/shm/params"};
|
||||||
|
|
||||||
|
bool isMetric = params.getBool("IsMetric");
|
||||||
|
float steerRatioStock = params.getFloat("SteerRatioStock");
|
||||||
|
};
|
||||||
@@ -45,13 +45,13 @@ void setDefaultParams() {
|
|||||||
Params params = Params();
|
Params params = Params();
|
||||||
bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6";
|
bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6";
|
||||||
|
|
||||||
bool brianbot = true;
|
bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71";
|
||||||
|
|
||||||
std::map<std::string, std::string> defaultValues {
|
std::map<std::string, std::string> defaultValues {
|
||||||
{"AccelerationPath", brianbot ? "1" : "0"},
|
{"AccelerationPath", brianbot ? "1" : "0"},
|
||||||
{"AccelerationProfile", brianbot ? "2" : "2"},
|
{"AccelerationProfile", brianbot ? "2" : "2"},
|
||||||
{"AdjacentPath", FrogsGoMoo ? "1" : "0"},
|
{"AdjacentPath", FrogsGoMoo ? "1" : "0"},
|
||||||
{"AdjustablePersonalities", "3"},
|
{"AdjustablePersonalities", "0"},
|
||||||
{"AggressiveAcceleration", "1"},
|
{"AggressiveAcceleration", "1"},
|
||||||
{"AggressiveFollow", FrogsGoMoo ? "10" : "12"},
|
{"AggressiveFollow", FrogsGoMoo ? "10" : "12"},
|
||||||
{"AggressiveJerk", FrogsGoMoo ? "6" : "5"},
|
{"AggressiveJerk", FrogsGoMoo ? "6" : "5"},
|
||||||
@@ -67,8 +67,8 @@ void setDefaultParams() {
|
|||||||
{"CESlowerLead", "0"},
|
{"CESlowerLead", "0"},
|
||||||
{"CESpeed", "0"},
|
{"CESpeed", "0"},
|
||||||
{"CESpeedLead", "0"},
|
{"CESpeedLead", "0"},
|
||||||
{"CEStopLights", "1"},
|
{"CEStopLights", "0"},
|
||||||
{"CEStopLightsLead", FrogsGoMoo ? "0" : "1"},
|
{"CEStopLightsLead", FrogsGoMoo ? "0" : "0"},
|
||||||
{"Compass", FrogsGoMoo ? "1" : "0"},
|
{"Compass", FrogsGoMoo ? "1" : "0"},
|
||||||
{"ConditionalExperimental", "1"},
|
{"ConditionalExperimental", "1"},
|
||||||
{"CurveSensitivity", FrogsGoMoo ? "125" : "100"},
|
{"CurveSensitivity", FrogsGoMoo ? "125" : "100"},
|
||||||
@@ -80,6 +80,7 @@ void setDefaultParams() {
|
|||||||
{"CustomTheme", "1"},
|
{"CustomTheme", "1"},
|
||||||
{"CustomUI", "0"},
|
{"CustomUI", "0"},
|
||||||
{"DeviceShutdown", "1"},
|
{"DeviceShutdown", "1"},
|
||||||
|
{"DisableOnroadUploads", "1"},
|
||||||
{"DriverCamera", "0"},
|
{"DriverCamera", "0"},
|
||||||
{"DriveStats", "1"},
|
{"DriveStats", "1"},
|
||||||
{"EVTable", FrogsGoMoo ? "0" : "1"},
|
{"EVTable", FrogsGoMoo ? "0" : "1"},
|
||||||
@@ -114,14 +115,14 @@ void setDefaultParams() {
|
|||||||
{"NoLogging", "1"},
|
{"NoLogging", "1"},
|
||||||
{"NudgelessLaneChange", "0"},
|
{"NudgelessLaneChange", "0"},
|
||||||
{"NumericalTemp", FrogsGoMoo ? "1" : "0"},
|
{"NumericalTemp", FrogsGoMoo ? "1" : "0"},
|
||||||
{"Offset1", "5"},
|
{"Offset1", "3"},
|
||||||
{"Offset2", FrogsGoMoo ? "7" : "5"},
|
{"Offset2", FrogsGoMoo ? "7" : "5"},
|
||||||
{"Offset3", "5"},
|
{"Offset3", "7"},
|
||||||
{"Offset4", FrogsGoMoo ? "20" : "10"},
|
{"Offset4", FrogsGoMoo ? "20" : "7"},
|
||||||
{"OneLaneChange", "1"},
|
{"OneLaneChange", "1"},
|
||||||
{"PathEdgeWidth", "20"},
|
{"PathEdgeWidth", "20"},
|
||||||
{"PathWidth", "61"},
|
{"PathWidth", "61"},
|
||||||
{"PauseLateralOnSignal", "0"},
|
{"PauseLateralOnSignal", "20"},
|
||||||
{"PreferredSchedule", "0"},
|
{"PreferredSchedule", "0"},
|
||||||
{"QOLControls", "1"},
|
{"QOLControls", "1"},
|
||||||
{"QOLVisuals", "1"},
|
{"QOLVisuals", "1"},
|
||||||
@@ -150,8 +151,8 @@ void setDefaultParams() {
|
|||||||
{"StandardJerk", "10"},
|
{"StandardJerk", "10"},
|
||||||
{"StoppingDistance", FrogsGoMoo ? "6" : "0"},
|
{"StoppingDistance", FrogsGoMoo ? "6" : "0"},
|
||||||
{"TSS2Tune", "1"},
|
{"TSS2Tune", "1"},
|
||||||
{"TurnAggressiveness", FrogsGoMoo ? "150" : "100"},
|
{"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90?
|
||||||
{"TurnDesires", "1"},
|
{"TurnDesires", "0"},
|
||||||
{"UnlimitedLength", "1"},
|
{"UnlimitedLength", "1"},
|
||||||
{"UseSI", FrogsGoMoo ? "1" : "0"},
|
{"UseSI", FrogsGoMoo ? "1" : "0"},
|
||||||
{"UseVienna", "0"},
|
{"UseVienna", "0"},
|
||||||
|
|||||||
177
selfdrive/frogpilot/ui/frogpilot_functions.cc.org
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) {
|
||||||
|
btn.setText(text);
|
||||||
|
btn.setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 35px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
btn.setFixedSize(250, 100);
|
||||||
|
QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked);
|
||||||
|
hlayout->addWidget(&btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDefaultParams() {
|
||||||
|
Params params = Params();
|
||||||
|
bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6";
|
||||||
|
|
||||||
|
bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71";
|
||||||
|
|
||||||
|
std::map<std::string, std::string> defaultValues {
|
||||||
|
{"AccelerationPath", brianbot ? "1" : "0"},
|
||||||
|
{"AccelerationProfile", brianbot ? "2" : "2"},
|
||||||
|
{"AdjacentPath", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"AdjustablePersonalities", "0"},
|
||||||
|
{"AggressiveAcceleration", "1"},
|
||||||
|
{"AggressiveFollow", FrogsGoMoo ? "10" : "12"},
|
||||||
|
{"AggressiveJerk", FrogsGoMoo ? "6" : "5"},
|
||||||
|
{"AlwaysOnLateral", "1"},
|
||||||
|
{"AlwaysOnLateralMain", brianbot ? "1" : "0"},
|
||||||
|
{"AverageCurvature", brianbot ? "1" : "0"},
|
||||||
|
{"BlindSpotPath", "1"},
|
||||||
|
{"CameraView", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"CECurves", "1"},
|
||||||
|
{"CECurvesLead", "0"},
|
||||||
|
{"CENavigation", "1"},
|
||||||
|
{"CESignal", "1"},
|
||||||
|
{"CESlowerLead", "0"},
|
||||||
|
{"CESpeed", "0"},
|
||||||
|
{"CESpeedLead", "0"},
|
||||||
|
{"CEStopLights", "0"},
|
||||||
|
{"CEStopLightsLead", FrogsGoMoo ? "0" : "0"},
|
||||||
|
{"Compass", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ConditionalExperimental", "1"},
|
||||||
|
{"CurveSensitivity", FrogsGoMoo ? "125" : "100"},
|
||||||
|
{"CustomColors", "1"},
|
||||||
|
{"CustomIcons", "1"},
|
||||||
|
{"CustomPersonalities", "0"},
|
||||||
|
{"CustomSignals", "0"},
|
||||||
|
{"CustomSounds", "1"},
|
||||||
|
{"CustomTheme", "1"},
|
||||||
|
{"CustomUI", "0"},
|
||||||
|
{"DeviceShutdown", "1"},
|
||||||
|
{"DisableOnroadUploads", "1"},
|
||||||
|
{"DriverCamera", "0"},
|
||||||
|
{"DriveStats", "1"},
|
||||||
|
{"EVTable", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"ExperimentalModeActivation", "1"},
|
||||||
|
{"ExperimentalModeViaLKAS", "0"},
|
||||||
|
{"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"Fahrenheit", "0"},
|
||||||
|
{"FireTheBabysitter", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"FullMap", "0"},
|
||||||
|
{"GasRegenCmd", "0"},
|
||||||
|
{"GoatScream", "0"},
|
||||||
|
{"GreenLightAlert", "0"},
|
||||||
|
{"HideSpeed", "0"},
|
||||||
|
{"HigherBitrate", "0"},
|
||||||
|
{"LaneChangeTime", "0"},
|
||||||
|
{"LaneDetection", "1"},
|
||||||
|
{"LaneLinesWidth", "4"},
|
||||||
|
{"LateralTune", "1"},
|
||||||
|
{"LeadInfo", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"LockDoors", "0"},
|
||||||
|
{"LongitudinalTune", "1"},
|
||||||
|
{"LongPitch", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"LowerVolt", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"Model", "3"},
|
||||||
|
{"ModelUI", "1"},
|
||||||
|
{"MTSCEnabled", "1"},
|
||||||
|
{"MuteDM", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"MuteDoor", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"MuteOverheated", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"MuteSeatbelt", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"NNFF", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"NoLogging", "1"},
|
||||||
|
{"NudgelessLaneChange", "0"},
|
||||||
|
{"NumericalTemp", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"Offset1", "3"},
|
||||||
|
{"Offset2", FrogsGoMoo ? "7" : "5"},
|
||||||
|
{"Offset3", "7"},
|
||||||
|
{"Offset4", FrogsGoMoo ? "20" : "7"},
|
||||||
|
{"OneLaneChange", "1"},
|
||||||
|
{"PathEdgeWidth", "20"},
|
||||||
|
{"PathWidth", "61"},
|
||||||
|
{"PauseLateralOnSignal", "20"},
|
||||||
|
{"PreferredSchedule", "0"},
|
||||||
|
{"QOLControls", "1"},
|
||||||
|
{"QOLVisuals", "1"},
|
||||||
|
{"RandomEvents", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"RelaxedFollow", "30"},
|
||||||
|
{"RelaxedJerk", "50"},
|
||||||
|
{"ReverseCruise", "0"},
|
||||||
|
{"RoadEdgesWidth", "2"},
|
||||||
|
{"RoadNameUI", "1"},
|
||||||
|
{"RotatingWheel", "1"},
|
||||||
|
{"ScreenBrightness", "101"},
|
||||||
|
{"SearchInput", "0"},
|
||||||
|
{"ShowCPU", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ShowFPS", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ShowGPU", "0"},
|
||||||
|
{"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"Sidebar", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"SilentMode", "0"},
|
||||||
|
{"SLCFallback", "2"},
|
||||||
|
{"SLCOverride", FrogsGoMoo ? "2" : "1"},
|
||||||
|
{"SLCPriority", "1"},
|
||||||
|
{"SmoothBraking", "1"},
|
||||||
|
{"SNGHack", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"SpeedLimitController", "1"},
|
||||||
|
{"StandardFollow", "15"},
|
||||||
|
{"StandardJerk", "10"},
|
||||||
|
{"StoppingDistance", FrogsGoMoo ? "6" : "0"},
|
||||||
|
{"TSS2Tune", "1"},
|
||||||
|
{"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90?
|
||||||
|
{"TurnDesires", "0"},
|
||||||
|
{"UnlimitedLength", "1"},
|
||||||
|
{"UseSI", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"UseVienna", "0"},
|
||||||
|
{"VisionTurnControl", "1"},
|
||||||
|
{"WheelIcon", FrogsGoMoo ? "1" : "0"}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool rebootRequired = false;
|
||||||
|
for (const auto &[key, value] : defaultValues) {
|
||||||
|
if (params.get(key).empty()) {
|
||||||
|
params.put(key, value);
|
||||||
|
rebootRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rebootRequired) {
|
||||||
|
while (!std::filesystem::exists("/data/openpilot/prebuilt")) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ public:
|
|||||||
background-color: #4a4a4a;
|
background-color: #4a4a4a;
|
||||||
}
|
}
|
||||||
QPushButton:checked:enabled {
|
QPushButton:checked:enabled {
|
||||||
background-color: #33Ab4C;
|
background-color: #0048FF;
|
||||||
}
|
}
|
||||||
QPushButton:disabled {
|
QPushButton:disabled {
|
||||||
color: #33E4E4E4;
|
color: #33E4E4E4;
|
||||||
@@ -202,7 +202,7 @@ public:
|
|||||||
background-color: #4a4a4a;
|
background-color: #4a4a4a;
|
||||||
}
|
}
|
||||||
QPushButton:checked:enabled {
|
QPushButton:checked:enabled {
|
||||||
background-color: #33Ab4C;
|
background-color: #0048FF;
|
||||||
}
|
}
|
||||||
QPushButton:disabled {
|
QPushButton:disabled {
|
||||||
color: #33E4E4E4;
|
color: #33E4E4E4;
|
||||||
@@ -523,7 +523,7 @@ public:
|
|||||||
background-color: #4a4a4a;
|
background-color: #4a4a4a;
|
||||||
}
|
}
|
||||||
QPushButton:checked:enabled {
|
QPushButton:checked:enabled {
|
||||||
background-color: #33Ab4C;
|
background-color: #0048FF;
|
||||||
}
|
}
|
||||||
QPushButton:disabled {
|
QPushButton:disabled {
|
||||||
color: #33E4E4E4;
|
color: #33E4E4E4;
|
||||||
|
|||||||
661
selfdrive/frogpilot/ui/frogpilot_functions.h.org
Normal file
@@ -0,0 +1,661 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||||
|
|
||||||
|
class FrogPilotConfirmationDialog : public ConfirmationDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FrogPilotConfirmationDialog(const QString &prompt_text, const QString &confirm_text,
|
||||||
|
const QString &cancel_text, const bool rich, QWidget* parent);
|
||||||
|
static bool toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent);
|
||||||
|
static bool toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent);
|
||||||
|
static bool yesorno(const QString &prompt_text, QWidget *parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotListWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FrogPilotListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) {
|
||||||
|
outer_layout.setMargin(0);
|
||||||
|
outer_layout.setSpacing(0);
|
||||||
|
outer_layout.addLayout(&inner_layout);
|
||||||
|
inner_layout.setMargin(0);
|
||||||
|
inner_layout.setSpacing(25); // default spacing is 25
|
||||||
|
outer_layout.addStretch();
|
||||||
|
}
|
||||||
|
inline void addItem(QWidget *w) { inner_layout.addWidget(w); }
|
||||||
|
inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); }
|
||||||
|
inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *) override {
|
||||||
|
QPainter p(this);
|
||||||
|
p.setPen(Qt::gray);
|
||||||
|
|
||||||
|
int visibleWidgetCount = 0;
|
||||||
|
std::vector<QRect> visibleRects;
|
||||||
|
|
||||||
|
for (int i = 0; i < inner_layout.count(); ++i) {
|
||||||
|
QWidget *widget = inner_layout.itemAt(i)->widget();
|
||||||
|
if (widget && widget->isVisible()) {
|
||||||
|
visibleWidgetCount++;
|
||||||
|
visibleRects.push_back(inner_layout.itemAt(i)->geometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < visibleWidgetCount - 1; ++i) {
|
||||||
|
int bottom = visibleRects[i].bottom() + inner_layout.spacing() / 2;
|
||||||
|
p.drawLine(visibleRects[i].left() + 40, bottom, visibleRects[i].right() - 40, bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QVBoxLayout outer_layout;
|
||||||
|
QVBoxLayout inner_layout;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotButtonIconControl : public AbstractControl {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr);
|
||||||
|
inline void setText(const QString &text) { btn.setText(text); }
|
||||||
|
inline QString text() const { return btn.text(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void clicked();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setEnabled(bool enabled) { btn.setEnabled(enabled); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPushButton btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotButtonParamControl : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
FrogPilotButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
|
const std::vector<QString> &button_texts, const int minimum_button_width = 225)
|
||||||
|
: ParamControl(param, title, desc, icon) {
|
||||||
|
const QString style = R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 500;
|
||||||
|
height:100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:checked:enabled {
|
||||||
|
background-color: #0048FF;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
key = param.toStdString();
|
||||||
|
int value = atoi(params.get(key).c_str());
|
||||||
|
|
||||||
|
button_group = new QButtonGroup(this);
|
||||||
|
button_group->setExclusive(true);
|
||||||
|
for (size_t i = 0; i < button_texts.size(); i++) {
|
||||||
|
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||||
|
button->setCheckable(true);
|
||||||
|
button->setChecked(i == value);
|
||||||
|
button->setStyleSheet(style);
|
||||||
|
button->setMinimumWidth(minimum_button_width);
|
||||||
|
hlayout->addWidget(button);
|
||||||
|
button_group->addButton(button, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(button_group, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
params.put(key, std::to_string(id));
|
||||||
|
refresh();
|
||||||
|
emit buttonClicked(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
toggle.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEnabled(bool enable) {
|
||||||
|
for (auto btn : button_group->buttons()) {
|
||||||
|
btn->setEnabled(enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void buttonClicked(int id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string key;
|
||||||
|
Params params;
|
||||||
|
QButtonGroup *button_group;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotParamManageControl : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotParamManageControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr)
|
||||||
|
: ParamControl(param, title, desc, icon, parent),
|
||||||
|
key(param.toStdString()),
|
||||||
|
manageButton(new ButtonControl(tr(""), tr("MANAGE"), tr(""))) {
|
||||||
|
hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, manageButton);
|
||||||
|
|
||||||
|
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(manageButton, &ButtonControl::clicked, this, &FrogPilotParamManageControl::manageButtonClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
ParamControl::refresh();
|
||||||
|
manageButton->setVisible(params.getBool(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event) override {
|
||||||
|
ParamControl::showEvent(event);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void manageButtonClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string key;
|
||||||
|
Params params;
|
||||||
|
ButtonControl *manageButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotParamToggleControl : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
FrogPilotParamToggleControl(const QString ¶m, const QString &title, const QString &desc,
|
||||||
|
const QString &icon, const std::vector<QString> &button_params,
|
||||||
|
const std::vector<QString> &button_texts, QWidget *parent = nullptr,
|
||||||
|
const int minimum_button_width = 225)
|
||||||
|
: ParamControl(param, title, desc, icon, parent) {
|
||||||
|
|
||||||
|
connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) {
|
||||||
|
refreshButtons(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
const QString style = R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 500;
|
||||||
|
height:100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:checked:enabled {
|
||||||
|
background-color: #0048FF;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
button_group = new QButtonGroup(this);
|
||||||
|
button_group->setExclusive(false);
|
||||||
|
|
||||||
|
std::map<QString, bool> paramState;
|
||||||
|
for (const QString &button_param : button_params) {
|
||||||
|
paramState[button_param] = params.getBool(button_param.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < button_texts.size(); ++i) {
|
||||||
|
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||||
|
button->setCheckable(true);
|
||||||
|
button->setChecked(paramState[button_params[i]]);
|
||||||
|
button->setStyleSheet(style);
|
||||||
|
button->setMinimumWidth(minimum_button_width);
|
||||||
|
button_group->addButton(button, i);
|
||||||
|
|
||||||
|
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
|
||||||
|
params.putBool(button_params[i].toStdString(), checked);
|
||||||
|
button_group->button(i)->setChecked(checked);
|
||||||
|
emit buttonClicked(checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
hlayout->insertWidget(hlayout->indexOf(&toggle), button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshButtons(bool state) {
|
||||||
|
for (QAbstractButton *button : button_group->buttons()) {
|
||||||
|
button->setVisible(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void buttonClicked(const bool checked);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Params params;
|
||||||
|
QButtonGroup *button_group;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotParamValueControl : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotParamValueControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
|
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
|
||||||
|
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1)
|
||||||
|
: ParamControl(param, title, desc, icon, parent),
|
||||||
|
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
|
||||||
|
key = param.toStdString();
|
||||||
|
|
||||||
|
valueLabel = new QLabel(this);
|
||||||
|
hlayout->addWidget(valueLabel);
|
||||||
|
|
||||||
|
QPushButton *decrementButton = createButton("-", this);
|
||||||
|
QPushButton *incrementButton = createButton("+", this);
|
||||||
|
|
||||||
|
hlayout->addWidget(decrementButton);
|
||||||
|
hlayout->addWidget(incrementButton);
|
||||||
|
|
||||||
|
connect(decrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(incrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
toggle.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateValue(int increment) {
|
||||||
|
value = value + increment;
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
if (value < minValue) value = maxValue;
|
||||||
|
else if (value > maxValue) value = minValue;
|
||||||
|
} else {
|
||||||
|
value = std::max(minValue, std::min(maxValue, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
params.putInt(key, value);
|
||||||
|
refresh();
|
||||||
|
emit buttonPressed();
|
||||||
|
emit valueChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
value = params.getInt(key);
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
auto it = valueLabelMappings.find(value);
|
||||||
|
if (division > 1) {
|
||||||
|
text = QString::number(value / (division * 1.0), 'g');
|
||||||
|
} else {
|
||||||
|
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
|
||||||
|
}
|
||||||
|
if (!labelText.isEmpty()) {
|
||||||
|
text += labelText;
|
||||||
|
}
|
||||||
|
valueLabel->setText(text);
|
||||||
|
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision = 1) {
|
||||||
|
minValue = newMinValue;
|
||||||
|
maxValue = newMaxValue;
|
||||||
|
labelText = newLabel;
|
||||||
|
division = newDivision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event) override {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void buttonPressed();
|
||||||
|
void valueChanged(int value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool loop;
|
||||||
|
int division;
|
||||||
|
int maxValue;
|
||||||
|
int minValue;
|
||||||
|
int value;
|
||||||
|
QLabel *valueLabel;
|
||||||
|
QString labelText;
|
||||||
|
std::map<int, QString> valueLabelMappings;
|
||||||
|
std::string key;
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
QPushButton *createButton(const QString &text, QWidget *parent) {
|
||||||
|
QPushButton *button = new QPushButton(text, parent);
|
||||||
|
button->setFixedSize(150, 100);
|
||||||
|
button->setAutoRepeat(true);
|
||||||
|
button->setAutoRepeatInterval(150);
|
||||||
|
button->setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotParamValueControlFloat : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotParamValueControlFloat(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
|
const float &minValue, const float &maxValue, const std::map<int, QString> &valueLabels,
|
||||||
|
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const float &division = 1.0f)
|
||||||
|
: ParamControl(param, title, desc, icon, parent),
|
||||||
|
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
|
||||||
|
key = param.toStdString();
|
||||||
|
|
||||||
|
valueLabel = new QLabel(this);
|
||||||
|
hlayout->addWidget(valueLabel);
|
||||||
|
|
||||||
|
QPushButton *decrementButton = createButton("-", this);
|
||||||
|
QPushButton *incrementButton = createButton("+", this);
|
||||||
|
|
||||||
|
hlayout->addWidget(decrementButton);
|
||||||
|
hlayout->addWidget(incrementButton);
|
||||||
|
|
||||||
|
connect(decrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(-1.0f);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(incrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(1.0f);
|
||||||
|
});
|
||||||
|
|
||||||
|
toggle.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateValue(float increment) {
|
||||||
|
value += increment * 0.1f;
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
if (value < minValue) value = maxValue;
|
||||||
|
else if (value > maxValue) value = minValue;
|
||||||
|
} else {
|
||||||
|
value = std::max(minValue, std::min(maxValue, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
params.putFloat(key, value);
|
||||||
|
refresh();
|
||||||
|
emit buttonPressed();
|
||||||
|
emit valueChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
value = params.getFloat(key);
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
auto it = valueLabelMappings.find(value);
|
||||||
|
if (division > 0.1f) {
|
||||||
|
text = QString::number(value, 'f', 1);
|
||||||
|
} else {
|
||||||
|
text = it != valueLabelMappings.end() ? it->second : QString::number(value, 'f', 1);
|
||||||
|
}
|
||||||
|
if (!labelText.isEmpty()) {
|
||||||
|
text += labelText;
|
||||||
|
}
|
||||||
|
valueLabel->setText(text);
|
||||||
|
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateControl(float newMinValue, float newMaxValue, const QString &newLabel, float newDivision = 1.0f) {
|
||||||
|
minValue = newMinValue;
|
||||||
|
maxValue = newMaxValue;
|
||||||
|
labelText = newLabel;
|
||||||
|
division = newDivision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event) override {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void buttonPressed();
|
||||||
|
void valueChanged(float value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool loop;
|
||||||
|
float division;
|
||||||
|
float maxValue;
|
||||||
|
float minValue;
|
||||||
|
float value;
|
||||||
|
QLabel *valueLabel;
|
||||||
|
QString labelText;
|
||||||
|
std::map<int, QString> valueLabelMappings;
|
||||||
|
std::string key;
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
QPushButton *createButton(const QString &text, QWidget *parent) {
|
||||||
|
QPushButton *button = new QPushButton(text, parent);
|
||||||
|
button->setFixedSize(150, 100);
|
||||||
|
button->setAutoRepeat(true);
|
||||||
|
button->setAutoRepeatInterval(150);
|
||||||
|
button->setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotDualParamControl : public QFrame {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotDualParamControl(ParamControl *control1, ParamControl *control2, QWidget *parent = nullptr, bool split=false)
|
||||||
|
: QFrame(parent) {
|
||||||
|
QHBoxLayout *hlayout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
control1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||||
|
control1->setMaximumWidth(split ? 800 : 700);
|
||||||
|
|
||||||
|
control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
control2->setMaximumWidth(800);
|
||||||
|
|
||||||
|
hlayout->addWidget(control1);
|
||||||
|
hlayout->addWidget(control2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrogPilotParamValueToggleControl : public ParamControl {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrogPilotParamValueToggleControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||||
|
const int &minValue, const int &maxValue, const std::map<int, QString> &valueLabels,
|
||||||
|
QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1,
|
||||||
|
const std::vector<QString> &button_params = std::vector<QString>(), const std::vector<QString> &button_texts = std::vector<QString>(),
|
||||||
|
const int minimum_button_width = 225)
|
||||||
|
: ParamControl(param, title, desc, icon, parent),
|
||||||
|
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) {
|
||||||
|
key = param.toStdString();
|
||||||
|
|
||||||
|
const QString style = R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: 500;
|
||||||
|
height:100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:checked:enabled {
|
||||||
|
background-color: #0048FF;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
button_group = new QButtonGroup(this);
|
||||||
|
button_group->setExclusive(false);
|
||||||
|
|
||||||
|
std::map<QString, bool> paramState;
|
||||||
|
for (const QString &button_param : button_params) {
|
||||||
|
paramState[button_param] = params.getBool(button_param.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < button_texts.size(); ++i) {
|
||||||
|
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||||
|
button->setCheckable(true);
|
||||||
|
button->setChecked(paramState[button_params[i]]);
|
||||||
|
button->setStyleSheet(style);
|
||||||
|
button->setMinimumWidth(minimum_button_width);
|
||||||
|
button_group->addButton(button, i);
|
||||||
|
|
||||||
|
connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) {
|
||||||
|
params.putBool(button_params[i].toStdString(), checked);
|
||||||
|
button_group->button(i)->setChecked(checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
hlayout->addWidget(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
valueLabel = new QLabel(this);
|
||||||
|
hlayout->addWidget(valueLabel);
|
||||||
|
|
||||||
|
QPushButton *decrementButton = createButton("-", this);
|
||||||
|
QPushButton *incrementButton = createButton("+", this);
|
||||||
|
|
||||||
|
hlayout->addWidget(decrementButton);
|
||||||
|
hlayout->addWidget(incrementButton);
|
||||||
|
|
||||||
|
connect(decrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(incrementButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
updateValue(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
toggle.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateValue(int increment) {
|
||||||
|
value = value + increment;
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
if (value < minValue) value = maxValue;
|
||||||
|
else if (value > maxValue) value = minValue;
|
||||||
|
} else {
|
||||||
|
value = std::max(minValue, std::min(maxValue, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
params.putInt(key, value);
|
||||||
|
refresh();
|
||||||
|
emit buttonPressed();
|
||||||
|
emit valueChanged(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
value = params.getInt(key);
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
auto it = valueLabelMappings.find(value);
|
||||||
|
if (division > 1) {
|
||||||
|
text = QString::number(value / (division * 1.0), 'g');
|
||||||
|
} else {
|
||||||
|
text = it != valueLabelMappings.end() ? it->second : QString::number(value);
|
||||||
|
}
|
||||||
|
if (!labelText.isEmpty()) {
|
||||||
|
text += labelText;
|
||||||
|
}
|
||||||
|
valueLabel->setText(text);
|
||||||
|
valueLabel->setStyleSheet("QLabel { color: #E0E879; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision) {
|
||||||
|
minValue = newMinValue;
|
||||||
|
maxValue = newMaxValue;
|
||||||
|
labelText = newLabel;
|
||||||
|
division = newDivision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event) override {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void buttonPressed();
|
||||||
|
void valueChanged(int value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool loop;
|
||||||
|
int division;
|
||||||
|
int maxValue;
|
||||||
|
int minValue;
|
||||||
|
int value;
|
||||||
|
QButtonGroup *button_group;
|
||||||
|
QLabel *valueLabel;
|
||||||
|
QString labelText;
|
||||||
|
std::map<int, QString> valueLabelMappings;
|
||||||
|
std::string key;
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
QPushButton *createButton(const QString &text, QWidget *parent) {
|
||||||
|
QPushButton *button = new QPushButton(text, parent);
|
||||||
|
button->setFixedSize(150, 100);
|
||||||
|
button->setAutoRepeat(true);
|
||||||
|
button->setAutoRepeatInterval(150);
|
||||||
|
button->setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 50px;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 100px;
|
||||||
|
padding: 0 25 0 25;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void setDefaultParams();
|
||||||
185
selfdrive/frogpilot/ui/vehicle_settings.cc.org
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/vehicle_settings.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
QStringList getCarNames(const QString &carMake) {
|
||||||
|
QMap<QString, QString> makeMap;
|
||||||
|
makeMap["acura"] = "honda";
|
||||||
|
makeMap["audi"] = "volkswagen";
|
||||||
|
makeMap["buick"] = "gm";
|
||||||
|
makeMap["cadillac"] = "gm";
|
||||||
|
makeMap["chevrolet"] = "gm";
|
||||||
|
makeMap["chrysler"] = "chrysler";
|
||||||
|
makeMap["dodge"] = "chrysler";
|
||||||
|
makeMap["ford"] = "ford";
|
||||||
|
makeMap["gm"] = "gm";
|
||||||
|
makeMap["gmc"] = "gm";
|
||||||
|
makeMap["genesis"] = "hyundai";
|
||||||
|
makeMap["honda"] = "honda";
|
||||||
|
makeMap["hyundai"] = "hyundai";
|
||||||
|
makeMap["infiniti"] = "nissan";
|
||||||
|
makeMap["jeep"] = "chrysler";
|
||||||
|
makeMap["kia"] = "hyundai";
|
||||||
|
makeMap["lexus"] = "toyota";
|
||||||
|
makeMap["lincoln"] = "ford";
|
||||||
|
makeMap["man"] = "volkswagen";
|
||||||
|
makeMap["mazda"] = "mazda";
|
||||||
|
makeMap["nissan"] = "nissan";
|
||||||
|
makeMap["ram"] = "chrysler";
|
||||||
|
makeMap["seat"] = "volkswagen";
|
||||||
|
makeMap["subaru"] = "subaru";
|
||||||
|
makeMap["tesla"] = "tesla";
|
||||||
|
makeMap["toyota"] = "toyota";
|
||||||
|
makeMap["volkswagen"] = "volkswagen";
|
||||||
|
makeMap["skoda"] = "volkswagen";
|
||||||
|
|
||||||
|
QString dirPath = "../../selfdrive/car";
|
||||||
|
QDir dir(dirPath);
|
||||||
|
QString targetFolder = makeMap.value(carMake, carMake);
|
||||||
|
QStringList names;
|
||||||
|
|
||||||
|
foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
|
if (folder == targetFolder) {
|
||||||
|
QFile file(dirPath + "/" + folder + "/values.py");
|
||||||
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QRegularExpression regex("class CAR\\(StrEnum\\):([\\s\\S]*?)(?=^\\w)", QRegularExpression::MultilineOption);
|
||||||
|
QRegularExpressionMatch match = regex.match(QTextStream(&file).readAll());
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QRegularExpression nameRegex("=\\s*\"([^\"]+)\"");
|
||||||
|
QRegularExpressionMatchIterator it = nameRegex.globalMatch(match.captured(1));
|
||||||
|
while (it.hasNext()) {
|
||||||
|
names << it.next().captured(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(names.begin(), names.end());
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
|
selectMakeButton = new ButtonControl(tr("Select Make"), tr("SELECT"));
|
||||||
|
QObject::connect(selectMakeButton, &ButtonControl::clicked, [this]() {
|
||||||
|
std::string currentMake = params.get("CarMake");
|
||||||
|
QStringList makes = {
|
||||||
|
"Acura", "Audi", "BMW", "Buick", "Cadillac", "Chevrolet", "Chrysler", "Dodge", "Ford", "GM", "GMC",
|
||||||
|
"Genesis", "Honda", "Hyundai", "Infiniti", "Jeep", "Kia", "Lexus", "Lincoln", "MAN", "Mazda",
|
||||||
|
"Mercedes", "Nissan", "Ram", "SEAT", "Subaru", "Tesla", "Toyota", "Volkswagen", "Volvo", "Škoda",
|
||||||
|
};
|
||||||
|
|
||||||
|
QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, QString::fromStdString(currentMake), this);
|
||||||
|
if (!newMakeSelection.isEmpty()) {
|
||||||
|
carMake = newMakeSelection;
|
||||||
|
params.put("CarMake", carMake.toStdString());
|
||||||
|
selectMakeButton->setValue(newMakeSelection);
|
||||||
|
setModels();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addItem(selectMakeButton);
|
||||||
|
|
||||||
|
selectModelButton = new ButtonControl(tr("Select Model"), tr("SELECT"));
|
||||||
|
QString modelSelection = QString::fromStdString(params.get("CarModel"));
|
||||||
|
QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() {
|
||||||
|
std::string currentModel = params.get("CarModel");
|
||||||
|
QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, QString::fromStdString(currentModel), this);
|
||||||
|
if (!newModelSelection.isEmpty()) {
|
||||||
|
params.put("CarModel", newModelSelection.toStdString());
|
||||||
|
selectModelButton->setValue(newModelSelection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
selectModelButton->setValue(modelSelection);
|
||||||
|
addItem(selectModelButton);
|
||||||
|
selectModelButton->setVisible(false);
|
||||||
|
|
||||||
|
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
|
||||||
|
{"EVTable", "EV Lookup Tables", "Smoothen out the gas and brake controls for EV vehicles.", ""},
|
||||||
|
{"GasRegenCmd", "Gas Regen Cmd", "", ""},
|
||||||
|
{"LongPitch", "Long Pitch Compensation", "Reduce speed and acceleration error for greater passenger comfort and improved vehicle efficiency.", ""},
|
||||||
|
{"LowerVolt", "Lower Volt Enable Speed", "Lower the Volt's minimum enable speed to enable openpilot at any speed.", ""},
|
||||||
|
|
||||||
|
{"LockDoors", "Lock Doors In Drive", "Automatically lock the doors when in drive and unlock when in park.", ""},
|
||||||
|
{"SNGHack", "Stop and Go Hack", "Enable the 'Stop and Go' hack for vehicles without stock stop and go functionality.", ""},
|
||||||
|
{"TSS2Tune", "TSS2 Tune", "Tuning profile based on the tuning profile from DragonPilot for TSS2 vehicles.", ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &[param, title, desc, icon] : vehicleToggles) {
|
||||||
|
ParamControl *toggle = new ParamControl(param, title, desc, icon, this);
|
||||||
|
|
||||||
|
addItem(toggle);
|
||||||
|
toggle->setVisible(false);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
|
||||||
|
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
gmKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt"};
|
||||||
|
toyotaKeys = {"LockDoors", "SNGHack", "TSS2Tune"};
|
||||||
|
|
||||||
|
std::set<std::string> rebootKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt", "TSS2Tune"};
|
||||||
|
for (const std::string &key : rebootKeys) {
|
||||||
|
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) {
|
||||||
|
if (!offroad) {
|
||||||
|
std::thread([this]() {
|
||||||
|
while (carMake.isEmpty()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
carMake = QString::fromStdString(params.get("CarMake"));
|
||||||
|
}
|
||||||
|
setModels();
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
carMake = QString::fromStdString(params.get("CarMake"));
|
||||||
|
if (!carMake.isEmpty()) {
|
||||||
|
setModels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVehiclesPanel::updateToggles() {
|
||||||
|
std::thread([this]() {
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVehiclesPanel::setModels() {
|
||||||
|
models = getCarNames(carMake.toLower());
|
||||||
|
setToggles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVehiclesPanel::setToggles() {
|
||||||
|
selectMakeButton->setValue(carMake);
|
||||||
|
selectModelButton->setVisible(!carMake.isEmpty());
|
||||||
|
|
||||||
|
bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC";
|
||||||
|
bool toyota = carMake == "Lexus" || carMake == "Toyota";
|
||||||
|
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(false);
|
||||||
|
|
||||||
|
if (gm) {
|
||||||
|
toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end());
|
||||||
|
} else if (toyota) {
|
||||||
|
toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
34
selfdrive/frogpilot/ui/vehicle_settings.h.org
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
|
|
||||||
|
class FrogPilotVehiclesPanel : public FrogPilotListWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FrogPilotVehiclesPanel(SettingsWindow *parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setModels();
|
||||||
|
void setToggles();
|
||||||
|
void updateToggles();
|
||||||
|
|
||||||
|
ButtonControl *selectMakeButton;
|
||||||
|
ButtonControl *selectModelButton;
|
||||||
|
|
||||||
|
QString carMake;
|
||||||
|
QStringList models;
|
||||||
|
|
||||||
|
std::map<std::string, ParamControl*> toggles;
|
||||||
|
|
||||||
|
std::set<QString> gmKeys;
|
||||||
|
std::set<QString> toyotaKeys;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
Params paramsMemory{"/dev/shm/params"};
|
||||||
|
};
|
||||||
242
selfdrive/frogpilot/ui/visual_settings.cc.org
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
#include "selfdrive/frogpilot/ui/visual_settings.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
|
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||||
|
{"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"},
|
||||||
|
{"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
|
||||||
|
{"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"},
|
||||||
|
{"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"},
|
||||||
|
|
||||||
|
{"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"},
|
||||||
|
{"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""},
|
||||||
|
{"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""},
|
||||||
|
{"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""},
|
||||||
|
{"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""},
|
||||||
|
{"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""},
|
||||||
|
{"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""},
|
||||||
|
|
||||||
|
{"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"},
|
||||||
|
{"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"},
|
||||||
|
|
||||||
|
{"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"},
|
||||||
|
{"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""},
|
||||||
|
{"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""},
|
||||||
|
{"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""},
|
||||||
|
{"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""},
|
||||||
|
{"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""},
|
||||||
|
{"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""},
|
||||||
|
|
||||||
|
{"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"},
|
||||||
|
{"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""},
|
||||||
|
{"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""},
|
||||||
|
{"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""},
|
||||||
|
|
||||||
|
{"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"},
|
||||||
|
{"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"},
|
||||||
|
{"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||||
|
{"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[param, title, desc, icon] : visualToggles) {
|
||||||
|
ParamControl *toggle;
|
||||||
|
|
||||||
|
if (param == "CameraView") {
|
||||||
|
std::vector<QString> cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")};
|
||||||
|
FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions);
|
||||||
|
toggle = preferredCamera;
|
||||||
|
|
||||||
|
} else if (param == "CustomTheme") {
|
||||||
|
FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = customThemeToggle;
|
||||||
|
} else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") {
|
||||||
|
std::vector<QString> themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")};
|
||||||
|
FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions);
|
||||||
|
toggle = themeSelection;
|
||||||
|
|
||||||
|
if (param == "CustomSounds") {
|
||||||
|
QObject::connect(static_cast<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 1) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) {
|
||||||
|
params.putBool("GoatScream", true);
|
||||||
|
} else {
|
||||||
|
params.putBool("GoatScream", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (param == "CustomUI") {
|
||||||
|
FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = customUIToggle;
|
||||||
|
} else if (param == "LeadInfo") {
|
||||||
|
std::vector<QString> leadInfoToggles{tr("UseSI")};
|
||||||
|
std::vector<QString> leadInfoToggleNames{tr("Use SI Values")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames);
|
||||||
|
|
||||||
|
} else if (param == "ModelUI") {
|
||||||
|
FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = modelUIToggle;
|
||||||
|
} else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map<int, QString>(), this, false, " inches");
|
||||||
|
} else if (param == "PathEdgeWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map<int, QString>(), this, false, "%");
|
||||||
|
} else if (param == "PathWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map<int, QString>(), this, false, " feet", 10);
|
||||||
|
|
||||||
|
} else if (param == "QOLVisuals") {
|
||||||
|
FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = qolToggle;
|
||||||
|
|
||||||
|
} else if (param == "ScreenBrightness") {
|
||||||
|
std::map<int, QString> brightnessLabels;
|
||||||
|
for (int i = 0; i <= 101; ++i) {
|
||||||
|
brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%";
|
||||||
|
}
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false);
|
||||||
|
|
||||||
|
} else if (param == "WheelIcon") {
|
||||||
|
std::vector<QString> wheelToggles{"RotatingWheel"};
|
||||||
|
std::vector<QString> wheelToggleNames{tr("Rotating")};
|
||||||
|
std::map<int, QString> steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}};
|
||||||
|
toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
toggle = new ParamControl(param, title, desc, icon, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem(toggle);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
|
||||||
|
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> rebootKeys = {"DriveStats"};
|
||||||
|
for (const std::string &key : rebootKeys) {
|
||||||
|
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"};
|
||||||
|
customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"};
|
||||||
|
modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
||||||
|
qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"};
|
||||||
|
|
||||||
|
QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles);
|
||||||
|
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles);
|
||||||
|
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric);
|
||||||
|
|
||||||
|
hideSubToggles();
|
||||||
|
updateMetric();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVisualsPanel::updateToggles() {
|
||||||
|
std::thread([this]() {
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVisualsPanel::updateMetric() {
|
||||||
|
bool previousIsMetric = isMetric;
|
||||||
|
isMetric = params.getBool("IsMetric");
|
||||||
|
|
||||||
|
if (isMetric != previousIsMetric) {
|
||||||
|
double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH;
|
||||||
|
double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
|
||||||
|
params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion));
|
||||||
|
params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion));
|
||||||
|
params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion));
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotParamValueControl *laneLinesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["LaneLinesWidth"]);
|
||||||
|
FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["RoadEdgesWidth"]);
|
||||||
|
FrogPilotParamValueControl *pathWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["PathWidth"]);
|
||||||
|
|
||||||
|
if (isMetric) {
|
||||||
|
laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters.");
|
||||||
|
roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters.");
|
||||||
|
|
||||||
|
laneLinesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
roadEdgesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
pathWidthToggle->updateControl(0, 30, " meters");
|
||||||
|
} else {
|
||||||
|
laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches.");
|
||||||
|
roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.");
|
||||||
|
|
||||||
|
laneLinesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
roadEdgesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
pathWidthToggle->updateControl(0, 100, " feet");
|
||||||
|
}
|
||||||
|
|
||||||
|
laneLinesWidthToggle->refresh();
|
||||||
|
roadEdgesWidthToggle->refresh();
|
||||||
|
|
||||||
|
previousIsMetric = isMetric;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVisualsPanel::parentToggleClicked() {
|
||||||
|
this->openParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVisualsPanel::hideSubToggles() {
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() ||
|
||||||
|
customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() ||
|
||||||
|
customThemeKeys.find(key.c_str()) != customThemeKeys.end() ||
|
||||||
|
qolKeys.find(key.c_str()) != qolKeys.end();
|
||||||
|
toggle->setVisible(!subToggles);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->closeParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrogPilotVisualsPanel::hideEvent(QHideEvent *event) {
|
||||||
|
hideSubToggles();
|
||||||
|
}
|
||||||
36
selfdrive/frogpilot/ui/visual_settings.h.org
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
|
|
||||||
|
class FrogPilotVisualsPanel : public FrogPilotListWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FrogPilotVisualsPanel(SettingsWindow *parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeParentToggle();
|
||||||
|
void openParentToggle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void hideEvent(QHideEvent *event);
|
||||||
|
void hideSubToggles();
|
||||||
|
void parentToggleClicked();
|
||||||
|
void updateMetric();
|
||||||
|
void updateToggles();
|
||||||
|
|
||||||
|
std::set<QString> customOnroadUIKeys;
|
||||||
|
std::set<QString> customThemeKeys;
|
||||||
|
std::set<QString> modelUIKeys;
|
||||||
|
std::set<QString> qolKeys;
|
||||||
|
|
||||||
|
std::map<std::string, ParamControl*> toggles;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
Params paramsMemory{"/dev/shm/params"};
|
||||||
|
|
||||||
|
bool isMetric = params.getBool("IsMetric");
|
||||||
|
};
|
||||||
@@ -19,12 +19,15 @@ class DRIVER_MONITOR_SETTINGS():
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._DT_DMON = DT_DMON
|
self._DT_DMON = DT_DMON
|
||||||
# ref (page15-16): https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:42018X1947&rid=2
|
# ref (page15-16): https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:42018X1947&rid=2
|
||||||
self._AWARENESS_TIME = 90. # passive wheeltouch total timeout
|
# self._AWARENESS_TIME = 90. # passive wheeltouch total timeout
|
||||||
self._AWARENESS_PRE_TIME_TILL_TERMINAL = 60.
|
# self._AWARENESS_PRE_TIME_TILL_TERMINAL = 60.
|
||||||
self._AWARENESS_PROMPT_TIME_TILL_TERMINAL = 30.
|
# self._AWARENESS_PROMPT_TIME_TILL_TERMINAL = 30.
|
||||||
self._DISTRACTED_TIME = 90. # active monitoring total timeout
|
self._AWARENESS_TIME = 30. # passive wheeltouch total timeout
|
||||||
self._DISTRACTED_PRE_TIME_TILL_TERMINAL = 60.
|
self._AWARENESS_PRE_TIME_TILL_TERMINAL = 15.
|
||||||
self._DISTRACTED_PROMPT_TIME_TILL_TERMINAL = 30.
|
self._AWARENESS_PROMPT_TIME_TILL_TERMINAL = 6.
|
||||||
|
self._DISTRACTED_TIME = 60. # active monitoring total timeout
|
||||||
|
self._DISTRACTED_PRE_TIME_TILL_TERMINAL = 15.
|
||||||
|
self._DISTRACTED_PROMPT_TIME_TILL_TERMINAL = 10.
|
||||||
|
|
||||||
self._FACE_THRESHOLD = 0.7
|
self._FACE_THRESHOLD = 0.7
|
||||||
self._EYE_THRESHOLD = 0.65
|
self._EYE_THRESHOLD = 0.65
|
||||||
|
|||||||
22
selfdrive/oscarpilot/buttons.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import cereal.messaging as messaging
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.numpy_fast import clip, interp
|
||||||
|
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, V_CRUISE_MAX
|
||||||
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
|
||||||
|
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, A_CRUISE_MAX_VALS, A_CRUISE_MAX_BP, get_max_accel
|
||||||
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
|
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.conditional_experimental_mode import ConditionalExperimentalMode
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.map_turn_speed_controller import MapTurnSpeedController
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
|
||||||
|
|
||||||
|
# Class for intercepting when buttons are pressed, or dispatching buttons to be pressed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OscarPilotButtons:
|
||||||
|
def __init__(self, params, params_memory):
|
||||||
|
self.params_memory = params_memory
|
||||||
|
|
||||||
40
selfdrive/oscarpilot/events.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import cereal.messaging as messaging
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from openpilot.common.conversions import Conversions as CV
|
||||||
|
from openpilot.common.numpy_fast import clip, interp
|
||||||
|
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, V_CRUISE_MAX
|
||||||
|
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
|
||||||
|
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, A_CRUISE_MAX_VALS, A_CRUISE_MAX_BP, get_max_accel
|
||||||
|
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||||
|
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.conditional_experimental_mode import ConditionalExperimentalMode
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.map_turn_speed_controller import MapTurnSpeedController
|
||||||
|
from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController
|
||||||
|
|
||||||
|
# class FrogPilotPlanner:
|
||||||
|
# def __init__(self, params, params_memory):
|
||||||
|
# self.params_memory = params_memory
|
||||||
|
# self.cem = ConditionalExperimentalMode()
|
||||||
|
# self.mtsc = MapTurnSpeedController()
|
||||||
|
|
||||||
|
# self.override_slc = False
|
||||||
|
|
||||||
|
# self.overridden_speed = 0
|
||||||
|
# self.mtsc_target = 0
|
||||||
|
# self.slc_target = 0
|
||||||
|
# self.v_cruise = 0
|
||||||
|
# self.vtsc_target = 0
|
||||||
|
|
||||||
|
# self.x_desired_trajectory = np.zeros(CONTROL_N)
|
||||||
|
|
||||||
|
# self.update_frogpilot_params(params, params_memory)
|
||||||
|
|
||||||
|
# def update(self, sm, mpc):
|
||||||
|
# carState, controlsState, modelData = sm['carState'], sm['controlsState'], sm['modelV2']
|
||||||
|
|
||||||
|
# enabled = controlsState.enabled
|
||||||
|
|
||||||
|
# v_cruise_kph = min(controlsState.vCruise, V_CRUISE_MAX)
|
||||||
|
# v_cruise = v_cruise_kph * CV.KPH_TO_MS
|
||||||
|
# v_ego = carState.vEgo
|
||||||
1
selfdrive/oscarpilot/settings/advanced.cc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// Should show a UI showing the settings menu for stock frogpilot
|
||||||
0
selfdrive/oscarpilot/settings/advanced.h
Normal file
146
selfdrive/oscarpilot/settings/basic.cc
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#include "selfdrive/oscarpilot/settings/basic.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
OscarPilotBasicPanel::OscarPilotBasicPanel(OscarSettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
|
|
||||||
|
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||||
|
// {"HelloWorld", "Hello World", "Hi!", "../frogpilot/assets/wheel_images/frog.png"},
|
||||||
|
{
|
||||||
|
"OpenpilotEnabledToggle","Enable OpenPilot",
|
||||||
|
"Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.",
|
||||||
|
"../assets/offroad/icon_openpilot.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AlwaysOnLateral", "Always on Lateral",
|
||||||
|
"Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"
|
||||||
|
},
|
||||||
|
{"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "ConditionalExperimental", "Slow for curves",
|
||||||
|
// "Engages 'experimental mode' when a curve is detected, temporairly reducing max speed.", "../frogpilot/assets/toggle_icons/icon_conditional.png"
|
||||||
|
// },
|
||||||
|
// Alert on stopsign / stoplight
|
||||||
|
{"LaneChangeAssist", "Lane Change Assist", "Automatically change lanes on turn signal and wheel nudge at highway speeds.", "../frogpilot/assets/toggle_icons/icon_lane.png"},
|
||||||
|
{"FireTheBabysitter", "Custom Driver Monitoring", "Customize the driver awareness alert timeouts.", ""},
|
||||||
|
// - Hands On Wheel: Always / At Dusk / 2+ hrs driving
|
||||||
|
|
||||||
|
{"DashCam", "Dash Cam Recording", "Record video and gps data for all drives automatically.", ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[param, title, desc, icon] : visualToggles) {
|
||||||
|
ParamControl *toggle;
|
||||||
|
|
||||||
|
toggle = new ParamControl(param, title, desc, icon, this);
|
||||||
|
|
||||||
|
addItem(toggle);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
|
||||||
|
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::set<std::string> rebootKeys = {"DriveStats"};
|
||||||
|
// for (const std::string &key : rebootKeys) {
|
||||||
|
// QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
// if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
// Hardware::reboot();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// power buttons
|
||||||
|
QHBoxLayout *power_layout = new QHBoxLayout();
|
||||||
|
power_layout->setSpacing(30);
|
||||||
|
|
||||||
|
QPushButton *reboot_btn = new QPushButton(tr("Reboot"));
|
||||||
|
reboot_btn->setObjectName("reboot_btn");
|
||||||
|
power_layout->addWidget(reboot_btn);
|
||||||
|
QObject::connect(reboot_btn, &QPushButton::clicked, this, &OscarPilotBasicPanel::reboot);
|
||||||
|
|
||||||
|
QPushButton *poweroff_btn = new QPushButton(tr("Power Off"));
|
||||||
|
poweroff_btn->setObjectName("poweroff_btn");
|
||||||
|
power_layout->addWidget(poweroff_btn);
|
||||||
|
QObject::connect(poweroff_btn, &QPushButton::clicked, this, &OscarPilotBasicPanel::poweroff);
|
||||||
|
|
||||||
|
if (!Hardware::PC()) {
|
||||||
|
connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
#reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; }
|
||||||
|
#reboot_btn:pressed { background-color: #4a4a4a; }
|
||||||
|
#poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; }
|
||||||
|
#poweroff_btn:pressed { background-color: #FF2424; }
|
||||||
|
)");
|
||||||
|
addItem(power_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::updateToggles() {
|
||||||
|
std::thread([this]() {
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::parentToggleClicked() {
|
||||||
|
this->openParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::hideSubToggles() {
|
||||||
|
// for (auto &[key, toggle] : toggles) {
|
||||||
|
// bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() ||
|
||||||
|
// customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() ||
|
||||||
|
// customThemeKeys.find(key.c_str()) != customThemeKeys.end() ||
|
||||||
|
// qolKeys.find(key.c_str()) != qolKeys.end();
|
||||||
|
// toggle->setVisible(!subToggles);
|
||||||
|
// }
|
||||||
|
|
||||||
|
this->closeParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::hideEvent(QHideEvent *event) {
|
||||||
|
hideSubToggles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::reboot() {
|
||||||
|
if (!uiState()->engaged()) {
|
||||||
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), tr("Reboot"), this)) {
|
||||||
|
// Check engaged again in case it changed while the dialog was open
|
||||||
|
if (!uiState()->engaged()) {
|
||||||
|
params.putBool("DoReboot", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ConfirmationDialog::alert(tr("Disengage to Reboot"), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::poweroff() {
|
||||||
|
if (!uiState()->engaged()) {
|
||||||
|
if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) {
|
||||||
|
// Check engaged again in case it changed while the dialog was open
|
||||||
|
if (!uiState()->engaged()) {
|
||||||
|
params.putBool("DoShutdown", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ConfirmationDialog::alert(tr("Disengage to Power Off"), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
280
selfdrive/oscarpilot/settings/basic.example
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#include "selfdrive/oscarpilot/settings/basic.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
OscarPilotBasicPanel::OscarPilotBasicPanel(OscarSettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||||
|
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||||
|
{"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"},
|
||||||
|
{"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
{"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""},
|
||||||
|
|
||||||
|
{"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"},
|
||||||
|
{"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"},
|
||||||
|
|
||||||
|
{"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"},
|
||||||
|
{"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""},
|
||||||
|
{"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""},
|
||||||
|
{"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""},
|
||||||
|
{"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""},
|
||||||
|
{"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""},
|
||||||
|
{"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""},
|
||||||
|
|
||||||
|
{"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"},
|
||||||
|
{"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"},
|
||||||
|
|
||||||
|
{"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"},
|
||||||
|
{"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""},
|
||||||
|
{"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""},
|
||||||
|
{"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""},
|
||||||
|
{"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""},
|
||||||
|
{"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""},
|
||||||
|
{"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""},
|
||||||
|
|
||||||
|
{"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"},
|
||||||
|
{"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""},
|
||||||
|
{"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""},
|
||||||
|
{"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""},
|
||||||
|
|
||||||
|
{"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"},
|
||||||
|
{"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"},
|
||||||
|
{"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"},
|
||||||
|
{"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[param, title, desc, icon] : visualToggles) {
|
||||||
|
ParamControl *toggle;
|
||||||
|
|
||||||
|
if (param == "CameraView") {
|
||||||
|
std::vector<QString> cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")};
|
||||||
|
FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions);
|
||||||
|
toggle = preferredCamera;
|
||||||
|
|
||||||
|
} else if (param == "CustomTheme") {
|
||||||
|
FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = customThemeToggle;
|
||||||
|
} else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") {
|
||||||
|
std::vector<QString> themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")};
|
||||||
|
FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions);
|
||||||
|
toggle = themeSelection;
|
||||||
|
|
||||||
|
if (param == "CustomSounds") {
|
||||||
|
QObject::connect(static_cast<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) {
|
||||||
|
if (id == 1) {
|
||||||
|
if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) {
|
||||||
|
params.putBool("GoatScream", true);
|
||||||
|
} else {
|
||||||
|
params.putBool("GoatScream", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (param == "CustomUI") {
|
||||||
|
FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = customUIToggle;
|
||||||
|
} else if (param == "LeadInfo") {
|
||||||
|
std::vector<QString> leadInfoToggles{tr("UseSI")};
|
||||||
|
std::vector<QString> leadInfoToggleNames{tr("Use SI Values")};
|
||||||
|
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames);
|
||||||
|
|
||||||
|
} else if (param == "ModelUI") {
|
||||||
|
FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = modelUIToggle;
|
||||||
|
} else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map<int, QString>(), this, false, " inches");
|
||||||
|
} else if (param == "PathEdgeWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map<int, QString>(), this, false, "%");
|
||||||
|
} else if (param == "PathWidth") {
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map<int, QString>(), this, false, " feet", 10);
|
||||||
|
|
||||||
|
} else if (param == "QOLVisuals") {
|
||||||
|
FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||||
|
QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||||
|
parentToggleClicked();
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toggle = qolToggle;
|
||||||
|
|
||||||
|
} else if (param == "ScreenBrightness") {
|
||||||
|
std::map<int, QString> brightnessLabels;
|
||||||
|
for (int i = 0; i <= 101; ++i) {
|
||||||
|
brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%";
|
||||||
|
}
|
||||||
|
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false);
|
||||||
|
|
||||||
|
} else if (param == "WheelIcon") {
|
||||||
|
std::vector<QString> wheelToggles{"RotatingWheel"};
|
||||||
|
std::vector<QString> wheelToggleNames{tr("Rotating")};
|
||||||
|
std::map<int, QString> steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}};
|
||||||
|
toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
toggle = new ParamControl(param, title, desc, icon, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem(toggle);
|
||||||
|
toggles[param.toStdString()] = toggle;
|
||||||
|
|
||||||
|
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() {
|
||||||
|
updateToggles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<std::string> rebootKeys = {"DriveStats"};
|
||||||
|
for (const std::string &key : rebootKeys) {
|
||||||
|
QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() {
|
||||||
|
if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) {
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"};
|
||||||
|
customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"};
|
||||||
|
modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
|
||||||
|
qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"};
|
||||||
|
|
||||||
|
QObject::connect(device(), &Device::interactiveTimeout, this, &OscarPilotBasicPanel::hideSubToggles);
|
||||||
|
QObject::connect(parent, &OscarSettingsWindow::closeParentToggle, this, &OscarPilotBasicPanel::hideSubToggles);
|
||||||
|
// QObject::connect(parent, &OscarSettingsWindow::updateMetric, this, &OscarPilotBasicPanel::updateMetric);
|
||||||
|
|
||||||
|
hideSubToggles();
|
||||||
|
// updateMetric();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::updateToggles() {
|
||||||
|
std::thread([this]() {
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void OscarPilotBasicPanel::updateMetric() {
|
||||||
|
// bool previousIsMetric = isMetric;
|
||||||
|
// isMetric = params.getBool("IsMetric");
|
||||||
|
|
||||||
|
// if (isMetric != previousIsMetric) {
|
||||||
|
// double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH;
|
||||||
|
// double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
|
||||||
|
// params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion));
|
||||||
|
// params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion));
|
||||||
|
// params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FrogPilotParamValueControl *laneLinesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["LaneLinesWidth"]);
|
||||||
|
// FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["RoadEdgesWidth"]);
|
||||||
|
// FrogPilotParamValueControl *pathWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["PathWidth"]);
|
||||||
|
|
||||||
|
// if (isMetric) {
|
||||||
|
// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters.");
|
||||||
|
// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters.");
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
// roadEdgesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
// pathWidthToggle->updateControl(0, 30, " meters");
|
||||||
|
// } else {
|
||||||
|
// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches.");
|
||||||
|
// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.");
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
// roadEdgesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
// pathWidthToggle->updateControl(0, 100, " feet");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->refresh();
|
||||||
|
// roadEdgesWidthToggle->refresh();
|
||||||
|
|
||||||
|
// previousIsMetric = isMetric;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void OscarPilotBasicPanel::updateMetric() {
|
||||||
|
// bool previousIsMetric = isMetric;
|
||||||
|
// isMetric = params.getBool("IsMetric");
|
||||||
|
|
||||||
|
// if (isMetric != previousIsMetric) {
|
||||||
|
// double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH;
|
||||||
|
// double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT;
|
||||||
|
// params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion));
|
||||||
|
// params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion));
|
||||||
|
// params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FrogPilotParamValueControl *laneLinesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["LaneLinesWidth"]);
|
||||||
|
// FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["RoadEdgesWidth"]);
|
||||||
|
// FrogPilotParamValueControl *pathWidthToggle = static_cast<FrogPilotParamValueControl*>(toggles["PathWidth"]);
|
||||||
|
|
||||||
|
// if (isMetric) {
|
||||||
|
// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters.");
|
||||||
|
// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters.");
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
// roadEdgesWidthToggle->updateControl(0, 60, " centimeters");
|
||||||
|
// pathWidthToggle->updateControl(0, 30, " meters");
|
||||||
|
// } else {
|
||||||
|
// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches.");
|
||||||
|
// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.");
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
// roadEdgesWidthToggle->updateControl(0, 24, " inches");
|
||||||
|
// pathWidthToggle->updateControl(0, 100, " feet");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// laneLinesWidthToggle->refresh();
|
||||||
|
// roadEdgesWidthToggle->refresh();
|
||||||
|
|
||||||
|
// previousIsMetric = isMetric;
|
||||||
|
// }
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::parentToggleClicked() {
|
||||||
|
this->openParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::hideSubToggles() {
|
||||||
|
for (auto &[key, toggle] : toggles) {
|
||||||
|
bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() ||
|
||||||
|
customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() ||
|
||||||
|
customThemeKeys.find(key.c_str()) != customThemeKeys.end() ||
|
||||||
|
qolKeys.find(key.c_str()) != qolKeys.end();
|
||||||
|
toggle->setVisible(!subToggles);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->closeParentToggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarPilotBasicPanel::hideEvent(QHideEvent *event) {
|
||||||
|
hideSubToggles();
|
||||||
|
}
|
||||||
34
selfdrive/oscarpilot/settings/basic.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/oscarpilot/settings/settings.h"
|
||||||
|
|
||||||
|
class OscarPilotBasicPanel : public FrogPilotListWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OscarPilotBasicPanel(OscarSettingsWindow *parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeParentToggle();
|
||||||
|
void openParentToggle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void hideEvent(QHideEvent *event);
|
||||||
|
void hideSubToggles();
|
||||||
|
void parentToggleClicked();
|
||||||
|
void updateToggles();
|
||||||
|
void poweroff();
|
||||||
|
void reboot();
|
||||||
|
|
||||||
|
std::set<QString> customOnroadUIKeys;
|
||||||
|
|
||||||
|
std::map<std::string, ParamControl*> toggles;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
Params paramsMemory{"/dev/shm/params"};
|
||||||
|
|
||||||
|
bool isMetric = params.getBool("IsMetric");
|
||||||
|
};
|
||||||
36
selfdrive/oscarpilot/settings/basic.h.example
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/oscarpilot/settings/settings.h"
|
||||||
|
|
||||||
|
class OscarPilotBasicPanel : public FrogPilotListWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OscarPilotBasicPanel(OscarSettingsWindow *parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeParentToggle();
|
||||||
|
void openParentToggle();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void hideEvent(QHideEvent *event);
|
||||||
|
void hideSubToggles();
|
||||||
|
void parentToggleClicked();
|
||||||
|
void updateMetric();
|
||||||
|
void updateToggles();
|
||||||
|
|
||||||
|
std::set<QString> customOnroadUIKeys;
|
||||||
|
std::set<QString> customThemeKeys;
|
||||||
|
std::set<QString> modelUIKeys;
|
||||||
|
std::set<QString> qolKeys;
|
||||||
|
|
||||||
|
std::map<std::string, ParamControl*> toggles;
|
||||||
|
|
||||||
|
Params params;
|
||||||
|
Params paramsMemory{"/dev/shm/params"};
|
||||||
|
|
||||||
|
bool isMetric = params.getBool("IsMetric");
|
||||||
|
};
|
||||||
177
selfdrive/oscarpilot/settings/defaults.cc
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) {
|
||||||
|
btn.setText(text);
|
||||||
|
btn.setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 35px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
btn.setFixedSize(250, 100);
|
||||||
|
QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked);
|
||||||
|
hlayout->addWidget(&btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDefaultParams() {
|
||||||
|
Params params = Params();
|
||||||
|
bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6";
|
||||||
|
|
||||||
|
bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71";
|
||||||
|
|
||||||
|
std::map<std::string, std::string> defaultValues {
|
||||||
|
{"AccelerationPath", brianbot ? "1" : "0"},
|
||||||
|
{"AccelerationProfile", brianbot ? "2" : "2"},
|
||||||
|
{"AdjacentPath", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"AdjustablePersonalities", "0"},
|
||||||
|
{"AggressiveAcceleration", "1"},
|
||||||
|
{"AggressiveFollow", FrogsGoMoo ? "10" : "12"},
|
||||||
|
{"AggressiveJerk", FrogsGoMoo ? "6" : "5"},
|
||||||
|
{"AlwaysOnLateral", "1"},
|
||||||
|
{"AlwaysOnLateralMain", brianbot ? "1" : "0"},
|
||||||
|
{"AverageCurvature", brianbot ? "1" : "0"},
|
||||||
|
{"BlindSpotPath", "1"},
|
||||||
|
{"CameraView", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"CECurves", "1"},
|
||||||
|
{"CECurvesLead", "0"},
|
||||||
|
{"CENavigation", "1"},
|
||||||
|
{"CESignal", "1"},
|
||||||
|
{"CESlowerLead", "0"},
|
||||||
|
{"CESpeed", "0"},
|
||||||
|
{"CESpeedLead", "0"},
|
||||||
|
{"CEStopLights", "0"},
|
||||||
|
{"CEStopLightsLead", FrogsGoMoo ? "0" : "0"},
|
||||||
|
{"Compass", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ConditionalExperimental", "1"},
|
||||||
|
{"CurveSensitivity", FrogsGoMoo ? "125" : "100"},
|
||||||
|
{"CustomColors", "1"},
|
||||||
|
{"CustomIcons", "1"},
|
||||||
|
{"CustomPersonalities", "0"},
|
||||||
|
{"CustomSignals", "0"},
|
||||||
|
{"CustomSounds", "1"},
|
||||||
|
{"CustomTheme", "1"},
|
||||||
|
{"CustomUI", "0"},
|
||||||
|
{"DeviceShutdown", "1"},
|
||||||
|
{"DisableOnroadUploads", "1"},
|
||||||
|
{"DriverCamera", "0"},
|
||||||
|
{"DriveStats", "1"},
|
||||||
|
{"EVTable", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"ExperimentalModeActivation", "1"},
|
||||||
|
{"ExperimentalModeViaLKAS", "0"},
|
||||||
|
{"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"Fahrenheit", "0"},
|
||||||
|
{"FireTheBabysitter", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"FullMap", "0"},
|
||||||
|
{"GasRegenCmd", "0"},
|
||||||
|
{"GoatScream", "0"},
|
||||||
|
{"GreenLightAlert", "0"},
|
||||||
|
{"HideSpeed", "0"},
|
||||||
|
{"HigherBitrate", "0"},
|
||||||
|
{"LaneChangeTime", "0"},
|
||||||
|
{"LaneDetection", "1"},
|
||||||
|
{"LaneLinesWidth", "4"},
|
||||||
|
{"LateralTune", "1"},
|
||||||
|
{"LeadInfo", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"LockDoors", "0"},
|
||||||
|
{"LongitudinalTune", "1"},
|
||||||
|
{"LongPitch", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"LowerVolt", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"Model", "3"},
|
||||||
|
{"ModelUI", "1"},
|
||||||
|
{"MTSCEnabled", "1"},
|
||||||
|
{"MuteDM", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"MuteDoor", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"MuteOverheated", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"MuteSeatbelt", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"NNFF", FrogsGoMoo ? "1" : "1"},
|
||||||
|
{"NoLogging", "1"},
|
||||||
|
{"NudgelessLaneChange", "0"},
|
||||||
|
{"NumericalTemp", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"Offset1", "3"},
|
||||||
|
{"Offset2", FrogsGoMoo ? "7" : "5"},
|
||||||
|
{"Offset3", "7"},
|
||||||
|
{"Offset4", FrogsGoMoo ? "20" : "7"},
|
||||||
|
{"OneLaneChange", "1"},
|
||||||
|
{"PathEdgeWidth", "20"},
|
||||||
|
{"PathWidth", "61"},
|
||||||
|
{"PauseLateralOnSignal", "20"},
|
||||||
|
{"PreferredSchedule", "0"},
|
||||||
|
{"QOLControls", "1"},
|
||||||
|
{"QOLVisuals", "1"},
|
||||||
|
{"RandomEvents", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"RelaxedFollow", "30"},
|
||||||
|
{"RelaxedJerk", "50"},
|
||||||
|
{"ReverseCruise", "0"},
|
||||||
|
{"RoadEdgesWidth", "2"},
|
||||||
|
{"RoadNameUI", "1"},
|
||||||
|
{"RotatingWheel", "1"},
|
||||||
|
{"ScreenBrightness", "101"},
|
||||||
|
{"SearchInput", "0"},
|
||||||
|
{"ShowCPU", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ShowFPS", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"ShowGPU", "0"},
|
||||||
|
{"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"Sidebar", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"SilentMode", "0"},
|
||||||
|
{"SLCFallback", "2"},
|
||||||
|
{"SLCOverride", FrogsGoMoo ? "2" : "1"},
|
||||||
|
{"SLCPriority", "1"},
|
||||||
|
{"SmoothBraking", "1"},
|
||||||
|
{"SNGHack", FrogsGoMoo ? "0" : "1"},
|
||||||
|
{"SpeedLimitController", "1"},
|
||||||
|
{"StandardFollow", "15"},
|
||||||
|
{"StandardJerk", "10"},
|
||||||
|
{"StoppingDistance", FrogsGoMoo ? "6" : "0"},
|
||||||
|
{"TSS2Tune", "1"},
|
||||||
|
{"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90?
|
||||||
|
{"TurnDesires", "0"},
|
||||||
|
{"UnlimitedLength", "1"},
|
||||||
|
{"UseSI", FrogsGoMoo ? "1" : "0"},
|
||||||
|
{"UseVienna", "0"},
|
||||||
|
{"VisionTurnControl", "1"},
|
||||||
|
{"WheelIcon", FrogsGoMoo ? "1" : "0"}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool rebootRequired = false;
|
||||||
|
for (const auto &[key, value] : defaultValues) {
|
||||||
|
if (params.get(key).empty()) {
|
||||||
|
params.put(key, value);
|
||||||
|
rebootRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rebootRequired) {
|
||||||
|
while (!std::filesystem::exists("/data/openpilot/prebuilt")) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
}
|
||||||
|
Hardware::reboot();
|
||||||
|
}
|
||||||
|
}
|
||||||
0
selfdrive/oscarpilot/settings/defaults.h
Normal file
38
selfdrive/oscarpilot/settings/newmenus
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
Device
|
||||||
|
Network & Services
|
||||||
|
- Standard Wifi
|
||||||
|
- Metered Wifi
|
||||||
|
- SSH
|
||||||
|
- Web companion
|
||||||
|
- Route logging
|
||||||
|
- Dashcam upload
|
||||||
|
- Live driver monitoring / fleet mgr
|
||||||
|
- Weather
|
||||||
|
- Display alerts
|
||||||
|
- API key
|
||||||
|
- Random facts
|
||||||
|
- Get random fact about area driver is in (spoken, ai)
|
||||||
|
Basic
|
||||||
|
- Enable openpilot / Dashcam only
|
||||||
|
- Always on Lateral: True / False
|
||||||
|
- Longitudial Control scheme: Stock / Stock+SLC / OpenPilot
|
||||||
|
- Experimental Mode: never / on curves / always
|
||||||
|
- Longitudial Control scheme: Stock / Stock+SLC / Experimental
|
||||||
|
- Speed Limit offset customization:
|
||||||
|
- Lane Change Assist: Disabled / Nudge Wheel
|
||||||
|
- Driver Attention Monitoring: Strict / Relaxed
|
||||||
|
- Hands On Wheel: Always / At Dusk / 2+ hrs driving
|
||||||
|
Advanced
|
||||||
|
Navigation
|
||||||
|
Customization
|
||||||
|
Extras
|
||||||
|
- Window down notification
|
||||||
|
- Set climate on drive mode
|
||||||
|
|
||||||
|
Fleet Mgr Notes:
|
||||||
|
- Seperate fork for fleet mgr
|
||||||
|
- Self drive preferences
|
||||||
|
- Distance traveled
|
||||||
|
- SLC
|
||||||
|
- Driver camera
|
||||||
|
|
||||||
20
selfdrive/oscarpilot/settings/notes
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Goals:
|
||||||
|
|
||||||
|
- slow down on experimental mode
|
||||||
|
- LKAS button - should toggle between drive, weather, weather radar. Hold for screen off
|
||||||
|
- car dashboard should have enough indicators that it is able to represent drive state without screen on
|
||||||
|
- set speed limit on engage cruise control
|
||||||
|
|
||||||
|
qol:
|
||||||
|
- customize babysitter - driver awareness timeouts daytime, nighttime, require steering wheel
|
||||||
|
- set climate on start, roll up windows on stop
|
||||||
|
- upload park location on stop
|
||||||
|
- low bandwidth / high bandwidth wifi, upload recordings on high bandwidth
|
||||||
|
- list drives w/ image on stop
|
||||||
|
- stop light / stop sign warning alert
|
||||||
|
|
||||||
|
release:
|
||||||
|
- reenable training screen
|
||||||
|
- - disregard for my device id
|
||||||
|
- cleanup code
|
||||||
|
- rename to diamondpilot
|
||||||
176
selfdrive/oscarpilot/settings/settings.cc
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/network/networking.h"
|
||||||
|
|
||||||
|
#include "common/params.h"
|
||||||
|
#include "common/watchdog.h"
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "system/hardware/hw.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/input.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/ssh_keys.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/toggle.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
#include "selfdrive/ui/qt/qt_window.h"
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/navigation/ui/navigation_settings.h"
|
||||||
|
#include "selfdrive/frogpilot/ui/control_settings.h"
|
||||||
|
#include "selfdrive/oscarpilot/settings/basic.h"
|
||||||
|
#include "selfdrive/frogpilot/ui/visual_settings.h"
|
||||||
|
|
||||||
|
#include "selfdrive/oscarpilot/settings/settings.h"
|
||||||
|
|
||||||
|
|
||||||
|
void OscarSettingsWindow::showEvent(QShowEvent *event) {
|
||||||
|
setCurrentPanel(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscarSettingsWindow::setCurrentPanel(int index, const QString ¶m) {
|
||||||
|
panel_widget->setCurrentIndex(index);
|
||||||
|
nav_btns->buttons()[index]->setChecked(true);
|
||||||
|
if (!param.isEmpty()) {
|
||||||
|
emit expandToggleDescription(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OscarSettingsWindow::OscarSettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||||
|
|
||||||
|
// setup two main layouts
|
||||||
|
sidebar_widget = new QWidget;
|
||||||
|
QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget);
|
||||||
|
sidebar_layout->setMargin(0);
|
||||||
|
panel_widget = new QStackedWidget();
|
||||||
|
|
||||||
|
// close button
|
||||||
|
QPushButton *close_btn = new QPushButton(tr("← Back"));
|
||||||
|
close_btn->setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
font-size: 50px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
border 1px grey solid;
|
||||||
|
border-radius: 25px;
|
||||||
|
background-color: #292929;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #3B3B3B;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
close_btn->setFixedSize(300, 125);
|
||||||
|
sidebar_layout->addSpacing(10);
|
||||||
|
sidebar_layout->addWidget(close_btn, 0, Qt::AlignRight);
|
||||||
|
QObject::connect(close_btn, &QPushButton::clicked, [this]() {
|
||||||
|
if (frogPilotTogglesOpen) {
|
||||||
|
frogPilotTogglesOpen = false;
|
||||||
|
this->closeParentToggle();
|
||||||
|
} else {
|
||||||
|
this->closeSettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
||||||
|
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
||||||
|
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;});
|
||||||
|
|
||||||
|
// DevicePanel *device = new DevicePanel(this);
|
||||||
|
// QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide);
|
||||||
|
// QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView);
|
||||||
|
|
||||||
|
QList<QPair<QString, QWidget *>> panels = {
|
||||||
|
{tr("Basic"), new OscarPilotBasicPanel(this)},
|
||||||
|
{tr("Advanced"), frogpilotControls},
|
||||||
|
{tr("Network"), new Networking(this)},
|
||||||
|
{tr("Software"), new SoftwarePanel(this)},
|
||||||
|
// {tr("Device"), new DevicePanel(this)},
|
||||||
|
// FrogPilotControlsPanel
|
||||||
|
// {tr("OscarCloud"), basic},
|
||||||
|
// {tr("Logging"), basic}, // Log / Upload driver cam, Routes
|
||||||
|
// {tr("System"), new OscarPilotBasicPanel(this)}, // Debugging
|
||||||
|
// {tr("Status"), basic}, // Report on stuff like connectivity, free space, detected features
|
||||||
|
// {tr("Extra"), basic}, // Custom cloud services, QOL automations
|
||||||
|
};
|
||||||
|
|
||||||
|
nav_btns = new QButtonGroup(this);
|
||||||
|
for (auto &[name, panel] : panels) {
|
||||||
|
QPushButton *btn = new QPushButton(name);
|
||||||
|
btn->setCheckable(true);
|
||||||
|
btn->setChecked(nav_btns->buttons().size() == 0);
|
||||||
|
btn->setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
color: grey;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: 65px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
QPushButton:checked {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
color: #ADADAD;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||||
|
nav_btns->addButton(btn);
|
||||||
|
sidebar_layout->addWidget(btn, 0, Qt::AlignRight);
|
||||||
|
|
||||||
|
const int lr_margin = name != tr("Network") ? 50 : 0; // Network panel handles its own margins
|
||||||
|
panel->setContentsMargins(lr_margin, 25, lr_margin, 25);
|
||||||
|
|
||||||
|
ScrollView *panel_frame = new ScrollView(panel, this);
|
||||||
|
panel_widget->addWidget(panel_frame);
|
||||||
|
|
||||||
|
if (name == tr("Controls") || name == tr("Visuals")) {
|
||||||
|
QScrollBar *scrollbar = panel_frame->verticalScrollBar();
|
||||||
|
|
||||||
|
QObject::connect(scrollbar, &QScrollBar::valueChanged, this, [this](int value) {
|
||||||
|
if (!frogPilotTogglesOpen) {
|
||||||
|
previousScrollPosition = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(scrollbar, &QScrollBar::rangeChanged, this, [this, panel_frame]() {
|
||||||
|
panel_frame->restorePosition(previousScrollPosition);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() {
|
||||||
|
previousScrollPosition = 0;
|
||||||
|
btn->setChecked(true);
|
||||||
|
panel_widget->setCurrentWidget(w);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sidebar_layout->setContentsMargins(50, 50, 100, 50);
|
||||||
|
|
||||||
|
// main settings layout, sidebar + main panel
|
||||||
|
QHBoxLayout *main_layout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
sidebar_widget->setFixedWidth(500);
|
||||||
|
main_layout->addWidget(sidebar_widget);
|
||||||
|
main_layout->addWidget(panel_widget);
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
* {
|
||||||
|
color: white;
|
||||||
|
font-size: 50px;
|
||||||
|
}
|
||||||
|
OscarSettingsWindow {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
QStackedWidget, ScrollView {
|
||||||
|
background-color: #292929;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
}
|
||||||
43
selfdrive/oscarpilot/settings/settings.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QButtonGroup>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QStackedWidget>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||||
|
|
||||||
|
// ********** settings window + top-level panels **********
|
||||||
|
class OscarSettingsWindow : public QFrame {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OscarSettingsWindow(QWidget *parent = 0);
|
||||||
|
void setCurrentPanel(int index, const QString ¶m = "");
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeSettings();
|
||||||
|
void showDriverView();
|
||||||
|
void expandToggleDescription(const QString ¶m);
|
||||||
|
|
||||||
|
// FrogPilot signals
|
||||||
|
void closeParentToggle();
|
||||||
|
private:
|
||||||
|
QWidget *sidebar_widget;
|
||||||
|
QButtonGroup *nav_btns;
|
||||||
|
QStackedWidget *panel_widget;
|
||||||
|
|
||||||
|
// FrogPilot variables
|
||||||
|
bool frogPilotTogglesOpen;
|
||||||
|
int previousScrollPosition;
|
||||||
|
};
|
||||||
|
|
||||||
42
selfdrive/oscarpilot/settings/style.cc
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "selfdrive/frogpilot/ui/frogpilot_functions.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) {
|
||||||
|
ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent);
|
||||||
|
return d.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) {
|
||||||
|
btn.setText(text);
|
||||||
|
btn.setStyleSheet(R"(
|
||||||
|
QPushButton {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 35px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #E4E4E4;
|
||||||
|
background-color: #393939;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
background-color: #4a4a4a;
|
||||||
|
}
|
||||||
|
QPushButton:disabled {
|
||||||
|
color: #33E4E4E4;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
btn.setFixedSize(250, 100);
|
||||||
|
QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked);
|
||||||
|
hlayout->addWidget(&btn);
|
||||||
|
}
|
||||||
16
selfdrive/oscarpilot/settings/style.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
const button_style = R"(
|
||||||
|
QPushButton {
|
||||||
|
color: grey;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: 65px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
QPushButton:checked {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
QPushButton:pressed {
|
||||||
|
color: #ADADAD;
|
||||||
|
}
|
||||||
|
)";
|
||||||
0
selfdrive/oscarpilot/settings_sync.py
Normal file
0
selfdrive/oscarpilot/stocklong.py
Normal file
0
selfdrive/oscarpilot/weather.cc
Normal file
0
selfdrive/oscarpilot/weather.h
Normal file
@@ -27,7 +27,9 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/drive_stats.cc", "qt/
|
|||||||
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc",
|
"qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc",
|
||||||
"../frogpilot/ui/frogpilot_functions.cc", "../frogpilot/navigation/ui/navigation_settings.cc",
|
"../frogpilot/ui/frogpilot_functions.cc", "../frogpilot/navigation/ui/navigation_settings.cc",
|
||||||
"../frogpilot/ui/control_settings.cc", "../frogpilot/ui/vehicle_settings.cc",
|
"../frogpilot/ui/control_settings.cc", "../frogpilot/ui/vehicle_settings.cc",
|
||||||
"../frogpilot/ui/visual_settings.cc"]
|
"../frogpilot/ui/visual_settings.cc",
|
||||||
|
"../oscarpilot/settings/settings.cc", "../oscarpilot/settings/basic.cc",
|
||||||
|
]
|
||||||
|
|
||||||
qt_env['CPPDEFINES'] = []
|
qt_env['CPPDEFINES'] = []
|
||||||
if maps:
|
if maps:
|
||||||
|
|||||||
@@ -6,156 +6,51 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStackedLayout>
|
#include <QStackedLayout>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTransform>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
#include "common/params.h"
|
#include "common/params.h"
|
||||||
#include "common/timing.h"
|
#include "common/timing.h"
|
||||||
|
|
||||||
RecordButton::RecordButton(QWidget *parent) : QPushButton(parent) {
|
#include "system/hardware/hw.h"
|
||||||
setCheckable(true);
|
#include "selfdrive/ui/qt/qt_window.h"
|
||||||
setChecked(false);
|
#include "selfdrive/ui/qt/util.h"
|
||||||
setFixedSize(148, 148);
|
|
||||||
|
|
||||||
QObject::connect(this, &QPushButton::toggled, [=]() {
|
BodyWindow::BodyWindow(QWidget *parent) : QWidget(parent) {
|
||||||
setEnabled(false);
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
});
|
layout->setSpacing(0);
|
||||||
}
|
layout->setMargin(200);
|
||||||
|
|
||||||
void RecordButton::paintEvent(QPaintEvent *event) {
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
QPainter p(this);
|
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
|
||||||
|
|
||||||
QPoint center(width() / 2, height() / 2);
|
setStyleSheet(R"(
|
||||||
|
BodyWindow {
|
||||||
QColor bg(isChecked() ? "#FFFFFF" : "#737373");
|
background-color: blue;
|
||||||
QColor accent(isChecked() ? "#FF0000" : "#FFFFFF");
|
}
|
||||||
if (!isEnabled()) {
|
)");
|
||||||
bg = QColor("#404040");
|
|
||||||
accent = QColor("#FFFFFF");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDown()) {
|
|
||||||
accent.setAlphaF(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(bg);
|
|
||||||
p.drawEllipse(center, 74, 74);
|
|
||||||
|
|
||||||
p.setPen(QPen(accent, 6));
|
|
||||||
p.setBrush(Qt::NoBrush);
|
|
||||||
p.drawEllipse(center, 42, 42);
|
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(accent);
|
|
||||||
p.drawEllipse(center, 22, 22);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BodyWindow::BodyWindow(QWidget *parent) : fuel_filter(1.0, 5., 1. / UI_FREQ), QWidget(parent) {
|
|
||||||
QStackedLayout *layout = new QStackedLayout(this);
|
|
||||||
layout->setStackingMode(QStackedLayout::StackAll);
|
|
||||||
|
|
||||||
QWidget *w = new QWidget;
|
|
||||||
QVBoxLayout *vlayout = new QVBoxLayout(w);
|
|
||||||
vlayout->setMargin(45);
|
|
||||||
layout->addWidget(w);
|
|
||||||
|
|
||||||
// face
|
|
||||||
face = new QLabel();
|
|
||||||
face->setAlignment(Qt::AlignCenter);
|
|
||||||
layout->addWidget(face);
|
|
||||||
awake = new QMovie("../assets/body/awake.gif", {}, this);
|
|
||||||
awake->setCacheMode(QMovie::CacheAll);
|
|
||||||
sleep = new QMovie("../assets/body/sleep.gif", {}, this);
|
|
||||||
sleep->setCacheMode(QMovie::CacheAll);
|
|
||||||
|
|
||||||
// record button
|
|
||||||
btn = new RecordButton(this);
|
|
||||||
vlayout->addWidget(btn, 0, Qt::AlignBottom | Qt::AlignRight);
|
|
||||||
QObject::connect(btn, &QPushButton::clicked, [=](bool checked) {
|
|
||||||
btn->setEnabled(false);
|
|
||||||
Params().putBool("DisableLogging", !checked);
|
|
||||||
last_button = nanos_since_boot();
|
|
||||||
});
|
|
||||||
w->raise();
|
|
||||||
|
|
||||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState);
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BodyWindow::paintEvent(QPaintEvent *event) {
|
void BodyWindow::paintEvent(QPaintEvent *event) {
|
||||||
QPainter p(this);
|
QPainter painter(this);
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
|
||||||
|
|
||||||
p.fillRect(rect(), QColor(0, 0, 0));
|
QPixmap comma_img = loadPixmap("../assets/oscarpilot_ready.png");
|
||||||
|
|
||||||
// battery outline + detail
|
// Calculate the top-left position to center the image in the window.
|
||||||
p.translate(width() - 136, 16);
|
int x = (this->width() - comma_img.width()) / 2;
|
||||||
const QColor gray = QColor("#737373");
|
int y = (this->height() - comma_img.height()) / 2;
|
||||||
p.setBrush(Qt::NoBrush);
|
|
||||||
p.setPen(QPen(gray, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
|
||||||
p.drawRoundedRect(2, 2, 78, 36, 8, 8);
|
|
||||||
|
|
||||||
p.setPen(Qt::NoPen);
|
// Draw the pixmap at the calculated position.
|
||||||
p.setBrush(gray);
|
painter.drawPixmap(x, y, comma_img);
|
||||||
p.drawRoundedRect(84, 12, 6, 16, 4, 4);
|
}
|
||||||
p.drawRect(84, 12, 3, 16);
|
|
||||||
|
|
||||||
// battery level
|
|
||||||
double fuel = std::clamp(fuel_filter.x(), 0.2f, 1.0f);
|
|
||||||
const int m = 5; // manual margin since we can't do an inner border
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(fuel > 0.25 ? QColor("#32D74B") : QColor("#FF453A"));
|
|
||||||
p.drawRoundedRect(2 + m, 2 + m, (78 - 2*m)*fuel, 36 - 2*m, 4, 4);
|
|
||||||
|
|
||||||
// charging status
|
void BodyWindow::updateState(const UIState &s) {
|
||||||
if (charging) {
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.setBrush(Qt::white);
|
|
||||||
const QPolygonF charger({
|
|
||||||
QPointF(12.31, 0),
|
|
||||||
QPointF(12.31, 16.92),
|
|
||||||
QPointF(18.46, 16.92),
|
|
||||||
QPointF(6.15, 40),
|
|
||||||
QPointF(6.15, 23.08),
|
|
||||||
QPointF(0, 23.08),
|
|
||||||
});
|
|
||||||
p.drawPolygon(charger.translated(98, 0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BodyWindow::offroadTransition(bool offroad) {
|
void BodyWindow::offroadTransition(bool offroad) {
|
||||||
btn->setChecked(true);
|
|
||||||
btn->setEnabled(true);
|
|
||||||
fuel_filter.reset(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BodyWindow::updateState(const UIState &s) {
|
|
||||||
if (!isVisible()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SubMaster &sm = *(s.sm);
|
|
||||||
auto cs = sm["carState"].getCarState();
|
|
||||||
|
|
||||||
charging = cs.getCharging();
|
|
||||||
fuel_filter.update(cs.getFuelGauge());
|
|
||||||
|
|
||||||
// TODO: use carState.standstill when that's fixed
|
|
||||||
const bool standstill = std::abs(cs.getVEgo()) < 0.01;
|
|
||||||
QMovie *m = standstill ? sleep : awake;
|
|
||||||
if (m != face->movie()) {
|
|
||||||
face->setMovie(m);
|
|
||||||
face->movie()->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// update record button state
|
|
||||||
if (sm.updated("managerState") && (sm.rcv_time("managerState") - last_button)*1e-9 > 0.5) {
|
|
||||||
for (auto proc : sm["managerState"].getManagerState().getProcesses()) {
|
|
||||||
if (proc.getName() == "loggerd") {
|
|
||||||
btn->setEnabled(true);
|
|
||||||
btn->setChecked(proc.getRunning());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|||||||
60
selfdrive/ui/qt/body.good
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "selfdrive/ui/qt/body.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStackedLayout>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTransform>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
|
#include "common/params.h"
|
||||||
|
#include "common/timing.h"
|
||||||
|
|
||||||
|
#include "system/hardware/hw.h"
|
||||||
|
#include "selfdrive/ui/qt/qt_window.h"
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
|
void LogoWidget::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyWindow::BodyWindow(QWidget *parent) : QWidget(parent) {
|
||||||
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setMargin(200);
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
BodyWindow {
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
QPixmap comma_img = loadPixmap("../assets/oscarpilot_ready.png");
|
||||||
|
|
||||||
|
// Calculate the top-left position to center the image in the window.
|
||||||
|
int x = (this->width() - comma_img.width()) / 2;
|
||||||
|
int y = (this->height() - comma_img.height()) / 2;
|
||||||
|
|
||||||
|
// Draw the pixmap at the calculated position.
|
||||||
|
painter.drawPixmap(x, y, comma_img);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BodyWindow::updateState(const UIState &s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::offroadTransition(bool offroad) {
|
||||||
|
}
|
||||||
@@ -3,35 +3,21 @@
|
|||||||
#include <QMovie>
|
#include <QMovie>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QSocketNotifier>
|
||||||
|
#include <QVariantAnimation>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "selfdrive/ui/ui.h"
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
class RecordButton : public QPushButton {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
RecordButton(QWidget* parent = 0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void paintEvent(QPaintEvent*) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BodyWindow : public QWidget {
|
class BodyWindow : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BodyWindow(QWidget* parent = 0);
|
BodyWindow(QWidget* parent = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool charging = false;
|
|
||||||
uint64_t last_button = 0;
|
|
||||||
FirstOrderFilter fuel_filter;
|
|
||||||
QLabel *face;
|
|
||||||
QMovie *awake, *sleep;
|
|
||||||
RecordButton *btn;
|
|
||||||
void paintEvent(QPaintEvent*) override;
|
void paintEvent(QPaintEvent*) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateState(const UIState &s);
|
void updateState(const UIState &s);
|
||||||
void offroadTransition(bool onroad);
|
void offroadTransition(bool onroad);
|
||||||
|
|||||||
38
selfdrive/ui/qt/body.h.org
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMovie>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "selfdrive/ui/ui.h"
|
||||||
|
|
||||||
|
class RecordButton : public QPushButton {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
RecordButton(QWidget* parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent*) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BodyWindow : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
BodyWindow(QWidget* parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool charging = false;
|
||||||
|
uint64_t last_button = 0;
|
||||||
|
FirstOrderFilter fuel_filter;
|
||||||
|
QLabel *face;
|
||||||
|
QMovie *awake, *sleep;
|
||||||
|
RecordButton *btn;
|
||||||
|
void paintEvent(QPaintEvent*) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateState(const UIState &s);
|
||||||
|
void offroadTransition(bool onroad);
|
||||||
|
};
|
||||||
161
selfdrive/ui/qt/body.org
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
#include "selfdrive/ui/qt/body.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStackedLayout>
|
||||||
|
|
||||||
|
#include "common/params.h"
|
||||||
|
#include "common/timing.h"
|
||||||
|
|
||||||
|
RecordButton::RecordButton(QWidget *parent) : QPushButton(parent) {
|
||||||
|
setCheckable(true);
|
||||||
|
setChecked(false);
|
||||||
|
setFixedSize(148, 148);
|
||||||
|
|
||||||
|
QObject::connect(this, &QPushButton::toggled, [=]() {
|
||||||
|
setEnabled(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordButton::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter p(this);
|
||||||
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
QPoint center(width() / 2, height() / 2);
|
||||||
|
|
||||||
|
QColor bg(isChecked() ? "#FFFFFF" : "#737373");
|
||||||
|
QColor accent(isChecked() ? "#FF0000" : "#FFFFFF");
|
||||||
|
if (!isEnabled()) {
|
||||||
|
bg = QColor("#404040");
|
||||||
|
accent = QColor("#FFFFFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDown()) {
|
||||||
|
accent.setAlphaF(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(bg);
|
||||||
|
p.drawEllipse(center, 74, 74);
|
||||||
|
|
||||||
|
p.setPen(QPen(accent, 6));
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
p.drawEllipse(center, 42, 42);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(accent);
|
||||||
|
p.drawEllipse(center, 22, 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BodyWindow::BodyWindow(QWidget *parent) : fuel_filter(1.0, 5., 1. / UI_FREQ), QWidget(parent) {
|
||||||
|
QStackedLayout *layout = new QStackedLayout(this);
|
||||||
|
layout->setStackingMode(QStackedLayout::StackAll);
|
||||||
|
|
||||||
|
QWidget *w = new QWidget;
|
||||||
|
QVBoxLayout *vlayout = new QVBoxLayout(w);
|
||||||
|
vlayout->setMargin(45);
|
||||||
|
layout->addWidget(w);
|
||||||
|
|
||||||
|
// face
|
||||||
|
face = new QLabel();
|
||||||
|
face->setAlignment(Qt::AlignCenter);
|
||||||
|
layout->addWidget(face);
|
||||||
|
awake = new QMovie("../assets/body/awake.gif", {}, this);
|
||||||
|
awake->setCacheMode(QMovie::CacheAll);
|
||||||
|
sleep = new QMovie("../assets/body/sleep.gif", {}, this);
|
||||||
|
sleep->setCacheMode(QMovie::CacheAll);
|
||||||
|
|
||||||
|
// record button
|
||||||
|
btn = new RecordButton(this);
|
||||||
|
vlayout->addWidget(btn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||||
|
QObject::connect(btn, &QPushButton::clicked, [=](bool checked) {
|
||||||
|
btn->setEnabled(false);
|
||||||
|
Params().putBool("DisableLogging", !checked);
|
||||||
|
last_button = nanos_since_boot();
|
||||||
|
});
|
||||||
|
w->raise();
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter p(this);
|
||||||
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
p.fillRect(rect(), QColor(0, 0, 0));
|
||||||
|
|
||||||
|
// battery outline + detail
|
||||||
|
p.translate(width() - 136, 16);
|
||||||
|
const QColor gray = QColor("#737373");
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
p.setPen(QPen(gray, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||||
|
p.drawRoundedRect(2, 2, 78, 36, 8, 8);
|
||||||
|
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(gray);
|
||||||
|
p.drawRoundedRect(84, 12, 6, 16, 4, 4);
|
||||||
|
p.drawRect(84, 12, 3, 16);
|
||||||
|
|
||||||
|
// battery level
|
||||||
|
double fuel = std::clamp(fuel_filter.x(), 0.2f, 1.0f);
|
||||||
|
const int m = 5; // manual margin since we can't do an inner border
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(fuel > 0.25 ? QColor("#32D74B") : QColor("#FF453A"));
|
||||||
|
p.drawRoundedRect(2 + m, 2 + m, (78 - 2*m)*fuel, 36 - 2*m, 4, 4);
|
||||||
|
|
||||||
|
// charging status
|
||||||
|
if (charging) {
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(Qt::white);
|
||||||
|
const QPolygonF charger({
|
||||||
|
QPointF(12.31, 0),
|
||||||
|
QPointF(12.31, 16.92),
|
||||||
|
QPointF(18.46, 16.92),
|
||||||
|
QPointF(6.15, 40),
|
||||||
|
QPointF(6.15, 23.08),
|
||||||
|
QPointF(0, 23.08),
|
||||||
|
});
|
||||||
|
p.drawPolygon(charger.translated(98, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::offroadTransition(bool offroad) {
|
||||||
|
btn->setChecked(true);
|
||||||
|
btn->setEnabled(true);
|
||||||
|
fuel_filter.reset(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::updateState(const UIState &s) {
|
||||||
|
if (!isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubMaster &sm = *(s.sm);
|
||||||
|
auto cs = sm["carState"].getCarState();
|
||||||
|
|
||||||
|
charging = cs.getCharging();
|
||||||
|
fuel_filter.update(cs.getFuelGauge());
|
||||||
|
|
||||||
|
// TODO: use carState.standstill when that's fixed
|
||||||
|
const bool standstill = std::abs(cs.getVEgo()) < 0.01;
|
||||||
|
QMovie *m = standstill ? sleep : awake;
|
||||||
|
if (m != face->movie()) {
|
||||||
|
face->setMovie(m);
|
||||||
|
face->movie()->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update record button state
|
||||||
|
if (sm.updated("managerState") && (sm.rcv_time("managerState") - last_button)*1e-9 > 0.5) {
|
||||||
|
for (auto proc : sm["managerState"].getManagerState().getProcesses()) {
|
||||||
|
if (proc.getName() == "loggerd") {
|
||||||
|
btn->setEnabled(true);
|
||||||
|
btn->setChecked(proc.getRunning());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
52
selfdrive/ui/qt/body.webbrowser.test
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include "selfdrive/ui/qt/body.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStackedLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTransform>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QWebEngineView> // Include the QWebEngineView header
|
||||||
|
|
||||||
|
#include "common/params.h"
|
||||||
|
#include "common/timing.h"
|
||||||
|
#include "system/hardware/hw.h"
|
||||||
|
#include "selfdrive/ui/qt/qt_window.h"
|
||||||
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
|
void LogoWidget::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyWindow::BodyWindow(QWidget *parent) : QWidget(parent) {
|
||||||
|
// Create a QWebEngineView
|
||||||
|
QWebEngineView *view = new QWebEngineView(this);
|
||||||
|
view->setUrl(QUrl("http://www.fark.com/")); // Set the URL to fark.com
|
||||||
|
|
||||||
|
// Filler
|
||||||
|
|
||||||
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->setMargin(0); // Set margin to 0 to fill the entire window
|
||||||
|
layout->addWidget(view, 0, 0); // Add the view to the layout
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
setStyleSheet(R"(
|
||||||
|
BodyWindow {
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
QObject::connect(uiState(), &UIState::uiUpdate, this, &BodyWindow::updateState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::updateState(const UIState &s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BodyWindow::offroadTransition(bool offroad) {
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
|
|||||||
});
|
});
|
||||||
slayout->addWidget(driver_view);
|
slayout->addWidget(driver_view);
|
||||||
setAttribute(Qt::WA_NoSystemBackground);
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState);
|
// QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState);
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition);
|
QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition);
|
||||||
QObject::connect(uiState(), &UIState::offroadTransition, sidebar, &Sidebar::offroadTransition);
|
QObject::connect(uiState(), &UIState::offroadTransition, sidebar, &Sidebar::offroadTransition);
|
||||||
}
|
}
|
||||||
@@ -70,9 +70,9 @@ void HomeWindow::updateState(const UIState &s) {
|
|||||||
|
|
||||||
void HomeWindow::offroadTransition(bool offroad) {
|
void HomeWindow::offroadTransition(bool offroad) {
|
||||||
body->setEnabled(false);
|
body->setEnabled(false);
|
||||||
sidebar->setVisible(offroad);
|
sidebar->setVisible(false);
|
||||||
if (offroad) {
|
if (offroad) {
|
||||||
slayout->setCurrentWidget(home);
|
slayout->setCurrentWidget(body);
|
||||||
} else {
|
} else {
|
||||||
slayout->setCurrentWidget(onroad);
|
slayout->setCurrentWidget(onroad);
|
||||||
}
|
}
|
||||||
@@ -83,15 +83,20 @@ void HomeWindow::showDriverView(bool show) {
|
|||||||
emit closeSettings();
|
emit closeSettings();
|
||||||
slayout->setCurrentWidget(driver_view);
|
slayout->setCurrentWidget(driver_view);
|
||||||
} else {
|
} else {
|
||||||
slayout->setCurrentWidget(home);
|
slayout->setCurrentWidget(body);
|
||||||
}
|
}
|
||||||
sidebar->setVisible(show == false);
|
sidebar->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||||
|
if (body->isVisible()) {
|
||||||
|
showSidebar(true);
|
||||||
|
slayout->setCurrentWidget(home);
|
||||||
|
} else {
|
||||||
// Handle sidebar collapsing
|
// Handle sidebar collapsing
|
||||||
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
||||||
sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible());
|
sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,8 +183,8 @@ void DeclinePage::showEvent(QShowEvent *event) {
|
|||||||
void OnboardingWindow::updateActiveScreen() {
|
void OnboardingWindow::updateActiveScreen() {
|
||||||
if (!accepted_terms) {
|
if (!accepted_terms) {
|
||||||
setCurrentIndex(0);
|
setCurrentIndex(0);
|
||||||
} else if (!training_done && !params.getBool("Passive")) {
|
// } else if (!training_done && !params.getBool("Passive")) {
|
||||||
setCurrentIndex(1);
|
// setCurrentIndex(1);
|
||||||
} else {
|
} else {
|
||||||
emit onboardingDone();
|
emit onboardingDone();
|
||||||
}
|
}
|
||||||
@@ -230,5 +230,11 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) {
|
|||||||
background-color: #4F4F4F;
|
background-color: #4F4F4F;
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
// # Oscar sez
|
||||||
|
Params().put("HasAcceptedTerms", current_terms_version);
|
||||||
|
Params().put("CompletedTrainingVersion", current_training_version);
|
||||||
|
accepted_terms = true;
|
||||||
|
emit onboardingDone();
|
||||||
updateActiveScreen();
|
updateActiveScreen();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -435,9 +435,9 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
|||||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||||
QObject::connect(toggles, &TogglesPanel::updateMetric, this, &SettingsWindow::updateMetric);
|
QObject::connect(toggles, &TogglesPanel::updateMetric, this, &SettingsWindow::updateMetric);
|
||||||
|
|
||||||
FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
// FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
||||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
// QObject::connect(frogpilotControls, &FrogPilotControlsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
||||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;});
|
// QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;});
|
||||||
|
|
||||||
FrogPilotVisualsPanel *frogpilotVisuals = new FrogPilotVisualsPanel(this);
|
FrogPilotVisualsPanel *frogpilotVisuals = new FrogPilotVisualsPanel(this);
|
||||||
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;});
|
||||||
@@ -448,7 +448,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
|||||||
{tr("Network"), new Networking(this)},
|
{tr("Network"), new Networking(this)},
|
||||||
{tr("Toggles"), toggles},
|
{tr("Toggles"), toggles},
|
||||||
{tr("Software"), new SoftwarePanel(this)},
|
{tr("Software"), new SoftwarePanel(this)},
|
||||||
{tr("Controls"), frogpilotControls},
|
// {tr("Controls"), frogpilotControls},
|
||||||
{tr("Navigation"), new FrogPilotNavigationPanel(this)},
|
{tr("Navigation"), new FrogPilotNavigationPanel(this)},
|
||||||
{tr("Vehicles"), new FrogPilotVehiclesPanel(this)},
|
{tr("Vehicles"), new FrogPilotVehiclesPanel(this)},
|
||||||
{tr("Visuals"), frogpilotVisuals},
|
{tr("Visuals"), frogpilotVisuals},
|
||||||
|
|||||||
@@ -29,20 +29,20 @@ static void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, cons
|
|||||||
p.setOpacity(1.0);
|
p.setOpacity(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawIconRotate(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity, const int angle) {
|
// static void drawIconRotate(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity, const int angle) {
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
// p.setRenderHint(QPainter::Antialiasing);
|
||||||
p.setOpacity(1.0); // bg dictates opacity of ellipse
|
// p.setOpacity(1.0); // bg dictates opacity of ellipse
|
||||||
p.setPen(Qt::NoPen);
|
// p.setPen(Qt::NoPen);
|
||||||
p.setBrush(bg);
|
// p.setBrush(bg);
|
||||||
p.drawEllipse(center, btn_size / 2, btn_size / 2);
|
// p.drawEllipse(center, btn_size / 2, btn_size / 2);
|
||||||
p.save();
|
// p.save();
|
||||||
p.translate(center);
|
// p.translate(center);
|
||||||
p.rotate(-angle);
|
// p.rotate(-angle);
|
||||||
p.setOpacity(opacity);
|
// p.setOpacity(opacity);
|
||||||
p.drawPixmap(-QPoint(img.width() / 2, img.height() / 2), img);
|
// p.drawPixmap(-QPoint(img.width() / 2, img.height() / 2), img);
|
||||||
p.setOpacity(1.0);
|
// p.setOpacity(1.0);
|
||||||
p.restore();
|
// p.restore();
|
||||||
}
|
// }
|
||||||
|
|
||||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent), scene(uiState()->scene) {
|
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent), scene(uiState()->scene) {
|
||||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||||
@@ -427,24 +427,26 @@ void ExperimentalButton::updateState(const UIState &s, bool leadInfo) {
|
|||||||
|
|
||||||
void ExperimentalButton::paintEvent(QPaintEvent *event) {
|
void ExperimentalButton::paintEvent(QPaintEvent *event) {
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
// Custom steering wheel icon
|
// Steering wheel icon disabled
|
||||||
engage_img = wheelImages[wheelIcon];
|
|
||||||
QPixmap img = wheelIcon ? engage_img : (experimental_mode ? experimental_img : engage_img);
|
|
||||||
|
|
||||||
QColor background_color = wheelIcon && !isDown() && engageable ?
|
// // Custom steering wheel icon
|
||||||
(scene.always_on_lateral_active ? QColor(10, 186, 181, 255) :
|
// engage_img = wheelImages[wheelIcon];
|
||||||
(scene.conditional_status == 1 ? QColor(255, 246, 0, 255) :
|
// QPixmap img = wheelIcon ? engage_img : (experimental_mode ? experimental_img : engage_img);
|
||||||
(experimental_mode ? QColor(218, 111, 37, 241) :
|
|
||||||
(scene.navigate_on_openpilot ? QColor(49, 161, 238, 255) : QColor(0, 0, 0, 166))))) :
|
|
||||||
QColor(0, 0, 0, 166);
|
|
||||||
|
|
||||||
if (!scene.show_driver_camera) {
|
// QColor background_color = wheelIcon && !isDown() && engageable ?
|
||||||
if (rotatingWheel || firefoxRandomEventTriggered) {
|
// (scene.always_on_lateral_active ? QColor(10, 186, 181, 255) :
|
||||||
drawIconRotate(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || (!engageable && !scene.always_on_lateral_active)) ? 0.6 : 1.0, steeringAngleDeg);
|
// (scene.conditional_status == 1 ? QColor(255, 246, 0, 255) :
|
||||||
} else {
|
// (experimental_mode ? QColor(218, 111, 37, 241) :
|
||||||
drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || (!engageable && !scene.always_on_lateral_active)) ? 0.6 : 1.0);
|
// (scene.navigate_on_openpilot ? QColor(49, 161, 238, 255) : QColor(0, 0, 0, 166))))) :
|
||||||
}
|
// QColor(0, 0, 0, 166);
|
||||||
}
|
|
||||||
|
// if (!scene.show_driver_camera) {
|
||||||
|
// if (rotatingWheel || firefoxRandomEventTriggered) {
|
||||||
|
// drawIconRotate(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || (!engageable && !scene.always_on_lateral_active)) ? 0.6 : 1.0, steeringAngleDeg);
|
||||||
|
// } else {
|
||||||
|
// drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || (!engageable && !scene.always_on_lateral_active)) ? 0.6 : 1.0);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -475,11 +477,12 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par
|
|||||||
// Neokii screen recorder
|
// Neokii screen recorder
|
||||||
QHBoxLayout *top_right_layout = new QHBoxLayout();
|
QHBoxLayout *top_right_layout = new QHBoxLayout();
|
||||||
top_right_layout->setSpacing(0);
|
top_right_layout->setSpacing(0);
|
||||||
recorder_btn = new ScreenRecorder(this);
|
|
||||||
top_right_layout->addWidget(recorder_btn);
|
|
||||||
|
|
||||||
experimental_btn = new ExperimentalButton(this);
|
// recorder_btn = new ScreenRecorder(this);
|
||||||
top_right_layout->addWidget(experimental_btn);
|
// top_right_layout->addWidget(recorder_btn);
|
||||||
|
|
||||||
|
// experimental_btn = new ExperimentalButton(this);
|
||||||
|
// top_right_layout->addWidget(experimental_btn);
|
||||||
|
|
||||||
main_layout->addLayout(top_right_layout, 0);
|
main_layout->addLayout(top_right_layout, 0);
|
||||||
main_layout->setAlignment(top_right_layout, Qt::AlignTop | Qt::AlignRight);
|
main_layout->setAlignment(top_right_layout, Qt::AlignTop | Qt::AlignRight);
|
||||||
@@ -1592,32 +1595,35 @@ void AnnotatedCameraWidget::drawStatusBar(QPainter &p) {
|
|||||||
p.setOpacity(1.0);
|
p.setOpacity(1.0);
|
||||||
p.drawRoundedRect(statusBarRect, 30, 30);
|
p.drawRoundedRect(statusBarRect, 30, 30);
|
||||||
|
|
||||||
QString roadName = roadNameUI ? QString::fromStdString(paramsMemory.get("RoadName")) : QString();
|
QString roadName = roadNameUI ? QString::fromStdString(paramsMemory.get("RoadName")) : QString();
|
||||||
|
// // QString roadName = QString::fromStdString(paramsMemory.get("oscar_debug"));
|
||||||
|
|
||||||
QMap<int, QString> conditionalStatusMap = {
|
// QMap<int, QString> conditionalStatusMap = {
|
||||||
{0, "Conditional Experimental Mode ready"},
|
// {0, "Conditional Experimental Mode ready"},
|
||||||
{1, "Conditional Experimental overridden"},
|
// {1, "Conditional Experimental overridden"},
|
||||||
{2, "Experimental Mode manually activated"},
|
// {2, "Experimental Mode manually activated"},
|
||||||
{3, "Conditional Experimental overridden"},
|
// {3, "Conditional Experimental overridden"},
|
||||||
{4, "Experimental Mode manually activated"},
|
// {4, "Experimental Mode manually activated"},
|
||||||
{5, "Experimental Mode activated for navigation" + (mapOpen ? "" : QString(" instructions input"))},
|
// {5, "Experimental Mode activated for navigation" + (mapOpen ? "" : QString(" instructions input"))},
|
||||||
{6, "Experimental Mode activated due to" + (mapOpen ? "SLC" : QString(" no speed limit set"))},
|
// {6, "Experimental Mode activated due to" + (mapOpen ? "SLC" : QString(" no speed limit set"))},
|
||||||
{7, "Experimental Mode activated due to" + (mapOpen ? " speed" : " speed being less than " + QString::number(conditionalSpeedLead) + (is_metric ? " kph" : " mph"))},
|
// {7, "Experimental Mode activated due to" + (mapOpen ? " speed" : " speed being less than " + QString::number(conditionalSpeedLead) + (is_metric ? " kph" : " mph"))},
|
||||||
{8, "Experimental Mode activated due to" + (mapOpen ? " speed" : " speed being less than " + QString::number(conditionalSpeed) + (is_metric ? " kph" : " mph"))},
|
// {8, "Experimental Mode activated due to" + (mapOpen ? " speed" : " speed being less than " + QString::number(conditionalSpeed) + (is_metric ? " kph" : " mph"))},
|
||||||
{9, "Experimental Mode activated for slower lead"},
|
// {9, "Experimental Mode activated for slower lead"},
|
||||||
{10, "Experimental Mode activated for turn" + (mapOpen ? "" : QString(" / lane change"))},
|
// {10, "Experimental Mode activated for turn" + (mapOpen ? "" : QString(" / lane change"))},
|
||||||
{11, "Experimental Mode activated for curve"},
|
// {11, "Experimental Mode activated for curve"},
|
||||||
{12, "Experimental Mode activated for stop" + (mapOpen ? "" : QString(" sign / stop light"))},
|
// {12, "Experimental Mode activated for stop" + (mapOpen ? "" : QString(" sign / stop light"))},
|
||||||
};
|
// };
|
||||||
|
|
||||||
QString screenSuffix = ". Double tap the screen to revert";
|
QString screenSuffix = ". Double tap the screen to revert";
|
||||||
QString wheelSuffix = ". Double press the \"LKAS\" button to revert";
|
QString wheelSuffix = ". Double press the \"LKAS\" button to revert";
|
||||||
|
|
||||||
if (alwaysOnLateral) {
|
// if (alwaysOnLateral) {
|
||||||
newStatus = QString("Always On Lateral active") + (mapOpen ? "" : ". Press the \"Cruise Control\" button to disable");
|
// newStatus = QString("Always On Lateral active") + (mapOpen ? "" : ". Press the \"Cruise Control\" button to disable");
|
||||||
} else if (conditionalExperimental) {
|
// } else if (conditionalExperimental) {
|
||||||
newStatus = conditionalStatusMap.contains(conditionalStatus) && status != STATUS_DISENGAGED ? conditionalStatusMap[conditionalStatus] : conditionalStatusMap[0];
|
// newStatus = conditionalStatusMap.contains(conditionalStatus) && status != STATUS_DISENGAGED ? conditionalStatusMap[conditionalStatus] : conditionalStatusMap[0];
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
newStatus = QString::fromStdString(paramsMemory.get("oscar_debug"));
|
||||||
|
|
||||||
// Check if status has changed or if the road name is empty
|
// Check if status has changed or if the road name is empty
|
||||||
if (newStatus != lastShownStatus || roadName.isEmpty()) {
|
if (newStatus != lastShownStatus || roadName.isEmpty()) {
|
||||||
|
|||||||
@@ -54,7 +54,12 @@ Updater::Updater(const QString &updater_path, const QString &manifest_path, QWid
|
|||||||
background-color: #3049F4;
|
background-color: #3049F4;
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
QObject::connect(install, &QPushButton::clicked, this, &Updater::installUpdate);
|
|
||||||
|
QObject::connect(connect, &QPushButton::clicked, [=]() {
|
||||||
|
countdownTimer->stop();
|
||||||
|
setCurrentWidget(wifi);
|
||||||
|
});
|
||||||
|
|
||||||
hlayout->addWidget(install);
|
hlayout->addWidget(install);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +119,20 @@ Updater::Updater(const QString &updater_path, const QString &manifest_path, QWid
|
|||||||
addWidget(wifi);
|
addWidget(wifi);
|
||||||
addWidget(progress);
|
addWidget(progress);
|
||||||
|
|
||||||
|
// Initialize the countdown timer and value
|
||||||
|
countdownValue = 5; // 5 seconds countdown
|
||||||
|
countdownTimer = new QTimer(this);
|
||||||
|
countdownTimer->setInterval(1000); // 1 second interval
|
||||||
|
|
||||||
|
// Connect the timer's timeout signal to update the countdown and button text
|
||||||
|
QObject::connect(countdownTimer, &QTimer::timeout, this, &Updater::updateCountdown);
|
||||||
|
|
||||||
|
// Start the countdown
|
||||||
|
countdownTimer->start();
|
||||||
|
|
||||||
|
// Set initial button text
|
||||||
|
install->setText(tr("Install (5)"));
|
||||||
|
|
||||||
setStyleSheet(R"(
|
setStyleSheet(R"(
|
||||||
* {
|
* {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -144,6 +163,16 @@ Updater::Updater(const QString &updater_path, const QString &manifest_path, QWid
|
|||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Updater::updateCountdown() {
|
||||||
|
countdownValue--;
|
||||||
|
if (countdownValue > 0) {
|
||||||
|
install->setText(tr("Install (%1)").arg(countdownValue));
|
||||||
|
} else {
|
||||||
|
countdownTimer->stop();
|
||||||
|
installUpdate(); // Assuming this is the method that starts the update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Updater::installUpdate() {
|
void Updater::installUpdate() {
|
||||||
setCurrentWidget(progress);
|
setCurrentWidget(progress);
|
||||||
QObject::connect(&proc, &QProcess::readyReadStandardOutput, this, &Updater::readProgress);
|
QObject::connect(&proc, &QProcess::readyReadStandardOutput, this, &Updater::readProgress);
|
||||||
|
|||||||
@@ -26,4 +26,7 @@ private:
|
|||||||
QProgressBar *bar;
|
QProgressBar *bar;
|
||||||
QPushButton *reboot;
|
QPushButton *reboot;
|
||||||
QWidget *prompt, *wifi, *progress;
|
QWidget *prompt, *wifi, *progress;
|
||||||
|
QTimer *countdownTimer;
|
||||||
|
int countdownValue;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||