mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-02-18 16:33:57 +08:00
Merge branch 'refs/heads/master-at-17032025' into sync-17032025
# Conflicts: # opendbc_repo # selfdrive/car/card.py # selfdrive/car/tests/test_car_interfaces.py # selfdrive/car/tests/test_models.py # selfdrive/controls/controlsd.py # selfdrive/controls/lib/tests/test_latcontrol.py # selfdrive/pandad/panda.h # system/manager/process_config.py Sync: `commaai/opendbc:master` into `sunnypilot/opendbc:master-new`
This commit is contained in:
@@ -6,7 +6,7 @@ Version 0.9.8 (2025-02-28)
|
||||
========================
|
||||
* New driving model
|
||||
* Model now gates applying positive acceleration in Chill mode
|
||||
* New driving monitoring model
|
||||
* New driver monitoring model
|
||||
* Reduced false positives related to passengers
|
||||
* Image processing pipeline moved to the ISP
|
||||
* More GPU time for bigger driving models
|
||||
|
||||
@@ -59,6 +59,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
pcmEnable @23;
|
||||
pcmDisable @24;
|
||||
radarFault @25;
|
||||
radarTempUnavailable @93;
|
||||
brakeHold @26;
|
||||
parkBrake @27;
|
||||
manualRestart @28;
|
||||
@@ -728,7 +729,7 @@ struct PeripheralState {
|
||||
struct RadarState @0x9a185389d6fdd05f {
|
||||
mdMonoTime @6 :UInt64;
|
||||
carStateMonoTime @11 :UInt64;
|
||||
radarErrors @12 :List(Car.RadarData.Error);
|
||||
radarErrors @13 :Car.RadarData.Error;
|
||||
|
||||
leadOne @3 :LeadData;
|
||||
leadTwo @4 :LeadData;
|
||||
@@ -762,6 +763,7 @@ struct RadarState @0x9a185389d6fdd05f {
|
||||
calPercDEPRECATED @9 :Int8;
|
||||
canMonoTimesDEPRECATED @10 :List(UInt64);
|
||||
cumLagMsDEPRECATED @5 :Float32;
|
||||
radarErrorsDEPRECATED @12 :List(Car.RadarData.ErrorDEPRECATED);
|
||||
}
|
||||
|
||||
struct LiveCalibrationData {
|
||||
|
||||
Submodule opendbc_repo updated: 9fbd19d3a6...9298a1ac9d
@@ -40,8 +40,6 @@ rm -f panda/board/obj/panda.bin.signed
|
||||
rm -f panda/board/obj/panda_h7.bin.signed
|
||||
|
||||
VERSION=$(cat common/version.h | awk -F[\"-] '{print $2}')
|
||||
echo "#define COMMA_VERSION \"$VERSION-release\"" > common/version.h
|
||||
|
||||
echo "[-] committing version $VERSION T=$SECONDS"
|
||||
git add -f .
|
||||
git commit -a -m "openpilot v$VERSION release"
|
||||
|
||||
@@ -16,7 +16,7 @@ from opendbc.car import DT_CTRL, structs
|
||||
from opendbc.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
|
||||
from opendbc.car.carlog import carlog
|
||||
from opendbc.car.fw_versions import ObdCallback
|
||||
from opendbc.car.car_helpers import get_car, get_radar_interface
|
||||
from opendbc.car.car_helpers import get_car, interfaces
|
||||
from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
|
||||
@@ -25,7 +25,7 @@ from openpilot.selfdrive.car.car_specific import MockCarState
|
||||
from openpilot.selfdrive.car.helpers import convert_carControlSP, convert_to_capnp
|
||||
|
||||
from openpilot.sunnypilot.mads.mads import MadsParams
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces
|
||||
|
||||
REPLAY = "REPLAY" in os.environ
|
||||
|
||||
@@ -108,8 +108,8 @@ class Car:
|
||||
fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle", encoding='utf-8') or "{}").get("platform", None)
|
||||
|
||||
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params, fixed_fingerprint)
|
||||
interfaces.setup_car_interface_sp(self.CI.CP, self.CI.CP_SP, self.params)
|
||||
self.RI = get_radar_interface(self.CI.CP, self.CI.CP_SP)
|
||||
sunnypilot_interfaces.setup_car_interface_sp(self.CI.CP, self.CI.CP_SP, self.params)
|
||||
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_SP)
|
||||
self.CP = self.CI.CP
|
||||
self.CP_SP = self.CI.CP_SP
|
||||
|
||||
@@ -192,7 +192,7 @@ class Car:
|
||||
self.rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
|
||||
# log fingerprint in sentry
|
||||
interfaces.log_fingerprint(self.CP)
|
||||
sunnypilot_interfaces.log_fingerprint(self.CP)
|
||||
|
||||
def state_update(self) -> tuple[car.CarState, structs.RadarDataT | None]:
|
||||
"""carState update loop, driven by can"""
|
||||
@@ -256,7 +256,7 @@ class Car:
|
||||
|
||||
if RD is not None:
|
||||
tracks_msg = messaging.new_message('liveTracks')
|
||||
tracks_msg.valid = len(RD.errors) == 0
|
||||
tracks_msg.valid = not any(RD.errors.to_dict().values())
|
||||
tracks_msg.liveTracks = RD
|
||||
self.pm.send('liveTracks', tracks_msg)
|
||||
|
||||
@@ -274,7 +274,7 @@ class Car:
|
||||
# Initialize CarInterface, once controls are ready
|
||||
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
|
||||
self.CI.init(self.CP, self.CP_SP, *self.can_callbacks)
|
||||
interfaces.initialize_car_interface_sp(self.CP, self.CP_SP, self.params, *self.can_callbacks)
|
||||
sunnypilot_interfaces.initialize_car_interface_sp(self.CP, self.CP_SP, self.params, *self.can_callbacks)
|
||||
# signal pandad to switch to car safety mode
|
||||
self.params.put_bool_nonblocking("ControlsReady", True)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class TestCarInterfaces:
|
||||
phases=(Phase.reuse, Phase.generate, Phase.shrink))
|
||||
@given(data=st.data())
|
||||
def test_car_interfaces(self, car_name, data):
|
||||
CarInterface, CarController, CarState, RadarInterface = interfaces[car_name]
|
||||
CarInterface = interfaces[car_name]
|
||||
|
||||
args = get_fuzzy_car_interface_args(data.draw)
|
||||
|
||||
@@ -44,7 +44,7 @@ class TestCarInterfaces:
|
||||
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
|
||||
experimental_long=args['experimental_long'], docs=False)
|
||||
car_params = car_params.as_reader()
|
||||
car_interface = CarInterface(car_params, car_params_sp, CarController, CarState)
|
||||
car_interface = CarInterface(car_params, car_params_sp)
|
||||
assert car_params
|
||||
assert car_params_sp
|
||||
assert car_interface
|
||||
|
||||
@@ -152,8 +152,8 @@ class TestCarModelBase(unittest.TestCase):
|
||||
# if relay is expected to be open in the route
|
||||
cls.openpilot_enabled = cls.car_safety_mode_frame is not None
|
||||
|
||||
cls.CarInterface, cls.CarController, cls.CarState, cls.RadarInterface = interfaces[cls.platform]
|
||||
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
cls.CarInterface = interfaces[cls.platform]
|
||||
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
assert cls.CP
|
||||
assert cls.CP_SP
|
||||
@@ -166,7 +166,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
del cls.can_msgs
|
||||
|
||||
def setUp(self):
|
||||
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP), self.CarController, self.CarState)
|
||||
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP))
|
||||
assert self.CI
|
||||
|
||||
# TODO: check safetyModel is in release panda build
|
||||
@@ -217,7 +217,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
self.assertEqual(can_invalid_cnt, 0)
|
||||
|
||||
def test_radar_interface(self):
|
||||
RI = self.RadarInterface(self.CP, self.CP_SP)
|
||||
RI = self.CarInterface.RadarInterface(self.CP, self.CP_SP)
|
||||
assert RI
|
||||
|
||||
# Since OBD port is multiplexed to bus 1 (commonly radar bus) while fingerprinting,
|
||||
@@ -226,7 +226,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
for i, msg in enumerate(self.can_msgs[self.elm_frame:]):
|
||||
rr: structs.RadarData | None = RI.update(msg)
|
||||
if rr is not None and i > 50:
|
||||
error_cnt += structs.RadarData.Error.canError in rr.errors
|
||||
error_cnt += rr.errors.canError
|
||||
self.assertEqual(error_cnt, 0)
|
||||
|
||||
def test_panda_safety_rx_checks(self):
|
||||
@@ -280,7 +280,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
def test_car_controller(car_control, car_control_sp):
|
||||
now_nanos = 0
|
||||
msgs_sent = 0
|
||||
CI = self.CarInterface(self.CP, self.CP_SP, self.CarController, self.CarState)
|
||||
CI = self.CarInterface(self.CP, self.CP_SP)
|
||||
for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages
|
||||
CI.update([])
|
||||
_, sendcan = CI.apply(car_control, car_control_sp, now_nanos)
|
||||
|
||||
@@ -9,7 +9,7 @@ from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
from opendbc.car.car_helpers import get_car_interface
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import clip_curvature
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
|
||||
@@ -37,7 +37,7 @@ class Controls:
|
||||
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
|
||||
cloudlog.info("controlsd got CarParamsSP")
|
||||
|
||||
self.CI = get_car_interface(self.CP, self.CP_SP)
|
||||
self.CI = interfaces[self.CP.carFingerprint](self.CP, self.CP_SP)
|
||||
|
||||
self.sm = messaging.SubMaster(['liveParameters', 'liveTorqueParameters', 'modelV2', 'selfdriveState',
|
||||
'liveCalibration', 'livePose', 'longitudinalPlan', 'carState', 'carOutput',
|
||||
|
||||
@@ -17,10 +17,10 @@ class TestLatControl:
|
||||
|
||||
@parameterized.expand([(HONDA.HONDA_CIVIC, LatControlPID), (TOYOTA.TOYOTA_RAV4, LatControlTorque), (NISSAN.NISSAN_LEAF, LatControlAngle)])
|
||||
def test_saturation(self, car_name, controller):
|
||||
CarInterface, CarController, CarState, RadarInterface = interfaces[car_name]
|
||||
CarInterface = interfaces[car_name]
|
||||
CP = CarInterface.get_non_essential_params(car_name)
|
||||
CP_SP = CarInterface.get_non_essential_params_sp(CP, car_name)
|
||||
CI = CarInterface(CP, CP_SP, CarController, CarState)
|
||||
CI = CarInterface(CP, CP_SP)
|
||||
VM = VehicleModel(CP)
|
||||
|
||||
controller = controller(CP.as_reader(), CI)
|
||||
|
||||
@@ -20,7 +20,7 @@ def main():
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'],
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
poll='modelV2')
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any
|
||||
|
||||
import capnp
|
||||
from cereal import messaging, log, car
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL, Priority, config_realtime_process
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
@@ -51,7 +52,7 @@ class Track:
|
||||
def __init__(self, identifier: int, v_lead: float, kalman_params: KalmanParams):
|
||||
self.identifier = identifier
|
||||
self.cnt = 0
|
||||
self.aLeadTau = _LEAD_ACCEL_TAU
|
||||
self.aLeadTau = FirstOrderFilter(_LEAD_ACCEL_TAU, 0.45, DT_MDL)
|
||||
self.K_A = kalman_params.A
|
||||
self.K_C = kalman_params.C
|
||||
self.K_K = kalman_params.K
|
||||
@@ -74,17 +75,12 @@ class Track:
|
||||
|
||||
# Learn if constant acceleration
|
||||
if abs(self.aLeadK) < 0.5:
|
||||
self.aLeadTau = _LEAD_ACCEL_TAU
|
||||
self.aLeadTau.x = _LEAD_ACCEL_TAU
|
||||
else:
|
||||
self.aLeadTau *= 0.9
|
||||
self.aLeadTau.update(0.0)
|
||||
|
||||
self.cnt += 1
|
||||
|
||||
def reset_a_lead(self, aLeadK: float, aLeadTau: float):
|
||||
self.kf = KF1D([[self.vLead], [aLeadK]], self.K_A, self.K_C, self.K_K)
|
||||
self.aLeadK = aLeadK
|
||||
self.aLeadTau = aLeadTau
|
||||
|
||||
def get_RadarState(self, model_prob: float = 0.0):
|
||||
return {
|
||||
"dRel": float(self.dRel),
|
||||
@@ -93,7 +89,7 @@ class Track:
|
||||
"vLead": float(self.vLead),
|
||||
"vLeadK": float(self.vLeadK),
|
||||
"aLeadK": float(self.aLeadK),
|
||||
"aLeadTau": float(self.aLeadTau),
|
||||
"aLeadTau": float(self.aLeadTau.x),
|
||||
"status": True,
|
||||
"fcw": self.is_potential_fcw(model_prob),
|
||||
"modelProb": model_prob,
|
||||
@@ -231,10 +227,10 @@ class RadarD:
|
||||
self.tracks[ids].update(rpt[0], rpt[1], rpt[2], v_lead, rpt[3])
|
||||
|
||||
# *** publish radarState ***
|
||||
self.radar_state_valid = sm.all_checks() and len(rr.errors) == 0
|
||||
self.radar_state_valid = sm.all_checks()
|
||||
self.radar_state = log.RadarState.new_message()
|
||||
self.radar_state.mdMonoTime = sm.logMonoTime['modelV2']
|
||||
self.radar_state.radarErrors = list(rr.errors)
|
||||
self.radar_state.radarErrors = rr.errors
|
||||
self.radar_state.carStateMonoTime = sm.logMonoTime['carState']
|
||||
|
||||
if len(sm['modelV2'].velocity.x):
|
||||
|
||||
@@ -26,6 +26,6 @@ class TestLeads:
|
||||
msgs = [m for _ in range(3) for m in single_iter_pkg()]
|
||||
out = replay_process_with_name("card", msgs, fingerprint=TOYOTA.TOYOTA_COROLLA_TSS2)
|
||||
states = [m for m in out if m.which() == "liveTracks"]
|
||||
failures = [not state.valid and len(state.liveTracks.errors) for state in states]
|
||||
failures = [not state.valid for state in states]
|
||||
|
||||
assert len(states) == 0 or all(failures)
|
||||
|
||||
@@ -10,21 +10,21 @@ if __name__ == "__main__":
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("--fingerprint", help="The fingerprint to use")
|
||||
parser.add_argument("route", help="The route name to use")
|
||||
parser.add_argument("process", help="The process to run")
|
||||
parser.add_argument("process", nargs='+', help="The process(s) to run")
|
||||
args = parser.parse_args()
|
||||
|
||||
cfg = [c for c in CONFIGS if c.proc_name == args.process][0]
|
||||
cfgs = [c for c in CONFIGS if c.proc_name in args.process]
|
||||
|
||||
lr = LogReader(args.route)
|
||||
inputs = list(lr)
|
||||
|
||||
outputs = replay_process(cfg, inputs, fingerprint=args.fingerprint)
|
||||
outputs = replay_process(cfgs, inputs, fingerprint=args.fingerprint)
|
||||
|
||||
# Remove message generated by the process under test and merge in the new messages
|
||||
produces = {o.which() for o in outputs}
|
||||
inputs = [i for i in inputs if i.which() not in produces]
|
||||
outputs = sorted(inputs + outputs, key=lambda x: x.logMonoTime)
|
||||
|
||||
fn = f"{args.route.replace('/', '_')}_{args.process}.zst"
|
||||
fn = f"{args.route.replace('/', '_')}_{'_'.join(args.process)}.zst"
|
||||
print(f"Saving log to {fn}")
|
||||
save_log(fn, outputs)
|
||||
|
||||
@@ -52,14 +52,14 @@ class ParamsLearner:
|
||||
device_pose = Pose.from_live_pose(msg)
|
||||
calibrated_pose = self.calibrator.build_calibrated_pose(device_pose)
|
||||
|
||||
yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrator.calib_valid
|
||||
yaw_rate_valid = msg.angularVelocityDevice.valid
|
||||
yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s
|
||||
yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s
|
||||
if yaw_rate_valid:
|
||||
self.yaw_rate, self.yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
|
||||
else:
|
||||
# This is done to bound the yaw rate estimate when localizer values are invalid or calibrating
|
||||
self.yaw_rate, self.yaw_rate_std = 0.0, np.radians(1)
|
||||
self.yaw_rate, self.yaw_rate_std = 0.0, np.radians(10.0)
|
||||
|
||||
localizer_roll, localizer_roll_std = device_pose.orientation.x, device_pose.orientation.x_std
|
||||
localizer_roll_std = np.radians(1) if np.isnan(localizer_roll_std) else localizer_roll_std
|
||||
@@ -225,13 +225,13 @@ def main():
|
||||
liveParameters.posenetValid = True
|
||||
liveParameters.sensorValid = sensors_valid
|
||||
liveParameters.steerRatio = float(x[States.STEER_RATIO].item())
|
||||
liveParameters.steerRatioValid = min_sr <= liveParameters.steerRatio <= max_sr
|
||||
liveParameters.stiffnessFactor = float(x[States.STIFFNESS].item())
|
||||
liveParameters.stiffnessFactorValid = 0.2 <= liveParameters.stiffnessFactor <= 5.0
|
||||
liveParameters.roll = float(roll)
|
||||
liveParameters.angleOffsetAverageDeg = float(angle_offset_average)
|
||||
liveParameters.angleOffsetAverageValid = bool(avg_offset_valid)
|
||||
liveParameters.angleOffsetDeg = float(angle_offset)
|
||||
liveParameters.steerRatioValid = min_sr <= liveParameters.steerRatio <= max_sr
|
||||
liveParameters.stiffnessFactorValid = 0.2 <= liveParameters.stiffnessFactor <= 5.0
|
||||
liveParameters.angleOffsetAverageValid = bool(avg_offset_valid)
|
||||
liveParameters.angleOffsetValid = bool(total_offset_valid)
|
||||
liveParameters.valid = all((
|
||||
liveParameters.angleOffsetAverageValid,
|
||||
|
||||
@@ -66,6 +66,25 @@ void Panda::set_alternative_experience(uint16_t alternative_experience, uint16_t
|
||||
handle->control_write(0xdf, alternative_experience, safety_param_sp);
|
||||
}
|
||||
|
||||
std::string Panda::serial_read(int port_number) {
|
||||
std::string ret;
|
||||
char buffer[USBPACKET_MAX_SIZE] = {};
|
||||
|
||||
while (true) {
|
||||
int bytes_read = handle->control_read(0xe0, port_number, 0, (unsigned char *)buffer, USBPACKET_MAX_SIZE);
|
||||
if (bytes_read <= 0) {
|
||||
break;
|
||||
}
|
||||
ret.append(buffer, bytes_read);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Panda::set_uart_baud(int uart, int rate) {
|
||||
handle->control_write(0xe4, uart, int(rate / 300));
|
||||
}
|
||||
|
||||
cereal::PandaState::PandaType Panda::get_hw_type() {
|
||||
unsigned char hw_query[1] = {0};
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ public:
|
||||
cereal::PandaState::PandaType get_hw_type();
|
||||
void set_safety_model(cereal::CarParams::SafetyModel safety_model, uint16_t safety_param=0U);
|
||||
void set_alternative_experience(uint16_t alternative_experience, uint16_t safety_param_sp=0U);
|
||||
std::string serial_read(int port_number = 0);
|
||||
void set_uart_baud(int uart, int rate);
|
||||
void set_fan_speed(uint16_t fan_speed);
|
||||
uint16_t get_fan_speed();
|
||||
void set_ir_pwr(uint16_t ir_pwr);
|
||||
|
||||
@@ -470,6 +470,14 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
send_peripheral_state(peripheral_panda, &pm);
|
||||
}
|
||||
|
||||
// Forward logs from pandas to cloudlog if available
|
||||
for (auto *panda : pandas) {
|
||||
std::string log = panda->serial_read();
|
||||
if (!log.empty()) {
|
||||
LOGD("%s", log.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
rk.keepTime();
|
||||
}
|
||||
|
||||
|
||||
@@ -672,6 +672,11 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
ET.NO_ENTRY: NoEntryAlert("Radar Error: Restart the Car"),
|
||||
},
|
||||
|
||||
EventName.radarTempUnavailable: {
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Radar Temporarily Unavailable"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Radar Temporarily Unavailable"),
|
||||
},
|
||||
|
||||
# Every frame from the camera should be processed by the model. If modeld
|
||||
# is not processing frames fast enough they have to be dropped. This alert is
|
||||
# thrown when over 20% of frames are dropped.
|
||||
|
||||
@@ -92,7 +92,7 @@ class SelfdriveD(CruiseHelper):
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'controlsState', 'carControl', 'driverAssistance', 'alertDebug'] + \
|
||||
self.camera_packets + self.sensor_packets + self.gps_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState',],
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore,
|
||||
ignore_valid=ignore, frequency=int(1/DT_CTRL))
|
||||
|
||||
# read params
|
||||
@@ -294,7 +294,13 @@ class SelfdriveD(CruiseHelper):
|
||||
self.events.add(EventName.cameraFrameRate)
|
||||
if not REPLAY and self.rk.lagging:
|
||||
self.events.add(EventName.selfdrivedLagging)
|
||||
if len(self.sm['radarState'].radarErrors) or ((not self.rk.lagging or REPLAY) and not self.sm.all_checks(['radarState'])):
|
||||
if not self.sm.valid['radarState']:
|
||||
if self.sm['radarState'].radarErrors.canError:
|
||||
self.events.add(EventName.canError)
|
||||
elif self.sm['radarState'].radarErrors.radarUnavailableTemporary:
|
||||
self.events.add(EventName.radarTempUnavailable)
|
||||
else:
|
||||
self.events.add(EventName.radarFault)
|
||||
self.events.add(EventName.radarFault)
|
||||
if not self.sm.valid['pandaStates']:
|
||||
self.events.add(EventName.usbError)
|
||||
@@ -330,7 +336,7 @@ class SelfdriveD(CruiseHelper):
|
||||
self.events.add(EventName.posenetInvalid)
|
||||
if not self.sm['livePose'].inputsOK:
|
||||
self.events.add(EventName.locationdTemporaryError)
|
||||
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
|
||||
if not self.sm['liveParameters'].valid and cal_status == log.LiveCalibrationData.Status.calibrated and not TESTING_CLOSET and (not SIMULATION or REPLAY):
|
||||
self.events.add(EventName.paramsdTemporaryError)
|
||||
|
||||
# conservative HW alert. if the data or frequency are off, locationd will throw an error
|
||||
|
||||
@@ -241,14 +241,16 @@ def migrate_gpsLocation(msgs):
|
||||
|
||||
@migration(inputs=["deviceState", "initData"])
|
||||
def migrate_deviceState(msgs):
|
||||
init_data = next((m.initData for _, m in msgs if m.which() == 'initData'), None)
|
||||
device_state = next((m.deviceState for _, m in msgs if m.which() == 'deviceState'), None)
|
||||
if init_data is None or device_state is None:
|
||||
return [], [], []
|
||||
|
||||
ops = []
|
||||
dt = None
|
||||
for i, msg in msgs:
|
||||
if msg.which() == 'initData':
|
||||
dt = msg.initData.deviceType
|
||||
if msg.which() == 'deviceState':
|
||||
n = msg.as_builder()
|
||||
n.deviceState.deviceType = dt
|
||||
n.deviceState.deviceType = init_data.deviceType
|
||||
ops.append((i, n.as_reader()))
|
||||
return ops, [], []
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ def card_fingerprint_callback(rc, pm, msgs, fingerprint):
|
||||
def get_car_params_callback(rc, pm, msgs, fingerprint):
|
||||
params = Params()
|
||||
if fingerprint:
|
||||
CarInterface, _, _, _ = interfaces[fingerprint]
|
||||
CarInterface = interfaces[fingerprint]
|
||||
CP = CarInterface.get_non_essential_params(fingerprint)
|
||||
CP_SP = CarInterface.get_non_essential_params_sp(CP, fingerprint)
|
||||
else:
|
||||
|
||||
@@ -1 +1 @@
|
||||
37041a45841e83f0641ef1e87c0e567181d47172
|
||||
e9d57157494480637a8ffb52257d2b660a48be67
|
||||
@@ -48,7 +48,8 @@ void Setup::download(QString url) {
|
||||
auto version = util::read_file("/VERSION");
|
||||
|
||||
struct curl_slist *list = NULL;
|
||||
list = curl_slist_append(list, ("X-openpilot-serial: " + Hardware::get_serial()).c_str());
|
||||
std::string header = "X-openpilot-serial: " + Hardware::get_serial();
|
||||
list = curl_slist_append(list, header.c_str());
|
||||
|
||||
char tmpfile[] = "/tmp/installer_XXXXXX";
|
||||
FILE *fp = fdopen(mkstemp(tmpfile), "wb");
|
||||
|
||||
@@ -425,28 +425,30 @@
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>openpilot 通过观察人类驾驶(包括您)来学习如何驾驶。
|
||||
|
||||
“训练数据上传模式”允许您最大化上传训练数据,以改进 openpilot 的驾驶模型。更多数据意味着更强大的模型,也就意味着更优秀的“实验模式”。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>训练数据上传模式:激活中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>激活中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>未激活</span>:请连接至不限流量的网络</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>为了达到最佳效果,请每周将您的设备带回室内,并连接到优质的 USB-C 充电器和 Wi-Fi。<br><br>Firehose 模式在行驶时也能运行,但需连接到移动热点或使用不限流量的 SIM 卡。<br><br><br><b>常见问题</b><br><br><i>我开车的方式或地点有影响吗?</i>不会,请像平常一样驾驶即可。<br><br><i>Firehose 模式会上传所有的驾驶片段吗?</i>不会,我们会选择性地上传部分片段。<br><br><i>什么是好的 USB-C 充电器?</i>任何快速手机或笔记本电脑充电器都应该适用。<br><br><i>我使用的软件版本有影响吗?</i>有的,只有官方 openpilot(以及特定的分支)可以用于训练。</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source><b>%n segment(s)</b> of your driving is in the training dataset so far.</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<translation>
|
||||
<numerusform><b>目前已有 %n 段</b> 您的驾驶数据被纳入训练数据集。</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1534,11 +1536,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>欢迎使用 openpilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>您必须接受《条款与条件》才能使用 openpilot。在继续之前,请先阅读最新条款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -425,28 +425,30 @@
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>openpilot 透過觀察人類駕駛(包括您)來學習如何駕駛。
|
||||
|
||||
「訓練資料上傳模式」可讓您最大化上傳訓練數據,以改進 openpilot 的駕駛模型。更多數據代表更強大的模型,也就意味著更優秀的「實驗模式」。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>訓練資料上傳模式:啟用中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>啟用中</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>未啟用</span>:請連接至不限流量的網路</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>為了達到最佳效果,請每週將您的裝置帶回室內,並連接至優質的 USB-C 充電器與 Wi-Fi。<br><br>訓練資料上傳模式在行駛時也能運作,但需連接至行動熱點或使用不限流量的 SIM 卡。<br><br><br><b>常見問題</b><br><br><i>我開車的方式或地點有影響嗎?</i> 不會,請像平常一樣駕駛即可。<br><br><i>訓練資料上傳模式會上傳所有的駕駛片段嗎?</i>不會,我們會選擇性地上傳部分片段。<br><br><i>什麼是好的 USB-C 充電器?</i>任何快速手機或筆電充電器都應該適用。<br><br><i>我使用的軟體版本有影響嗎?</i>有的,只有官方 openpilot(以及特定的分支)可以用於訓練。</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source><b>%n segment(s)</b> of your driving is in the training dataset so far.</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<translation>
|
||||
<numerusform><b>目前已有 %n 段</b> 您的駕駛數據被納入訓練資料集。</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1534,11 +1536,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>歡迎使用 openpilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>您必須接受《條款與條件》才能使用 openpilot。在繼續之前,請先閱讀最新條款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -237,7 +237,7 @@ SpectraCamera::SpectraCamera(SpectraMaster *master, const CameraConfig &config)
|
||||
: m(master),
|
||||
enabled(config.enabled),
|
||||
cc(config) {
|
||||
ife_buf_depth = (cc.output_type == ISP_RAW_OUTPUT) ? 4 : VIPC_BUFFER_COUNT;
|
||||
ife_buf_depth = VIPC_BUFFER_COUNT;
|
||||
assert(ife_buf_depth < MAX_IFE_BUFS);
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ int SpectraCamera::clear_req_queue() {
|
||||
req_mgr_flush_request.link_hdl = link_handle;
|
||||
req_mgr_flush_request.flush_type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
|
||||
int ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
|
||||
LOGD("flushed all req: %d", ret);
|
||||
LOGD("flushed all req: %d", ret); // returns a "time until timeout" on clearing the workq
|
||||
|
||||
for (int i = 0; i < MAX_IFE_BUFS; ++i) {
|
||||
destroySyncObjectAt(i);
|
||||
@@ -1330,7 +1330,16 @@ bool SpectraCamera::handle_camera_event(const cam_req_mgr_message *event_data) {
|
||||
uint64_t timestamp = event_data->u.frame_msg.timestamp; // timestamped in the kernel's SOF IRQ callback
|
||||
//LOGD("handle cam %d ts %lu req id %lu frame id %lu", cc.camera_num, timestamp, request_id, frame_id_raw);
|
||||
|
||||
if (stress_test("skipping SOF event")) return false;
|
||||
// if there's a lag, some more frames could have already come in before
|
||||
// we cleared the queue, so we'll still get them with valid (> 0) request IDs.
|
||||
if (timestamp < last_requeue_ts) {
|
||||
LOGD("skipping frame: ts before requeue / cam %d ts %lu req id %lu frame id %lu", cc.camera_num, timestamp, request_id, frame_id_raw);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stress_test("skipping SOF event")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validateEvent(request_id, frame_id_raw)) {
|
||||
return false;
|
||||
@@ -1381,7 +1390,7 @@ bool SpectraCamera::validateEvent(uint64_t request_id, uint64_t frame_id_raw) {
|
||||
|
||||
if (request_id != request_id_last + 1) {
|
||||
LOGE("camera %d requests skipped %ld -> %ld", cc.camera_num, request_id_last, request_id);
|
||||
clearAndRequeue(request_id_last + 1);
|
||||
clearAndRequeue(request_id + 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1392,6 +1401,7 @@ void SpectraCamera::clearAndRequeue(uint64_t from_request_id) {
|
||||
// clear everything, then queue up a fresh set of frames
|
||||
LOGW("clearing and requeuing camera %d from %lu", cc.camera_num, from_request_id);
|
||||
clear_req_queue();
|
||||
last_requeue_ts = nanos_since_boot();
|
||||
for (uint64_t id = from_request_id; id < from_request_id + ife_buf_depth; ++id) {
|
||||
enqueue_frame(id);
|
||||
}
|
||||
@@ -1402,12 +1412,19 @@ bool SpectraCamera::waitForFrameReady(uint64_t request_id) {
|
||||
int buf_idx = request_id % ife_buf_depth;
|
||||
assert(sync_objs_ife[buf_idx]);
|
||||
|
||||
if (stress_test("sync sleep time")) {
|
||||
util::sleep_for(350);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto waitForSync = [&](uint32_t sync_obj, int timeout_ms, const char *sync_type) {
|
||||
double st = millis_since_boot();
|
||||
struct cam_sync_wait sync_wait = {};
|
||||
sync_wait.sync_obj = sync_obj;
|
||||
sync_wait.timeout_ms = stress_test(sync_type) ? 1 : timeout_ms;
|
||||
bool ret = do_sync_control(m->cam_sync_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait)) == 0;
|
||||
if (!ret) LOGE("camera %d %s failed", cc.camera_num, sync_type);
|
||||
double et = millis_since_boot();
|
||||
if (!ret) LOGE("camera %d %s failed after %.2fms", cc.camera_num, sync_type, et-st);
|
||||
return ret;
|
||||
};
|
||||
|
||||
@@ -1419,6 +1436,7 @@ bool SpectraCamera::waitForFrameReady(uint64_t request_id) {
|
||||
// BPS is typically 7ms
|
||||
success = waitForSync(sync_objs_bps[buf_idx], 50, "BPS sync");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ public:
|
||||
int sync_objs_ife[MAX_IFE_BUFS] = {};
|
||||
int sync_objs_bps[MAX_IFE_BUFS] = {};
|
||||
uint64_t request_id_last = 0;
|
||||
uint64_t last_requeue_ts = 0;
|
||||
uint64_t frame_id_raw_last = 0;
|
||||
int invalid_request_count = 0;
|
||||
bool skip_expected = true;
|
||||
@@ -202,11 +203,16 @@ private:
|
||||
inline static bool first_frame_synced = false;
|
||||
|
||||
// a mode for stressing edge cases: realignment, sync failures, etc.
|
||||
inline bool stress_test(const char* log) {
|
||||
static double prob = std::stod(util::getenv("SPECTRA_ERROR_PROB", "-1"));;
|
||||
bool triggered = (prob > 0) && ((static_cast<double>(rand()) / RAND_MAX) < prob);
|
||||
inline bool stress_test(std::string log) {
|
||||
static double last_trigger = 0;
|
||||
static double prob = std::stod(util::getenv("SPECTRA_ERROR_PROB", "-1"));
|
||||
static double dt = std::stod(util::getenv("SPECTRA_ERROR_DT", "1"));
|
||||
bool triggered = (prob > 0) && \
|
||||
((static_cast<double>(rand()) / RAND_MAX) < prob) && \
|
||||
(millis_since_boot() - last_trigger) > dt;
|
||||
if (triggered) {
|
||||
LOGE("stress test (cam %d): %s", cc.camera_num, log);
|
||||
last_trigger = millis_since_boot();
|
||||
LOGE("stress test (cam %d): %s", cc.camera_num, log.c_str());
|
||||
}
|
||||
return triggered;
|
||||
}
|
||||
|
||||
@@ -221,8 +221,12 @@ class PythonProcess(ManagerProcess):
|
||||
if self.proc is not None:
|
||||
return
|
||||
|
||||
# TODO: this is just a workaround for this tinygrad check:
|
||||
# https://github.com/tinygrad/tinygrad/blob/ac9c96dae1656dc220ee4acc39cef4dd449aa850/tinygrad/device.py#L26
|
||||
name = self.name if "modeld" not in self.name else "MainProcess"
|
||||
|
||||
cloudlog.info(f"starting python {self.module}")
|
||||
self.proc = Process(name=self.name, target=self.launcher, args=(self.module, self.name))
|
||||
self.proc = Process(name=name, target=self.launcher, args=(self.module, self.name))
|
||||
self.proc.start()
|
||||
self.watchdog_seen = False
|
||||
self.shutting_down = False
|
||||
|
||||
@@ -105,10 +105,8 @@ procs = [
|
||||
PythonProcess("micd", "system.micd", iscar),
|
||||
PythonProcess("timed", "system.timed", always_run, enabled=not PC),
|
||||
|
||||
# TODO: Make python process once TG allows opening QCOM from child pro
|
||||
# https://github.com/tinygrad/tinygrad/blob/ac9c96dae1656dc220ee4acc39cef4dd449aa850/tinygrad/device.py#L26
|
||||
NativeProcess("modeld", "selfdrive/modeld", ["./modeld.py"], and_(only_onroad, is_stock_model)),
|
||||
NativeProcess("dmonitoringmodeld", "selfdrive/modeld", ["./dmonitoringmodeld.py"], driverview, enabled=(WEBCAM or not PC)),
|
||||
PythonProcess("modeld", "selfdrive.modeld.modeld", and_(only_onroad, is_stock_model)),
|
||||
PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(WEBCAM or not PC)),
|
||||
|
||||
NativeProcess("sensord", "system/sensord", ["./sensord"], only_onroad, enabled=not PC),
|
||||
NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=(5 if not PC else None)),
|
||||
|
||||
Reference in New Issue
Block a user