FrogPilot setup
@@ -117,6 +117,9 @@ struct CarEvent @0x9b1657f34caf3ad3 {
|
||||
paramsdTemporaryError @50;
|
||||
paramsdPermanentError @119;
|
||||
|
||||
# FrogPilot events
|
||||
blockUser @123;
|
||||
|
||||
radarCanErrorDEPRECATED @15;
|
||||
communityFeatureDisallowedDEPRECATED @62;
|
||||
radarCommIssueDEPRECATED @67;
|
||||
|
||||
@@ -8,19 +8,22 @@ $Cxx.namespace("cereal");
|
||||
# cereal, so use these if you want custom events in your fork.
|
||||
|
||||
# you can rename the struct, but don't change the identifier
|
||||
struct CustomReserved0 @0x81c2f05a394cf4af {
|
||||
struct FrogPilotCarControl @0x81c2f05a394cf4af {
|
||||
}
|
||||
|
||||
struct CustomReserved1 @0xaedffd8f31e7b55d {
|
||||
struct FrogPilotCarState @0xaedffd8f31e7b55d {
|
||||
}
|
||||
|
||||
struct CustomReserved2 @0xf35cc4560bbf6ec2 {
|
||||
struct FrogPilotDeviceState @0xf35cc4560bbf6ec2 {
|
||||
}
|
||||
|
||||
struct CustomReserved3 @0xda96579883444c35 {
|
||||
struct FrogPilotNavigation @0xda96579883444c35 {
|
||||
}
|
||||
|
||||
struct CustomReserved4 @0x80ae746ee2596b11 {
|
||||
struct FrogPilotPlan @0x80ae746ee2596b11 {
|
||||
jerk @7 :Float32;
|
||||
tFollow @20 :Float32;
|
||||
vCruise @22 :Float32;
|
||||
}
|
||||
|
||||
struct CustomReserved5 @0xa5cd762cd951a455 {
|
||||
|
||||
@@ -738,6 +738,7 @@ struct ControlsState @0x97ff69c53601abf1 {
|
||||
normal @0; # low priority alert for user's convenience
|
||||
userPrompt @1; # mid priority alert that might require user intervention
|
||||
critical @2; # high priority alert that needs immediate user intervention
|
||||
frogpilot @3; # green startup alert
|
||||
}
|
||||
|
||||
enum AlertSize {
|
||||
@@ -2330,11 +2331,11 @@ struct Event {
|
||||
customReservedRawData2 @126 :Data;
|
||||
|
||||
# *********** Custom: reserved for forks ***********
|
||||
customReserved0 @107 :Custom.CustomReserved0;
|
||||
customReserved1 @108 :Custom.CustomReserved1;
|
||||
customReserved2 @109 :Custom.CustomReserved2;
|
||||
customReserved3 @110 :Custom.CustomReserved3;
|
||||
customReserved4 @111 :Custom.CustomReserved4;
|
||||
frogpilotCarControl @107 :Custom.FrogPilotCarControl;
|
||||
frogpilotCarState @108 :Custom.FrogPilotCarState;
|
||||
frogpilotDeviceState @109 :Custom.FrogPilotDeviceState;
|
||||
frogpilotNavigation @110 :Custom.FrogPilotNavigation;
|
||||
frogpilotPlan @111 :Custom.FrogPilotPlan;
|
||||
customReserved5 @112 :Custom.CustomReserved5;
|
||||
customReserved6 @113 :Custom.CustomReserved6;
|
||||
customReserved7 @114 :Custom.CustomReserved7;
|
||||
|
||||
@@ -82,6 +82,13 @@ services: dict[str, tuple] = {
|
||||
"userFlag": (True, 0., 1),
|
||||
"microphone": (True, 10., 10),
|
||||
|
||||
# FrogPilot
|
||||
"frogpilotCarControl": (True, 100., 10),
|
||||
"frogpilotCarState": (True, 100., 10),
|
||||
"frogpilotDeviceState": (True, 2., 1),
|
||||
"frogpilotNavigation": (True, 1., 10),
|
||||
"frogpilotPlan": (True, 20., 5),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
"testJoystick": (True, 0.),
|
||||
|
||||
@@ -8,6 +8,10 @@ class Conversions:
|
||||
KPH_TO_MS = 1. / MS_TO_KPH
|
||||
MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
|
||||
MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
|
||||
METER_TO_FOOT = 3.28084
|
||||
FOOT_TO_METER = 1 / METER_TO_FOOT
|
||||
CM_TO_INCH = METER_TO_FOOT / 100.0 * 12.0;
|
||||
INCH_TO_CM = 1.0 / CM_TO_INCH;
|
||||
MS_TO_KNOTS = 1.9438
|
||||
KNOTS_TO_MS = 1. / MS_TO_KNOTS
|
||||
|
||||
|
||||
@@ -207,6 +207,18 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterLastFetchTime", PERSISTENT},
|
||||
{"Version", PERSISTENT},
|
||||
|
||||
// FrogPilot parameters
|
||||
{"CustomAlerts", PERSISTENT},
|
||||
{"CustomPaths", PERSISTENT},
|
||||
{"CustomUI", PERSISTENT},
|
||||
{"FrogPilotTogglesUpdated", PERSISTENT},
|
||||
{"FrogsGoMoo", PERSISTENT},
|
||||
{"LateralTune", PERSISTENT},
|
||||
{"LongitudinalTune", PERSISTENT},
|
||||
{"QOLControls", PERSISTENT},
|
||||
{"QOLVisuals", PERSISTENT},
|
||||
{"StockTune", PERSISTENT},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -43,6 +43,14 @@ public:
|
||||
inline bool getBool(const std::string &key, bool block = false) {
|
||||
return get(key, block) == "1";
|
||||
}
|
||||
inline int getInt(const std::string &key, bool block = false) {
|
||||
std::string value = get(key, block);
|
||||
return value.empty() ? 0 : std::stoi(value);
|
||||
}
|
||||
inline float getFloat(const std::string &key, bool block = false) {
|
||||
std::string value = get(key, block);
|
||||
return value.empty() ? 0.0 : std::stof(value);
|
||||
}
|
||||
std::map<std::string, std::string> readAll();
|
||||
|
||||
// helpers for writing values
|
||||
@@ -53,10 +61,24 @@ public:
|
||||
inline int putBool(const std::string &key, bool val) {
|
||||
return put(key.c_str(), val ? "1" : "0", 1);
|
||||
}
|
||||
inline int putInt(const std::string &key, int val) {
|
||||
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
|
||||
}
|
||||
inline int putFloat(const std::string &key, float val) {
|
||||
return put(key.c_str(), std::to_string(val).c_str(), std::to_string(val).size());
|
||||
}
|
||||
void putNonBlocking(const std::string &key, const std::string &val);
|
||||
inline void putBoolNonBlocking(const std::string &key, bool val) {
|
||||
putNonBlocking(key, val ? "1" : "0");
|
||||
}
|
||||
void putIntNonBlocking(const std::string &key, const std::string &val);
|
||||
inline void putIntNonBlocking(const std::string &key, int val) {
|
||||
putNonBlocking(key, std::to_string(val));
|
||||
}
|
||||
void putFloatNonBlocking(const std::string &key, const std::string &val);
|
||||
inline void putFloatNonBlocking(const std::string &key, float val) {
|
||||
putNonBlocking(key, std::to_string(val));
|
||||
}
|
||||
|
||||
private:
|
||||
void asyncWriteThread();
|
||||
|
||||
@@ -17,11 +17,17 @@ cdef extern from "common/params.h":
|
||||
c_Params(string) except + nogil
|
||||
string get(string, bool) nogil
|
||||
bool getBool(string, bool) nogil
|
||||
int getInt(string, bool) nogil
|
||||
float getFloat(string, bool) nogil
|
||||
int remove(string) nogil
|
||||
int put(string, string) nogil
|
||||
void putNonBlocking(string, string) nogil
|
||||
void putBoolNonBlocking(string, bool) nogil
|
||||
void putIntNonBlocking(string, int) nogil
|
||||
void putFloatNonBlocking(string, float) nogil
|
||||
int putBool(string, bool) nogil
|
||||
int putInt(string, int) nogil
|
||||
int putFloat(string, float) nogil
|
||||
bool checkKey(string) nogil
|
||||
string getParamPath(string) nogil
|
||||
void clearAll(ParamKeyType)
|
||||
@@ -77,6 +83,20 @@ cdef class Params:
|
||||
r = self.p.getBool(k, block)
|
||||
return r
|
||||
|
||||
def get_int(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef int r
|
||||
with nogil:
|
||||
r = self.p.getInt(k, block)
|
||||
return r
|
||||
|
||||
def get_float(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef float r
|
||||
with nogil:
|
||||
r = self.p.getFloat(k, block)
|
||||
return r
|
||||
|
||||
def put(self, key, dat):
|
||||
"""
|
||||
Warning: This function blocks until the param is written to disk!
|
||||
@@ -94,6 +114,16 @@ cdef class Params:
|
||||
with nogil:
|
||||
self.p.putBool(k, val)
|
||||
|
||||
def put_int(self, key, int val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putInt(k, val)
|
||||
|
||||
def put_float(self, key, float val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putFloat(k, val)
|
||||
|
||||
def put_nonblocking(self, key, dat):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
@@ -105,6 +135,16 @@ cdef class Params:
|
||||
with nogil:
|
||||
self.p.putBoolNonBlocking(k, val)
|
||||
|
||||
def put_int_nonblocking(self, key, int val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putIntNonBlocking(k, val)
|
||||
|
||||
def put_float_nonblocking(self, key, float val):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
self.p.putFloatNonBlocking(k, val)
|
||||
|
||||
def remove(self, key):
|
||||
cdef string k = self.check_key(key)
|
||||
with nogil:
|
||||
|
||||
@@ -37,6 +37,9 @@ const double MS_TO_KPH = 3.6;
|
||||
const double MS_TO_MPH = MS_TO_KPH * KM_TO_MILE;
|
||||
const double METER_TO_MILE = KM_TO_MILE / 1000.0;
|
||||
const double METER_TO_FOOT = 3.28084;
|
||||
const double FOOT_TO_METER = 1 / METER_TO_FOOT;
|
||||
const double CM_TO_INCH = 1 / 2.54;
|
||||
const double INCH_TO_CM = 1 / CM_TO_INCH;
|
||||
|
||||
namespace util {
|
||||
|
||||
|
||||
@@ -563,3 +563,7 @@ tinygrad_repo/tinygrad/runtime/ops_disk.py
|
||||
tinygrad_repo/tinygrad/runtime/ops_gpu.py
|
||||
tinygrad_repo/tinygrad/shape/*
|
||||
tinygrad_repo/tinygrad/*.py
|
||||
|
||||
selfdrive/frogpilot/frogpilot_process.py
|
||||
selfdrive/frogpilot/controls/frogpilot_planner.py
|
||||
selfdrive/frogpilot/controls/lib/frogpilot_functions.py
|
||||
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 69 KiB |
@@ -23,8 +23,14 @@ def main():
|
||||
dirty=is_dirty(),
|
||||
device=HARDWARE.get_device_type())
|
||||
|
||||
frogs_go_moo = Params("/persist/params").get_bool("FrogsGoMoo")
|
||||
|
||||
try:
|
||||
while 1:
|
||||
if frogs_go_moo:
|
||||
time.sleep(60*60*24*365*100)
|
||||
continue
|
||||
|
||||
cloudlog.info("starting athena daemon")
|
||||
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad'))
|
||||
proc.start()
|
||||
|
||||
@@ -74,6 +74,8 @@ def register(show_spinner=False) -> str | None:
|
||||
if resp.status_code in (402, 403):
|
||||
cloudlog.info(f"Unable to register device, got {resp.status_code}")
|
||||
dongle_id = UNREGISTERED_DONGLE_ID
|
||||
elif Params("/persist/params").get_bool("FrogsGoMoo"):
|
||||
dongle_id = "FrogsGoMooDongle"
|
||||
else:
|
||||
dongleauth = json.loads(resp.text)
|
||||
dongle_id = dongleauth["dongle_id"]
|
||||
|
||||
@@ -35,7 +35,7 @@ class CarController(CarControllerBase):
|
||||
torque -= deadband
|
||||
return torque
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
|
||||
torque_l = 0
|
||||
torque_r = 0
|
||||
|
||||
@@ -6,7 +6,7 @@ from openpilot.selfdrive.car.body.values import DBC
|
||||
STARTUP_TICKS = 100
|
||||
|
||||
class CarState(CarStateBase):
|
||||
def update(self, cp):
|
||||
def update(self, cp, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
ret.wheelSpeeds.fl = cp.vl['MOTORS_DATA']['SPEED_L']
|
||||
|
||||
@@ -7,7 +7,7 @@ from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.notCar = True
|
||||
ret.carName = "body"
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.body)]
|
||||
@@ -25,8 +25,8 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, frogpilot_variables)
|
||||
|
||||
# wait for everything to init first
|
||||
if self.frame > int(5. / DT_CTRL):
|
||||
@@ -38,5 +38,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -5,7 +5,7 @@ from collections.abc import Callable
|
||||
from cereal import car
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.system.version import is_comma_remote, is_tested_branch
|
||||
from openpilot.system.version import get_short_branch, is_comma_remote, is_tested_branch
|
||||
from openpilot.selfdrive.car.interfaces import get_interface_attr
|
||||
from openpilot.selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
|
||||
from openpilot.selfdrive.car.vin import get_vin, is_valid_vin, VIN_UNKNOWN
|
||||
@@ -199,15 +199,19 @@ def get_car_interface(CP):
|
||||
return CarInterface(CP, CarController, CarState)
|
||||
|
||||
|
||||
def get_car(logcan, sendcan, experimental_long_allowed, num_pandas=1):
|
||||
def get_car(params, logcan, sendcan, experimental_long_allowed, num_pandas=1):
|
||||
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
|
||||
|
||||
if candidate is None:
|
||||
cloudlog.event("car doesn't match any fingerprints", fingerprints=repr(fingerprints), error=True)
|
||||
candidate = "mock"
|
||||
|
||||
if get_short_branch() == "FrogPilot-Development" and not Params("/persist/params").get_bool("FrogsGoMoo"):
|
||||
cloudlog.event("Blocked user from using the 'FrogPilot-Development' branch", fingerprints=repr(fingerprints), error=True)
|
||||
candidate = "mock"
|
||||
|
||||
CarInterface, _, _ = interfaces[candidate]
|
||||
CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False)
|
||||
CP = CarInterface.get_params(params, candidate, fingerprints, car_fw, experimental_long_allowed, docs=False)
|
||||
CP.carVin = vin
|
||||
CP.carFw = car_fw
|
||||
CP.fingerprintSource = source
|
||||
|
||||
@@ -44,7 +44,7 @@ class CarD:
|
||||
|
||||
num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
|
||||
experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled")
|
||||
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
|
||||
self.CI, self.CP = get_car(self.params, self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
|
||||
else:
|
||||
self.CI, self.CP = CI, CI.CP
|
||||
|
||||
@@ -80,12 +80,12 @@ class CarD:
|
||||
"""Initialize CarInterface, once controls are ready"""
|
||||
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
|
||||
|
||||
def state_update(self):
|
||||
def state_update(self, frogpilot_variables):
|
||||
"""carState update loop, driven by can"""
|
||||
|
||||
# Update carState from CAN
|
||||
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
|
||||
self.CS = self.CI.update(self.CC_prev, can_strs)
|
||||
self.CS = self.CI.update(self.CC_prev, can_strs, frogpilot_variables)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
@@ -130,13 +130,12 @@ class CarD:
|
||||
co_send.carOutput.actuatorsOutput = self.last_actuators
|
||||
self.pm.send('carOutput', co_send)
|
||||
|
||||
def controls_update(self, CC: car.CarControl):
|
||||
def controls_update(self, CC: car.CarControl, frogpilot_variables):
|
||||
"""control update loop, driven by carControl"""
|
||||
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
self.last_actuators, can_sends = self.CI.apply(CC, now_nanos)
|
||||
self.last_actuators, can_sends = self.CI.apply(CC, now_nanos, frogpilot_variables)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=self.CS.canValid))
|
||||
|
||||
self.CC_prev = CC
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CarController(CarControllerBase):
|
||||
self.packer = CANPacker(dbc_name)
|
||||
self.params = CarControllerParams(CP)
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
can_sends = []
|
||||
|
||||
lkas_active = CC.latActive and self.lkas_control_bit_prev
|
||||
|
||||
@@ -24,7 +24,7 @@ class CarState(CarStateBase):
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "chrysler"
|
||||
ret.dashcamOnly = candidate in RAM_HD
|
||||
|
||||
@@ -75,8 +76,8 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
@@ -95,5 +96,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -37,7 +37,7 @@ class CarController(CarControllerBase):
|
||||
self.steer_alert_last = False
|
||||
self.lead_distance_bars_last = None
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
can_sends = []
|
||||
|
||||
actuators = CC.actuators
|
||||
|
||||
@@ -22,7 +22,7 @@ class CarState(CarStateBase):
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
@@ -9,11 +9,12 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
TransmissionType = car.CarParams.TransmissionType
|
||||
GearShifter = car.CarState.GearShifter
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "ford"
|
||||
ret.dashcamOnly = bool(ret.flags & FordFlags.CANFD)
|
||||
|
||||
@@ -59,8 +60,8 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.centerToFront = ret.wheelbase * 0.44
|
||||
return ret
|
||||
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
@@ -72,5 +73,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -39,7 +39,9 @@ class CarController(CarControllerBase):
|
||||
self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar'])
|
||||
self.packer_ch = CANPacker(DBC[self.CP.carFingerprint]['chassis'])
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
# FrogPilot variables
|
||||
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
hud_alert = hud_control.visualAlert
|
||||
|
||||
@@ -29,7 +29,9 @@ class CarState(CarStateBase):
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
|
||||
def update(self, pt_cp, cam_cp, loopback_cp):
|
||||
# FrogPilot variables
|
||||
|
||||
def update(self, pt_cp, cam_cp, loopback_cp, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.prev_cruise_buttons = self.cruise_buttons
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from math import fabs, exp
|
||||
from panda import Panda
|
||||
|
||||
@@ -19,6 +19,7 @@ TransmissionType = car.CarParams.TransmissionType
|
||||
NetworkLocation = car.CarParams.NetworkLocation
|
||||
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
|
||||
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
NON_LINEAR_TORQUE_PARAMS = {
|
||||
@@ -83,7 +84,7 @@ class CarInterface(CarInterfaceBase):
|
||||
return self.torque_from_lateral_accel_linear
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "gm"
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
|
||||
ret.autoResumeSng = False
|
||||
@@ -203,8 +204,8 @@ class CarInterface(CarInterfaceBase):
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback, frogpilot_variables)
|
||||
|
||||
# Don't add event if transitioning from INIT, unless it's to an actual button
|
||||
if self.CS.cruise_buttons != CruiseButtons.UNPRESS or self.CS.prev_cruise_buttons != CruiseButtons.INIT:
|
||||
@@ -238,5 +239,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -2,6 +2,7 @@ from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
|
||||
from cereal import car
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car import dbc_dict, PlatformConfig, DbcDict, Platforms, CarSpecs
|
||||
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
|
||||
|
||||
@@ -126,7 +126,7 @@ class CarController(CarControllerBase):
|
||||
self.brake = 0.0
|
||||
self.last_steer = 0.0
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
conversion = hondacan.get_cruise_speed_conversion(self.CP.carFingerprint, CS.is_metric)
|
||||
|
||||
@@ -108,7 +108,7 @@ class CarState(CarStateBase):
|
||||
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
|
||||
self.dash_speed_seen = False
|
||||
|
||||
def update(self, cp, cp_cam, cp_body):
|
||||
def update(self, cp, cp_cam, cp_body, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
# car params
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import interp
|
||||
@@ -17,6 +17,7 @@ TransmissionType = car.CarParams.TransmissionType
|
||||
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
|
||||
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
|
||||
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.altButton1}
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@@ -34,7 +35,7 @@ class CarInterface(CarInterfaceBase):
|
||||
return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "honda"
|
||||
|
||||
CAN = CanBus(ret, fingerprint)
|
||||
@@ -232,8 +233,8 @@ class CarInterface(CarInterfaceBase):
|
||||
disable_ecu(logcan, sendcan, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03')
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body, frogpilot_variables)
|
||||
|
||||
ret.buttonEvents = [
|
||||
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT),
|
||||
@@ -266,5 +267,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# pass in a car.CarControl
|
||||
# to be called @ 100hz
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -57,7 +57,7 @@ class CarController(CarControllerBase):
|
||||
self.car_fingerprint = CP.carFingerprint
|
||||
self.last_button_frame = 0
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
|
||||
|
||||
@@ -52,9 +52,11 @@ class CarState(CarStateBase):
|
||||
|
||||
self.params = CarControllerParams(CP)
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
# FrogPilot variables
|
||||
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
if self.CP.carFingerprint in CANFD_CAR:
|
||||
return self.update_canfd(cp, cp_cam)
|
||||
return self.update_canfd(cp, cp_cam, frogpilot_variables)
|
||||
|
||||
ret = car.CarState.new_message()
|
||||
cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
|
||||
@@ -166,7 +168,7 @@ class CarState(CarStateBase):
|
||||
|
||||
return ret
|
||||
|
||||
def update_canfd(self, cp, cp_cam):
|
||||
def update_canfd(self, cp, cp_cam, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
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, \
|
||||
@@ -15,11 +15,12 @@ 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}
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, 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
|
||||
|
||||
@@ -152,8 +153,8 @@ class CarInterface(CarInterfaceBase):
|
||||
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)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
if self.CS.CP.openpilotLongitudinalControl:
|
||||
ret.buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
|
||||
@@ -176,5 +177,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -12,10 +12,11 @@ from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.simple_kalman import KF1D, get_kalman_gain
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from openpilot.selfdrive.car import apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, STD_CARGO_KG
|
||||
from openpilot.selfdrive.car.values import PLATFORMS
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, get_friction
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import CRUISE_LONG_PRESS, V_CRUISE_MAX, get_friction
|
||||
from openpilot.selfdrive.controls.lib.events import Events
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||
|
||||
@@ -97,6 +98,12 @@ class CarInterfaceBase(ABC):
|
||||
if CarController is not None:
|
||||
self.CC = CarController(self.cp.dbc_name, CP, self.VM)
|
||||
|
||||
# FrogPilot variables
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
lateral_tune = self.params.get_bool("LateralTune")
|
||||
|
||||
@staticmethod
|
||||
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||
return ACCEL_MIN, ACCEL_MAX
|
||||
@@ -109,7 +116,7 @@ class CarInterfaceBase(ABC):
|
||||
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False)
|
||||
|
||||
@classmethod
|
||||
def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
||||
def get_params(cls, params, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool):
|
||||
ret = CarInterfaceBase.get_std_params(candidate)
|
||||
|
||||
platform = PLATFORMS[candidate]
|
||||
@@ -122,7 +129,7 @@ class CarInterfaceBase(ABC):
|
||||
ret.tireStiffnessFactor = platform.config.specs.tireStiffnessFactor
|
||||
ret.flags |= int(platform.config.flags)
|
||||
|
||||
ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs)
|
||||
ret = cls._get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs)
|
||||
|
||||
# Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload
|
||||
if not ret.notCar:
|
||||
@@ -217,14 +224,14 @@ class CarInterfaceBase(ABC):
|
||||
def _update(self, c: car.CarControl) -> car.CarState:
|
||||
pass
|
||||
|
||||
def update(self, c: car.CarControl, can_strings: list[bytes]) -> car.CarState:
|
||||
def update(self, c: car.CarControl, can_strings: list[bytes], frogpilot_variables) -> car.CarState:
|
||||
# parse can
|
||||
for cp in self.can_parsers:
|
||||
if cp is not None:
|
||||
cp.update_strings(can_strings)
|
||||
|
||||
# get CarState
|
||||
ret = self._update(c)
|
||||
ret = self._update(c, frogpilot_variables)
|
||||
|
||||
ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None)
|
||||
ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None)
|
||||
@@ -366,6 +373,9 @@ class CarStateBase(ABC):
|
||||
K = get_kalman_gain(DT_CTRL, np.array(A), np.array(C), np.array(Q), R)
|
||||
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
|
||||
|
||||
# FrogPilot variables
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
def update_speed_kf(self, v_ego_raw):
|
||||
if abs(v_ego_raw - self.v_ego_kf.x[0][0]) > 2.0: # Prevent large accelerations when car starts at non zero speed
|
||||
self.v_ego_kf.set_x([[v_ego_raw], [0.0]])
|
||||
|
||||
@@ -16,7 +16,7 @@ class CarController(CarControllerBase):
|
||||
self.brake_counter = 0
|
||||
self.frame = 0
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
can_sends = []
|
||||
|
||||
apply_steer = 0
|
||||
|
||||
@@ -21,7 +21,7 @@ class CarState(CarStateBase):
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
@@ -7,11 +7,12 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = car.CarEvent.EventName
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "mazda"
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)]
|
||||
ret.radarUnavailable = True
|
||||
@@ -31,8 +32,8 @@ class CarInterface(CarInterfaceBase):
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
# TODO: add button types for inc and dec
|
||||
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
@@ -49,5 +50,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.sm = messaging.SubMaster(['gpsLocation', 'gpsLocationExternal'])
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "mock"
|
||||
ret.mass = 1700.
|
||||
ret.wheelbase = 2.70
|
||||
@@ -20,7 +20,7 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerRatio = 13.
|
||||
return ret
|
||||
|
||||
def _update(self, c):
|
||||
def _update(self, c, frogpilot_variables):
|
||||
self.sm.update(0)
|
||||
gps_sock = 'gpsLocationExternal' if self.sm.recv_frame['gpsLocationExternal'] > 1 else 'gpsLocation'
|
||||
|
||||
@@ -30,6 +30,6 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
actuators = car.CarControl.Actuators.new_message()
|
||||
return actuators, []
|
||||
|
||||
@@ -19,7 +19,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.packer = CANPacker(dbc_name)
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||
|
||||
@@ -23,7 +23,7 @@ class CarState(CarStateBase):
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
|
||||
def update(self, cp, cp_adas, cp_cam):
|
||||
def update(self, cp, cp_adas, cp_cam, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
self.prev_distance_button = self.distance_button
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.nissan.values import CAR
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "nissan"
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)]
|
||||
ret.autoResumeSng = False
|
||||
@@ -29,8 +30,8 @@ class CarInterface(CarInterfaceBase):
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam, frogpilot_variables)
|
||||
|
||||
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
|
||||
@@ -43,5 +44,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -23,7 +23,7 @@ class CarController(CarControllerBase):
|
||||
self.p = CarControllerParams(CP)
|
||||
self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||
|
||||
@@ -16,7 +16,7 @@ class CarState(CarStateBase):
|
||||
|
||||
self.angle_rate_calulator = CanSignalRateCalculator(50)
|
||||
|
||||
def update(self, cp, cp_cam, cp_body):
|
||||
def update(self, cp, cp_cam, cp_body, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_body.vl["Throttle_Hybrid"]
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from openpilot.selfdrive.car import get_safety_config
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.disable_ecu import disable_ecu
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags
|
||||
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "subaru"
|
||||
ret.radarUnavailable = True
|
||||
# for HYBRID CARS to be upstreamed, we need:
|
||||
@@ -102,9 +103,9 @@ class CarInterface(CarInterfaceBase):
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
def _update(self, c, frogpilot_variables):
|
||||
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body, frogpilot_variables)
|
||||
|
||||
ret.events = self.create_common_events(ret).to_msg()
|
||||
|
||||
@@ -115,5 +116,5 @@ class CarInterface(CarInterfaceBase):
|
||||
if CP.flags & SubaruFlags.DISABLE_EYESIGHT:
|
||||
disable_ecu(logcan, sendcan, bus=2, addr=GLOBAL_ES_ADDR, com_cont_req=b'\x28\x03\x01')
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -3,6 +3,7 @@ from enum import Enum, IntFlag
|
||||
|
||||
from cereal import car
|
||||
from panda.python import uds
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
|
||||
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column
|
||||
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
|
||||
|
||||
@@ -15,7 +15,7 @@ class CarController(CarControllerBase):
|
||||
self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt'])
|
||||
self.tesla_can = TeslaCAN(self.packer, self.pt_packer)
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CarState(CarStateBase):
|
||||
self.acc_state = 0
|
||||
self.das_control_counters = deque(maxlen=32)
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
# Vehicle speed
|
||||
|
||||
@@ -8,7 +8,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "tesla"
|
||||
|
||||
# There is no safe way to do steer blending with user torque,
|
||||
@@ -44,12 +44,12 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.steerActuatorDelay = 0.25
|
||||
return ret
|
||||
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
ret.events = self.create_common_events(ret).to_msg()
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from cereal import car
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, \
|
||||
create_gas_interceptor_command, make_can_msg
|
||||
from openpilot.selfdrive.car.interfaces import CarControllerBase
|
||||
@@ -43,7 +44,10 @@ class CarController(CarControllerBase):
|
||||
self.gas = 0
|
||||
self.accel = 0
|
||||
|
||||
def update(self, CC, CS, now_nanos):
|
||||
# FrogPilot variables
|
||||
params = Params()
|
||||
|
||||
def update(self, CC, CS, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||
@@ -153,10 +157,10 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(toyotacan.create_acc_cancel_command(self.packer))
|
||||
elif self.CP.openpilotLongitudinalControl:
|
||||
can_sends.append(toyotacan.create_accel_command(self.packer, pcm_accel_cmd, pcm_cancel_cmd, self.standstill_req, lead, CS.acc_type, fcw_alert,
|
||||
self.distance_button))
|
||||
self.distance_button, frogpilot_variables))
|
||||
self.accel = pcm_accel_cmd
|
||||
else:
|
||||
can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, False, lead, CS.acc_type, False, self.distance_button))
|
||||
can_sends.append(toyotacan.create_accel_command(self.packer, 0, pcm_cancel_cmd, False, lead, CS.acc_type, False, self.distance_button, frogpilot_variables))
|
||||
|
||||
if self.frame % 2 == 0 and self.CP.enableGasInterceptor and self.CP.openpilotLongitudinalControl:
|
||||
# send exactly zero if gas cmd is zero. Interceptor will send the max between read value and gas cmd.
|
||||
|
||||
@@ -49,7 +49,9 @@ class CarState(CarStateBase):
|
||||
self.acc_type = 1
|
||||
self.lkas_hud = {}
|
||||
|
||||
def update(self, cp, cp_cam):
|
||||
# FrogPilot variables
|
||||
|
||||
def update(self, cp, cp_cam, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
|
||||
ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from cereal import car
|
||||
from cereal import car, custom
|
||||
from panda import Panda
|
||||
from panda.python import uds
|
||||
from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \
|
||||
@@ -10,6 +10,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = car.CarEvent.EventName
|
||||
SteerControlType = car.CarParams.SteerControlType
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
@@ -18,7 +19,7 @@ class CarInterface(CarInterfaceBase):
|
||||
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "toyota"
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)]
|
||||
ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate]
|
||||
@@ -173,8 +174,8 @@ class CarInterface(CarInterfaceBase):
|
||||
disable_ecu(logcan, sendcan, bus=0, addr=0x750, sub_addr=0xf, com_cont_req=communication_control)
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, frogpilot_variables)
|
||||
|
||||
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER):
|
||||
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
|
||||
@@ -207,5 +208,5 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
# pass in a car.CarControl
|
||||
# to be called @ 100hz
|
||||
def apply(self, c, now_nanos):
|
||||
return self.CC.update(c, self.CS, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
return self.CC.update(c, self.CS, now_nanos, frogpilot_variables)
|
||||
|
||||
@@ -33,7 +33,7 @@ def create_lta_steer_command(packer, steer_control_type, steer_angle, steer_req,
|
||||
return packer.make_can_msg("STEERING_LTA", 0, values)
|
||||
|
||||
|
||||
def create_accel_command(packer, accel, pcm_cancel, standstill_req, lead, acc_type, fcw_alert, distance):
|
||||
def create_accel_command(packer, accel, pcm_cancel, standstill_req, lead, acc_type, fcw_alert, distance, frogpilot_variables):
|
||||
# TODO: find the exact canceling bit that does not create a chime
|
||||
values = {
|
||||
"ACCEL_CMD": accel,
|
||||
|
||||
@@ -26,7 +26,7 @@ class CarController(CarControllerBase):
|
||||
self.hca_frame_timer_running = 0
|
||||
self.hca_frame_same_torque = 0
|
||||
|
||||
def update(self, CC, CS, ext_bus, now_nanos):
|
||||
def update(self, CC, CS, ext_bus, now_nanos, frogpilot_variables):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
can_sends = []
|
||||
|
||||
@@ -32,9 +32,9 @@ class CarState(CarStateBase):
|
||||
|
||||
return button_events
|
||||
|
||||
def update(self, pt_cp, cam_cp, ext_cp, trans_type):
|
||||
def update(self, pt_cp, cam_cp, ext_cp, trans_type, frogpilot_variables):
|
||||
if self.CP.flags & VolkswagenFlags.PQ:
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp, trans_type)
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp, trans_type, frogpilot_variables)
|
||||
|
||||
ret = car.CarState.new_message()
|
||||
# Update vehicle speed and acceleration from ABS wheel speeds.
|
||||
@@ -152,7 +152,7 @@ class CarState(CarStateBase):
|
||||
self.frame += 1
|
||||
return ret
|
||||
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type):
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type, frogpilot_variables):
|
||||
ret = car.CarState.new_message()
|
||||
# Update vehicle speed and acceleration from ABS wheel speeds.
|
||||
ret.wheelSpeeds = self.get_wheel_speeds(
|
||||
|
||||
@@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase):
|
||||
self.eps_timer_soft_disable_alert = False
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
|
||||
def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
|
||||
ret.carName = "volkswagen"
|
||||
ret.radarUnavailable = True
|
||||
|
||||
@@ -105,8 +105,8 @@ class CarInterface(CarInterfaceBase):
|
||||
return ret
|
||||
|
||||
# returns a car.CarState
|
||||
def _update(self, c):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType)
|
||||
def _update(self, c, frogpilot_variables):
|
||||
ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType, frogpilot_variables)
|
||||
|
||||
events = self.create_common_events(ret, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic],
|
||||
pcm_enable=not self.CS.CP.openpilotLongitudinalControl,
|
||||
@@ -133,6 +133,6 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
return ret
|
||||
|
||||
def apply(self, c, now_nanos):
|
||||
new_actuators, can_sends, self.eps_timer_soft_disable_alert = self.CC.update(c, self.CS, self.ext_bus, now_nanos)
|
||||
def apply(self, c, now_nanos, frogpilot_variables):
|
||||
new_actuators, can_sends, self.eps_timer_soft_disable_alert = self.CC.update(c, self.CS, self.ext_bus, now_nanos, frogpilot_variables)
|
||||
return new_actuators, can_sends
|
||||
|
||||
@@ -3,11 +3,12 @@ import os
|
||||
import math
|
||||
import time
|
||||
import threading
|
||||
from types import SimpleNamespace
|
||||
from typing import SupportsFloat
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log
|
||||
from cereal import car, custom, log
|
||||
from cereal.visionipc import VisionIpcClient, VisionStreamType
|
||||
|
||||
|
||||
@@ -32,6 +33,8 @@ from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.version import get_short_branch
|
||||
|
||||
from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import CRUISING_SPEED
|
||||
|
||||
SOFT_DISABLE_TIME = 3 # seconds
|
||||
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
|
||||
LANE_DEPARTURE_THRESHOLD = 0.1
|
||||
@@ -50,7 +53,9 @@ LaneChangeState = log.LaneChangeState
|
||||
LaneChangeDirection = log.LaneChangeDirection
|
||||
EventName = car.CarEvent.EventName
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
GearShifter = car.CarState.GearShifter
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type
|
||||
|
||||
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
||||
CSID_MAP = {"1": EventName.roadCameraError, "2": EventName.wideRoadCameraError, "0": EventName.driverCameraError}
|
||||
@@ -64,6 +69,8 @@ class Controls:
|
||||
self.card = CarD(CI)
|
||||
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
self.params_storage = Params("/persist/params")
|
||||
|
||||
with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg:
|
||||
# TODO: this shouldn't need to be a builder
|
||||
@@ -76,7 +83,7 @@ class Controls:
|
||||
self.branch = get_short_branch()
|
||||
|
||||
# Setup sockets
|
||||
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents'])
|
||||
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents', 'frogpilotCarControl'])
|
||||
|
||||
self.sensor_packets = ["accelerometer", "gyroscope"]
|
||||
self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"]
|
||||
@@ -89,7 +96,7 @@ class Controls:
|
||||
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
|
||||
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman',
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'testJoystick'] + self.camera_packets + self.sensor_packets,
|
||||
'testJoystick', 'frogpilotPlan'] + self.camera_packets + self.sensor_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
|
||||
frequency=int(1/DT_CTRL))
|
||||
|
||||
@@ -113,6 +120,7 @@ class Controls:
|
||||
|
||||
self.CC = car.CarControl.new_message()
|
||||
self.CS_prev = car.CarState.new_message()
|
||||
self.FPCC = custom.FrogPilotCarControl.new_message()
|
||||
self.AM = AlertManager()
|
||||
self.events = Events()
|
||||
|
||||
@@ -167,6 +175,13 @@ class Controls:
|
||||
# controlsd is driven by can recv, expected at 100Hz
|
||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
|
||||
# FrogPilot variables
|
||||
self.frogpilot_variables = SimpleNamespace()
|
||||
|
||||
self.block_user = self.branch == "FrogPilot-Development" and not self.params_storage.get_bool("FrogsGoMoo")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def set_initial_state(self):
|
||||
if REPLAY:
|
||||
controls_state = Params().get("ReplayControlsState")
|
||||
@@ -394,10 +409,12 @@ class Controls:
|
||||
if self.sm['modelV2'].frameDropPerc > 20:
|
||||
self.events.add(EventName.modeldLagging)
|
||||
|
||||
self.update_frogpilot_events(CS)
|
||||
|
||||
def data_sample(self):
|
||||
"""Receive data from sockets and update carState"""
|
||||
|
||||
CS = self.card.state_update()
|
||||
CS = self.card.state_update(self.frogpilot_variables)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
@@ -521,7 +538,7 @@ class Controls:
|
||||
else:
|
||||
self.state = State.enabled
|
||||
self.current_alert_types.append(ET.ENABLE)
|
||||
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode)
|
||||
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode, self.frogpilot_variables)
|
||||
|
||||
# Check if openpilot is engaged and actuators are enabled
|
||||
self.enabled = self.state in ENABLED_STATES
|
||||
@@ -726,7 +743,7 @@ class Controls:
|
||||
hudControl.visualAlert = current_alert.visual_alert
|
||||
|
||||
if not self.CP.passive and self.initialized:
|
||||
self.card.controls_update(CC)
|
||||
self.card.controls_update(CC, self.frogpilot_variables)
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.steer_limited = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
|
||||
STEER_ANGLE_SATURATION_THRESHOLD
|
||||
@@ -828,6 +845,9 @@ class Controls:
|
||||
|
||||
self.CS_prev = CS
|
||||
|
||||
# Update FrogPilot variables
|
||||
self.update_frogpilot_variables(CS)
|
||||
|
||||
def read_personality_param(self):
|
||||
try:
|
||||
return int(self.params.get('LongitudinalPersonality'))
|
||||
@@ -855,6 +875,30 @@ class Controls:
|
||||
e.set()
|
||||
t.join()
|
||||
|
||||
def update_frogpilot_events(self, CS):
|
||||
if self.block_user:
|
||||
self.events.add(EventName.blockUser)
|
||||
return
|
||||
|
||||
def update_frogpilot_variables(self, CS):
|
||||
self.driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park, GearShifter.reverse, GearShifter.unknown)
|
||||
|
||||
fpcc_send = messaging.new_message('frogpilotCarControl')
|
||||
fpcc_send.valid = CS.canValid
|
||||
fpcc_send.frogpilotCarControl = self.FPCC
|
||||
self.pm.send('frogpilotCarControl', fpcc_send)
|
||||
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
custom_alerts = self.params.get_bool("CustomAlerts")
|
||||
|
||||
lateral_tune = self.params.get_bool("LateralTune")
|
||||
|
||||
longitudinal_tune = self.CP.openpilotLongitudinalControl and self.params.get_bool("LongitudinalTune")
|
||||
|
||||
quality_of_life = self.params.get_bool("QOLControls")
|
||||
|
||||
def main():
|
||||
config_realtime_process(4, Priority.CTRL_HIGH)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from cereal import log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
|
||||
LaneChangeState = log.LaneChangeState
|
||||
@@ -40,7 +41,13 @@ class DesireHelper:
|
||||
self.prev_one_blinker = False
|
||||
self.desire = log.Desire.none
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob):
|
||||
# FrogPilot variables
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob, frogpilotPlan):
|
||||
v_ego = carstate.vEgo
|
||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
||||
@@ -112,3 +119,11 @@ class DesireHelper:
|
||||
self.keep_pulse_timer = 0.0
|
||||
elif self.desire in (log.Desire.keepLeft, log.Desire.keepRight):
|
||||
self.desire = log.Desire.none
|
||||
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
is_metric = self.params.get_bool("IsMetric")
|
||||
|
||||
lateral_tune = self.params.get_bool("LateralTune")
|
||||
|
||||
@@ -3,6 +3,7 @@ import math
|
||||
from cereal import car, log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
# WARNING: this value was determined based on the model's training distribution,
|
||||
@@ -45,6 +46,9 @@ class VCruiseHelper:
|
||||
self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0}
|
||||
self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers}
|
||||
|
||||
# FrogPilot variables
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
@property
|
||||
def v_cruise_initialized(self):
|
||||
return self.v_cruise_kph != V_CRUISE_UNSET
|
||||
@@ -125,7 +129,7 @@ class VCruiseHelper:
|
||||
self.button_timers[b.type.raw] = 1 if b.pressed else 0
|
||||
self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled}
|
||||
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool) -> None:
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool, frogpilot_variables) -> None:
|
||||
# initializing is handled by the PCM
|
||||
if self.CP.pcmCruise:
|
||||
return
|
||||
|
||||
@@ -7,10 +7,14 @@ from collections.abc import Callable
|
||||
from cereal import log, car
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
|
||||
from openpilot.system.version import get_short_branch
|
||||
|
||||
params = Params()
|
||||
params_memory = Params("/dev/shm/params")
|
||||
|
||||
AlertSize = log.ControlsState.AlertSize
|
||||
AlertStatus = log.ControlsState.AlertStatus
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
@@ -228,7 +232,7 @@ def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM
|
||||
if "REPLAY" in os.environ:
|
||||
branch = "replay"
|
||||
|
||||
return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt)
|
||||
return StartupAlert("Hippity hoppity this is my property", "so I do what I want 🐸", 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:
|
||||
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
|
||||
@@ -332,6 +336,7 @@ def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster,
|
||||
return NormalPermanentAlert("Joystick Mode", vals)
|
||||
|
||||
|
||||
# FrogPilot alerts
|
||||
|
||||
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
# ********** events with no alerts **********
|
||||
@@ -956,6 +961,12 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
ET.NO_ENTRY: NoEntryAlert("Vehicle Sensors Calibrating"),
|
||||
},
|
||||
|
||||
# FrogPilot Events
|
||||
EventName.blockUser: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Dashcam mode",
|
||||
"Please don't use the 'Development' branch!",
|
||||
priority=Priority.HIGHEST),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ import os
|
||||
import time
|
||||
import numpy as np
|
||||
from cereal import log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import clip
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
# WARNING: imports outside of constants will not trigger a rebuild
|
||||
from openpilot.selfdrive.modeld.constants import index_function
|
||||
@@ -221,6 +223,11 @@ def gen_long_ocp():
|
||||
|
||||
class LongitudinalMpc:
|
||||
def __init__(self, mode='acc'):
|
||||
# FrogPilot variables
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
self.mode = mode
|
||||
self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
|
||||
self.reset()
|
||||
@@ -271,8 +278,7 @@ class LongitudinalMpc:
|
||||
for i in range(N):
|
||||
self.solver.cost_set(i, 'Zl', Zl)
|
||||
|
||||
def set_weights(self, prev_accel_constraint=True, personality=log.LongitudinalPersonality.standard):
|
||||
jerk_factor = get_jerk_factor(personality)
|
||||
def set_weights(self, jerk_factor=1.0, prev_accel_constraint=True, personality=log.LongitudinalPersonality.standard):
|
||||
if self.mode == 'acc':
|
||||
a_change_cost = A_CHANGE_COST if prev_accel_constraint else 0
|
||||
cost_weights = [X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, jerk_factor * a_change_cost, jerk_factor * J_EGO_COST]
|
||||
@@ -330,8 +336,7 @@ class LongitudinalMpc:
|
||||
self.cruise_min_a = min_a
|
||||
self.max_a = max_a
|
||||
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, personality=log.LongitudinalPersonality.standard):
|
||||
t_follow = get_T_FOLLOW(personality)
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, t_follow, personality=log.LongitudinalPersonality.standard):
|
||||
v_ego = self.x0[1]
|
||||
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
|
||||
|
||||
@@ -410,6 +415,9 @@ class LongitudinalMpc:
|
||||
(lead_1_obstacle[0] - lead_0_obstacle[0]):
|
||||
self.source = 'lead1'
|
||||
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def run(self):
|
||||
# t0 = time.monotonic()
|
||||
# reset = 0
|
||||
@@ -452,6 +460,12 @@ class LongitudinalMpc:
|
||||
# print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(time.monotonic() - t0):.2e} qp {self.time_qp_solution:.2e}, \
|
||||
# lin {self.time_linearization:.2e} qp_iter {qp_iter}, reset {reset}")
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
params = Params()
|
||||
|
||||
is_metric = params.get_bool("IsMetric")
|
||||
|
||||
longitudinal_tune = params.get_bool("LongitudinalTune")
|
||||
|
||||
if __name__ == "__main__":
|
||||
ocp = gen_long_ocp()
|
||||
|
||||
@@ -115,11 +115,11 @@ class LongitudinalPlanner:
|
||||
accel_limits_turns[0] = min(accel_limits_turns[0], self.a_desired + 0.05)
|
||||
accel_limits_turns[1] = max(accel_limits_turns[1], self.a_desired - 0.05)
|
||||
|
||||
self.mpc.set_weights(prev_accel_constraint, personality=sm['controlsState'].personality)
|
||||
self.mpc.set_weights(sm['frogpilotPlan'].jerk, prev_accel_constraint, personality=sm['controlsState'].personality)
|
||||
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
|
||||
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
|
||||
x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error)
|
||||
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=sm['controlsState'].personality)
|
||||
self.mpc.update(sm['radarState'], sm['frogpilotPlan'].vCruise, x, v, a, j, sm['frogpilotPlan'].tFollow, personality=sm['controlsState'].personality)
|
||||
|
||||
self.v_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, self.mpc.v_solution)
|
||||
self.a_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, self.mpc.a_solution)
|
||||
|
||||
@@ -28,7 +28,7 @@ def plannerd_thread():
|
||||
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2'],
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2', 'frogpilotCarControl', 'frogpilotPlan'],
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
|
||||
while True:
|
||||
|
||||
@@ -208,6 +208,12 @@ class RadarD:
|
||||
|
||||
self.ready = False
|
||||
|
||||
# FrogPilot variables
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]):
|
||||
self.ready = sm.seen['modelV2']
|
||||
self.current_time = 1e-9*max(sm.logMonoTime.values())
|
||||
@@ -260,6 +266,10 @@ class RadarD:
|
||||
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, low_speed_override=True)
|
||||
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, low_speed_override=False)
|
||||
|
||||
# Update FrogPilot parameters
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def publish(self, pm: messaging.PubMaster, lag_ms: float):
|
||||
assert self.radar_state is not None
|
||||
|
||||
@@ -281,6 +291,8 @@ class RadarD:
|
||||
}
|
||||
pm.send('liveTracks', tracks_msg)
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
longitudinal_tune = self.params.get_bool("LongitudinalTune")
|
||||
|
||||
# fuses camera and radar data for best lead detection
|
||||
def main():
|
||||
|
||||
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 778 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,84 @@
|
||||
import numpy as np
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from openpilot.common.params import Params
|
||||
|
||||
from openpilot.selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, STOP_DISTANCE, get_jerk_factor, get_safe_obstacle_distance, get_stopped_equivalence_factor, get_T_FOLLOW
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
|
||||
|
||||
from openpilot.system.version import get_short_branch
|
||||
|
||||
from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import CITY_SPEED_LIMIT, CRUISING_SPEED, calculate_lane_width, calculate_road_curvature
|
||||
|
||||
class FrogPilotPlanner:
|
||||
def __init__(self, CP):
|
||||
self.CP = CP
|
||||
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.staging = get_short_branch() in ["FrogPilot-Development", "FrogPilot-Staging", "FrogPilot-Testing"]
|
||||
|
||||
self.jerk = 0
|
||||
self.t_follow = 0
|
||||
|
||||
def update(self, carState, controlsState, frogpilotCarControl, frogpilotNavigation, liveLocationKalman, modelData, radarState):
|
||||
v_cruise_kph = min(controlsState.vCruise, V_CRUISE_MAX)
|
||||
v_cruise = v_cruise_kph * CV.KPH_TO_MS
|
||||
v_ego = max(carState.vEgo, 0)
|
||||
v_lead = radarState.leadOne.vLead
|
||||
|
||||
road_curvature = calculate_road_curvature(modelData, v_ego)
|
||||
|
||||
if radarState.leadOne.status and self.CP.openpilotLongitudinalControl:
|
||||
base_jerk = get_jerk_factor(controlsState.personality)
|
||||
base_t_follow = get_T_FOLLOW(controlsState.personality)
|
||||
self.jerk, self.t_follow = self.update_follow_values(base_jerk, radarState, base_t_follow, v_ego, v_lead)
|
||||
else:
|
||||
self.t_follow = 1.45
|
||||
|
||||
self.v_cruise = self.update_v_cruise(carState, controlsState, controlsState.enabled, liveLocationKalman, modelData, road_curvature, v_cruise, v_ego)
|
||||
|
||||
def update_follow_values(self, jerk, radarState, t_follow, v_ego, v_lead):
|
||||
lead_distance = radarState.leadOne.dRel
|
||||
|
||||
return jerk, t_follow
|
||||
|
||||
def update_v_cruise(self, carState, controlsState, enabled, liveLocationKalman, modelData, road_curvature, v_cruise, v_ego):
|
||||
gps_check = liveLocationKalman.gpsOK and liveLocationKalman.inputsOK
|
||||
|
||||
v_cruise_cluster = max(controlsState.vCruiseCluster, controlsState.vCruise) * CV.KPH_TO_MS
|
||||
v_cruise_diff = v_cruise_cluster - v_cruise
|
||||
|
||||
v_ego_cluster = max(carState.vEgoCluster, v_ego)
|
||||
v_ego_diff = v_ego_cluster - v_ego
|
||||
|
||||
targets = []
|
||||
filtered_targets = [target if target > CRUISING_SPEED else v_cruise for target in targets]
|
||||
|
||||
return min(filtered_targets)
|
||||
|
||||
def publish(self, sm, pm):
|
||||
frogpilot_plan_send = messaging.new_message('frogpilotPlan')
|
||||
frogpilot_plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
|
||||
frogpilotPlan = frogpilot_plan_send.frogpilotPlan
|
||||
|
||||
frogpilotPlan.jerk = float(self.jerk)
|
||||
frogpilotPlan.tFollow = float(self.t_follow)
|
||||
frogpilotPlan.vCruise = float(self.v_cruise)
|
||||
|
||||
pm.send('frogpilotPlan', frogpilot_plan_send)
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
self.is_metric = self.params.get_bool("IsMetric")
|
||||
|
||||
custom_alerts = self.params.get_bool("CustomAlerts")
|
||||
|
||||
custom_ui = self.params.get_bool("CustomUI")
|
||||
|
||||
longitudinal_tune = self.CP.openpilotLongitudinalControl and self.params.get_bool("LongitudinalTune")
|
||||
@@ -0,0 +1,96 @@
|
||||
import datetime
|
||||
import filecmp
|
||||
import glob
|
||||
import numpy as np
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.version import get_short_branch, get_commit_date
|
||||
|
||||
CITY_SPEED_LIMIT = 25 # 55mph is typically the minimum speed for highways
|
||||
CRUISING_SPEED = 5 # Roughly the speed cars go when not touching the gas while in drive
|
||||
PROBABILITY = 0.6 # 60% chance of condition being true
|
||||
THRESHOLD = 5 # Time threshold (0.25s)
|
||||
|
||||
def calculate_lane_width(lane, current_lane, road_edge):
|
||||
lane_x, lane_y = np.array(lane.x), np.array(lane.y)
|
||||
edge_x, edge_y = np.array(road_edge.x), np.array(road_edge.y)
|
||||
current_x, current_y = np.array(current_lane.x), np.array(current_lane.y)
|
||||
|
||||
lane_y_interp = np.interp(current_x, lane_x[lane_x.argsort()], lane_y[lane_x.argsort()])
|
||||
road_edge_y_interp = np.interp(current_x, edge_x[edge_x.argsort()], edge_y[edge_x.argsort()])
|
||||
|
||||
distance_to_lane = np.mean(np.abs(current_y - lane_y_interp))
|
||||
distance_to_road_edge = np.mean(np.abs(current_y - road_edge_y_interp))
|
||||
|
||||
return min(distance_to_lane, distance_to_road_edge)
|
||||
|
||||
def calculate_road_curvature(modelData, v_ego):
|
||||
predicted_velocities = np.array(modelData.velocity.x)
|
||||
curvature_ratios = np.abs(np.array(modelData.acceleration.y)) / (predicted_velocities**2)
|
||||
return np.amax(curvature_ratios * (v_ego**2))
|
||||
|
||||
class MovingAverageCalculator:
|
||||
def __init__(self):
|
||||
self.data = []
|
||||
self.total = 0
|
||||
|
||||
def add_data(self, value):
|
||||
if len(self.data) == THRESHOLD:
|
||||
self.total -= self.data.pop(0)
|
||||
self.data.append(value)
|
||||
self.total += value
|
||||
|
||||
def get_moving_average(self):
|
||||
if len(self.data) == 0:
|
||||
return None
|
||||
return self.total / len(self.data)
|
||||
|
||||
def reset_data(self):
|
||||
self.data = []
|
||||
self.total = 0
|
||||
|
||||
class FrogPilotFunctions:
|
||||
@classmethod
|
||||
def run_cmd(cls, cmd, success_msg, fail_msg):
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
print(success_msg)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"{fail_msg}: {e}")
|
||||
except Exception as e:
|
||||
print(f"Unexpected error occurred: {e}")
|
||||
|
||||
@classmethod
|
||||
def setup_frogpilot(cls):
|
||||
remount_cmd = ['sudo', 'mount', '-o', 'remount,rw', '/persist']
|
||||
cls.run_cmd(remount_cmd, "Successfully remounted /persist as read-write.", "Failed to remount /persist.")
|
||||
|
||||
if os.path.isdir('/persist/comma/params') and os.path.isdir('/persist/params'):
|
||||
if os.listdir('/persist/comma/params') and os.listdir('/persist/params'):
|
||||
shutil.rmtree('/persist/comma/params')
|
||||
|
||||
frogpilot_boot_logo = f'{BASEDIR}/selfdrive/frogpilot/assets/other_images/frogpilot_boot_logo.png'
|
||||
boot_logo_location = '/usr/comma/bg.jpg'
|
||||
|
||||
remount_cmd = ['sudo', 'mount', '-o', 'remount,rw', '/']
|
||||
cls.run_cmd(remount_cmd, "File system remounted as read-write.", "Failed to remount file system")
|
||||
|
||||
if not filecmp.cmp(frogpilot_boot_logo, boot_logo_location, shallow=False):
|
||||
copy_cmd = ['sudo', 'cp', frogpilot_boot_logo, boot_logo_location]
|
||||
cls.run_cmd(copy_cmd, "Successfully replaced bg.jpg with frogpilot_boot_logo.png.", "Failed to replace boot logo")
|
||||
|
||||
@classmethod
|
||||
def uninstall_frogpilot(cls):
|
||||
original_boot_logo = f'{BASEDIR}/selfdrive/frogpilot/assets/other_images/bg.jpg'
|
||||
boot_logo_location = '/usr/comma/bg.jpg'
|
||||
|
||||
copy_cmd = ['sudo', 'cp', original_boot_logo, boot_logo_location]
|
||||
cls.run_cmd(copy_cmd, "Successfully restored the original boot logo.", "Failed to restore the original boot logo.")
|
||||
|
||||
HARDWARE.uninstall()
|
||||
@@ -0,0 +1,68 @@
|
||||
import datetime
|
||||
import os
|
||||
import time
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL, Priority, config_realtime_process
|
||||
from openpilot.common.time import system_time_valid
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
from openpilot.selfdrive.frogpilot.controls.frogpilot_planner import FrogPilotPlanner
|
||||
from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import FrogPilotFunctions
|
||||
|
||||
NetworkType = log.DeviceState.NetworkType
|
||||
|
||||
def frogpilot_thread():
|
||||
config_realtime_process(5, Priority.CTRL_LOW)
|
||||
|
||||
params = Params()
|
||||
params_memory = Params("/dev/shm/params")
|
||||
|
||||
frogpilot_functions = FrogPilotFunctions()
|
||||
|
||||
CP = None
|
||||
|
||||
time_validated = system_time_valid()
|
||||
|
||||
pm = messaging.PubMaster(['frogpilotPlan'])
|
||||
sm = messaging.SubMaster(['carState', 'controlsState', 'deviceState', 'frogpilotCarControl', 'frogpilotNavigation',
|
||||
'frogpilotPlan', 'liveLocationKalman', 'longitudinalPlan', 'modelV2', 'radarState'],
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
|
||||
deviceState = sm['deviceState']
|
||||
started = deviceState.started
|
||||
|
||||
if started:
|
||||
if CP is None:
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||
CP = msg
|
||||
frogpilot_planner = FrogPilotPlanner(CP)
|
||||
frogpilot_planner.update_frogpilot_params()
|
||||
|
||||
if sm.updated['modelV2']:
|
||||
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['frogpilotCarControl'], sm['frogpilotNavigation'],
|
||||
sm['liveLocationKalman'], sm['modelV2'], sm['radarState'])
|
||||
frogpilot_planner.publish(sm, pm)
|
||||
|
||||
if params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
if started:
|
||||
frogpilot_planner.update_frogpilot_params()
|
||||
|
||||
if not time_validated:
|
||||
time_validated = system_time_valid()
|
||||
if not time_validated:
|
||||
continue
|
||||
|
||||
time.sleep(DT_MDL)
|
||||
|
||||
def main():
|
||||
frogpilot_thread()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,192 @@
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/control_settings.h"
|
||||
|
||||
FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||
std::string branch = params.get("GitBranch");
|
||||
isStaging = branch == "FrogPilot-Development" || branch == "FrogPilot-Staging" || branch == "FrogPilot-Testing";
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> controlToggles {
|
||||
{"LateralTune", tr("Lateral Tuning"), tr("Modify openpilot's steering behavior."), "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
|
||||
|
||||
{"LongitudinalTune", tr("Longitudinal Tuning"), tr("Modify openpilot's acceleration and braking behavior."), "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
|
||||
|
||||
{"QOLControls", tr("Quality of Life"), tr("Miscellaneous quality of life changes to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/quality_of_life.png"},
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : controlToggles) {
|
||||
ParamControl *toggle;
|
||||
|
||||
if (param == "LateralTune") {
|
||||
FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = lateralTuneToggle;
|
||||
|
||||
} else if (param == "LongitudinalTune") {
|
||||
FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = longitudinalTuneToggle;
|
||||
|
||||
} else if (param == "QOLControls") {
|
||||
FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
std::set<QString> modifiedQolKeys = qolKeys;
|
||||
|
||||
toggle->setVisible(modifiedQolKeys.find(key.c_str()) != modifiedQolKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = qolToggle;
|
||||
|
||||
} 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<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::valueChanged, [this]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
|
||||
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> rebootKeys = {};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(toggles[key.toStdString().c_str()], &ToggleControl::toggleFlipped, [this]() {
|
||||
if (started) {
|
||||
if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideToggles);
|
||||
QObject::connect(parent, &SettingsWindow::closeSubParentToggle, this, &FrogPilotControlsPanel::hideSubToggles);
|
||||
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotControlsPanel::updateCarToggles);
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotControlsPanel::updateState);
|
||||
|
||||
updateMetric();
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::showEvent(QShowEvent *event, const UIState &s) {
|
||||
online = s.scene.online;
|
||||
bool parked = s.scene.parked;
|
||||
started = s.scene.started;
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::updateState() {
|
||||
if (!isVisible()) return;
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::updateToggles() {
|
||||
std::thread([this]() {
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::updateCarToggles() {
|
||||
auto carParams = params.get("CarParamsPersistent");
|
||||
if (!carParams.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(carParams.data(), carParams.size()));
|
||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||
auto carFingerprint = CP.getCarFingerprint();
|
||||
auto carName = CP.getCarName();
|
||||
|
||||
hasOpenpilotLongitudinal = CP.getOpenpilotLongitudinalControl() && !params.getBool("DisableOpenpilotLongitudinal");
|
||||
hasPCMCruise = CP.getPcmCruise();
|
||||
isToyota = carName == "toyota";
|
||||
} else {
|
||||
hasAutoTune = false;
|
||||
hasCommaNNFFSupport = false;
|
||||
hasDashSpeedLimits = true;
|
||||
hasNNFFLog = true;
|
||||
hasOpenpilotLongitudinal = true;
|
||||
hasPCMCruise = true;
|
||||
isToyota = true;
|
||||
}
|
||||
|
||||
hideToggles();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (isMetric) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::hideToggles() {
|
||||
std::set<QString> longitudinalKeys = {"LongitudinalTune"};
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
toggle->setVisible(false);
|
||||
|
||||
if (!hasOpenpilotLongitudinal && longitudinalKeys.find(key.c_str()) != longitudinalKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool subToggles = aolKeys.find(key.c_str()) != aolKeys.end() ||
|
||||
conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() ||
|
||||
experimentalModeActivationKeys.find(key.c_str()) != experimentalModeActivationKeys.end() ||
|
||||
deviceManagementKeys.find(key.c_str()) != deviceManagementKeys.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() ||
|
||||
speedLimitControllerControlsKeys.find(key.c_str()) != speedLimitControllerControlsKeys.end() ||
|
||||
speedLimitControllerQOLKeys.find(key.c_str()) != speedLimitControllerQOLKeys.end() ||
|
||||
speedLimitControllerVisualsKeys.find(key.c_str()) != speedLimitControllerVisualsKeys.end() ||
|
||||
visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end();
|
||||
toggle->setVisible(!subToggles);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void FrogPilotControlsPanel::hideSubToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
bool isVisible = false;
|
||||
toggle->setVisible(isVisible);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h"
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
class FrogPilotControlsPanel : public FrogPilotListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FrogPilotControlsPanel(SettingsWindow *parent);
|
||||
|
||||
signals:
|
||||
void openParentToggle();
|
||||
void openSubParentToggle();
|
||||
|
||||
private:
|
||||
void hideSubToggles();
|
||||
void hideToggles();
|
||||
void showEvent(QShowEvent *event, const UIState &s);
|
||||
void updateCarToggles();
|
||||
void updateMetric();
|
||||
void updateState();
|
||||
void updateToggles();
|
||||
|
||||
std::set<QString> aolKeys = {};
|
||||
std::set<QString> conditionalExperimentalKeys = {};
|
||||
std::set<QString> deviceManagementKeys = {};
|
||||
std::set<QString> experimentalModeActivationKeys = {};
|
||||
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> speedLimitControllerControlsKeys = {};
|
||||
std::set<QString> speedLimitControllerQOLKeys = {};
|
||||
std::set<QString> speedLimitControllerVisualsKeys = {};
|
||||
std::set<QString> visionTurnControlKeys = {};
|
||||
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
Params params;
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
|
||||
bool hasAutoTune;
|
||||
bool hasCommaNNFFSupport;
|
||||
bool hasNNFFLog;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool hasPCMCruise;
|
||||
bool hasDashSpeedLimits;
|
||||
bool isMetric = params.getBool("IsMetric");
|
||||
bool isStaging;
|
||||
bool isToyota;
|
||||
bool online;
|
||||
bool started;
|
||||
};
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h"
|
||||
|
||||
FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
|
||||
{"LongitudinalTune", tr("Longitudinal Tune"), tr("Use a custom Toyota longitudinal tune.\n\nCydia = More focused on TSS-P vehicles but works for all Toyotas\n\nDragonPilot = Focused on TSS2 vehicles\n\nFrogPilot = Takes the best of both worlds with some personal tweaks focused around FrogsGoMoo's 2019 Lexus ES 350"), ""},
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : vehicleToggles) {
|
||||
ParamControl *toggle;
|
||||
|
||||
if (param == "LongitudinalTune") {
|
||||
std::vector<std::pair<QString, QString>> tuneOptions{
|
||||
{"StockTune", tr("Stock")},
|
||||
};
|
||||
toggle = new FrogPilotButtonsParamControl(param, title, desc, icon, tuneOptions);
|
||||
|
||||
QObject::connect(static_cast<FrogPilotButtonsParamControl*>(toggle), &FrogPilotButtonsParamControl::buttonClicked, [this]() {
|
||||
if (started) {
|
||||
if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
toggle = new ParamControl(param, title, desc, icon, this);
|
||||
}
|
||||
|
||||
toggle->setVisible(false);
|
||||
addItem(toggle);
|
||||
toggles[param.toStdString()] = toggle;
|
||||
|
||||
QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
std::set<QString> rebootKeys = {};
|
||||
for (const QString &key : rebootKeys) {
|
||||
QObject::connect(toggles[key.toStdString().c_str()], &ToggleControl::toggleFlipped, [this]() {
|
||||
if (started) {
|
||||
if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotVehiclesPanel::updateCarToggles);
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVehiclesPanel::updateState);
|
||||
}
|
||||
|
||||
void FrogPilotVehiclesPanel::updateState(const UIState &s) {
|
||||
if (!isVisible()) return;
|
||||
|
||||
started = s.scene.started;
|
||||
}
|
||||
|
||||
void FrogPilotVehiclesPanel::updateToggles() {
|
||||
std::thread([this]() {
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void FrogPilotVehiclesPanel::updateCarToggles() {
|
||||
std::set<std::string> evCars = {
|
||||
"CHEVROLET BOLT EUV 2022",
|
||||
"CHEVROLET BOLT EV NO ACC",
|
||||
"CHEVROLET VOLT NO ACC",
|
||||
"CHEVROLET VOLT PREMIER 2017",
|
||||
};
|
||||
|
||||
auto carParams = params.get("CarParamsPersistent");
|
||||
if (!carParams.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(carParams.data(), carParams.size()));
|
||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||
|
||||
auto carFingerprint = CP.getCarFingerprint();
|
||||
|
||||
hasExperimentalOpenpilotLongitudinal = CP.getExperimentalLongitudinalAvailable();
|
||||
hasOpenpilotLongitudinal = CP.getOpenpilotLongitudinalControl();
|
||||
hasSNG = CP.getMinEnableSpeed() <= 0;
|
||||
isEVCar = evCars.count(carFingerprint) > 0;
|
||||
isGMTruck = carFingerprint == "CHEVROLET SILVERADO 1500 2020";
|
||||
isImpreza = carFingerprint == "SUBARU IMPREZA LIMITED 2019";
|
||||
} else {
|
||||
hasExperimentalOpenpilotLongitudinal = false;
|
||||
hasOpenpilotLongitudinal = true;
|
||||
hasSNG = false;
|
||||
isEVCar = true;
|
||||
isGMTruck = true;
|
||||
isImpreza = true;
|
||||
}
|
||||
|
||||
hideToggles();
|
||||
}
|
||||
|
||||
void FrogPilotVehiclesPanel::hideToggles() {
|
||||
bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC";
|
||||
bool subaru = carMake == "Subaru";
|
||||
bool toyota = carMake == "Lexus" || carMake == "Toyota";
|
||||
|
||||
std::set<QString> evCarKeys = {};
|
||||
std::set<QString> gmTruckKeys = {};
|
||||
std::set<QString> imprezaKeys = {};
|
||||
std::set<QString> longitudinalKeys = {"LongitudinalTune"};
|
||||
std::set<QString> sngKeys = {};
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (toggle) {
|
||||
toggle->setVisible(false);
|
||||
|
||||
if (!hasOpenpilotLongitudinal && longitudinalKeys.find(key.c_str()) != longitudinalKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasSNG && sngKeys.find(key.c_str()) != sngKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isEVCar && evCarKeys.find(key.c_str()) != evCarKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isGMTruck && gmTruckKeys.find(key.c_str()) != gmTruckKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isImpreza && imprezaKeys.find(key.c_str()) != imprezaKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gm) {
|
||||
toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end());
|
||||
} else if (subaru) {
|
||||
toggle->setVisible(subaruKeys.find(key.c_str()) != subaruKeys.end());
|
||||
} else if (toyota) {
|
||||
toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h"
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
class FrogPilotVehiclesPanel : public FrogPilotListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FrogPilotVehiclesPanel(SettingsWindow *parent);
|
||||
|
||||
private:
|
||||
void hideToggles();
|
||||
void updateCarToggles();
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
std::set<QString> gmKeys = {};
|
||||
std::set<QString> subaruKeys = {};
|
||||
std::set<QString> toyotaKeys = {"LongitudinalTune"};
|
||||
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
Params params;
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
|
||||
bool hasExperimentalOpenpilotLongitudinal;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool hasSNG;
|
||||
bool isEVCar;
|
||||
bool isGMTruck;
|
||||
bool isImpreza;
|
||||
bool started;
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/visual_settings.h"
|
||||
|
||||
FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) {
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> visualToggles {
|
||||
{"CustomAlerts", tr("Custom Alerts"), tr("Enable custom alerts for openpilot events."), "../frogpilot/assets/toggle_icons/icon_green_light.png"},
|
||||
|
||||
{"CustomUI", tr("Custom Onroad UI"), tr("Customize the Onroad UI."), "../assets/offroad/icon_road.png"},
|
||||
{"CustomPaths", tr("Paths"), tr("Show your projected acceleration on the driving path, detected adjacent lanes, or when a vehicle is detected in your blindspot."), ""},
|
||||
|
||||
{"QOLVisuals", tr("Quality of Life"), tr("Miscellaneous quality of life changes to improve your overall openpilot experience."), "../frogpilot/assets/toggle_icons/quality_of_life.png"},
|
||||
};
|
||||
|
||||
for (const auto &[param, title, desc, icon] : visualToggles) {
|
||||
ParamControl *toggle;
|
||||
|
||||
if (param == "CustomAlerts") {
|
||||
FrogPilotParamManageControl *customAlertsToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(customAlertsToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
std::set<QString> modifiedCustomAlertsKeys = customAlertsKeys;
|
||||
|
||||
toggle->setVisible(modifiedCustomAlertsKeys.find(key.c_str()) != modifiedCustomAlertsKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = customAlertsToggle;
|
||||
|
||||
} else if (param == "CustomUI") {
|
||||
FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
std::set<QString> modifiedCustomOnroadUIKeys = customOnroadUIKeys;
|
||||
|
||||
toggle->setVisible(modifiedCustomOnroadUIKeys.find(key.c_str()) != modifiedCustomOnroadUIKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = customUIToggle;
|
||||
} else if (param == "CustomPaths") {
|
||||
std::vector<QString> pathToggles{};
|
||||
std::vector<QString> pathToggleNames{};
|
||||
toggle = new FrogPilotParamToggleControl(param, title, desc, icon, pathToggles, pathToggleNames);
|
||||
|
||||
} else if (param == "QOLVisuals") {
|
||||
FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
|
||||
QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
|
||||
openParentToggle();
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end());
|
||||
}
|
||||
});
|
||||
toggle = qolToggle;
|
||||
|
||||
} 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<FrogPilotButtonParamControl*>(toggle), &FrogPilotButtonParamControl::buttonClicked, [this]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
QObject::connect(static_cast<FrogPilotParamValueControl*>(toggle), &FrogPilotParamValueControl::valueChanged, [this]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() {
|
||||
update();
|
||||
});
|
||||
|
||||
QObject::connect(static_cast<FrogPilotParamManageControl*>(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideToggles);
|
||||
QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotVisualsPanel::updateCarToggles);
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVisualsPanel::updateState);
|
||||
|
||||
updateMetric();
|
||||
}
|
||||
|
||||
void FrogPilotVisualsPanel::updateState(const UIState &s) {
|
||||
if (!isVisible()) return;
|
||||
|
||||
started = s.scene.started;
|
||||
}
|
||||
|
||||
void FrogPilotVisualsPanel::updateToggles() {
|
||||
std::thread([this]() {
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
paramsMemory.putBool("FrogPilotTogglesUpdated", false);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void FrogPilotVisualsPanel::updateCarToggles() {
|
||||
auto carParams = params.get("CarParamsPersistent");
|
||||
if (!carParams.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(carParams.data(), carParams.size()));
|
||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||
|
||||
hasBSM = CP.getEnableBsm();
|
||||
hasOpenpilotLongitudinal = CP.getOpenpilotLongitudinalControl();
|
||||
} else {
|
||||
hasBSM = true;
|
||||
hasOpenpilotLongitudinal = true;
|
||||
}
|
||||
|
||||
hideToggles();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (isMetric) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
void FrogPilotVisualsPanel::hideToggles() {
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
bool subToggles = alertVolumeControlKeys.find(key.c_str()) != alertVolumeControlKeys.end() ||
|
||||
customAlertsKeys.find(key.c_str()) != customAlertsKeys.end() ||
|
||||
customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() ||
|
||||
customThemeKeys.find(key.c_str()) != customThemeKeys.end() ||
|
||||
modelUIKeys.find(key.c_str()) != modelUIKeys.end() ||
|
||||
qolKeys.find(key.c_str()) != qolKeys.end() ||
|
||||
screenKeys.find(key.c_str()) != screenKeys.end();
|
||||
toggle->setVisible(!subToggles);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h"
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#include "selfdrive/ui/ui.h"
|
||||
|
||||
class FrogPilotVisualsPanel : public FrogPilotListWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FrogPilotVisualsPanel(SettingsWindow *parent);
|
||||
|
||||
signals:
|
||||
void openParentToggle();
|
||||
|
||||
private:
|
||||
void hideToggles();
|
||||
void updateCarToggles();
|
||||
void updateMetric();
|
||||
void updateState(const UIState &s);
|
||||
void updateToggles();
|
||||
|
||||
std::set<QString> alertVolumeControlKeys = {};
|
||||
std::set<QString> customAlertsKeys = {};
|
||||
std::set<QString> customOnroadUIKeys = {"CustomPaths"};
|
||||
std::set<QString> customThemeKeys = {};
|
||||
std::set<QString> modelUIKeys = {};
|
||||
std::set<QString> qolKeys = {};
|
||||
std::set<QString> screenKeys = {};
|
||||
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
|
||||
Params params;
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
|
||||
bool hasBSM;
|
||||
bool hasOpenpilotLongitudinal;
|
||||
bool isMetric = params.getBool("IsMetric");
|
||||
bool started;
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <filesystem>
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.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);
|
||||
}
|
||||
@@ -0,0 +1,699 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#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 = nullptr) : 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
|
||||
}
|
||||
|
||||
inline void addItem(QWidget *w) {
|
||||
inner_layout.addWidget(w);
|
||||
adjustStretch();
|
||||
}
|
||||
|
||||
inline void addItem(QLayout *layout) {
|
||||
inner_layout.addLayout(layout);
|
||||
adjustStretch();
|
||||
}
|
||||
|
||||
inline void setSpacing(int spacing) {
|
||||
inner_layout.setSpacing(spacing);
|
||||
adjustStretch();
|
||||
}
|
||||
|
||||
private:
|
||||
void adjustStretch() {
|
||||
if (inner_layout.stretch(inner_layout.count() - 1) > 0) {
|
||||
inner_layout.setStretch(inner_layout.count() - 1, 0);
|
||||
}
|
||||
if (inner_layout.count() > 3) {
|
||||
outer_layout.addStretch();
|
||||
}
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *event) 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 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 ? 850 : 700);
|
||||
|
||||
control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
control2->setMaximumWidth(split ? 700 : 850);
|
||||
|
||||
hlayout->addWidget(control1);
|
||||
hlayout->addWidget(control2);
|
||||
}
|
||||
};
|
||||
|
||||
class FrogPilotButtonControl : public AbstractControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FrogPilotButtonControl(const QString &title, const QString &text, const QString &desc = "", 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 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: #33Ab4C;
|
||||
}
|
||||
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 FrogPilotButtonsControl : public ParamControl {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FrogPilotButtonsControl(const QString &title, const QString &desc, const QString &icon,
|
||||
const std::vector<QString> &button_texts, const int minimum_button_width = 225)
|
||||
: ParamControl("", title, desc, icon) {
|
||||
const QString style = R"(
|
||||
QPushButton {
|
||||
border-radius: 50px;
|
||||
font-size: 40px;
|
||||
font-weight: 500;
|
||||
height: 100px;
|
||||
padding: 0 25px 0 25px;
|
||||
color: #E4E4E4;
|
||||
background-color: #393939;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #33Ab4C;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33E4E4E4;
|
||||
}
|
||||
)";
|
||||
|
||||
button_group = new QButtonGroup(this);
|
||||
|
||||
for (size_t i = 0; i < button_texts.size(); i++) {
|
||||
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||
button->setStyleSheet(style);
|
||||
button->setMinimumWidth(minimum_button_width);
|
||||
hlayout->addWidget(button);
|
||||
button_group->addButton(button, static_cast<int>(i));
|
||||
|
||||
connect(button, &QPushButton::clicked, this, [this, i]() {
|
||||
emit buttonClicked(static_cast<int>(i));
|
||||
});
|
||||
}
|
||||
|
||||
toggle.hide();
|
||||
}
|
||||
|
||||
signals:
|
||||
void buttonClicked(int id);
|
||||
|
||||
private:
|
||||
QButtonGroup *button_group;
|
||||
};
|
||||
|
||||
class FrogPilotButtonsParamControl : public ParamControl {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FrogPilotButtonsParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon,
|
||||
const std::vector<std::pair<QString, QString>> &button_params)
|
||||
: 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: #33Ab4C;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33E4E4E4;
|
||||
}
|
||||
)";
|
||||
|
||||
button_group = new QButtonGroup(this);
|
||||
button_group->setExclusive(true);
|
||||
|
||||
for (const auto ¶m_pair : button_params) {
|
||||
const QString ¶m_toggle = param_pair.first;
|
||||
const QString &button_text = param_pair.second;
|
||||
|
||||
QPushButton *button = new QPushButton(button_text, this);
|
||||
button->setCheckable(true);
|
||||
|
||||
bool value = params.getBool(param_toggle.toStdString());
|
||||
button->setChecked(value);
|
||||
button->setStyleSheet(style);
|
||||
button->setMinimumWidth(225);
|
||||
hlayout->addWidget(button);
|
||||
|
||||
QObject::connect(button, &QPushButton::toggled, this, [=](bool checked) {
|
||||
if (checked) {
|
||||
for (const auto &inner_param_pair : button_params) {
|
||||
const QString &inner_param = inner_param_pair.first;
|
||||
params.putBool(inner_param.toStdString(), inner_param == param_toggle);
|
||||
}
|
||||
refresh();
|
||||
emit buttonClicked();
|
||||
}
|
||||
});
|
||||
|
||||
button_group->addButton(button);
|
||||
}
|
||||
|
||||
toggle.hide();
|
||||
}
|
||||
|
||||
void setEnabled(bool enable) {
|
||||
for (auto btn : button_group->buttons()) {
|
||||
btn->setEnabled(enable);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void buttonClicked();
|
||||
|
||||
private:
|
||||
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, bool hideToggle = false)
|
||||
: ParamControl(param, title, desc, icon, parent),
|
||||
hideToggle(hideToggle),
|
||||
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);
|
||||
|
||||
if (hideToggle) {
|
||||
toggle.hide();
|
||||
}
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
ParamControl::refresh();
|
||||
manageButton->setVisible(params.getBool(key) || hideToggle);
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled) {
|
||||
manageButton->setEnabled(enabled);
|
||||
toggle.setEnabled(enabled);
|
||||
toggle.update();
|
||||
}
|
||||
|
||||
void showEvent(QShowEvent *event) override {
|
||||
ParamControl::showEvent(event);
|
||||
refresh();
|
||||
}
|
||||
|
||||
signals:
|
||||
void manageButtonClicked();
|
||||
|
||||
private:
|
||||
bool hideToggle;
|
||||
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) {
|
||||
|
||||
key = param.toStdString();
|
||||
|
||||
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: #33Ab4C;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33E4E4E4;
|
||||
}
|
||||
)";
|
||||
|
||||
button_group = new QButtonGroup(this);
|
||||
button_group->setExclusive(false);
|
||||
this->button_params = button_params;
|
||||
|
||||
for (int i = 0; i < button_texts.size(); ++i) {
|
||||
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||
button->setCheckable(true);
|
||||
button->setStyleSheet(style);
|
||||
button->setMinimumWidth(minimum_button_width);
|
||||
button_group->addButton(button, i);
|
||||
|
||||
connect(button, &QPushButton::clicked, [this, i](bool checked) {
|
||||
params.putBool(this->button_params[i].toStdString(), checked);
|
||||
button_group->button(i)->setChecked(checked);
|
||||
emit buttonClicked(checked);
|
||||
});
|
||||
|
||||
hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, button);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
bool state = params.getBool(key);
|
||||
if (state != toggle.on) {
|
||||
toggle.togglePosition();
|
||||
}
|
||||
|
||||
refreshButtons(state);
|
||||
updateButtonStates();
|
||||
}
|
||||
|
||||
void refreshButtons(bool state) {
|
||||
for (QAbstractButton *button : button_group->buttons()) {
|
||||
button->setVisible(state);
|
||||
}
|
||||
}
|
||||
|
||||
void updateButtonStates() {
|
||||
for (int i = 0; i < button_group->buttons().size(); ++i) {
|
||||
bool checked = params.getBool(button_params[i].toStdString());
|
||||
QAbstractButton *button = button_group->button(i);
|
||||
if (button) {
|
||||
button->setChecked(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showEvent(QShowEvent *event) override {
|
||||
refresh();
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
signals:
|
||||
void buttonClicked(const bool checked);
|
||||
|
||||
private:
|
||||
std::string key;
|
||||
Params params;
|
||||
QButtonGroup *button_group;
|
||||
std::vector<QString> button_params;
|
||||
};
|
||||
|
||||
class FrogPilotParamValueControl : public ParamControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FrogPilotParamValueControl(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, const float &interval = 1.0f)
|
||||
: ParamControl(param, title, desc, icon, parent),
|
||||
minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label),
|
||||
division(division), interval(interval), previousValue(0.0f), value(0.0f) {
|
||||
key = param.toStdString();
|
||||
|
||||
valueLabel = new QLabel(this);
|
||||
hlayout->addWidget(valueLabel);
|
||||
|
||||
QPushButton *decrementButton = createButton("-", this);
|
||||
QPushButton *incrementButton = createButton("+", this);
|
||||
|
||||
hlayout->addWidget(decrementButton);
|
||||
hlayout->addWidget(incrementButton);
|
||||
|
||||
countdownTimer = new QTimer(this);
|
||||
countdownTimer->setInterval(150);
|
||||
countdownTimer->setSingleShot(true);
|
||||
|
||||
connect(countdownTimer, &QTimer::timeout, this, &FrogPilotParamValueControl::handleTimeout);
|
||||
|
||||
connect(decrementButton, &QPushButton::pressed, this, [=]() { updateValue(-interval); });
|
||||
connect(incrementButton, &QPushButton::pressed, this, [=]() { updateValue(interval); });
|
||||
|
||||
connect(decrementButton, &QPushButton::released, this, &FrogPilotParamValueControl::restartTimer);
|
||||
connect(incrementButton, &QPushButton::released, this, &FrogPilotParamValueControl::restartTimer);
|
||||
|
||||
toggle.hide();
|
||||
}
|
||||
|
||||
void restartTimer() {
|
||||
countdownTimer->stop();
|
||||
countdownTimer->start();
|
||||
|
||||
emit valueChanged(value);
|
||||
}
|
||||
|
||||
void handleTimeout() {
|
||||
previousValue = value;
|
||||
}
|
||||
|
||||
void updateValue(float intervalChange) {
|
||||
int previousValueAdjusted = round(previousValue * 100) / 100 / intervalChange;
|
||||
int valueAdjusted = round(value * 100) / 100 / intervalChange;
|
||||
|
||||
if (std::fabs(previousValueAdjusted - valueAdjusted) > 5 && std::fmod(valueAdjusted, 5) == 0) {
|
||||
intervalChange *= 5;
|
||||
}
|
||||
|
||||
value += intervalChange;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
value = params.getFloat(key);
|
||||
|
||||
QString text;
|
||||
auto it = valueLabelMappings.find(value);
|
||||
|
||||
if (division > 1.0f) {
|
||||
text = QString::number(value / division, 'g', division >= 10.0f ? 4 : 3);
|
||||
} else if (interval < 1.0f && value < 10.0f) {
|
||||
text = QString::number(value / division, 'f', 2);
|
||||
} else if (interval < 1.0f && value > 10.0f) {
|
||||
text = QString::number(value, 'f', 2);
|
||||
} else {
|
||||
if (it != valueLabelMappings.end()) {
|
||||
text = it->second;
|
||||
} else {
|
||||
text = QString::number(value, 'g', 4);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
previousValue = value;
|
||||
}
|
||||
|
||||
signals:
|
||||
void valueChanged(float value);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
|
||||
bool loop;
|
||||
|
||||
float division;
|
||||
float interval;
|
||||
float maxValue;
|
||||
float minValue;
|
||||
float previousValue;
|
||||
float value;
|
||||
|
||||
QLabel *valueLabel;
|
||||
QString labelText;
|
||||
|
||||
std::map<int, QString> valueLabelMappings;
|
||||
std::string key;
|
||||
|
||||
QTimer *countdownTimer;
|
||||
|
||||
QPushButton *createButton(const QString &text, QWidget *parent) {
|
||||
QPushButton *button = new QPushButton(text, parent);
|
||||
button->setFixedSize(150, 100);
|
||||
button->setAutoRepeat(true);
|
||||
button->setAutoRepeatInterval(150);
|
||||
button->setAutoRepeatDelay(500);
|
||||
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 FrogPilotParamValueToggleControl : public FrogPilotParamValueControl {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FrogPilotParamValueToggleControl(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, const float &interval = 1.0f,
|
||||
const std::vector<QString> &button_params = std::vector<QString>(), const std::vector<QString> &button_texts = std::vector<QString>(),
|
||||
const int minimum_button_width = 225)
|
||||
: FrogPilotParamValueControl(param, title, desc, icon, minValue, maxValue, valueLabels, parent, loop, label, division, interval) {
|
||||
|
||||
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: #33Ab4C;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
color: #33E4E4E4;
|
||||
}
|
||||
)";
|
||||
|
||||
button_group = new QButtonGroup(this);
|
||||
button_group->setExclusive(false);
|
||||
|
||||
for (int i = 0; i < button_texts.size(); ++i) {
|
||||
QPushButton *button = new QPushButton(button_texts[i], this);
|
||||
button->setCheckable(true);
|
||||
button->setChecked(params.getBool(button_params[i].toStdString()));
|
||||
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);
|
||||
refresh();
|
||||
});
|
||||
|
||||
buttons[button_params[i]] = button;
|
||||
hlayout->insertWidget(3, button);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh() {
|
||||
FrogPilotParamValueControl::refresh();
|
||||
|
||||
auto keys = buttons.keys();
|
||||
for (const QString ¶m : keys) {
|
||||
QPushButton *button = buttons.value(param);
|
||||
button->setChecked(params.getBool(param.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Params params;
|
||||
QButtonGroup *button_group;
|
||||
QMap<QString, QPushButton*> buttons;
|
||||
};
|
||||
@@ -136,6 +136,7 @@ def main():
|
||||
min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
|
||||
params = params_reader.get("LiveParameters")
|
||||
params_memory = Params("/dev/shm/params")
|
||||
|
||||
# Check if car model matches
|
||||
if params is not None:
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
import datetime
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from cereal import log
|
||||
@@ -10,6 +13,7 @@ import cereal.messaging as messaging
|
||||
import openpilot.selfdrive.sentry as sentry
|
||||
from openpilot.common.params import Params, ParamKeyType
|
||||
from openpilot.common.text_window import TextWindow
|
||||
from openpilot.common.time import system_time_valid
|
||||
from openpilot.system.hardware import HARDWARE, PC
|
||||
from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog
|
||||
from openpilot.selfdrive.manager.process import ensure_running
|
||||
@@ -20,12 +24,26 @@ from openpilot.system.version import is_dirty, get_commit, get_version, get_orig
|
||||
get_normalized_origin, terms_version, training_version, \
|
||||
is_tested_branch, is_release_branch, get_commit_date
|
||||
|
||||
from openpilot.selfdrive.frogpilot.controls.lib.frogpilot_functions import FrogPilotFunctions
|
||||
|
||||
|
||||
def manager_init() -> None:
|
||||
def frogpilot_boot_functions(frogpilot_functions):
|
||||
try:
|
||||
while not system_time_valid():
|
||||
print("Waiting for system time to become valid...")
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
|
||||
def manager_init(frogpilot_functions) -> None:
|
||||
frogpilot_boot = threading.Thread(target=frogpilot_boot_functions, args=(frogpilot_functions,))
|
||||
frogpilot_boot.start()
|
||||
|
||||
save_bootlog()
|
||||
|
||||
params = Params()
|
||||
params_storage = Params("/persist/params")
|
||||
params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)
|
||||
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION)
|
||||
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
|
||||
@@ -33,13 +51,218 @@ def manager_init() -> None:
|
||||
params.clear_all(ParamKeyType.DEVELOPMENT_ONLY)
|
||||
|
||||
default_params: list[tuple[str, str | bytes]] = [
|
||||
("CarParamsPersistent", ""),
|
||||
("CompletedTrainingVersion", "0"),
|
||||
("DisengageOnAccelerator", "0"),
|
||||
("ExperimentalLongitudinalEnabled", "1"),
|
||||
("GsmMetered", "1"),
|
||||
("HasAcceptedTerms", "0"),
|
||||
("IsLdwEnabled", "0"),
|
||||
("IsMetric", "0"),
|
||||
("LanguageSetting", "main_en"),
|
||||
("NavSettingLeftSide", "0"),
|
||||
("NavSettingTime24h", "0"),
|
||||
("OpenpilotEnabledToggle", "1"),
|
||||
("RecordFront", "0"),
|
||||
("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)),
|
||||
|
||||
# Default FrogPilot parameters
|
||||
("AccelerationPath", "1"),
|
||||
("AccelerationProfile", "2"),
|
||||
("AdjacentPath", "0"),
|
||||
("AdjacentPathMetrics", "0"),
|
||||
("AggressiveAcceleration", "1"),
|
||||
("AggressiveFollow", "1.25"),
|
||||
("AggressiveJerk", "0.5"),
|
||||
("AlertVolumeControl", "0"),
|
||||
("AlwaysOnLateral", "1"),
|
||||
("AlwaysOnLateralMain", "0"),
|
||||
("AMapKey1", ""),
|
||||
("AMapKey2", ""),
|
||||
("AutomaticUpdates", "0"),
|
||||
("BlindSpotPath", "1"),
|
||||
("CameraView", "2"),
|
||||
("CarMake", ""),
|
||||
("CarModel", ""),
|
||||
("CECurves", "1"),
|
||||
("CENavigation", "1"),
|
||||
("CENavigationIntersections", "1"),
|
||||
("CENavigationLead", "1"),
|
||||
("CENavigationTurns", "1"),
|
||||
("CESignal", "1"),
|
||||
("CESlowerLead", "1"),
|
||||
("CESpeed", "0"),
|
||||
("CESpeedLead", "0"),
|
||||
("CEStopLights", "1"),
|
||||
("CEStopLightsLead", "0"),
|
||||
("Compass", "1"),
|
||||
("ConditionalExperimental", "1"),
|
||||
("CrosstrekTorque", "1"),
|
||||
("CurveSensitivity", "100"),
|
||||
("CustomAlerts", "1"),
|
||||
("CustomColors", "1"),
|
||||
("CustomCruise", "1"),
|
||||
("CustomCruiseLong", "5"),
|
||||
("CustomIcons", "1"),
|
||||
("CustomPaths", "1"),
|
||||
("CustomPersonalities", "1"),
|
||||
("CustomSignals", "1"),
|
||||
("CustomSounds", "1"),
|
||||
("CustomTheme", "1"),
|
||||
("CustomUI", "1"),
|
||||
("CydiaTune", "0"),
|
||||
("DecelerationProfile", "1"),
|
||||
("DeveloperUI", "0"),
|
||||
("DeviceManagement", "1"),
|
||||
("DeviceShutdown", "9"),
|
||||
("DisableMTSCSmoothing", "0"),
|
||||
("DisableOnroadUploads", "0"),
|
||||
("DisableOpenpilotLongitudinal", "0"),
|
||||
("DisableVTSCSmoothing", "0"),
|
||||
("DisengageVolume", "100"),
|
||||
("DragonPilotTune", "0"),
|
||||
("DriverCamera", "0"),
|
||||
("DynamicPathWidth", "0"),
|
||||
("EngageVolume", "100"),
|
||||
("EVTable", "1"),
|
||||
("ExperimentalModeActivation", "1"),
|
||||
("ExperimentalModeViaDistance", "1"),
|
||||
("ExperimentalModeViaLKAS", "1"),
|
||||
("ExperimentalModeViaTap", "0"),
|
||||
("Fahrenheit", "0"),
|
||||
("ForceAutoTune", "1"),
|
||||
("ForceFingerprint", "0"),
|
||||
("ForceMPHDashboard", "0"),
|
||||
("FPSCounter", "0"),
|
||||
("FrogsGoMooTune", "1"),
|
||||
("FullMap", "0"),
|
||||
("GasRegenCmd", "0"),
|
||||
("GMapKey", ""),
|
||||
("GoatScream", "1"),
|
||||
("GreenLightAlert", "0"),
|
||||
("HideAlerts", "0"),
|
||||
("HideAOLStatusBar", "0"),
|
||||
("HideCEMStatusBar", "0"),
|
||||
("HideLeadMarker", "0"),
|
||||
("HideMapIcon", "0"),
|
||||
("HideMaxSpeed", "0"),
|
||||
("HideSpeed", "0"),
|
||||
("HideSpeedUI", "0"),
|
||||
("HideUIElements", "0"),
|
||||
("HigherBitrate", "0"),
|
||||
("HolidayThemes", "1"),
|
||||
("IncreaseThermalLimits", "0"),
|
||||
("LaneChangeTime", "0"),
|
||||
("LaneDetectionWidth", "60"),
|
||||
("LaneLinesWidth", "4"),
|
||||
("LateralTune", "1"),
|
||||
("LeadDepartingAlert", "0"),
|
||||
("LeadDetectionThreshold", "35"),
|
||||
("LeadInfo", "0"),
|
||||
("LockDoors", "1"),
|
||||
("LongitudinalTune", "1"),
|
||||
("LongPitch", "1"),
|
||||
("LoudBlindspotAlert", "0"),
|
||||
("LowVoltageShutdown", "11.8"),
|
||||
("MapsSelected", ""),
|
||||
("MapboxPublicKey", ""),
|
||||
("MapboxSecretKey", ""),
|
||||
("MapStyle", "0"),
|
||||
("MTSCAggressiveness", "100"),
|
||||
("MTSCCurvatureCheck", "0"),
|
||||
("Model", DEFAULT_MODEL),
|
||||
("ModelName", DEFAULT_MODEL_NAME),
|
||||
("ModelSelector", "1"),
|
||||
("ModelUI", "1"),
|
||||
("MTSCEnabled", "1"),
|
||||
("NNFF", "1"),
|
||||
("NNFFLite", "1"),
|
||||
("NoLogging", "0"),
|
||||
("NoUploads", "0"),
|
||||
("NudgelessLaneChange", "1"),
|
||||
("NumericalTemp", "0"),
|
||||
("OfflineMode", "1"),
|
||||
("Offset1", "5"),
|
||||
("Offset2", "5"),
|
||||
("Offset3", "5"),
|
||||
("Offset4", "10"),
|
||||
("OneLaneChange", "1"),
|
||||
("OnroadDistanceButton", "0"),
|
||||
("PathEdgeWidth", "20"),
|
||||
("PathWidth", "61"),
|
||||
("PauseAOLOnBrake", "0"),
|
||||
("PauseLateralOnSignal", "0"),
|
||||
("PedalsOnUI", "1"),
|
||||
("PreferredSchedule", "0"),
|
||||
("PromptVolume", "100"),
|
||||
("PromptDistractedVolume", "100"),
|
||||
("QOLControls", "1"),
|
||||
("QOLVisuals", "1"),
|
||||
("RandomEvents", "0"),
|
||||
("RefuseVolume", "100"),
|
||||
("RelaxedFollow", "1.75"),
|
||||
("RelaxedJerk", "1.0"),
|
||||
("ReverseCruise", "0"),
|
||||
("ReverseCruiseUI", "1"),
|
||||
("RoadEdgesWidth", "2"),
|
||||
("RoadNameUI", "1"),
|
||||
("RotatingWheel", "1"),
|
||||
("ScreenBrightness", "101"),
|
||||
("ScreenBrightnessOnroad", "101"),
|
||||
("ScreenManagement", "1"),
|
||||
("ScreenRecorder", "1"),
|
||||
("ScreenTimeout", "30"),
|
||||
("ScreenTimeoutOnroad", "30"),
|
||||
("SearchInput", "0"),
|
||||
("SetSpeedLimit", "0"),
|
||||
("SetSpeedOffset", "0"),
|
||||
("ShowCPU", "0"),
|
||||
("ShowGPU", "0"),
|
||||
("ShowIP", "0"),
|
||||
("ShowJerk", "1"),
|
||||
("ShowMemoryUsage", "0"),
|
||||
("ShowSLCOffset", "1"),
|
||||
("ShowSLCOffsetUI", "1"),
|
||||
("ShowStorageLeft", "0"),
|
||||
("ShowStorageUsed", "0"),
|
||||
("ShowTuning", "1"),
|
||||
("Sidebar", "0"),
|
||||
("SLCConfirmation", "1"),
|
||||
("SLCConfirmationLower", "1"),
|
||||
("SLCConfirmationHigher", "1"),
|
||||
("SLCFallback", "2"),
|
||||
("SLCOverride", "1"),
|
||||
("SLCPriority1", "Dashboard"),
|
||||
("SLCPriority2", "Offline Maps"),
|
||||
("SLCPriority3", "Navigation"),
|
||||
("SmoothBraking", "1"),
|
||||
("SmoothBrakingFarLead", "0"),
|
||||
("SmoothBrakingJerk", "0"),
|
||||
("SNGHack", "1"),
|
||||
("SpeedLimitChangedAlert", "1"),
|
||||
("SpeedLimitController", "1"),
|
||||
("StandardFollow", "1.45"),
|
||||
("StandardJerk", "1.0"),
|
||||
("StandbyMode", "0"),
|
||||
("SteerRatio", "0"),
|
||||
("StockTune", "0"),
|
||||
("StoppingDistance", "0"),
|
||||
("TacoTune", "1"),
|
||||
("ToyotaDoors", "0"),
|
||||
("TrafficFollow", "0.5"),
|
||||
("TrafficJerk", "1"),
|
||||
("TrafficMode", "0"),
|
||||
("TurnAggressiveness", "100"),
|
||||
("TurnDesires", "0"),
|
||||
("UnlimitedLength", "1"),
|
||||
("UnlockDoors", "1"),
|
||||
("UseSI", "1"),
|
||||
("UseVienna", "0"),
|
||||
("VisionTurnControl", "1"),
|
||||
("WarningSoftVolume", "100"),
|
||||
("WarningImmediateVolume", "100"),
|
||||
("WheelIcon", "3"),
|
||||
("WheelSpeed", "0")
|
||||
]
|
||||
if not PC:
|
||||
default_params.append(("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')))
|
||||
@@ -50,7 +273,12 @@ def manager_init() -> None:
|
||||
# set unset params
|
||||
for k, v in default_params:
|
||||
if params.get(k) is None:
|
||||
params.put(k, v)
|
||||
if params_storage.get(k) is None:
|
||||
params.put(k, v)
|
||||
else:
|
||||
params.put(k, params_storage.get(k))
|
||||
else:
|
||||
params_storage.put(k, params.get(k))
|
||||
|
||||
# Create folders needed for msgq
|
||||
try:
|
||||
@@ -119,6 +347,7 @@ def manager_thread() -> None:
|
||||
cloudlog.info({"environ": os.environ})
|
||||
|
||||
params = Params()
|
||||
params_memory = Params("/dev/shm/params")
|
||||
|
||||
ignore: list[str] = []
|
||||
if params.get("DongleId", encoding='utf8') in (None, UNREGISTERED_DONGLE_ID):
|
||||
@@ -144,6 +373,7 @@ def manager_thread() -> None:
|
||||
params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION)
|
||||
elif not started and started_prev:
|
||||
params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
|
||||
params_memory.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION)
|
||||
|
||||
# update onroad params, which drives boardd's safety setter thread
|
||||
if started != started_prev:
|
||||
@@ -176,7 +406,15 @@ def manager_thread() -> None:
|
||||
|
||||
|
||||
def main() -> None:
|
||||
manager_init()
|
||||
frogpilot_functions = FrogPilotFunctions()
|
||||
|
||||
try:
|
||||
frogpilot_functions.setup_frogpilot()
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to setup FrogPilot. Error: {e}")
|
||||
return
|
||||
|
||||
manager_init(frogpilot_functions)
|
||||
if os.getenv("PREPAREONLY") is not None:
|
||||
return
|
||||
|
||||
@@ -194,7 +432,7 @@ def main() -> None:
|
||||
params = Params()
|
||||
if params.get_bool("DoUninstall"):
|
||||
cloudlog.warning("uninstalling")
|
||||
HARDWARE.uninstall()
|
||||
frogpilot_functions.uninstall_frogpilot()
|
||||
elif params.get_bool("DoReboot"):
|
||||
cloudlog.warning("reboot")
|
||||
HARDWARE.reboot()
|
||||
|
||||
@@ -41,6 +41,8 @@ def only_onroad(started: bool, params, CP: car.CarParams) -> bool:
|
||||
def only_offroad(started, params, CP: car.CarParams) -> bool:
|
||||
return not started
|
||||
|
||||
# FrogPilot functions
|
||||
|
||||
procs = [
|
||||
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
|
||||
|
||||
@@ -87,6 +89,9 @@ procs = [
|
||||
NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar),
|
||||
PythonProcess("webrtcd", "system.webrtc.webrtcd", notcar),
|
||||
PythonProcess("webjoystick", "tools.bodyteleop.web", notcar),
|
||||
|
||||
# FrogPilot processes
|
||||
PythonProcess("frogpilot_process", "selfdrive.frogpilot.frogpilot_process", always_run),
|
||||
]
|
||||
|
||||
managed_processes = {p.name: p for p in procs}
|
||||
|
||||
@@ -154,7 +154,7 @@ def main(demo=False):
|
||||
|
||||
# messaging
|
||||
pm = PubMaster(["modelV2", "cameraOdometry"])
|
||||
sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "navModel", "navInstruction", "carControl"])
|
||||
sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "navModel", "navInstruction", "carControl", "frogpilotPlan"])
|
||||
|
||||
publish_state = PublishState()
|
||||
params = Params()
|
||||
@@ -299,7 +299,7 @@ def main(demo=False):
|
||||
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
|
||||
r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
|
||||
lane_change_prob = l_lane_change_prob + r_lane_change_prob
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, sm['frogpilotPlan'])
|
||||
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
|
||||
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class RouteEngine:
|
||||
self.pm = pm
|
||||
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
# Get last gps position from params
|
||||
self.last_position = coordinate_from_param("LastGPSPosition", self.params)
|
||||
@@ -59,6 +60,9 @@ class RouteEngine:
|
||||
self.mapbox_token = ""
|
||||
self.mapbox_host = "https://maps.comma.ai"
|
||||
|
||||
# FrogPilot variables
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update(self):
|
||||
self.sm.update(0)
|
||||
|
||||
@@ -77,6 +81,10 @@ class RouteEngine:
|
||||
except Exception:
|
||||
cloudlog.exception("navd.failed_to_compute")
|
||||
|
||||
# Update FrogPilot parameters
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update_location(self):
|
||||
location = self.sm['liveLocationKalman']
|
||||
self.gps_ok = location.gpsOK
|
||||
@@ -301,6 +309,11 @@ class RouteEngine:
|
||||
self.params.remove("NavDestination")
|
||||
self.clear_route()
|
||||
|
||||
frogpilot_plan_send = messaging.new_message('frogpilotNavigation')
|
||||
frogpilotNavigation = frogpilot_plan_send.frogpilotNavigation
|
||||
|
||||
self.pm.send('frogpilotNavigation', frogpilot_plan_send)
|
||||
|
||||
def send_route(self):
|
||||
coords = []
|
||||
|
||||
@@ -349,9 +362,10 @@ class RouteEngine:
|
||||
return self.reroute_counter > REROUTE_COUNTER_MIN
|
||||
# TODO: Check for going wrong way in segment
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
|
||||
def main():
|
||||
pm = messaging.PubMaster(['navInstruction', 'navRoute'])
|
||||
pm = messaging.PubMaster(['navInstruction', 'navRoute', 'frogpilotNavigation'])
|
||||
sm = messaging.SubMaster(['liveLocationKalman', 'managerState'])
|
||||
|
||||
rk = Ratekeeper(1.0)
|
||||
|
||||
@@ -36,6 +36,8 @@ class PowerMonitoring:
|
||||
# Reset capacity if it's low
|
||||
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
|
||||
|
||||
# FrogPilot variables
|
||||
|
||||
# Calculation tick
|
||||
def calculate(self, voltage: int | None, ignition: bool):
|
||||
try:
|
||||
|
||||
@@ -163,7 +163,7 @@ def hw_state_thread(end_event, hw_queue):
|
||||
|
||||
|
||||
def thermald_thread(end_event, hw_queue) -> None:
|
||||
pm = messaging.PubMaster(['deviceState'])
|
||||
pm = messaging.PubMaster(['deviceState', 'frogpilotDeviceState'])
|
||||
sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll="pandaStates")
|
||||
|
||||
count = 0
|
||||
@@ -242,6 +242,10 @@ def thermald_thread(end_event, hw_queue) -> None:
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
fpmsg = messaging.new_message('frogpilotDeviceState')
|
||||
|
||||
pm.send("frogpilotDeviceState", fpmsg)
|
||||
|
||||
msg.deviceState.freeSpacePercent = get_available_percent(default=100.0)
|
||||
msg.deviceState.memoryUsagePercent = int(round(psutil.virtual_memory().percent))
|
||||
msg.deviceState.gpuUsagePercent = int(round(HARDWARE.get_gpu_usage_percent()))
|
||||
|
||||
@@ -23,7 +23,10 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc",
|
||||
"qt/widgets/ssh_keys.cc", "qt/widgets/toggle.cc", "qt/widgets/controls.cc",
|
||||
"qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc",
|
||||
"qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc",
|
||||
"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/qt/widgets/frogpilot_controls.cc",
|
||||
"../frogpilot/ui/qt/offroad/control_settings.cc", "../frogpilot/ui/qt/offroad/vehicle_settings.cc",
|
||||
"../frogpilot/ui/qt/offroad/visual_settings.cc"]
|
||||
|
||||
qt_env['CPPDEFINES'] = []
|
||||
if maps:
|
||||
|
||||
@@ -74,6 +74,7 @@ void HomeWindow::offroadTransition(bool offroad) {
|
||||
slayout->setCurrentWidget(home);
|
||||
} else {
|
||||
slayout->setCurrentWidget(onroad);
|
||||
uiState()->scene.map_open = onroad->isMapVisible();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +92,7 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
// Handle sidebar collapsing
|
||||
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
||||
sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible());
|
||||
uiState()->scene.map_open = onroad->isMapVisible();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ private:
|
||||
OffroadAlert* alerts_widget;
|
||||
QPushButton* alert_notif;
|
||||
QPushButton* update_notif;
|
||||
|
||||
// FrogPilot variables
|
||||
};
|
||||
|
||||
class HomeWindow : public QWidget {
|
||||
@@ -69,6 +71,9 @@ private:
|
||||
DriverViewWindow *driver_view;
|
||||
QStackedLayout *slayout;
|
||||
|
||||
// FrogPilot variables
|
||||
Params params;
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
};
|
||||
|
||||
@@ -78,6 +78,9 @@ private:
|
||||
void updateDestinationMarker();
|
||||
uint64_t route_rcv_frame = 0;
|
||||
|
||||
// FrogPilot variables
|
||||
Params params;
|
||||
|
||||
private slots:
|
||||
void updateState(const UIState &s);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <eigen3/Eigen/Dense>
|
||||
#include <QGeoCoordinate>
|
||||
|
||||
#include "common/params.h"
|
||||
#include "common/util.h"
|
||||
#include "common/transformations/coordinates.hpp"
|
||||
#include "common/transformations/orientation.hpp"
|
||||
|
||||
@@ -64,6 +64,8 @@ private:
|
||||
DestinationWidget *work_widget;
|
||||
std::vector<DestinationWidget *> widgets;
|
||||
|
||||
// FrogPilot variables
|
||||
|
||||
signals:
|
||||
void closeSettings();
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
|
||||
@@ -23,6 +24,10 @@
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/control_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h"
|
||||
#include "selfdrive/frogpilot/ui/qt/offroad/visual_settings.h"
|
||||
|
||||
TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
// param, title, desc, icon
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> toggle_defs{
|
||||
@@ -122,6 +127,10 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() {
|
||||
updateToggles();
|
||||
});
|
||||
|
||||
connect(toggles["IsMetric"], &ToggleControl::toggleFlipped, [=]() {
|
||||
updateMetric();
|
||||
});
|
||||
}
|
||||
|
||||
void TogglesPanel::updateState(const UIState &s) {
|
||||
@@ -262,6 +271,22 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
});
|
||||
addItem(translateBtn);
|
||||
|
||||
// Delete long term toggle storage button
|
||||
auto deleteStorageParamsBtn = new ButtonControl(tr("Delete Toggle Storage Data"), tr("DELETE"), tr("This button provides a swift and secure way to permanently delete all "
|
||||
"long term stored toggle settings. Ideal for maintaining privacy or freeing up space.")
|
||||
);
|
||||
connect(deleteStorageParamsBtn, &ButtonControl::clicked, [=]() {
|
||||
if (!ConfirmationDialog::confirm(tr("Are you sure you want to permanently delete all of your long term toggle settings storage?"), tr("Delete"), this)) return;
|
||||
std::thread([&] {
|
||||
deleteStorageParamsBtn->setValue(tr("Deleting params..."));
|
||||
std::system("rm -rf /persist/params");
|
||||
deleteStorageParamsBtn->setValue(tr("Deleted!"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
deleteStorageParamsBtn->setValue("");
|
||||
}).detach();
|
||||
});
|
||||
addItem(deleteStorageParamsBtn);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
for (auto btn : findChildren<ButtonControl *>()) {
|
||||
btn->setEnabled(offroad);
|
||||
@@ -345,6 +370,15 @@ void DevicePanel::poweroff() {
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsWindow::hideEvent(QHideEvent *event) {
|
||||
closeParentToggle();
|
||||
|
||||
parentToggleOpen = false;
|
||||
subParentToggleOpen = false;
|
||||
|
||||
previousScrollPosition = 0;
|
||||
}
|
||||
|
||||
void SettingsWindow::showEvent(QShowEvent *event) {
|
||||
setCurrentPanel(0);
|
||||
}
|
||||
@@ -381,7 +415,17 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
close_btn->setFixedSize(200, 200);
|
||||
sidebar_layout->addSpacing(45);
|
||||
sidebar_layout->addWidget(close_btn, 0, Qt::AlignCenter);
|
||||
QObject::connect(close_btn, &QPushButton::clicked, this, &SettingsWindow::closeSettings);
|
||||
QObject::connect(close_btn, &QPushButton::clicked, [this]() {
|
||||
if (subParentToggleOpen) {
|
||||
closeSubParentToggle();
|
||||
subParentToggleOpen = false;
|
||||
} else if (parentToggleOpen) {
|
||||
closeParentToggle();
|
||||
parentToggleOpen = false;
|
||||
} else {
|
||||
closeSettings();
|
||||
}
|
||||
});
|
||||
|
||||
// setup panels
|
||||
DevicePanel *device = new DevicePanel(this);
|
||||
@@ -390,12 +434,23 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
|
||||
TogglesPanel *toggles = new TogglesPanel(this);
|
||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
QObject::connect(toggles, &TogglesPanel::updateMetric, this, &SettingsWindow::updateMetric);
|
||||
|
||||
FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this);
|
||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openSubParentToggle, this, [this]() {subParentToggleOpen = true;});
|
||||
QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {parentToggleOpen = true;});
|
||||
|
||||
FrogPilotVisualsPanel *frogpilotVisuals = new FrogPilotVisualsPanel(this);
|
||||
QObject::connect(frogpilotVisuals, &FrogPilotVisualsPanel::openParentToggle, this, [this]() {parentToggleOpen = true;});
|
||||
|
||||
QList<QPair<QString, QWidget *>> panels = {
|
||||
{tr("Device"), device},
|
||||
{tr("Network"), new Networking(this)},
|
||||
{tr("Toggles"), toggles},
|
||||
{tr("Software"), new SoftwarePanel(this)},
|
||||
{tr("Controls"), frogpilotControls},
|
||||
{tr("Vehicles"), new FrogPilotVehiclesPanel(this)},
|
||||
{tr("Visuals"), frogpilotVisuals},
|
||||
};
|
||||
|
||||
nav_btns = new QButtonGroup(this);
|
||||
@@ -428,7 +483,25 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
ScrollView *panel_frame = new ScrollView(panel, this);
|
||||
panel_widget->addWidget(panel_frame);
|
||||
|
||||
if (name == tr("Controls")) {
|
||||
QScrollBar *scrollbar = panel_frame->verticalScrollBar();
|
||||
|
||||
QObject::connect(scrollbar, &QScrollBar::valueChanged, this, [this](int value) {
|
||||
if (!parentToggleOpen) {
|
||||
previousScrollPosition = value;
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(scrollbar, &QScrollBar::rangeChanged, this, [this, panel_frame]() {
|
||||
if (!parentToggleOpen) {
|
||||
panel_frame->restorePosition(previousScrollPosition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() {
|
||||
closeParentToggle();
|
||||
previousScrollPosition = 0;
|
||||
btn->setChecked(true);
|
||||
panel_widget->setCurrentWidget(w);
|
||||
});
|
||||
|
||||
@@ -26,17 +26,31 @@ public:
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
// FrogPilot widgets
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
signals:
|
||||
void closeSettings();
|
||||
void reviewTrainingGuide();
|
||||
void showDriverView();
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
// FrogPilot signals
|
||||
void closeParentToggle();
|
||||
void closeSubParentToggle();
|
||||
void updateMetric();
|
||||
|
||||
private:
|
||||
QPushButton *sidebar_alert_widget;
|
||||
QWidget *sidebar_widget;
|
||||
QButtonGroup *nav_btns;
|
||||
QStackedWidget *panel_widget;
|
||||
|
||||
// FrogPilot variables
|
||||
bool parentToggleOpen;
|
||||
bool subParentToggleOpen;
|
||||
|
||||
int previousScrollPosition;
|
||||
};
|
||||
|
||||
class DevicePanel : public ListWidget {
|
||||
@@ -54,6 +68,9 @@ private slots:
|
||||
|
||||
private:
|
||||
Params params;
|
||||
|
||||
// FrogPilot variables
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
};
|
||||
|
||||
class TogglesPanel : public ListWidget {
|
||||
@@ -62,6 +79,10 @@ public:
|
||||
explicit TogglesPanel(SettingsWindow *parent);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
// FrogPilot signals
|
||||
void updateMetric();
|
||||
|
||||
public slots:
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
@@ -96,4 +117,8 @@ private:
|
||||
|
||||
Params params;
|
||||
ParamWatcher *fs_watch;
|
||||
|
||||
// FrogPilot variables
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
UIScene &scene;
|
||||
};
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "system/hardware/hw.h"
|
||||
|
||||
#include "selfdrive/frogpilot/ui/qt/widgets/frogpilot_controls.h"
|
||||
|
||||
void SoftwarePanel::checkForUpdates() {
|
||||
std::system("pkill -SIGUSR1 -f selfdrive.updated.updated");
|
||||
}
|
||||
|
||||
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent), scene(uiState()->scene) {
|
||||
onroadLbl = new QLabel(tr("Updates are only downloaded while the car is off."));
|
||||
onroadLbl->setStyleSheet("font-size: 50px; font-weight: 400; text-align: left; padding-top: 30px; padding-bottom: 30px;");
|
||||
addItem(onroadLbl);
|
||||
@@ -54,6 +55,11 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
connect(targetBranchBtn, &ButtonControl::clicked, [=]() {
|
||||
auto current = params.get("GitBranch");
|
||||
QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(",");
|
||||
if (!Params("/persist/params").getBool("FrogsGoMoo")) {
|
||||
branches.removeAll("FrogPilot-Development");
|
||||
branches.removeAll("FrogPilot-New");
|
||||
branches.removeAll("MAKE-PRS-HERE");
|
||||
}
|
||||
for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "master-ci", "master"}) {
|
||||
auto i = branches.indexOf(b);
|
||||
if (i >= 0) {
|
||||
|
||||
@@ -28,7 +28,7 @@ static void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, cons
|
||||
p.setOpacity(1.0);
|
||||
}
|
||||
|
||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
|
||||
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent), scene(uiState()->scene) {
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setMargin(UI_BORDER_SIZE);
|
||||
QStackedLayout *stacked_layout = new QStackedLayout;
|
||||
@@ -93,8 +93,11 @@ void OnroadWindow::updateState(const UIState &s) {
|
||||
}
|
||||
|
||||
void OnroadWindow::mousePressEvent(QMouseEvent* e) {
|
||||
// FrogPilot clickable widgets
|
||||
bool widgetClicked = false;
|
||||
|
||||
#ifdef ENABLE_MAPS
|
||||
if (map != nullptr) {
|
||||
if (map != nullptr && !widgetClicked) {
|
||||
// Switch between map and sidebar when using navigate on openpilot
|
||||
bool sidebarVisible = geometry().x() > 0;
|
||||
bool show_map = uiState()->scene.navigate_on_openpilot ? sidebarVisible : !sidebarVisible;
|
||||
@@ -102,7 +105,9 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) {
|
||||
}
|
||||
#endif
|
||||
// propagation event to parent(HomeWindow)
|
||||
QWidget::mousePressEvent(e);
|
||||
if (!widgetClicked) {
|
||||
QWidget::mousePressEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void OnroadWindow::offroadTransition(bool offroad) {
|
||||
@@ -114,6 +119,7 @@ void OnroadWindow::offroadTransition(bool offroad) {
|
||||
|
||||
QObject::connect(m, &MapPanel::mapPanelRequested, this, &OnroadWindow::mapPanelRequested);
|
||||
QObject::connect(nvg->map_settings_btn, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings);
|
||||
QObject::connect(nvg->map_settings_btn_bottom, &MapSettingsButton::clicked, m, &MapPanel::toggleMapSettings);
|
||||
nvg->map_settings_btn->setEnabled(true);
|
||||
|
||||
m->setFixedWidth(topWidget(this)->width() / 2 - UI_BORDER_SIZE);
|
||||
@@ -167,11 +173,13 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) {
|
||||
|
||||
int margin = 40;
|
||||
int radius = 30;
|
||||
int offset = true ? 25 : 0;
|
||||
if (alert.size == cereal::ControlsState::AlertSize::FULL) {
|
||||
margin = 0;
|
||||
radius = 0;
|
||||
offset = 0;
|
||||
}
|
||||
QRect r = QRect(0 + margin, height() - h + margin, width() - margin*2, h - margin*2);
|
||||
QRect r = QRect(0 + margin, height() - h + margin - offset, width() - margin*2, h - margin*2);
|
||||
|
||||
QPainter p(this);
|
||||
|
||||
@@ -212,7 +220,7 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) {
|
||||
}
|
||||
|
||||
// ExperimentalButton
|
||||
ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) {
|
||||
ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent), scene(uiState()->scene) {
|
||||
setFixedSize(btn_size, btn_size);
|
||||
|
||||
engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size});
|
||||
@@ -236,6 +244,8 @@ void ExperimentalButton::updateState(const UIState &s) {
|
||||
experimental_mode = cs.getExperimentalMode();
|
||||
update();
|
||||
}
|
||||
|
||||
// FrogPilot variables
|
||||
}
|
||||
|
||||
void ExperimentalButton::paintEvent(QPaintEvent *event) {
|
||||
@@ -247,7 +257,7 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) {
|
||||
|
||||
// MapSettingsButton
|
||||
MapSettingsButton::MapSettingsButton(QWidget *parent) : QPushButton(parent) {
|
||||
setFixedSize(btn_size, btn_size);
|
||||
setFixedSize(btn_size, btn_size + 20);
|
||||
settings_img = loadPixmap("../assets/navigation/icon_directions_outlined.svg", {img_size, img_size});
|
||||
|
||||
// hidden by default, made visible if map is created (has prime or mapbox token)
|
||||
@@ -262,7 +272,7 @@ void MapSettingsButton::paintEvent(QPaintEvent *event) {
|
||||
|
||||
|
||||
// Window that shows camera view and variety of info drawn on top
|
||||
AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent) {
|
||||
AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3, 1. / UI_FREQ), CameraWidget("camerad", type, true, parent), scene(uiState()->scene) {
|
||||
pm = std::make_unique<PubMaster, const std::initializer_list<const char *>>({"uiDebug"});
|
||||
|
||||
main_layout = new QVBoxLayout(this);
|
||||
@@ -276,6 +286,9 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget* par
|
||||
main_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
|
||||
dm_img = loadPixmap("../assets/img_driver_face.png", {img_size + 5, img_size + 5});
|
||||
|
||||
// Initialize FrogPilot widgets
|
||||
initializeFrogPilotWidgets();
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::updateState(const UIState &s) {
|
||||
@@ -328,6 +341,8 @@ void AnnotatedCameraWidget::updateState(const UIState &s) {
|
||||
map_settings_btn->setVisible(!hideBottomIcons);
|
||||
main_layout->setAlignment(map_settings_btn, (rightHandDM ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignBottom);
|
||||
}
|
||||
|
||||
updateFrogPilotWidgets();
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::drawHud(QPainter &p) {
|
||||
@@ -426,6 +441,9 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) {
|
||||
drawText(p, rect().center().x(), 290, speedUnit, 200);
|
||||
|
||||
p.restore();
|
||||
|
||||
// Draw FrogPilot widgets
|
||||
paintFrogPilotWidgets(p);
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &text, int alpha) {
|
||||
@@ -468,7 +486,6 @@ void AnnotatedCameraWidget::updateFrameMat() {
|
||||
void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
||||
painter.save();
|
||||
|
||||
const UIScene &scene = s->scene;
|
||||
SubMaster &sm = *(s->sm);
|
||||
|
||||
// lanelines
|
||||
@@ -485,7 +502,7 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
||||
|
||||
// paint path
|
||||
QLinearGradient bg(0, height(), 0, 0);
|
||||
if (sm["controlsState"].getControlsState().getExperimentalMode()) {
|
||||
if (experimentalMode) {
|
||||
// The first half of track_vertices are the points for the right side of the path
|
||||
// and the indices match the positions of accel from uiPlan
|
||||
const auto &acceleration = sm["uiPlan"].getUiPlan().getAccel();
|
||||
@@ -525,13 +542,12 @@ void AnnotatedCameraWidget::drawLaneLines(QPainter &painter, const UIState *s) {
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::drawDriverState(QPainter &painter, const UIState *s) {
|
||||
const UIScene &scene = s->scene;
|
||||
|
||||
painter.save();
|
||||
|
||||
// base icon
|
||||
int offset = UI_BORDER_SIZE + btn_size / 2;
|
||||
int x = rightHandDM ? width() - offset : offset;
|
||||
offset += true ? 25 : 0;
|
||||
int y = height() - offset;
|
||||
float opacity = dmActive ? 0.65 : 0.2;
|
||||
drawIcon(painter, QPoint(x, y), dm_img, blackColor(70), opacity);
|
||||
@@ -633,7 +649,7 @@ void AnnotatedCameraWidget::paintGL() {
|
||||
} else if (v_ego > 15) {
|
||||
wide_cam_requested = false;
|
||||
}
|
||||
wide_cam_requested = wide_cam_requested && sm["controlsState"].getControlsState().getExperimentalMode();
|
||||
wide_cam_requested = wide_cam_requested && experimentalMode;
|
||||
// for replay of old routes, never go to widecam
|
||||
wide_cam_requested = wide_cam_requested && s->scene.calibration_wide_valid;
|
||||
}
|
||||
@@ -701,3 +717,82 @@ void AnnotatedCameraWidget::showEvent(QShowEvent *event) {
|
||||
ui_update_params(uiState());
|
||||
prev_draw_t = millis_since_boot();
|
||||
}
|
||||
|
||||
// FrogPilot widgets
|
||||
void AnnotatedCameraWidget::initializeFrogPilotWidgets() {
|
||||
bottom_layout = new QHBoxLayout();
|
||||
|
||||
QSpacerItem *spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
bottom_layout->addItem(spacer);
|
||||
|
||||
map_settings_btn_bottom = new MapSettingsButton(this);
|
||||
bottom_layout->addWidget(map_settings_btn_bottom);
|
||||
|
||||
main_layout->addLayout(bottom_layout);
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::updateFrogPilotWidgets() {
|
||||
alertSize = scene.alert_size;
|
||||
|
||||
experimentalMode = scene.experimental_mode;
|
||||
|
||||
mapOpen = scene.map_open;
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p) {
|
||||
if (true) {
|
||||
drawStatusBar(p);
|
||||
}
|
||||
|
||||
map_settings_btn_bottom->setEnabled(map_settings_btn->isEnabled());
|
||||
if (map_settings_btn_bottom->isEnabled()) {
|
||||
map_settings_btn_bottom->setVisible(!hideBottomIcons);
|
||||
bottom_layout->setAlignment(map_settings_btn_bottom, rightHandDM ? Qt::AlignLeft : Qt::AlignRight);
|
||||
}
|
||||
}
|
||||
|
||||
void AnnotatedCameraWidget::drawStatusBar(QPainter &p) {
|
||||
p.save();
|
||||
|
||||
static bool displayStatusText = false;
|
||||
|
||||
constexpr qreal fadeDuration = 1500.0;
|
||||
constexpr qreal textDuration = 5000.0;
|
||||
|
||||
static QElapsedTimer timer;
|
||||
static QString lastShownStatus;
|
||||
|
||||
QString newStatus;
|
||||
|
||||
QRect currentRect = rect();
|
||||
QRect statusBarRect(currentRect.left() - 1, currentRect.bottom() - 50, currentRect.width() + 2, 100);
|
||||
|
||||
p.setBrush(QColor(0, 0, 0, 150));
|
||||
p.setOpacity(1.0);
|
||||
p.drawRoundedRect(statusBarRect, 30, 30);
|
||||
|
||||
if (newStatus != lastShownStatus) {
|
||||
displayStatusText = true;
|
||||
lastShownStatus = newStatus;
|
||||
timer.restart();
|
||||
} else if (displayStatusText && timer.hasExpired(textDuration + fadeDuration)) {
|
||||
displayStatusText = false;
|
||||
}
|
||||
|
||||
p.setFont(InterFont(40, QFont::Bold));
|
||||
p.setPen(Qt::white);
|
||||
p.setRenderHint(QPainter::TextAntialiasing);
|
||||
|
||||
static qreal statusTextOpacity;
|
||||
int elapsed = timer.elapsed();
|
||||
if (displayStatusText) {
|
||||
statusTextOpacity = qBound(0.0, 1.0 - (elapsed - textDuration) / fadeDuration, 1.0);
|
||||
}
|
||||
|
||||
p.setOpacity(statusTextOpacity);
|
||||
QRect textRect = p.fontMetrics().boundingRect(statusBarRect, Qt::AlignCenter | Qt::TextWordWrap, newStatus);
|
||||
textRect.moveBottom(statusBarRect.bottom() - 50);
|
||||
p.drawText(textRect, Qt::AlignCenter | Qt::TextWordWrap, newStatus);
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class OnroadAlerts : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OnroadAlerts(QWidget *parent = 0) : QWidget(parent) {}
|
||||
OnroadAlerts(QWidget *parent = 0) : QWidget(parent), scene(uiState()->scene) {}
|
||||
void updateAlert(const Alert &a);
|
||||
|
||||
protected:
|
||||
@@ -29,6 +29,9 @@ protected:
|
||||
private:
|
||||
QColor bg;
|
||||
Alert alert = {};
|
||||
|
||||
// FrogPilot variables
|
||||
UIScene &scene;
|
||||
};
|
||||
|
||||
class ExperimentalButton : public QPushButton {
|
||||
@@ -47,6 +50,10 @@ private:
|
||||
QPixmap experimental_img;
|
||||
bool experimental_mode;
|
||||
bool engageable;
|
||||
|
||||
// FrogPilot variables
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
UIScene &scene;
|
||||
};
|
||||
|
||||
|
||||
@@ -71,6 +78,7 @@ public:
|
||||
void updateState(const UIState &s);
|
||||
|
||||
MapSettingsButton *map_settings_btn;
|
||||
MapSettingsButton *map_settings_btn_bottom;
|
||||
|
||||
private:
|
||||
void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255);
|
||||
@@ -97,6 +105,24 @@ private:
|
||||
int skip_frame_count = 0;
|
||||
bool wide_cam_requested = false;
|
||||
|
||||
// FrogPilot widgets
|
||||
void initializeFrogPilotWidgets();
|
||||
void paintFrogPilotWidgets(QPainter &p);
|
||||
void updateFrogPilotWidgets();
|
||||
|
||||
void drawStatusBar(QPainter &p);
|
||||
|
||||
// FrogPilot variables
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
UIScene &scene;
|
||||
|
||||
QHBoxLayout *bottom_layout;
|
||||
|
||||
bool experimentalMode;
|
||||
bool mapOpen;
|
||||
|
||||
int alertSize;
|
||||
|
||||
protected:
|
||||
void paintGL() override;
|
||||
void initializeGL() override;
|
||||
@@ -135,6 +161,11 @@ private:
|
||||
QWidget *map = nullptr;
|
||||
QHBoxLayout* split;
|
||||
|
||||
// FrogPilot variables
|
||||
UIScene &scene;
|
||||
Params params;
|
||||
Params paramsMemory{"/dev/shm/params"};
|
||||
|
||||
private slots:
|
||||
void offroadTransition(bool offroad);
|
||||
void primeChanged(bool prime);
|
||||
|
||||