Merge branch 'upstream/openpilot/master' into sync-20260317

# Conflicts:
#	.github/workflows/auto_pr_review.yaml
#	.gitignore
#	opendbc_repo
#	panda
#	selfdrive/ui/mici/layouts/home.py
#	selfdrive/ui/mici/layouts/onboarding.py
#	selfdrive/ui/mici/layouts/settings/device.py
#	selfdrive/ui/tests/diff/replay.py
#	selfdrive/ui/translations/app_fr.po
#	system/ui/mici_setup.py
Sync: `commaai/opendbc:master` → `sunnypilot/opendbc:master`
Sync: `commaai/panda:master` → `sunnypilot/panda:master`
This commit is contained in:
Jason Wen
2026-03-17 17:11:48 -04:00
162 changed files with 5452 additions and 7254 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ scons -u -j$(nproc)
Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-24.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment. See [these instructions](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) for running GUI apps.
**NOTE**: If you are running WSL and any GUIs are failing (segfaulting or other strange issues) even after following the steps above, you may need to enable software rendering with `LIBGL_ALWAYS_SOFTWARE=1`, e.g. `LIBGL_ALWAYS_SOFTWARE=1 selfdrive/ui/ui`.
**NOTE**: If you are running WSL 2 and experiencing performance issues with the UI or simulator, you may need to explicitly enable hardware acceleration by setting `GALLIUM_DRIVER=d3d12` before commands. Add `export GALLIUM_DRIVER=d3d12` to your `~/.bashrc` file to make it automatic for future sessions.
## CTF
Learn about the openpilot ecosystem and tools by playing our [CTF](/tools/CTF.md).
-4
View File
@@ -1,4 +0,0 @@
av
av-10.0.0/*
key.pem
cert.pem
+2
View File
@@ -1,6 +1,8 @@
moc_*
*.moc
assets.cc
_cabana
dbc/car_fingerprint_to_dbc.json
tests/test_cabana
+15 -13
View File
@@ -2,6 +2,8 @@ import subprocess
import os
import shutil
import libusb
Import('env', 'arch', 'common', 'messaging', 'visionipc', 'cereal')
# Detect Qt - skip build if not available
@@ -64,21 +66,18 @@ qt_env['LIBPATH'] += ['#selfdrive/ui', ]
qt_env['LIBS'] = qt_libs
base_frameworks = qt_env['FRAMEWORKS']
base_libs = [common, messaging, cereal, visionipc, 'm', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]
base_libs = [common, messaging, cereal, visionipc, 'm', 'pthread'] + qt_env["LIBS"]
if arch == "Darwin":
base_frameworks.append('QtCharts')
else:
base_libs.append('Qt5Charts')
qt_libs = base_libs
cabana_env = qt_env.Clone()
if arch == "Darwin":
cabana_env['CPPPATH'] += [f"{brew_prefix}/include"]
cabana_env['LIBPATH'] += [f"{brew_prefix}/lib"]
cabana_env['CPPPATH'] += [libusb.INCLUDE_DIR]
cabana_env['LIBPATH'] += [libusb.LIB_DIR]
cabana_libs = [cereal, messaging, visionipc, replay_lib, 'avformat', 'avcodec', 'swresample', 'avutil', 'x264', 'z', 'bz2', 'zstd', 'yuv', 'usb-1.0'] + qt_libs
cabana_libs = [cereal, messaging, visionipc, replay_lib, 'avformat', 'avcodec', 'swresample', 'avutil', 'x264', 'z', 'bz2', 'zstd', 'yuv', 'usb-1.0'] + base_libs
opendbc_path = '-DOPENDBC_FILE_PATH=\'"%s"\'' % (cabana_env.Dir("../../opendbc/dbc").abspath)
cabana_env['CXXFLAGS'] += [opendbc_path]
@@ -88,12 +87,15 @@ assets_src = "assets/assets.qrc"
cabana_env.Command(assets, assets_src, f"rcc $SOURCES -o $TARGET")
cabana_env.Depends(assets, Glob('/assets/*', exclude=[assets, assets_src, "assets/assets.o"]))
cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/socketcanstream.cc', 'streams/pandastream.cc', 'streams/devicestream.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc',
'streams/routes.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc',
'utils/export.cc', 'utils/util.cc', 'utils/elidedlabel.cc',
'chart/chartswidget.cc', 'chart/chart.cc', 'chart/signalselector.cc', 'chart/tiplabel.cc', 'chart/sparkline.cc',
'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', 'panda.cc',
'cameraview.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc', 'tools/routeinfo.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
cabana_srcs = ['mainwin.cc', 'streams/pandastream.cc', 'streams/devicestream.cc', 'streams/livestream.cc', 'streams/abstractstream.cc', 'streams/replaystream.cc', 'binaryview.cc', 'historylog.cc', 'videowidget.cc', 'signalview.cc',
'streams/routes.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc',
'utils/export.cc', 'utils/util.cc', 'utils/elidedlabel.cc',
'chart/chartswidget.cc', 'chart/chart.cc', 'chart/signalselector.cc', 'chart/tiplabel.cc', 'chart/sparkline.cc',
'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', 'panda.cc',
'cameraview.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc', 'tools/routeinfo.cc']
if arch != "Darwin":
cabana_srcs += ['streams/socketcanstream.cc']
cabana_lib = cabana_env.Library("cabana_lib", cabana_srcs, LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
cabana_env.Program('_cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks)
if GetOption('extras'):
-1
View File
@@ -1 +0,0 @@
*.cc
+6
View File
@@ -5,7 +5,9 @@
#include "tools/cabana/streams/devicestream.h"
#include "tools/cabana/streams/pandastream.h"
#include "tools/cabana/streams/replaystream.h"
#ifdef __linux__
#include "tools/cabana/streams/socketcanstream.h"
#endif
int main(int argc, char *argv[]) {
QCoreApplication::setApplicationName("Cabana");
@@ -29,9 +31,11 @@ int main(int argc, char *argv[]) {
cmd_parser.addOption({"msgq", "read can messages from the msgq"});
cmd_parser.addOption({"panda", "read can messages from panda"});
cmd_parser.addOption({"panda-serial", "read can messages from panda with given serial", "panda-serial"});
#ifdef __linux__
if (SocketCanStream::available()) {
cmd_parser.addOption({"socketcan", "read can messages from given SocketCAN device", "socketcan"});
}
#endif
cmd_parser.addOption({"zmq", "read can messages from zmq at the specified ip-address", "ip-address"});
cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"});
cmd_parser.addOption({"no-vipc", "do not output video"});
@@ -51,8 +55,10 @@ int main(int argc, char *argv[]) {
qWarning() << e.what();
return 0;
}
#ifdef __linux__
} else if (SocketCanStream::available() && cmd_parser.isSet("socketcan")) {
stream = new SocketCanStream(&app, {.device = cmd_parser.value("socketcan").toStdString()});
#endif
} else {
uint32_t replay_flags = REPLAY_FLAG_NONE;
if (cmd_parser.isSet("ecam")) replay_flags |= REPLAY_FLAG_ECAM;
+4 -1
View File
@@ -4,11 +4,12 @@
#include <QLabel>
#include <QPushButton>
#include "streams/socketcanstream.h"
#include "tools/cabana/streams/devicestream.h"
#include "tools/cabana/streams/pandastream.h"
#include "tools/cabana/streams/replaystream.h"
#ifdef __linux__
#include "tools/cabana/streams/socketcanstream.h"
#endif
StreamSelector::StreamSelector(QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Open stream"));
@@ -35,9 +36,11 @@ StreamSelector::StreamSelector(QWidget *parent) : QDialog(parent) {
addStreamWidget(new OpenReplayWidget, tr("&Replay"));
addStreamWidget(new OpenPandaWidget, tr("&Panda"));
#ifdef __linux__
if (SocketCanStream::available()) {
addStreamWidget(new OpenSocketCanWidget, tr("&SocketCAN"));
}
#endif
addStreamWidget(new OpenDeviceWidget, tr("&Device"));
QObject::connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
+8 -5
View File
@@ -63,8 +63,10 @@ def parse_args():
return args
def setup_env(output_path: str, big: bool = False, speed: int = 1, target_mb: float = 0, duration: int = 0):
os.environ.update({"RECORD": "1", "OFFSCREEN": "1", "RECORD_OUTPUT": str(Path(output_path).with_suffix(".mp4"))})
def setup_env(output_path: str, big: bool = False, speed: int = 1, target_mb: float = 0, duration: int = 0, headless: bool = True):
os.environ.update({"RECORD": "1", "RECORD_OUTPUT": str(Path(output_path).with_suffix(".mp4"))})
if headless:
os.environ["OFFSCREEN"] = "1"
if speed > 1:
os.environ["RECORD_SPEED"] = str(speed)
if target_mb > 0 and duration > 0:
@@ -302,11 +304,11 @@ def clip(route: Route, output: str, start: int, end: int, headless: bool = True,
logger.error("No messages to render")
sys.exit(1)
metadata = load_route_metadata(route) if show_metadata else None
if headless:
rl.set_config_flags(rl.ConfigFlags.FLAG_WINDOW_HIDDEN)
with OpenpilotPrefix(shared_download_cache=True):
metadata = load_route_metadata(route) if show_metadata else None
camera_paths = route.qcamera_paths() if use_qcam else route.camera_paths()
frame_queue = FrameQueue(camera_paths, start, end, fps=FRAMERATE, use_qcam=use_qcam)
@@ -349,8 +351,9 @@ def main():
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s\t%(message)s")
args = parse_args()
setup_env(args.output, big=args.big, speed=args.speed, target_mb=args.file_size, duration=args.end - args.start)
clip(Route(args.route, data_dir=args.data_dir), args.output, args.start, args.end, not args.windowed,
headless = not args.windowed
setup_env(args.output, big=args.big, speed=args.speed, target_mb=args.file_size, duration=args.end - args.start, headless=headless)
clip(Route(args.route, data_dir=args.data_dir), args.output, args.start, args.end, headless,
args.big, args.title, not args.no_metadata, not args.no_time_overlay, args.qcam)
+1 -26
View File
@@ -167,29 +167,6 @@ function op_check_os() {
fi
}
function op_check_python() {
echo "Checking for compatible python version..."
REQUIRED_PYTHON_VERSION=$(grep "requires-python" $OPENPILOT_ROOT/pyproject.toml)
INSTALLED_PYTHON_VERSION=$(python3 --version 2> /dev/null || true)
if [[ -z $INSTALLED_PYTHON_VERSION ]]; then
echo -e " ↳ [${RED}✗${NC}] python3 not found on your system. You need python version satisfying $(echo $REQUIRED_PYTHON_VERSION | cut -d '=' -f2-) to continue!"
loge "ERROR_PYTHON_NOT_FOUND"
return 1
else
LB=$(echo $REQUIRED_PYTHON_VERSION | tr -d '",' | awk '{ split($4, v, "."); printf "%d%02d%02d", v[1], v[2], v[3] }')
UB=$(echo $REQUIRED_PYTHON_VERSION | tr -d '",' | awk '{ split($6, v, "."); printf "%d%02d%02d", v[1], v[2], v[3] }')
VERSION=$(echo $INSTALLED_PYTHON_VERSION | awk '{ split($2, v, "."); printf "%d%02d%02d", v[1], v[2], v[3] }')
if [[ $VERSION -ge LB && $VERSION -lt UB ]]; then
echo -e " ↳ [${GREEN}✔${NC}] $INSTALLED_PYTHON_VERSION detected."
else
echo -e " ↳ [${RED}✗${NC}] You need a python version satisfying $(echo $REQUIRED_PYTHON_VERSION | cut -d '=' -f2-) to continue!"
loge "ERROR_PYTHON_VERSION" "$INSTALLED_PYTHON_VERSION"
return 1
fi
fi
}
function op_check_venv() {
echo "Checking for venv..."
if [[ -f $OPENPILOT_ROOT/.venv/bin/activate ]]; then
@@ -214,8 +191,6 @@ function op_before_cmd() {
op_activate_venv
result="${result}\n$(( op_check_python ) 2>&1)" || (echo -e "$result" && return 1)
if [[ -z $VERBOSE ]]; then
echo -e "${BOLD}Checking system →${NC} [${GREEN}✔${NC}]"
else
@@ -436,7 +411,7 @@ function op_default() {
echo ""
echo -e "${BOLD}${UNDERLINE}Commands [System]:${NC}"
echo -e " ${BOLD}auth${NC} Authenticate yourself for API use"
echo -e " ${BOLD}check${NC} Check the development environment (git, os, python) to start using openpilot"
echo -e " ${BOLD}check${NC} Check the development environment (git, os) to start using openpilot"
echo -e " ${BOLD}esim${NC} Manage eSIM profiles on your comma device"
echo -e " ${BOLD}venv${NC} Activate the python virtual environment"
echo -e " ${BOLD}setup${NC} Install openpilot dependencies"
-3
View File
@@ -1,3 +0,0 @@
bin/
bin
*.rlog
-3
View File
@@ -1,5 +1,2 @@
moc_*
*.moc
replay
tests/test_replay
+1 -1
View File
@@ -4,7 +4,7 @@ replay_env = env.Clone()
replay_env['CCFLAGS'] += ['-Wno-deprecated-declarations']
base_frameworks = []
base_libs = [common, messaging, cereal, visionipc, 'm', 'ssl', 'crypto', 'pthread']
base_libs = [common, messaging, cereal, visionipc, 'm', 'pthread']
replay_lib_src = ["replay.cc", "consoleui.cc", "camera.cc", "filereader.cc", "logreader.cc", "framereader.cc",
"route.cc", "util.cc", "seg_mgr.cc", "timeline.cc", "py_downloader.cc"]
+4 -4
View File
@@ -218,7 +218,7 @@ def ui_thread(addr):
# Update camera texture from numpy array
img_rgba = cv2.cvtColor(img, cv2.COLOR_RGB2RGBA)
rl.update_texture(camera_texture, rl.ffi.cast("void *", img_rgba.ctypes.data))
rl.draw_texture(camera_texture, 0, 0, rl.WHITE)
rl.draw_texture(camera_texture, 0, 0, rl.WHITE) # noqa: TID251
# display alerts
rl.draw_text_ex(font, sm['selfdriveState'].alertText1, rl.Vector2(180, 150), 30, 0, rl.RED)
@@ -227,15 +227,15 @@ def ui_thread(addr):
# draw plots (texture is reused internally)
plot_texture = draw_plots(plot_arr)
if hor_mode:
rl.draw_texture(plot_texture, 640 + 384, 0, rl.WHITE)
rl.draw_texture(plot_texture, 640 + 384, 0, rl.WHITE) # noqa: TID251
else:
rl.draw_texture(plot_texture, 0, 600, rl.WHITE)
rl.draw_texture(plot_texture, 0, 600, rl.WHITE) # noqa: TID251
# Convert lid_overlay to RGBA and update top_down texture
# lid_overlay is (384, 960), need to transpose to (960, 384) for row-major RGBA buffer
lid_rgba = palette[lid_overlay.T]
rl.update_texture(top_down_texture, rl.ffi.cast("void *", np.ascontiguousarray(lid_rgba).ctypes.data))
rl.draw_texture(top_down_texture, 640, 0, rl.WHITE)
rl.draw_texture(top_down_texture, 640, 0, rl.WHITE) # noqa: TID251
SPACING = 25
lines = [
-10
View File
@@ -1,7 +1,6 @@
#include "tools/replay/util.h"
#include <bzlib.h>
#include <openssl/sha.h>
#include <cassert>
#include <cstdarg>
@@ -162,15 +161,6 @@ void precise_nano_sleep(int64_t nanoseconds, std::atomic<bool> &interrupt_reques
}
}
std::string sha256(const std::string &str) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
return util::hexdump(hash, SHA256_DIGEST_LENGTH);
}
std::vector<std::string> split(std::string_view source, char delimiter) {
std::vector<std::string> fields;
size_t last = 0;
-1
View File
@@ -46,7 +46,6 @@ private:
static constexpr float growth_factor = 1.5;
};
std::string sha256(const std::string &str);
void precise_nano_sleep(int64_t nanoseconds, std::atomic<bool> &interrupt_requested);
std::string decompressBZ2(const std::string &in, std::atomic<bool> *abort = nullptr);
std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic<bool> *abort = nullptr);
+7 -3
View File
@@ -31,8 +31,12 @@ for name, port in sorted(ports):
PY
)
# Forward SSH port first for interactive shell access.
adb forward tcp:2222 tcp:22
# Forward SSH port, finding a free local port if 2222 is taken.
SSH_PORT=2222
while ss -tln | grep -q ":${SSH_PORT} "; do
SSH_PORT=$((SSH_PORT + 1))
done
adb forward tcp:${SSH_PORT} tcp:22
# SSH!
ssh comma@localhost -p 2222 "$@"
ssh comma@localhost -p ${SSH_PORT} "$@"
-12
View File
@@ -113,24 +113,12 @@ function install_python_deps() {
source .venv/bin/activate
}
function install_macos_deps() {
if ! command -v brew > /dev/null 2>&1; then
echo "homebrew not found, skipping macOS system dependency install"
return 0
fi
if ! command -v cmake > /dev/null 2>&1; then
brew install cmake
fi
}
# --- Main ---
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
install_ubuntu_deps
echo "[ ] installed system dependencies t=$SECONDS"
elif [[ "$OSTYPE" == "darwin"* ]]; then
install_macos_deps
if [[ $SHELL == "/bin/zsh" ]]; then
RC_FILE="$HOME/.zshrc"
elif [[ $SHELL == "/bin/bash" ]]; then
@@ -13,11 +13,9 @@ class CopyRamRGBCamera(RGBCamera):
def get_rgb_array_cpu(self):
origin_img = self.cpu_texture
img = np.frombuffer(origin_img.getRamImage().getData(), dtype=np.uint8)
img = img.reshape((origin_img.getYSize(), origin_img.getXSize(), -1))
img = img[:,:,:3] # RGBA to RGB
# img = np.swapaxes(img, 1, 0)
img = img[::-1] # Flip on vertical axis
img = np.frombuffer(origin_img.getRamImageAs("RGB").getData(), dtype=np.uint8)
img = img.reshape((origin_img.getYSize(), origin_img.getXSize(), 3))
img = img[::-1] # Flip on vertical axis
return img