openpilot v0.11.1 release

date: 2026-06-04T09:49:56
master commit: c0ab3550eca2e9daf197c46b7e4b24aa9637cf2e
This commit is contained in:
Vehicle Researcher
2026-06-04 09:50:05 -07:00
commit 6adb63b915
3381 changed files with 1044370 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
# Forward all openpilot service ports
while IFS=' ' read -r name port; do
adb forward "tcp:${port}" "tcp:${port}" > /dev/null
done < <(python3 - <<'PY'
from cereal.services import SERVICE_LIST
FNV_PRIME = 0x100000001b3
FNV_OFFSET_BASIS = 0xcbf29ce484222325
START_PORT = 8023
MAX_PORT = 65535
PORT_RANGE = MAX_PORT - START_PORT
MASK = 0xffffffffffffffff
def fnv1a(endpoint: str) -> int:
h = FNV_OFFSET_BASIS
for b in endpoint.encode():
h ^= b
h = (h * FNV_PRIME) & MASK
return h
ports = set()
for name in SERVICE_LIST.keys():
port = START_PORT + fnv1a(name) % PORT_RANGE
ports.add((name, port))
for name, port in sorted(ports):
print(f"{name} {port}")
PY
)
# 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 ${SSH_PORT} "$@"
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env python3
import argparse
import shlex
import subprocess
import threading
import time
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from openpilot.common.basedir import BASEDIR
def build_rsync_cmd(args) -> list[str]:
ssh = [
"ssh",
"-o", "ControlMaster=auto",
"-o", f"ControlPath=/tmp/devsync-{args.ip}.ctl",
"-o", "ControlPersist=10m",
"-o", "StrictHostKeyChecking=accept-new",
]
if args.identity:
ssh += ["-i", args.identity]
return [
"rsync", "-az",
"--files-from=-", "--from0",
"-e", " ".join(shlex.quote(p) for p in ssh),
"--out-format=%n",
BASEDIR + "/", f"comma@{args.ip}:{args.remote}/",
]
def git_tracked_files() -> bytes:
return subprocess.check_output(
["git", "-C", BASEDIR, "ls-files", "--recurse-submodules", "-z"]
)
class Handler(FileSystemEventHandler):
def __init__(self, sync_fn):
self.dirty = threading.Event()
self.sync_fn = sync_fn
def on_any_event(self, event):
if not event.is_directory:
self.dirty.set()
def run(self):
while True:
time.sleep(1)
if self.dirty.is_set():
self.dirty.clear()
self.sync_fn()
def main():
p = argparse.ArgumentParser()
p.add_argument("ip", help="device IP / hostname")
p.add_argument("--remote", default="/data/openpilot", help="remote path on device")
p.add_argument("-i", "--identity", default=None, help="ssh identity file")
args = p.parse_args()
print(f"[devsync] watching {BASEDIR}")
print(f"[devsync] target comma@{args.ip}:{args.remote}")
def run_sync():
file_list = git_tracked_files()
cmd = build_rsync_cmd(args)
t0 = time.monotonic()
r = subprocess.run(cmd, input=file_list, capture_output=True)
dt = time.monotonic() - t0
if r.returncode:
print(f"[devsync] ERR rc={r.returncode} in {dt:.2f}s")
return
files = [ln for ln in r.stdout.decode().splitlines() if ln.strip()]
msg = f"{len(files)} files: {', '.join(files)}" if files else "no changes"
print(f"[devsync] {dt:.2f}s · {msg}")
run_sync()
handler = Handler(run_sync)
obs = Observer()
obs.schedule(handler, BASEDIR, recursive=True)
obs.start()
handler.run()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[devsync] stopping")
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
import os
import sys
import wave
import argparse
import numpy as np
from openpilot.tools.lib.logreader import LogReader, ReadMode
def extract_audio(route_or_segment_name, output_file=None, play=False):
lr = LogReader(route_or_segment_name, default_mode=ReadMode.AUTO_INTERACTIVE)
audio_messages = list(lr.filter("rawAudioData"))
if not audio_messages:
print("No rawAudioData messages found in logs")
return
sample_rate = audio_messages[0].sampleRate
audio_chunks = []
total_frames = 0
for msg in audio_messages:
audio_array = np.frombuffer(msg.data, dtype=np.int16)
audio_chunks.append(audio_array)
total_frames += len(audio_array)
full_audio = np.concatenate(audio_chunks)
print(f"Found {total_frames} frames from {len(audio_messages)} audio messages at {sample_rate} Hz")
if output_file:
if write_wav_file(output_file, full_audio, sample_rate):
print(f"Audio written to {output_file}")
else:
print("Audio extraction canceled.")
if play:
play_audio(full_audio, sample_rate)
def write_wav_file(filename, audio_data, sample_rate):
if os.path.exists(filename):
if input(f"File '{filename}' exists. Overwrite? (y/N): ").lower() not in ['y', 'yes']:
return False
with wave.open(filename, 'wb') as wav_file:
wav_file.setnchannels(1) # Mono
wav_file.setsampwidth(2) # 16-bit
wav_file.setframerate(sample_rate)
wav_file.writeframes(audio_data.tobytes())
return True
def play_audio(audio_data, sample_rate):
try:
import sounddevice as sd
print("Playing audio... Press Ctrl+C to stop")
sd.play(audio_data, sample_rate)
sd.wait()
except KeyboardInterrupt:
print("\nPlayback stopped")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Extract audio data from openpilot logs")
parser.add_argument("-o", "--output", help="Output WAV file path")
parser.add_argument("--play", action="store_true", help="Play audio with sounddevice")
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name")
if len(sys.argv) == 1:
parser.print_help()
sys.exit()
args = parser.parse_args()
output_file = args.output
if not args.output and not args.play:
output_file = "extracted_audio.wav"
extract_audio(args.route_or_segment_name.strip(), output_file, args.play)
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
import sys
if len(sys.argv) < 4:
print(f"{sys.argv[0]} <route> <segment> <frame number> [front|wide|driver]")
print('example: ./fetch_image_from_route.py "02c45f73a2e5c6e9|2020-06-01--18-03-08" 3 500 driver')
exit(0)
cameras = {
"front": "cameras",
"wide": "ecameras",
"driver": "dcameras"
}
import requests
from PIL import Image
from openpilot.tools.lib.auth_config import get_token
from openpilot.tools.lib.framereader import FrameReader
jwt = get_token()
route = sys.argv[1]
segment = int(sys.argv[2])
frame = int(sys.argv[3])
camera = cameras[sys.argv[4]] if len(sys.argv) > 4 and sys.argv[4] in cameras else "cameras"
url = f'https://api.commadotai.com/v1/route/{route}/files'
r = requests.get(url, headers={"Authorization": f"JWT {jwt}"}, timeout=10)
assert r.status_code == 200
print("got api response")
segments = r.json()[camera]
if segment >= len(segments):
raise Exception(f"segment {segment} not found, got {len(segments)} segments")
fr = FrameReader(segments[segment])
if frame >= fr.frame_count:
raise Exception("frame {frame} not found, got {fr.frame_count} frames")
im = Image.fromarray(fr.get(frame))
fn = f"uxxx_{route.replace('|', '_')}_{segment}_{frame}.png"
im.save(fn)
print(f"saved {fn}")
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
import argparse
import os
import sys
from openpilot.common.basedir import BASEDIR
from openpilot.tools.lib.logreader import LogReader
os.environ['BASEDIR'] = BASEDIR
def get_arg_parser():
parser = argparse.ArgumentParser(
description="Unlogging and save to file",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("route", type=(lambda x: x.replace("#", "|")), nargs="?",
help="The route whose messages will be published.")
parser.add_argument("--out_path", nargs='?', default='/data/ubloxRaw.stream',
help="Output pickle file path")
return parser
def main():
args = get_arg_parser().parse_args(sys.argv[1:])
lr = LogReader(args.route)
with open(args.out_path, 'wb') as f:
try:
done = False
i = 0
while not done:
msg = next(lr)
if not msg:
break
smsg = msg.as_builder()
typ = smsg.which()
if typ == 'ubloxRaw':
f.write(smsg.to_bytes())
i += 1
except StopIteration:
print('All done')
print(f'Writed {i} msgs')
if __name__ == "__main__":
main()
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
while true; do
if ls /dev/serial/by-id/usb-FTDI_FT230X* 2> /dev/null; then
sudo screen /dev/serial/by-id/usb-FTDI_FT230X* 115200
fi
sleep 0.005
done
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
import requests
from openpilot.common.params import Params
import sys
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"{sys.argv[0]} <github username>")
exit(1)
username = sys.argv[1]
keys = requests.get(f"https://github.com/{username}.keys", timeout=10)
if keys.status_code == 200:
params = Params()
params.put_bool("SshEnabled", True, block=True)
params.put("GithubSshKeys", keys.text, block=True)
params.put("GithubUsername", username, block=True)
print("Set up ssh keys successfully")
else:
print("Error getting public keys from github")
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import os
import sys
import argparse
import re
from openpilot.common.basedir import BASEDIR
from openpilot.tools.lib.auth_config import get_token
from openpilot.tools.lib.api import CommaApi
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="A helper for connecting to devices over the comma prime SSH proxy.\
Adding your SSH key to your SSH config is recommended for more convenient use; see https://docs.comma.ai/how-to/connect-to-comma/.")
parser.add_argument("device", help="device name or dongle id")
parser.add_argument("--host", help="ssh jump server host", default="ssh.comma.ai")
parser.add_argument("--port", help="ssh jump server port", default=22, type=int)
parser.add_argument("--key", help="ssh key", default=os.path.join(BASEDIR, "system/hardware/tici/id_rsa"))
parser.add_argument("--debug", help="enable debug output", action="store_true")
args = parser.parse_args()
r = CommaApi(get_token()).get("v1/me/devices")
devices = {x['dongle_id']: x['alias'] for x in r}
if not re.match("[0-9a-zA-Z]{16}", args.device):
user_input = args.device.replace(" ", "").lower()
matches = { k: v for k, v in devices.items() if isinstance(v, str) and user_input in v.replace(" ", "").lower() }
if len(matches) == 1:
dongle_id = list(matches.keys())[0]
else:
print(f"failed to look up dongle id for \"{args.device}\"", file=sys.stderr)
if len(matches) > 1:
print("found multiple matches:", file=sys.stderr)
for k, v in matches.items():
print(f" \"{v}\" ({k})", file=sys.stderr)
exit(1)
else:
dongle_id = args.device
name = dongle_id
if dongle_id in devices:
name = f"{devices[dongle_id]} ({dongle_id})"
print(f"connecting to {name} through {args.host}:{args.port} ...")
command = [
"ssh",
"-i", args.key,
"-o", f"ProxyCommand=ssh -i {args.key} -W %h:%p -p %p %h@{args.host}",
"-p", str(args.port),
]
if args.debug:
command += ["-v"]
command += [
f"comma@comma-{dongle_id}",
]
if args.debug:
print(" ".join([f"'{c}'" if " " in c else c for c in command]))
os.execvp(command[0], command)