mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-23 01:04:01 +08:00
Optimus Prime
This commit is contained in:
@@ -63,6 +63,15 @@ class RadarInterface(RadarInterfaceBase):
|
||||
self.ioniq_6_radar_probe_updates = 0
|
||||
self.rcp = get_radar_can_parser(CP, self.radar_config)
|
||||
|
||||
# Precompute (addr, "RADAR_TRACK_xxx") pairs once. _update runs on the
|
||||
# CAN-driven card loop (core 4, shared with controlsd/selfdrived), so avoid
|
||||
# rebuilding 32 f-strings per radar frame.
|
||||
self.track_addrs: list[tuple[int, str]] = []
|
||||
if self.radar_config is not None:
|
||||
self.track_addrs = [(addr, f"RADAR_TRACK_{addr:x}")
|
||||
for addr in range(self.radar_config.start_addr,
|
||||
self.radar_config.start_addr + self.radar_config.msg_count)]
|
||||
|
||||
def update(self, can_strings):
|
||||
if self.ioniq_6_radar_probe and self.rcp is not None and not self.ioniq_6_radar_probe_logged:
|
||||
vls = self.rcp.update(can_strings)
|
||||
@@ -104,10 +113,13 @@ class RadarInterface(RadarInterfaceBase):
|
||||
if self.radar_config is None:
|
||||
return ret
|
||||
|
||||
for addr in range(self.radar_config.start_addr, self.radar_config.start_addr + self.radar_config.msg_count):
|
||||
msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
|
||||
radar_type = self.radar_config.radar_type
|
||||
vl = self.rcp.vl
|
||||
|
||||
if self.radar_config.radar_type == "mrr30":
|
||||
for addr, track_name in self.track_addrs:
|
||||
msg = vl[track_name]
|
||||
|
||||
if radar_type == "mrr30":
|
||||
for i in ("1", "2"):
|
||||
track_key = addr * 2 + int(i) - 1
|
||||
if track_key not in self.pts:
|
||||
@@ -128,24 +140,32 @@ class RadarInterface(RadarInterfaceBase):
|
||||
del self.pts[track_key]
|
||||
continue
|
||||
|
||||
if radar_type == "mrr35":
|
||||
# Most of the 32 channels are empty each frame. Only allocate a point
|
||||
# when the channel is valid; drop it otherwise. Avoids the per-frame
|
||||
# alloc-then-delete churn on the ~27 idle channels.
|
||||
if msg["STATE"] in (3, 4):
|
||||
pt = self.pts.get(addr)
|
||||
if pt is None:
|
||||
pt = structs.RadarData.RadarPoint()
|
||||
pt.trackId = self.track_id
|
||||
self.track_id += 1
|
||||
self.pts[addr] = pt
|
||||
pt.measured = True
|
||||
pt.dRel = msg["LONG_DIST"]
|
||||
pt.yRel = msg["LAT_DIST"]
|
||||
pt.vRel = msg["REL_SPEED"]
|
||||
pt.aRel = msg["REL_ACCEL"]
|
||||
pt.yvRel = float("nan")
|
||||
elif addr in self.pts:
|
||||
del self.pts[addr]
|
||||
continue
|
||||
|
||||
if addr not in self.pts:
|
||||
self.pts[addr] = structs.RadarData.RadarPoint()
|
||||
self.pts[addr].trackId = self.track_id
|
||||
self.track_id += 1
|
||||
|
||||
if self.radar_config.radar_type == "mrr35":
|
||||
valid = msg["STATE"] in (3, 4)
|
||||
if valid:
|
||||
self.pts[addr].measured = True
|
||||
self.pts[addr].dRel = msg["LONG_DIST"]
|
||||
self.pts[addr].yRel = msg["LAT_DIST"]
|
||||
self.pts[addr].vRel = msg["REL_SPEED"]
|
||||
self.pts[addr].aRel = msg["REL_ACCEL"]
|
||||
self.pts[addr].yvRel = float("nan")
|
||||
else:
|
||||
del self.pts[addr]
|
||||
continue
|
||||
|
||||
valid = msg['STATE'] in (3, 4)
|
||||
if valid:
|
||||
azimuth = math.radians(msg['AZIMUTH'])
|
||||
|
||||
@@ -957,10 +957,16 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
# ten times the regular interval, or the average interval is more than 10% too high.
|
||||
EventName.commIssue: {
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue Between Processes"),
|
||||
ET.PERMANENT: Alert("Communication Issue Between Processes", "",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 1., creation_delay=30.),
|
||||
ET.NO_ENTRY: comm_issue_alert,
|
||||
},
|
||||
EventName.commIssueAvgFreq: {
|
||||
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate Between Processes"),
|
||||
ET.PERMANENT: Alert("Low Communication Rate Between Processes", "",
|
||||
AlertStatus.normal, AlertSize.small,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 1., creation_delay=30.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate Between Processes"),
|
||||
},
|
||||
|
||||
|
||||
+30
-1
@@ -1,17 +1,46 @@
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
#include "system/hardware/hw.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/window.h"
|
||||
|
||||
// Qt 5.12.8's qErrnoWarning() emits QtCriticalMsg then calls abort() directly,
|
||||
// bypassing the fatal-message path. Intercept critical+fatal Wayland messages
|
||||
// before the unconditional abort() fires and clean-exit so the manager restarts
|
||||
// us quickly instead of going through the slow abort/crash-handler path.
|
||||
void waylandAwareMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
if (type == QtCriticalMsg || type == QtFatalMsg) {
|
||||
QByteArray bytes = msg.toUtf8();
|
||||
if (bytes.contains("ayland") || bytes.contains("wl_display")) {
|
||||
swagLogMessageHandler(type, context, msg);
|
||||
LOGE("UI WAYLAND EXIT: %s", bytes.constData());
|
||||
_exit(0); // clean exit; manager restarts us
|
||||
}
|
||||
}
|
||||
swagLogMessageHandler(type, context, msg);
|
||||
// Non-Wayland fatal: let Qt abort normally; crash_handler will capture it.
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
setpriority(PRIO_PROCESS, 0, -20);
|
||||
|
||||
qInstallMessageHandler(swagLogMessageHandler);
|
||||
// Pin the UI to the little cores (0-3). The realtime control loop
|
||||
// (card/controlsd/selfdrived) runs SCHED_FIFO on core 4; without this pin the
|
||||
// kernel can schedule the UI there, and a UI stall/restart spike preempts
|
||||
// selfdrived, starving its 100 Hz loop and firing the "System Lagging" alert.
|
||||
// Set before any threads spawn so children inherit the affinity.
|
||||
if (!Hardware::PC()) {
|
||||
util::set_core_affinity({0, 1, 2, 3});
|
||||
}
|
||||
|
||||
qInstallMessageHandler(waylandAwareMessageHandler);
|
||||
initApp(argc, argv);
|
||||
|
||||
QTranslator translator;
|
||||
|
||||
@@ -82,7 +82,7 @@ FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent)
|
||||
// Set up the API request for firehose stats
|
||||
const QString dongle_id = QString::fromStdString(Params().get("DongleId"));
|
||||
firehose_stats = new RequestRepeater(this, CommaApi::BASE_URL + "/v1/devices/" + dongle_id + "/firehose_stats",
|
||||
"ApiCache_FirehoseStats", 30, true);
|
||||
"ApiCache_FirehoseStats", 30, false);
|
||||
QObject::connect(firehose_stats, &RequestRepeater::requestDone, [=](const QString &response, bool success) {
|
||||
if (success) {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
|
||||
|
||||
@@ -16,7 +16,7 @@ PrimeState::PrimeState(QObject* parent) : QObject(parent) {
|
||||
|
||||
if (auto dongleId = getDongleId()) {
|
||||
QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/";
|
||||
RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 5);
|
||||
RequestRepeater* repeater = new RequestRepeater(this, url, "ApiCache_Device", 60);
|
||||
QObject::connect(repeater, &RequestRepeater::requestDone, this, &PrimeState::handleReply);
|
||||
}
|
||||
|
||||
|
||||
@@ -391,6 +391,11 @@ void UIState::update() {
|
||||
if (!watchdog_kick(nanos_since_boot())) {
|
||||
LOGE("UI watchdog kick failed at frame %llu", static_cast<unsigned long long>(sm->frame));
|
||||
}
|
||||
// Re-pin to the little cores: power-save can offline our core and the
|
||||
// kernel may rebalance us onto core 4 (the realtime control loop).
|
||||
if (!Hardware::PC()) {
|
||||
util::set_core_affinity({0, 1, 2, 3});
|
||||
}
|
||||
}
|
||||
ui_stall_progress(UIStallPhase::AFTER_WATCHDOG, sm->frame);
|
||||
emit uiUpdate(*this, *starpilotUIState());
|
||||
|
||||
@@ -40,21 +40,26 @@ static void update_state(StarPilotUIState *fs) {
|
||||
}
|
||||
capnp::Text::Reader toggles = starpilotPlan.getStarpilotToggles();
|
||||
QByteArray current_toggles(toggles.cStr(), toggles.size());
|
||||
static QByteArray previous_toggles;
|
||||
if (previous_toggles != current_toggles) {
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument toggles_doc = QJsonDocument::fromJson(current_toggles, &parse_error);
|
||||
if (parse_error.error == QJsonParseError::NoError && toggles_doc.isObject()) {
|
||||
QJsonObject updated_toggles = starpilot_scene.starpilot_toggles;
|
||||
const QJsonObject parsed_toggles = toggles_doc.object();
|
||||
for (auto it = parsed_toggles.begin(); it != parsed_toggles.end(); ++it) {
|
||||
updated_toggles.insert(it.key(), it.value());
|
||||
// starpilot_process only broadcasts the full toggles JSON periodically and
|
||||
// sends an empty string on every other frame. Skip the empty broadcasts so
|
||||
// we don't parse "" (QJsonParseError "illegal value") every frame.
|
||||
if (!current_toggles.trimmed().isEmpty()) {
|
||||
static QByteArray previous_toggles;
|
||||
if (previous_toggles != current_toggles) {
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument toggles_doc = QJsonDocument::fromJson(current_toggles, &parse_error);
|
||||
if (parse_error.error == QJsonParseError::NoError && toggles_doc.isObject()) {
|
||||
QJsonObject updated_toggles = starpilot_scene.starpilot_toggles;
|
||||
const QJsonObject parsed_toggles = toggles_doc.object();
|
||||
for (auto it = parsed_toggles.begin(); it != parsed_toggles.end(); ++it) {
|
||||
updated_toggles.insert(it.key(), it.value());
|
||||
}
|
||||
starpilot_scene.starpilot_toggles = updated_toggles;
|
||||
} else {
|
||||
qWarning() << "Ignoring invalid StarPilot toggles JSON:" << parse_error.errorString();
|
||||
}
|
||||
starpilot_scene.starpilot_toggles = updated_toggles;
|
||||
} else {
|
||||
qWarning() << "Ignoring invalid StarPilot toggles JSON:" << parse_error.errorString();
|
||||
previous_toggles = current_toggles;
|
||||
}
|
||||
previous_toggles = current_toggles;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from openpilot.system.hardware import HARDWARE, PC, TICI
|
||||
from openpilot.system.manager.process import PythonProcess, NativeProcess, DaemonProcess
|
||||
|
||||
WEBCAM = os.getenv("USE_WEBCAM") is not None
|
||||
UI_WATCHDOG_MAX_DT = int(os.getenv("UI_WATCHDOG_MAX_DT", "5"))
|
||||
UI_WATCHDOG_MAX_DT = int(os.getenv("UI_WATCHDOG_MAX_DT", "10"))
|
||||
|
||||
def driverview(started: bool, params: Params, CP: car.CarParams, starpilot_toggles: SimpleNamespace) -> bool:
|
||||
return started or params.get_bool("IsDriverViewEnabled")
|
||||
|
||||
@@ -122,9 +122,13 @@ def downloader_loop(event):
|
||||
if alt_path is not None and os.path.exists(alt_path):
|
||||
shutil.copyfile(alt_path, ASSIST_DATA_FILE)
|
||||
|
||||
sm = messaging.SubMaster(['deviceState'])
|
||||
|
||||
try:
|
||||
while not os.path.exists(ASSIST_DATA_FILE) and not event.is_set():
|
||||
download_assistance()
|
||||
sm.update(0)
|
||||
if sm['deviceState'].networkType != log.DeviceState.NetworkType.none:
|
||||
download_assistance()
|
||||
event.wait(timeout=10)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user