Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77c8172167 | |||
| cbc88b461d | |||
| 209db8f320 | |||
| 8069b6611d |
-19
@@ -1,19 +0,0 @@
|
||||
---
|
||||
Checks: '
|
||||
bugprone-*,
|
||||
-bugprone-integer-division,
|
||||
-bugprone-narrowing-conversions,
|
||||
performance-*,
|
||||
clang-analyzer-*,
|
||||
misc-*,
|
||||
-misc-unused-parameters,
|
||||
modernize-*,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-deprecated-headers,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-using,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-trailing-return-type,
|
||||
'
|
||||
CheckOptions:
|
||||
...
|
||||
@@ -13,27 +13,6 @@
|
||||
*.o-*
|
||||
*.os
|
||||
*.os-*
|
||||
*.so
|
||||
*.a
|
||||
|
||||
venv/
|
||||
.venv/
|
||||
|
||||
notebooks
|
||||
phone
|
||||
massivemap
|
||||
neos
|
||||
installer
|
||||
chffr/app2
|
||||
chffr/backend/env
|
||||
selfdrive/nav
|
||||
selfdrive/baseui
|
||||
selfdrive/test/simulator2
|
||||
**/cache_data
|
||||
xx/plus
|
||||
xx/community
|
||||
xx/projects
|
||||
!xx/projects/eon_testing_master
|
||||
!xx/projects/map3d
|
||||
xx/ops
|
||||
xx/junk
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.py, *.pyx, *.pxd}]
|
||||
[*.{py,pyx,pxd}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
CI / testing:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: "{.github/**,**/test_*,Jenkinsfile}"
|
||||
- any-glob-to-all-files: "{.github/**,**/test_*,**/test/**,Jenkinsfile}"
|
||||
|
||||
car:
|
||||
- changed-files:
|
||||
@@ -12,7 +12,7 @@ simulation:
|
||||
|
||||
ui:
|
||||
- changed-files:
|
||||
- any-glob-to-all-files: 'selfdrive/ui/**'
|
||||
- any-glob-to-all-files: '{selfdrive/assets/**,selfdrive/ui/**,system/ui/**}'
|
||||
|
||||
tools:
|
||||
- changed-files:
|
||||
|
||||
+22
-38
@@ -7,18 +7,20 @@ venv/
|
||||
.tags
|
||||
.ipynb_checkpoints
|
||||
.idea
|
||||
*.iml
|
||||
.overlay_init
|
||||
.overlay_consistent
|
||||
.sconsign.dblite
|
||||
model2.png
|
||||
a.out
|
||||
.hypothesis
|
||||
.cache/
|
||||
bin/
|
||||
|
||||
/docs_site/
|
||||
|
||||
*.mp4
|
||||
*.dylib
|
||||
*.DSYM
|
||||
*.d
|
||||
*.pem
|
||||
*.pyc
|
||||
*.pyo
|
||||
.*.swp
|
||||
@@ -35,72 +37,54 @@ a.out
|
||||
*.class
|
||||
*.pyxbldc
|
||||
*.vcd
|
||||
*.qm
|
||||
*.mo
|
||||
*_pyx.cpp
|
||||
*.stats
|
||||
*.pkl
|
||||
*.pkl*
|
||||
config.json
|
||||
clcache
|
||||
compile_commands.json
|
||||
compare_runtime*.html
|
||||
selfdrive/modeld/models/tg_compiled_flags.json
|
||||
|
||||
persist
|
||||
# build artifacts
|
||||
selfdrive/pandad/pandad
|
||||
cereal/services.h
|
||||
cereal/gen
|
||||
cereal/messaging/bridge
|
||||
selfdrive/logcatd/logcatd
|
||||
selfdrive/mapd/default_speeds_by_region.json
|
||||
system/proclogd/proclogd
|
||||
selfdrive/ui/translations/alerts_generated.h
|
||||
selfdrive/ui/translations/tmp
|
||||
selfdrive/test/longitudinal_maneuvers/out
|
||||
selfdrive/car/tests/cars_dump
|
||||
system/camerad/camerad
|
||||
system/camerad/test/ae_gray_test
|
||||
|
||||
notebooks
|
||||
hyperthneed
|
||||
provisioning
|
||||
|
||||
.coverage*
|
||||
coverage.xml
|
||||
htmlcov
|
||||
pandaextra
|
||||
|
||||
.mypy_cache/
|
||||
flycheck_*
|
||||
|
||||
cppcheck_report.txt
|
||||
comma*.sh
|
||||
|
||||
selfdrive/modeld/thneed/compile
|
||||
selfdrive/modeld/models/*.thneed
|
||||
selfdrive/modeld/models/*.pkl
|
||||
|
||||
# openpilot log files
|
||||
*.bz2
|
||||
*.zst
|
||||
*.rlog
|
||||
|
||||
build/
|
||||
|
||||
!**/.gitkeep
|
||||
|
||||
poetry.toml
|
||||
Pipfile
|
||||
|
||||
### VisualStudioCode ###
|
||||
*.vsix
|
||||
.history
|
||||
.ionide
|
||||
.vscode/*
|
||||
.history/
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
# agents
|
||||
.claude/
|
||||
.context/
|
||||
PLAN.md
|
||||
TASK.md
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
3.12.13
|
||||
Vendored
+43
-1
@@ -23,6 +23,11 @@
|
||||
"id": "args",
|
||||
"description": "Arguments to pass to the process",
|
||||
"type": "promptString"
|
||||
},
|
||||
{
|
||||
"id": "replayArg",
|
||||
"type": "promptString",
|
||||
"description": "Enter route or segment to replay."
|
||||
}
|
||||
],
|
||||
"configurations": [
|
||||
@@ -40,7 +45,44 @@
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/${input:cpp_process}",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Attach LLDB to Replay drive",
|
||||
"type": "lldb",
|
||||
"request": "attach",
|
||||
"pid": "${command:pickMyProcess}",
|
||||
"sourceMap": {
|
||||
".": "${workspaceFolder}/opendbc/safety"
|
||||
},
|
||||
"initCommands": [
|
||||
"script import time; time.sleep(3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Replay drive",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/opendbc/safety/tests/safety_replay/replay_drive.py",
|
||||
"args": [
|
||||
"${input:replayArg}"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
"env": {
|
||||
"PYTHONPATH": "${workspaceFolder}"
|
||||
},
|
||||
"subProcess": true,
|
||||
"stopOnEntry": false
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Replay drive + Safety LLDB",
|
||||
"configurations": [
|
||||
"Replay drive",
|
||||
"Attach LLDB to Replay drive"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/bin/env sh
|
||||
|
||||
persist_dir=/persist
|
||||
target_dir=${persist_dir}/comma
|
||||
# Change target dir from sunnylink to comma to make this no longer a test
|
||||
|
||||
|
||||
# Function to remount /persist as read-only
|
||||
cleanup() {
|
||||
echo "Remounting ${persist_dir} as read-only..."
|
||||
sudo mount -o remount,ro ${persist_dir}
|
||||
}
|
||||
|
||||
# Function to check and backup existing keys
|
||||
backup_keys() {
|
||||
if [ -f "id_rsa" ] || [ -f "id_rsa.pub" ]; then
|
||||
timestamp=$(date +%s)
|
||||
backup_base="id_rsa_backup_$timestamp"
|
||||
backup_private="$backup_base"
|
||||
backup_public="${backup_base}.pub"
|
||||
|
||||
# Ensure we're not overwriting an existing backup
|
||||
counter=0
|
||||
while [ -f "$backup_private" ] || [ -f "$backup_public" ]; do
|
||||
counter=$((counter + 1))
|
||||
backup_private="${backup_base}_$counter"
|
||||
backup_public="${backup_base}_$counter.pub"
|
||||
done
|
||||
|
||||
# Backup the keys
|
||||
cp id_rsa "$backup_private"
|
||||
cp id_rsa.pub "$backup_public"
|
||||
|
||||
# Verify the backup
|
||||
original_private_hash=$(sha256sum id_rsa | cut -d ' ' -f 1)
|
||||
backup_private_hash=$(sha256sum "$backup_private" | cut -d ' ' -f 1)
|
||||
original_public_hash=$(sha256sum id_rsa.pub | cut -d ' ' -f 1)
|
||||
backup_public_hash=$(sha256sum "$backup_public" | cut -d ' ' -f 1)
|
||||
|
||||
if [ "$original_private_hash" = "$backup_private_hash" ] && [ "$original_public_hash" = "$backup_public_hash" ]; then
|
||||
echo "Backup verified successfully."
|
||||
# Safe to delete original keys after successful backup verification
|
||||
else
|
||||
echo "Backup verification failed. Aborting operation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Existing keys backed up as $backup_private and $backup_public"
|
||||
fi
|
||||
}
|
||||
|
||||
# Trap any signal that exits the script to run cleanup function
|
||||
trap cleanup EXIT
|
||||
|
||||
# Remount /persist as read-write
|
||||
sudo mount -o remount,rw ${persist_dir}
|
||||
|
||||
# Ensure the directory exists
|
||||
mkdir -p ${target_dir}
|
||||
cd ${target_dir}
|
||||
|
||||
# Check for and backup existing keys
|
||||
#backup_keys
|
||||
|
||||
# Generate new keys
|
||||
if ! ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa -N ''; then
|
||||
echo "Failed to generate new RSA keys. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert the generated SSH public key to PEM format and store it temporarily
|
||||
if ! openssl rsa -pubout -in id_rsa -out id_rsa.pub -outform PEM; then
|
||||
echo "Failed to convert the public key to PEM format. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display the public key
|
||||
echo "Displaying the public key:"
|
||||
cat id_rsa.pub
|
||||
|
||||
# Cleanup will be called automatically due to trap on EXIT
|
||||
#echo "Operation completed successfully. System will reboot now."
|
||||
#sudo reboot
|
||||
@@ -0,0 +1,98 @@
|
||||
# TSK Manager
|
||||
|
||||
## Background
|
||||
|
||||
### The Problem
|
||||
|
||||
comma.ai makes DIY ADAS devices. Older devices include the comma eon; current ones are comma three (C3, aka tici), comma threeX (C3X, aka tizi), and comma four (C4, aka mici). comma discontinued support for C3.
|
||||
|
||||
Not all cars work with comma. Some use FlexRay (e.g. BMW) instead of CAN/CAN-FD. Toyota added cryptographic signatures to CAN messages — comma can still read the bus but can't write because it can't generate valid signatures.
|
||||
|
||||
### The Hack
|
||||
|
||||
Willem, an ex-comma.ai employee, found a way to extract the security key from the EPS firmware on 2021-23 RAV4 Prime. The same hack works unmodified on 2021-23 Sienna Hybrid, and with modifications on Yaris. Details are in `/Users/calvin/GitRepos/docs/README.md`.
|
||||
|
||||
Willem's hack was a Python script run over SSH. Calvin built a GUI around it — that's TSK Manager (TSKM), living in `tsk/` in this repo.
|
||||
|
||||
### Calvin's Cars
|
||||
|
||||
- 2023 Sienna Hybrid — C3X
|
||||
- 2023 Bolt EV 2LT (no ACC) — C4
|
||||
|
||||
### Architecture
|
||||
|
||||
- `tsk/main.py` dispatches based on device type (C3X vs C4)
|
||||
- `tsk/c3/` — C3X code (maintenance mode, 1920x1080)
|
||||
- `tsk/c4/` — C4 code (active development, 536x240)
|
||||
- `tsk/common/` — shared code (extractor, key file manager, widget base)
|
||||
- Run with `./c3x` or `./c4`; requires .venv
|
||||
|
||||
### The Rebasing Problem
|
||||
|
||||
comma devices use vertical phone LCD screens (C3/C3X are 1920x1080 portrait). comma wrote their own GUI libs to draw on the rotated screen — there's no way to use the display without going through their libs. They replaced Qt with RayLib, and rewrite these GUI libs constantly with zero backwards compatibility. TSKM has been rewritten 3+ times to keep up.
|
||||
|
||||
TSKM rebases on `nightly-dev` to stay current with AGNOS (the device OS). This is necessary because:
|
||||
|
||||
- AGNOS updates are ~1GB and take ~10 minutes
|
||||
- The key extraction process is already stressful for users (removing camera housing, running the extractor, hoping the car still drives)
|
||||
- Adding an AGNOS update mid-process is a terrible experience
|
||||
- Some users have poor connectivity (rural US)
|
||||
|
||||
The goal: user installs the TSKM branch at home, AGNOS updates while on Wi-Fi, then they drive to do the extraction with everything already current.
|
||||
|
||||
SunnyPilot's SunnyLink integration is a potential long-term path to avoid the rebasing entirely.
|
||||
|
||||
### SSH / Device Tips
|
||||
|
||||
- tmux detach on comma devices: backtick (`` ` ``) then `d`
|
||||
|
||||
### comma Release Branches
|
||||
|
||||
Each device family has its own release branch:
|
||||
|
||||
- C3X (tizi): `release-tizi`
|
||||
- C4 (mici): `release-mici`
|
||||
- C3 (tici): `release-tici` (no longer supported)
|
||||
- `release3` is an older legacy device-agnostic branch
|
||||
|
||||
### Versioned Branches
|
||||
|
||||
Each release is tagged as a branch (e.g. `tskm-0.10.4`, `tskm-0.10.2`, `tskm-0.9.8`). These were meant to be frozen fallbacks, but comma's changes can break even old branches.
|
||||
|
||||
---
|
||||
|
||||
## Journal
|
||||
|
||||
When the user says "update the journal", write a summary of what was done in the current session into the journal below.
|
||||
|
||||
### 2025-11-15
|
||||
Released TSK Manager v0.10.4 (latest commit on `tskm` branch).
|
||||
|
||||
### 2026-04-09
|
||||
Current status: **fixed and verified end-to-end in car**.
|
||||
- Latest `tskm` branch had a Panda error; older `tskm-0.10.2` also broken (three stripes black/gray/white screen).
|
||||
- Diagnosed: `RuntimeError: CAN packet version mismatch` — the panda firmware is stale because TSKM kills boardd/pandad before they can flash it. The panda's `can_version` (firmware) doesn't match `CAN_PACKET_VERSION` (library). Different tskm versions show different library values: older tskm hardcoded `4`, current tskm uses `compute_version_hash()` which produces `1974202998`.
|
||||
- Fix: added `panda.flash()` to `TSKExtractor.hack()` right after `panda = Panda()` in `tsk/common/extractor.py`. The `up_to_date()` guard makes it safe to call every run (no-ops in 0.0s if current). C3X uses the same `tsk.common.extractor`, so the fix covers both devices.
|
||||
- Flash takes ~2.8s, no network required (firmware bundled locally). Reversible — when user installs nightly-dev/sunnypilot afterwards, pandad's signature check will reflash to that branch's version.
|
||||
- End-to-end test passed: install release3 → panda flashed to release3 firmware (`can_version=4`) → install pre-fix tskm → got mismatch error as expected → install post-fix tskm → `panda.flash()` ran, extractor proceeded all the way to writing SecOC key to `/data/params/d/SecOCKey`.
|
||||
- Bonus fix: `launch_chffrplus.sh` had an active `bash # Debug` line between `python3 tsk/main.py` and `sudo reboot`, which left the device in a debug shell after the user clicked "Install nightly-dev" instead of auto-rebooting. Commented it out so the install→reboot flow works end-to-end.
|
||||
|
||||
### 2026-04-10
|
||||
Two users reported successful key extraction using `calvinpark/tskm` — fix confirmed in the wild. Plan: squash the tskm branch to a single commit and push to `optskug/tskm` to ship it.
|
||||
|
||||
### 2026-04-15
|
||||
Third user hit the same `can_version=0, library v1974202998` error after the 2026-04-09 fix shipped to `optskug/tskm`. Root-cause investigation revealed a harder failure mode.
|
||||
|
||||
**What happened**: The user's device had `DEV-18392c3e-RELEASE` firmware. `panda.flash()` ran without error — but the firmware string and `up_to_date: False` were identical before and after. The SPI bulk writes were accepted without error but didn't persist. Immediately re-checking showed the same DEV firmware.
|
||||
|
||||
**Why bare `panda.flash()` worked before but not here**: Previous users' firmware was overwritable via SPI. This device's DEV firmware resists SPI writes — possibly flash write protection, a hardware difference, or something specific to DEV builds. We can't prove it from the outside. What we know: the same scenario is exactly what pandad handles with its GPIO recovery path.
|
||||
|
||||
**How the user was unblocked**: Installed `commaai/nightly-dev` on the device, which let pandad run and flash panda successfully via its full recovery sequence (GPIO BOOT0 HIGH → hardware DFU mode). Then ran TSKM from bare clone. This confirmed pandad's GPIO path could flash the device when bare `panda.flash()` could not.
|
||||
|
||||
**Fix**: Replaced `panda = Panda(); panda.flash()` with `flash_panda()` from `selfdrive/pandad/pandad.py`. pandad's sequence adds: (1) `HARDWARE.recover_internal_panda()` on `PandaProtocolMismatch` (asserts BOOT0 HIGH during reset, forcing STM32 into hardware DFU mode), (2) `panda.recover()` (flashes bootstub via USB DFU), then reflashes the main app. The GPIO path bypasses whatever blocks SPI writes on resistant firmware.
|
||||
|
||||
**Code changes** (`tsk/common/extractor.py`):
|
||||
- Added `class PandaError(Exception)` — hardware precondition failure, not retryable (falls through to "Unexpected error" handler, not `RetryError`)
|
||||
- Extracted flash logic to `TSKExtractor._connect_and_flash_panda()` staticmethod with full historical commentary (background, original fix, new failure, hypothesis, fix rationale, source attribution)
|
||||
- `hack()` call site: `panda = cls._connect_and_flash_panda()`
|
||||
- New imports: `from panda import PandaProtocolMismatch`, `from selfdrive.pandad.pandad import flash_panda`
|
||||
+30
-5
@@ -1,13 +1,38 @@
|
||||
FROM ghcr.io/commaai/openpilot-base:latest
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
ENV OPENPILOT_PATH=/home/batman/openpilot
|
||||
ENV PYTHONPATH=${OPENPILOT_PATH}:${PYTHONPATH}
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends sudo tzdata locales && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LANGUAGE=en_US:en
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
|
||||
ENV NVIDIA_VISIBLE_DEVICES=all
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
|
||||
|
||||
ARG USER=batman
|
||||
ARG USER_UID=1001
|
||||
RUN useradd -m -s /bin/bash -u $USER_UID $USER
|
||||
RUN usermod -aG sudo $USER
|
||||
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
USER $USER
|
||||
|
||||
ENV OPENPILOT_PATH=/home/$USER/openpilot
|
||||
RUN mkdir -p ${OPENPILOT_PATH}
|
||||
WORKDIR ${OPENPILOT_PATH}
|
||||
|
||||
COPY . ${OPENPILOT_PATH}/
|
||||
COPY --chown=$USER . ${OPENPILOT_PATH}/
|
||||
|
||||
RUN scons --cache-readonly -j$(nproc)
|
||||
ENV UV_BIN="/home/$USER/.local/bin/"
|
||||
ENV VIRTUAL_ENV=${OPENPILOT_PATH}/.venv
|
||||
ENV PATH="$UV_BIN:$VIRTUAL_ENV/bin:$PATH"
|
||||
RUN tools/setup_dependencies.sh && \
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
USER root
|
||||
RUN git config --global --add safe.directory '*'
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends sudo tzdata locales ssh pulseaudio xvfb x11-xserver-utils gnome-screenshot python3-tk python3-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
|
||||
ENV LANG=en_US.UTF-8
|
||||
ENV LANGUAGE=en_US:en
|
||||
ENV LC_ALL=en_US.UTF-8
|
||||
|
||||
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
|
||||
RUN /tmp/tools/install_ubuntu_dependencies.sh && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* && \
|
||||
cd /usr/lib/gcc/arm-none-eabi/* && \
|
||||
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
|
||||
|
||||
# Add OpenCL
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
apt-utils \
|
||||
alien \
|
||||
unzip \
|
||||
tar \
|
||||
curl \
|
||||
xz-utils \
|
||||
dbus \
|
||||
gcc-arm-none-eabi \
|
||||
tmux \
|
||||
vim \
|
||||
libx11-6 \
|
||||
wget \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir -p /tmp/opencl-driver-intel && \
|
||||
cd /tmp/opencl-driver-intel && \
|
||||
wget https://github.com/intel/llvm/releases/download/2024-WW14/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
|
||||
wget https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/oneapi-tbb-2021.12.0-lin.tgz && \
|
||||
mkdir -p /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
|
||||
cd /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
|
||||
tar -zxvf /tmp/opencl-driver-intel/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
|
||||
mkdir -p /etc/OpenCL/vendors && \
|
||||
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \
|
||||
cd /opt/intel && \
|
||||
tar -zxvf /tmp/opencl-driver-intel/oneapi-tbb-2021.12.0-lin.tgz && \
|
||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so.12 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
||||
ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so.2 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
|
||||
mkdir -p /etc/ld.so.conf.d && \
|
||||
echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 > /etc/ld.so.conf.d/libintelopenclexp.conf && \
|
||||
ldconfig -f /etc/ld.so.conf.d/libintelopenclexp.conf && \
|
||||
cd / && \
|
||||
rm -rf /tmp/opencl-driver-intel
|
||||
|
||||
ENV NVIDIA_VISIBLE_DEVICES=all
|
||||
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
|
||||
ENV QTWEBENGINE_DISABLE_SANDBOX=1
|
||||
|
||||
RUN dbus-uuidgen > /etc/machine-id
|
||||
|
||||
ARG USER=batman
|
||||
ARG USER_UID=1001
|
||||
RUN useradd -m -s /bin/bash -u $USER_UID $USER
|
||||
RUN usermod -aG sudo $USER
|
||||
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
USER $USER
|
||||
|
||||
COPY --chown=$USER pyproject.toml uv.lock /home/$USER
|
||||
COPY --chown=$USER tools/install_python_dependencies.sh /home/$USER/tools/
|
||||
|
||||
ENV VIRTUAL_ENV=/home/$USER/.venv
|
||||
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
||||
RUN cd /home/$USER && \
|
||||
tools/install_python_dependencies.sh && \
|
||||
rm -rf tools/ pyproject.toml uv.lock .cache
|
||||
|
||||
USER root
|
||||
RUN sudo git config --global --add safe.directory /tmp/openpilot
|
||||
@@ -5,7 +5,7 @@
|
||||
<p>
|
||||
<b>openpilot is an operating system for robotics.</b>
|
||||
<br>
|
||||
Currently, it upgrades the driver assistance system in 275+ supported cars.
|
||||
Currently, it upgrades the driver assistance system in 300+ supported cars.
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
@@ -17,13 +17,12 @@
|
||||
<span> · </span>
|
||||
<a href="https://discord.comma.ai">Community</a>
|
||||
<span> · </span>
|
||||
<a href="https://comma.ai/shop">Try it on a comma 3X</a>
|
||||
<a href="https://comma.ai/shop">Try it on a comma four</a>
|
||||
</h3>
|
||||
|
||||
Quick start: `bash <(curl -fsSL openpilot.comma.ai)`
|
||||
|
||||

|
||||
[](https://codecov.io/gh/commaai/openpilot)
|
||||
[](https://github.com/commaai/openpilot/actions/workflows/tests.yaml)
|
||||
[](LICENSE)
|
||||
[](https://x.com/comma_ai)
|
||||
[](https://discord.comma.ai)
|
||||
@@ -43,20 +42,24 @@ Using openpilot in a car
|
||||
------
|
||||
|
||||
To use openpilot in a car, you need four things:
|
||||
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
|
||||
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
|
||||
1. **Supported Device:** a comma four, available at [comma.ai/shop/comma-four](https://www.comma.ai/shop/comma-four).
|
||||
2. **Software:** The setup procedure for the comma four allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
|
||||
3. **Supported Car:** Ensure that you have one of [the 275+ supported cars](docs/CARS.md).
|
||||
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
|
||||
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma four to your car.
|
||||
|
||||
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup). Note that it's possible to run openpilot on [other hardware](https://blog.comma.ai/self-driving-car-for-free/), although it's not plug-and-play.
|
||||
|
||||
|
||||
### Branches
|
||||
| branch | URL | description |
|
||||
|------------------|----------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| `release3` | openpilot.comma.ai | This is openpilot's release branch. |
|
||||
| `release3-staging` | openpilot-test.comma.ai | This is the staging branch for releases. Use it to get new releases slightly early. |
|
||||
| `nightly` | openpilot-nightly.comma.ai | This is the bleeding edge development branch. Do not expect this to be stable. |
|
||||
| `nightly-dev` | installer.comma.ai/commaai/nightly-dev | Same as nightly, but includes experimental development features for some cars. |
|
||||
|
||||
Running `master` and other branches directly is supported, but it's recommended to run one of the following prebuilt branches:
|
||||
|
||||
| comma four branch | comma 3X branch | URL | description |
|
||||
|------------------------|------------------------|----------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| `release-mici` | `release-tizi` | openpilot.comma.ai | This is openpilot's release branch. |
|
||||
| `release-mici-staging` | `release-tizi-staging` | openpilot-test.comma.ai | This is the staging branch for releases. Use it to get new releases slightly early. |
|
||||
| `nightly` | `nightly` | openpilot-nightly.comma.ai | This is the bleeding edge development branch. Do not expect this to be stable. |
|
||||
| `nightly-dev` | `nightly-dev` | installer.comma.ai/commaai/nightly-dev | Same as nightly, but includes experimental development features for some cars. |
|
||||
|
||||
To start developing openpilot
|
||||
------
|
||||
@@ -66,7 +69,6 @@ openpilot is developed by [comma](https://comma.ai/) and by users like you. We w
|
||||
* Join the [community Discord](https://discord.comma.ai)
|
||||
* Check out [the contributing docs](docs/CONTRIBUTING.md)
|
||||
* Check out the [openpilot tools](tools/)
|
||||
* Read about the [development workflow](docs/WORKFLOW.md)
|
||||
* Code documentation lives at https://docs.comma.ai
|
||||
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
|
||||
|
||||
@@ -76,15 +78,15 @@ Safety and Testing
|
||||
----
|
||||
|
||||
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
|
||||
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
|
||||
* openpilot has software-in-the-loop [tests](.github/workflows/tests.yaml) that run on every commit.
|
||||
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
|
||||
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
|
||||
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
|
||||
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
|
||||
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
|
||||
|
||||
Licensing
|
||||
------
|
||||
<details>
|
||||
<summary>MIT Licensed</summary>
|
||||
|
||||
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
|
||||
|
||||
@@ -93,15 +95,17 @@ Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and i
|
||||
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
|
||||
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
|
||||
NO WARRANTY EXPRESSED OR IMPLIED.**
|
||||
</details>
|
||||
|
||||
User Data and comma Account
|
||||
------
|
||||
<details>
|
||||
<summary>User Data and comma Account</summary>
|
||||
|
||||
By default, openpilot uploads the driving data to our servers. You can also access your data through [comma connect](https://connect.comma.ai/). We use your data to train better models and improve openpilot for everyone.
|
||||
|
||||
openpilot is open source software: the user is free to disable data collection if they wish to do so.
|
||||
|
||||
openpilot logs the road-facing cameras, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
|
||||
The driver-facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
|
||||
The driver-facing camera and microphone are only logged if you explicitly opt-in in settings.
|
||||
|
||||
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
|
||||
</details>
|
||||
|
||||
+69
@@ -1,3 +1,72 @@
|
||||
Version 0.11.1 (2026-04-22)
|
||||
========================
|
||||
* New driver monitoring model
|
||||
* Improved image processing pipeline for driver camera
|
||||
* Rivian R1S and R1T 2025 support thanks to lukasloetkolben!
|
||||
|
||||
Version 0.11.0 (2026-03-17)
|
||||
========================
|
||||
* New driving model #36798
|
||||
* Fully trained using a learned simulator
|
||||
* Improved longitudinal performance in Experimental mode
|
||||
* Reduce comma four standby power usage by 77% to 52 mW
|
||||
* Kia K7 2017 support thanks to royjr!
|
||||
* Lexus LS 2018 support thanks to Hacheoy!
|
||||
|
||||
Version 0.10.3 (2025-12-17)
|
||||
========================
|
||||
* New driving model #36249
|
||||
* New temporal policy architecture
|
||||
* New on-policy training physics noise model
|
||||
* New driver monitoring model #36409
|
||||
* Trained on a new dataset, including comma four data
|
||||
* Improved inter-process communication memory efficiency
|
||||
|
||||
Version 0.10.2 (2025-11-19)
|
||||
========================
|
||||
* comma four support
|
||||
|
||||
Version 0.10.1 (2025-09-08)
|
||||
========================
|
||||
* New driving model #36276
|
||||
* World Model: removed global localization inputs
|
||||
* World Model: 2x the number of parameters
|
||||
* World Model: trained on 4x the number of segments
|
||||
* VAE Compression Model: new architecture and training objective
|
||||
* Driving Vision Model: trained on 4x the number of segments
|
||||
* New Driver Monitoring model #36198
|
||||
* Acura TLX 2021 support thanks to MVL!
|
||||
* Honda City 2023 support thanks to vanillagorillaa and drFritz!
|
||||
* Honda N-Box 2018 support thanks to miettal!
|
||||
* Honda Odyssey 2021-25 support thanks to csouers and MVL!
|
||||
* Honda Passport 2026 support thanks to vanillagorillaa and MVL!
|
||||
|
||||
Version 0.10.0 (2025-08-05)
|
||||
========================
|
||||
* New driving model
|
||||
* New training architecture
|
||||
* Described in our CVPR paper: "Learning to Drive from a World Model"
|
||||
* Longitudinal MPC replaced by E2E planning from World Model in Experimental Mode
|
||||
* Action from lateral MPC as training objective replaced by E2E planning from World Model
|
||||
* Low-speed lead car ground-truth fixes
|
||||
* Enable live-learned steering actuation delay
|
||||
* Opt-in audio recording for dashcam video
|
||||
* Acura MDX 2025 support thanks to vanillagorillaa and MVL!
|
||||
* Honda Accord 2023-25 support thanks to vanillagorillaa and MVL!
|
||||
* Honda CR-V 2023-25 support thanks to vanillagorillaa and MVL!
|
||||
* Honda Pilot 2023-25 support thanks to vanillagorillaa and MVL!
|
||||
|
||||
Version 0.9.9 (2025-05-23)
|
||||
========================
|
||||
* New driving model
|
||||
* New training architecture using parts from MLSIM
|
||||
* Steering actuation delay is now learned online
|
||||
* Ford Escape 2023-24 support thanks to incognitojam!
|
||||
* Ford Kuga 2024 support thanks to incognitojam!
|
||||
* Hyundai Nexo 2021 support thanks to sunnyhaibin!
|
||||
* Tesla Model 3 and Y support thanks to lukasloetkolben!
|
||||
* Lexus RC 2023 support thanks to nelsonjchen!
|
||||
|
||||
Version 0.9.8 (2025-02-28)
|
||||
========================
|
||||
* New driving model
|
||||
|
||||
+146
-260
@@ -3,339 +3,222 @@ import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import platform
|
||||
import shlex
|
||||
import importlib
|
||||
import numpy as np
|
||||
|
||||
import SCons.Errors
|
||||
from SCons.Defaults import _stripixes
|
||||
|
||||
SCons.Warnings.warningAsException(True)
|
||||
|
||||
# pending upstream fix - https://github.com/SCons/scons/issues/4461
|
||||
#SetOption('warn', 'all')
|
||||
|
||||
TICI = os.path.isfile('/TICI')
|
||||
AGNOS = TICI
|
||||
|
||||
Decider('MD5-timestamp')
|
||||
|
||||
SetOption('num_jobs', int(os.cpu_count()/2))
|
||||
|
||||
AddOption('--kaitai',
|
||||
action='store_true',
|
||||
help='Regenerate kaitai struct parsers')
|
||||
|
||||
AddOption('--asan',
|
||||
action='store_true',
|
||||
help='turn on ASAN')
|
||||
|
||||
AddOption('--ubsan',
|
||||
action='store_true',
|
||||
help='turn on UBSan')
|
||||
|
||||
AddOption('--coverage',
|
||||
action='store_true',
|
||||
help='build with test coverage options')
|
||||
|
||||
AddOption('--clazy',
|
||||
action='store_true',
|
||||
help='build with clazy')
|
||||
|
||||
AddOption('--compile_db',
|
||||
action='store_true',
|
||||
help='build clang compilation database')
|
||||
|
||||
AddOption('--ccflags',
|
||||
action='store',
|
||||
type='string',
|
||||
default='',
|
||||
help='pass arbitrary flags over the command line')
|
||||
|
||||
AddOption('--external-sconscript',
|
||||
action='store',
|
||||
metavar='FILE',
|
||||
dest='external_sconscript',
|
||||
help='add an external SConscript to the build')
|
||||
|
||||
AddOption('--pc-thneed',
|
||||
action='store_true',
|
||||
dest='pc_thneed',
|
||||
help='use thneed on pc')
|
||||
|
||||
AddOption('--mutation',
|
||||
action='store_true',
|
||||
help='generate mutation-ready code')
|
||||
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
|
||||
|
||||
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
|
||||
AddOption('--verbose', action='store_true', default=False, help='show full build commands')
|
||||
AddOption('--minimal',
|
||||
action='store_false',
|
||||
dest='extras',
|
||||
default=os.path.exists(File('#.lfsconfig').abspath), # minimal by default on release branch (where there's no LFS)
|
||||
default=os.path.exists(File('#.gitattributes').abspath), # minimal by default on release branch (where there's no LFS)
|
||||
help='the minimum build to run openpilot. no tests, tools, etc.')
|
||||
|
||||
## Architecture name breakdown (arch)
|
||||
## - larch64: linux tici aarch64
|
||||
## - aarch64: linux pc aarch64
|
||||
## - x86_64: linux pc x64
|
||||
## - Darwin: mac x64 or arm64
|
||||
real_arch = arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
||||
# Detect platform
|
||||
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
|
||||
if platform.system() == "Darwin":
|
||||
arch = "Darwin"
|
||||
brew_prefix = subprocess.check_output(['brew', '--prefix'], encoding='utf8').strip()
|
||||
elif arch == "aarch64" and AGNOS:
|
||||
elif arch == "aarch64" and os.path.isfile('/TICI'):
|
||||
arch = "larch64"
|
||||
assert arch in ["larch64", "aarch64", "x86_64", "Darwin"]
|
||||
assert arch in [
|
||||
"larch64", # linux tici arm64
|
||||
"aarch64", # linux pc arm64
|
||||
"x86_64", # linux pc x64
|
||||
"Darwin", # macOS arm64 (x86 not supported)
|
||||
]
|
||||
|
||||
lenv = {
|
||||
"PATH": os.environ['PATH'],
|
||||
"LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath],
|
||||
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
|
||||
pkg_names = ['bzip2', 'capnproto', 'eigen', 'ffmpeg', 'libjpeg', 'libyuv', 'ncurses', 'zeromq', 'zstd']
|
||||
pkgs = [importlib.import_module(name) for name in pkg_names]
|
||||
|
||||
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
|
||||
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
|
||||
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
|
||||
|
||||
# ***** enforce a whitelist of system libraries *****
|
||||
# this prevents silently relying on a 3rd party package,
|
||||
# e.g. apt-installed libusb. all libraries should either
|
||||
# be distributed with all Linux distros and macOS, or
|
||||
# vendored in commaai/dependencies.
|
||||
allowed_system_libs = {
|
||||
"EGL", "GLESv2", "GL",
|
||||
"Qt5Charts", "Qt5Core", "Qt5Gui", "Qt5Widgets",
|
||||
"dl", "drm", "gbm", "m", "pthread",
|
||||
}
|
||||
|
||||
rpath = lenv["LD_LIBRARY_PATH"].copy()
|
||||
def _resolve_lib(env, name):
|
||||
for d in env.Flatten(env.get('LIBPATH', [])):
|
||||
p = Dir(str(d)).abspath
|
||||
for ext in ('.a', '.so', '.dylib'):
|
||||
f = File(os.path.join(p, f'lib{name}{ext}'))
|
||||
if f.exists() or f.has_builder():
|
||||
return name
|
||||
if name in allowed_system_libs:
|
||||
return name
|
||||
raise SCons.Errors.UserError(f"Unexpected non-vendored library '{name}'")
|
||||
|
||||
if arch == "larch64":
|
||||
cpppath = [
|
||||
"#third_party/opencl/include",
|
||||
]
|
||||
|
||||
libpath = [
|
||||
"/usr/local/lib",
|
||||
"/system/vendor/lib64",
|
||||
f"#third_party/acados/{arch}/lib",
|
||||
]
|
||||
|
||||
libpath += [
|
||||
"#third_party/libyuv/larch64/lib",
|
||||
"/usr/lib/aarch64-linux-gnu"
|
||||
]
|
||||
cflags = ["-DQCOM2", "-mcpu=cortex-a57"]
|
||||
cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"]
|
||||
rpath += ["/usr/local/lib"]
|
||||
else:
|
||||
cflags = []
|
||||
cxxflags = []
|
||||
cpppath = []
|
||||
rpath += []
|
||||
|
||||
# MacOS
|
||||
if arch == "Darwin":
|
||||
libpath = [
|
||||
f"#third_party/libyuv/{arch}/lib",
|
||||
f"#third_party/acados/{arch}/lib",
|
||||
f"{brew_prefix}/lib",
|
||||
f"{brew_prefix}/opt/openssl@3.0/lib",
|
||||
"/System/Library/Frameworks/OpenGL.framework/Libraries",
|
||||
]
|
||||
|
||||
cflags += ["-DGL_SILENCE_DEPRECATION"]
|
||||
cxxflags += ["-DGL_SILENCE_DEPRECATION"]
|
||||
cpppath += [
|
||||
f"{brew_prefix}/include",
|
||||
f"{brew_prefix}/opt/openssl@3.0/include",
|
||||
]
|
||||
lenv["DYLD_LIBRARY_PATH"] = lenv["LD_LIBRARY_PATH"]
|
||||
# Linux
|
||||
else:
|
||||
libpath = [
|
||||
f"#third_party/acados/{arch}/lib",
|
||||
f"#third_party/libyuv/{arch}/lib",
|
||||
"/usr/lib",
|
||||
"/usr/local/lib",
|
||||
]
|
||||
|
||||
if GetOption('asan'):
|
||||
ccflags = ["-fsanitize=address", "-fno-omit-frame-pointer"]
|
||||
ldflags = ["-fsanitize=address"]
|
||||
elif GetOption('ubsan'):
|
||||
ccflags = ["-fsanitize=undefined"]
|
||||
ldflags = ["-fsanitize=undefined"]
|
||||
else:
|
||||
ccflags = []
|
||||
ldflags = []
|
||||
|
||||
# no --as-needed on mac linker
|
||||
if arch != "Darwin":
|
||||
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
|
||||
|
||||
ccflags_option = GetOption('ccflags')
|
||||
if ccflags_option:
|
||||
ccflags += ccflags_option.split(' ')
|
||||
def _libflags(target, source, env, for_signature):
|
||||
libs = []
|
||||
lp = env.subst('$LIBLITERALPREFIX')
|
||||
for lib in env.Flatten(env.get('LIBS', [])):
|
||||
if isinstance(lib, str):
|
||||
if os.sep in lib or lib.startswith('#'):
|
||||
libs.append(File(lib))
|
||||
elif lib.startswith('-') or (lp and lib.startswith(lp)):
|
||||
libs.append(lib)
|
||||
else:
|
||||
libs.append(_resolve_lib(env, lib))
|
||||
else:
|
||||
libs.append(lib)
|
||||
return _stripixes(env['LIBLINKPREFIX'], libs, env['LIBLINKSUFFIX'],
|
||||
env['LIBPREFIXES'], env['LIBSUFFIXES'], env, env['LIBLITERALPREFIX'])
|
||||
|
||||
env = Environment(
|
||||
ENV=lenv,
|
||||
ENV={
|
||||
"PATH": os.environ['PATH'],
|
||||
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
|
||||
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
|
||||
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
|
||||
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
|
||||
},
|
||||
CCFLAGS=[
|
||||
"-g",
|
||||
"-fPIC",
|
||||
"-O2",
|
||||
"-Wunused",
|
||||
"-Werror",
|
||||
"-Wshadow",
|
||||
"-Wshadow" if arch in ("Darwin", "larch64") else "-Wshadow=local",
|
||||
"-Wno-unknown-warning-option",
|
||||
"-Wno-inconsistent-missing-override",
|
||||
"-Wno-c99-designator",
|
||||
"-Wno-reorder-init-list",
|
||||
"-Wno-vla-cxx-extension",
|
||||
] + cflags + ccflags,
|
||||
|
||||
CPPPATH=cpppath + [
|
||||
],
|
||||
CFLAGS=["-std=gnu11"],
|
||||
CXXFLAGS=["-std=c++1z"],
|
||||
CPPPATH=[
|
||||
"#",
|
||||
"#msgq",
|
||||
"#third_party",
|
||||
"#third_party/json11",
|
||||
"#third_party/linux/include",
|
||||
"#third_party/acados/include",
|
||||
"#third_party/acados/include/blasfeo/include",
|
||||
"#third_party/acados/include/hpipm/include",
|
||||
"#third_party/catch2/include",
|
||||
"#third_party/libyuv/include",
|
||||
"#third_party/json11",
|
||||
"#third_party/linux/include",
|
||||
"#third_party",
|
||||
"#msgq",
|
||||
[x.INCLUDE_DIR for x in pkgs],
|
||||
],
|
||||
|
||||
CC='clang',
|
||||
CXX='clang++',
|
||||
LINKFLAGS=ldflags,
|
||||
|
||||
RPATH=rpath,
|
||||
|
||||
CFLAGS=["-std=gnu11"] + cflags,
|
||||
CXXFLAGS=["-std=c++1z"] + cxxflags,
|
||||
LIBPATH=libpath + [
|
||||
LIBPATH=[
|
||||
"#common",
|
||||
"#msgq_repo",
|
||||
"#third_party",
|
||||
"#selfdrive/pandad",
|
||||
"#common",
|
||||
"#rednose/helpers",
|
||||
f"#third_party/acados/{arch}/lib",
|
||||
[x.LIB_DIR for x in pkgs],
|
||||
],
|
||||
RPATH=[],
|
||||
CYTHONCFILESUFFIX=".cpp",
|
||||
COMPILATIONDB_USE_ABSPATH=True,
|
||||
REDNOSE_ROOT="#",
|
||||
tools=["default", "cython", "compilation_db", "rednose_filter"],
|
||||
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
|
||||
)
|
||||
if arch != "larch64":
|
||||
env['_LIBFLAGS'] = _libflags
|
||||
|
||||
if arch == "Darwin":
|
||||
# RPATH is not supported on macOS, instead use the linker flags
|
||||
darwin_rpath_link_flags = [f"-Wl,-rpath,{path}" for path in env["RPATH"]]
|
||||
env["LINKFLAGS"] += darwin_rpath_link_flags
|
||||
# Arch-specific flags and paths
|
||||
if arch == "larch64":
|
||||
env["CC"] = "clang"
|
||||
env["CXX"] = "clang++"
|
||||
env.Append(LIBPATH=[
|
||||
"/usr/lib/aarch64-linux-gnu",
|
||||
])
|
||||
arch_flags = ["-D__TICI__", "-mcpu=cortex-a57"]
|
||||
env.Append(CCFLAGS=arch_flags)
|
||||
env.Append(CXXFLAGS=arch_flags)
|
||||
elif arch == "Darwin":
|
||||
env.Append(LIBPATH=[
|
||||
"/System/Library/Frameworks/OpenGL.framework/Libraries",
|
||||
])
|
||||
env.Append(CCFLAGS=["-DGL_SILENCE_DEPRECATION"])
|
||||
env.Append(CXXFLAGS=["-DGL_SILENCE_DEPRECATION"])
|
||||
|
||||
if GetOption('compile_db'):
|
||||
env.CompilationDatabase('compile_commands.json')
|
||||
_extra_cc = shlex.split(GetOption('ccflags') or '')
|
||||
if _extra_cc:
|
||||
env.Append(CCFLAGS=_extra_cc)
|
||||
|
||||
# Setup cache dir
|
||||
cache_dir = '/data/scons_cache' if AGNOS else '/tmp/scons_cache'
|
||||
CacheDir(cache_dir)
|
||||
Clean(["."], cache_dir)
|
||||
# no --as-needed on mac linker
|
||||
if arch != "Darwin":
|
||||
env.Append(LINKFLAGS=["-Wl,--as-needed", "-Wl,--no-undefined"])
|
||||
|
||||
# Shorter build output: show brief descriptions instead of full commands.
|
||||
# Full command lines are still printed on failure by scons.
|
||||
if not GetOption('verbose'):
|
||||
for action, short in (
|
||||
("CC", "CC"),
|
||||
("CXX", "CXX"),
|
||||
("LINK", "LINK"),
|
||||
("SHCC", "CC"),
|
||||
("SHCXX", "CXX"),
|
||||
("SHLINK", "LINK"),
|
||||
("AR", "AR"),
|
||||
("RANLIB", "RANLIB"),
|
||||
("AS", "AS"),
|
||||
):
|
||||
env[f"{action}COMSTR"] = f" [{short}] $TARGET"
|
||||
|
||||
# progress output
|
||||
node_interval = 5
|
||||
node_count = 0
|
||||
def progress_function(node):
|
||||
global node_count
|
||||
node_count += node_interval
|
||||
sys.stderr.write("progress: %d\n" % node_count)
|
||||
|
||||
if os.environ.get('SCONS_PROGRESS'):
|
||||
Progress(progress_function, interval=node_interval)
|
||||
|
||||
# Cython build environment
|
||||
py_include = sysconfig.get_paths()['include']
|
||||
# ********** Cython build environment **********
|
||||
envCython = env.Clone()
|
||||
envCython["CPPPATH"] += [py_include, np.get_include()]
|
||||
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-shadow", "-Wno-deprecated-declarations"]
|
||||
envCython["CPPPATH"] += [sysconfig.get_paths()['include'], np.get_include()]
|
||||
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-cpp", "-Wno-shadow", "-Wno-deprecated-declarations"]
|
||||
envCython["CCFLAGS"].remove("-Werror")
|
||||
|
||||
envCython["LIBS"] = []
|
||||
if arch == "Darwin":
|
||||
envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"] + darwin_rpath_link_flags
|
||||
envCython["LINKFLAGS"] = env["LINKFLAGS"] + ["-bundle", "-undefined", "dynamic_lookup"]
|
||||
else:
|
||||
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
|
||||
|
||||
np_version = SCons.Script.Value(np.__version__)
|
||||
Export('envCython', 'np_version')
|
||||
|
||||
# Qt build environment
|
||||
qt_env = env.Clone()
|
||||
qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "DBus", "Xml"]
|
||||
Export('env', 'arch')
|
||||
|
||||
qt_libs = []
|
||||
if arch == "Darwin":
|
||||
qt_env['QTDIR'] = f"{brew_prefix}/opt/qt@5"
|
||||
qt_dirs = [
|
||||
os.path.join(qt_env['QTDIR'], "include"),
|
||||
]
|
||||
qt_dirs += [f"{qt_env['QTDIR']}/include/Qt{m}" for m in qt_modules]
|
||||
qt_env["LINKFLAGS"] += ["-F" + os.path.join(qt_env['QTDIR'], "lib")]
|
||||
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
|
||||
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
|
||||
else:
|
||||
qt_install_prefix = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_PREFIX'], encoding='utf8').strip()
|
||||
qt_install_headers = subprocess.check_output(['qmake', '-query', 'QT_INSTALL_HEADERS'], encoding='utf8').strip()
|
||||
# Setup cache dir
|
||||
cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache'
|
||||
CacheDir(cache_dir)
|
||||
Clean(["."], cache_dir)
|
||||
|
||||
qt_env['QTDIR'] = qt_install_prefix
|
||||
qt_dirs = [
|
||||
f"{qt_install_headers}",
|
||||
]
|
||||
|
||||
qt_gui_path = os.path.join(qt_install_headers, "QtGui")
|
||||
qt_gui_dirs = [d for d in os.listdir(qt_gui_path) if os.path.isdir(os.path.join(qt_gui_path, d))]
|
||||
qt_dirs += [f"{qt_install_headers}/QtGui/{qt_gui_dirs[0]}/QtGui", ] if qt_gui_dirs else []
|
||||
qt_dirs += [f"{qt_install_headers}/Qt{m}" for m in qt_modules]
|
||||
|
||||
qt_libs = [f"Qt5{m}" for m in qt_modules]
|
||||
if arch == "larch64":
|
||||
qt_libs += ["GLESv2", "wayland-client"]
|
||||
qt_env.PrependENVPath('PATH', Dir("#third_party/qt5/larch64/bin/").abspath)
|
||||
elif arch != "Darwin":
|
||||
qt_libs += ["GL"]
|
||||
qt_env['QT3DIR'] = qt_env['QTDIR']
|
||||
|
||||
# compatibility for older SCons versions
|
||||
try:
|
||||
qt_env.Tool('qt3')
|
||||
except SCons.Errors.UserError:
|
||||
qt_env.Tool('qt')
|
||||
|
||||
qt_env['CPPPATH'] += qt_dirs + ["#third_party/qrcode"]
|
||||
qt_flags = [
|
||||
"-D_REENTRANT",
|
||||
"-DQT_NO_DEBUG",
|
||||
"-DQT_WIDGETS_LIB",
|
||||
"-DQT_GUI_LIB",
|
||||
"-DQT_CORE_LIB",
|
||||
"-DQT_MESSAGELOGCONTEXT",
|
||||
]
|
||||
qt_env['CXXFLAGS'] += qt_flags
|
||||
qt_env['LIBPATH'] += ['#selfdrive/ui', ]
|
||||
qt_env['LIBS'] = qt_libs
|
||||
|
||||
if GetOption("clazy"):
|
||||
checks = [
|
||||
"level0",
|
||||
"level1",
|
||||
"no-range-loop",
|
||||
"no-non-pod-global-static",
|
||||
]
|
||||
qt_env['CXX'] = 'clazy'
|
||||
qt_env['ENV']['CLAZY_IGNORE_DIRS'] = qt_dirs[0]
|
||||
qt_env['ENV']['CLAZY_CHECKS'] = ','.join(checks)
|
||||
|
||||
Export('env', 'qt_env', 'arch', 'real_arch')
|
||||
# ********** start building stuff **********
|
||||
|
||||
# Build common module
|
||||
SConscript(['common/SConscript'])
|
||||
Import('_common', '_gpucommon')
|
||||
|
||||
Import('_common')
|
||||
common = [_common, 'json11', 'zmq']
|
||||
gpucommon = [_gpucommon]
|
||||
|
||||
Export('common', 'gpucommon')
|
||||
Export('common')
|
||||
|
||||
# Build messaging (cereal + msgq + socketmaster + their dependencies)
|
||||
# Enable swaglog include in submodules
|
||||
env_swaglog = env.Clone()
|
||||
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
|
||||
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
|
||||
SConscript(['opendbc_repo/SConscript'], exports={'env': env_swaglog})
|
||||
|
||||
SConscript(['cereal/SConscript'])
|
||||
|
||||
@@ -352,15 +235,8 @@ SConscript(['rednose/SConscript'])
|
||||
|
||||
# Build system services
|
||||
SConscript([
|
||||
'system/proclogd/SConscript',
|
||||
'system/ubloxd/SConscript',
|
||||
'system/loggerd/SConscript',
|
||||
])
|
||||
if arch != "Darwin":
|
||||
SConscript([
|
||||
'system/sensord/SConscript',
|
||||
'system/logcatd/SConscript',
|
||||
])
|
||||
|
||||
if arch == "larch64":
|
||||
SConscript(['system/camerad/SConscript'])
|
||||
@@ -368,13 +244,23 @@ if arch == "larch64":
|
||||
# Build openpilot
|
||||
SConscript(['third_party/SConscript'])
|
||||
|
||||
SConscript(['selfdrive/SConscript'])
|
||||
# Build selfdrive
|
||||
SConscript([
|
||||
'selfdrive/pandad/SConscript',
|
||||
'selfdrive/controls/lib/lateral_mpc_lib/SConscript',
|
||||
'selfdrive/controls/lib/longitudinal_mpc_lib/SConscript',
|
||||
'selfdrive/locationd/SConscript',
|
||||
'selfdrive/modeld/SConscript',
|
||||
'selfdrive/ui/SConscript',
|
||||
])
|
||||
|
||||
if Dir('#tools/cabana/').exists() and GetOption('extras'):
|
||||
SConscript(['tools/replay/SConscript'])
|
||||
if arch != "larch64":
|
||||
SConscript(['tools/cabana/SConscript'])
|
||||
# Build tools
|
||||
if arch != "larch64":
|
||||
SConscript([
|
||||
'tools/replay/SConscript',
|
||||
'tools/cabana/SConscript',
|
||||
'tools/jotpluggler/SConscript',
|
||||
])
|
||||
|
||||
external_sconscript = GetOption('external_sconscript')
|
||||
if external_sconscript:
|
||||
SConscript([external_sconscript])
|
||||
|
||||
env.CompilationDatabase('compile_commands.json')
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ cereal_dir = Dir('.')
|
||||
gen_dir = Dir('gen')
|
||||
|
||||
# Build cereal
|
||||
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
|
||||
schema_files = ['log.capnp', 'car.capnp', 'deprecated.capnp', 'custom.capnp']
|
||||
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
|
||||
schema_files,
|
||||
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
|
||||
@@ -13,7 +13,7 @@ cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
|
||||
|
||||
# Build messaging
|
||||
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
|
||||
env.Program('messaging/bridge', ['messaging/bridge.cc', 'messaging/msgq_to_zmq.cc'], LIBS=[msgq, common, 'pthread'])
|
||||
env.Program('messaging/bridge', ['messaging/bridge.cc', 'messaging/msgq_to_zmq.cc', 'messaging/bridge_zmq.cc'], LIBS=[msgq, common, 'pthread'])
|
||||
|
||||
socketmaster = env.Library('socketmaster', ['messaging/socketmaster.cc'])
|
||||
|
||||
|
||||
+6
-4
@@ -1,9 +1,11 @@
|
||||
import os
|
||||
import capnp
|
||||
from importlib.resources import as_file, files
|
||||
|
||||
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
capnp.remove_import_hook()
|
||||
|
||||
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
||||
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
||||
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
|
||||
with as_file(files("cereal")) as fspath:
|
||||
CEREAL_PATH = fspath.as_posix()
|
||||
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
|
||||
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
|
||||
custom = capnp.load(os.path.join(CEREAL_PATH, "custom.capnp"))
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
@0x80ef1ec4889c2a63;
|
||||
|
||||
# deprecated.capnp: a home for deprecated structs
|
||||
|
||||
struct LogRotate @0x9811e1f38f62f2d1 {
|
||||
segmentNum @0 :Int32;
|
||||
path @1 :Text;
|
||||
}
|
||||
|
||||
struct LiveUI @0xc08240f996aefced {
|
||||
rearViewCam @0 :Bool;
|
||||
alertText1 @1 :Text;
|
||||
alertText2 @2 :Text;
|
||||
awarenessStatus @3 :Float32;
|
||||
}
|
||||
|
||||
struct UiLayoutState @0x88dcce08ad29dda0 {
|
||||
activeApp @0 :App;
|
||||
sidebarCollapsed @1 :Bool;
|
||||
mapEnabled @2 :Bool;
|
||||
mockEngaged @3 :Bool;
|
||||
|
||||
enum App @0x9917470acf94d285 {
|
||||
home @0;
|
||||
music @1;
|
||||
nav @2;
|
||||
settings @3;
|
||||
none @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbslamCorrection @0x8afd33dc9b35e1aa {
|
||||
correctionMonoTime @0 :UInt64;
|
||||
prePositionECEF @1 :List(Float64);
|
||||
postPositionECEF @2 :List(Float64);
|
||||
prePoseQuatECEF @3 :List(Float32);
|
||||
postPoseQuatECEF @4 :List(Float32);
|
||||
numInliers @5 :UInt32;
|
||||
}
|
||||
|
||||
struct EthernetPacket @0xa99a9d5b33cf5859 {
|
||||
pkt @0 :Data;
|
||||
ts @1 :Float32;
|
||||
}
|
||||
|
||||
struct CellInfo @0xcff7566681c277ce {
|
||||
timestamp @0 :UInt64;
|
||||
repr @1 :Text; # android toString() for now
|
||||
}
|
||||
|
||||
struct WifiScan @0xd4df5a192382ba0b {
|
||||
bssid @0 :Text;
|
||||
ssid @1 :Text;
|
||||
capabilities @2 :Text;
|
||||
frequency @3 :Int32;
|
||||
level @4 :Int32;
|
||||
timestamp @5 :Int64;
|
||||
|
||||
centerFreq0 @6 :Int32;
|
||||
centerFreq1 @7 :Int32;
|
||||
channelWidth @8 :ChannelWidth;
|
||||
operatorFriendlyName @9 :Text;
|
||||
venueName @10 :Text;
|
||||
is80211mcResponder @11 :Bool;
|
||||
passpoint @12 :Bool;
|
||||
|
||||
distanceCm @13 :Int32;
|
||||
distanceSdCm @14 :Int32;
|
||||
|
||||
enum ChannelWidth @0xcb6a279f015f6b51 {
|
||||
w20Mhz @0;
|
||||
w40Mhz @1;
|
||||
w80Mhz @2;
|
||||
w160Mhz @3;
|
||||
w80Plus80Mhz @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveEventData @0x94b7baa90c5c321e {
|
||||
name @0 :Text;
|
||||
value @1 :Int32;
|
||||
}
|
||||
|
||||
struct ModelData @0xb8aad62cffef28a9 {
|
||||
frameId @0 :UInt32;
|
||||
frameAge @12 :UInt32;
|
||||
frameDropPerc @13 :Float32;
|
||||
timestampEof @9 :UInt64;
|
||||
modelExecutionTime @14 :Float32;
|
||||
gpuExecutionTime @16 :Float32;
|
||||
rawPred @15 :Data;
|
||||
|
||||
path @1 :PathData;
|
||||
leftLane @2 :PathData;
|
||||
rightLane @3 :PathData;
|
||||
lead @4 :LeadData;
|
||||
freePath @6 :List(Float32);
|
||||
|
||||
settings @5 :ModelSettings;
|
||||
leadFuture @7 :LeadData;
|
||||
speed @8 :List(Float32);
|
||||
meta @10 :MetaData;
|
||||
longitudinal @11 :LongitudinalData;
|
||||
|
||||
struct PathData @0x8817eeea389e9f08 {
|
||||
points @0 :List(Float32);
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
stds @3 :List(Float32);
|
||||
poly @4 :List(Float32);
|
||||
validLen @5 :Float32;
|
||||
}
|
||||
|
||||
struct LeadData @0xd1c9bef96d26fa91 {
|
||||
dist @0 :Float32;
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
relVel @3 :Float32;
|
||||
relVelStd @4 :Float32;
|
||||
relY @5 :Float32;
|
||||
relYStd @6 :Float32;
|
||||
relA @7 :Float32;
|
||||
relAStd @8 :Float32;
|
||||
}
|
||||
|
||||
struct ModelSettings @0xa26e3710efd3e914 {
|
||||
bigBoxX @0 :UInt16;
|
||||
bigBoxY @1 :UInt16;
|
||||
bigBoxWidth @2 :UInt16;
|
||||
bigBoxHeight @3 :UInt16;
|
||||
boxProjection @4 :List(Float32);
|
||||
yuvCorrection @5 :List(Float32);
|
||||
inputTransform @6 :List(Float32);
|
||||
}
|
||||
|
||||
struct MetaData @0x9744f25fb60f2bf8 {
|
||||
engagedProb @0 :Float32;
|
||||
desirePrediction @1 :List(Float32);
|
||||
brakeDisengageProb @2 :Float32;
|
||||
gasDisengageProb @3 :Float32;
|
||||
steerOverrideProb @4 :Float32;
|
||||
desireState @5 :List(Float32);
|
||||
}
|
||||
|
||||
struct LongitudinalData @0xf98f999c6a071122 {
|
||||
distances @2 :List(Float32);
|
||||
speeds @0 :List(Float32);
|
||||
accelerations @1 :List(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
struct ECEFPoint @0xc25bbbd524983447 {
|
||||
x @0 :Float64;
|
||||
y @1 :Float64;
|
||||
z @2 :Float64;
|
||||
}
|
||||
|
||||
struct ECEFPointDEPRECATED @0xe10e21168db0c7f7 {
|
||||
x @0 :Float32;
|
||||
y @1 :Float32;
|
||||
z @2 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPoints @0xab54c59699f8f9f3 {
|
||||
curPosDEPRECATED @0 :ECEFPointDEPRECATED;
|
||||
pointsDEPRECATED @1 :List(ECEFPointDEPRECATED);
|
||||
curPos @6 :ECEFPoint;
|
||||
points @7 :List(ECEFPoint);
|
||||
valid @2 :Bool;
|
||||
trackName @3 :Text;
|
||||
speedLimit @4 :Float32;
|
||||
accelTarget @5 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPlan @0xf5ad1d90cdc1dd6b {
|
||||
valid @0 :Bool;
|
||||
poly @1 :List(Float32);
|
||||
trackName @2 :Text;
|
||||
speed @3 :Float32;
|
||||
acceleration @4 :Float32;
|
||||
pointsDEPRECATED @5 :List(ECEFPointDEPRECATED);
|
||||
points @6 :List(ECEFPoint);
|
||||
xLookahead @7 :Float32;
|
||||
}
|
||||
|
||||
struct UiNavigationEvent @0x90c8426c3eaddd3b {
|
||||
type @0: Type;
|
||||
status @1: Status;
|
||||
distanceTo @2: Float32;
|
||||
endRoadPointDEPRECATED @3: ECEFPointDEPRECATED;
|
||||
endRoadPoint @4: ECEFPoint;
|
||||
|
||||
enum Type @0xe8db07dcf8fcea05 {
|
||||
none @0;
|
||||
laneChangeLeft @1;
|
||||
laneChangeRight @2;
|
||||
mergeLeft @3;
|
||||
mergeRight @4;
|
||||
turnLeft @5;
|
||||
turnRight @6;
|
||||
}
|
||||
|
||||
enum Status @0xb9aa88c75ef99a1f {
|
||||
none @0;
|
||||
passive @1;
|
||||
approaching @2;
|
||||
active @3;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveLocationData @0xb99b2bc7a57e8128 {
|
||||
status @0 :UInt8;
|
||||
|
||||
# 3D fix
|
||||
lat @1 :Float64;
|
||||
lon @2 :Float64;
|
||||
alt @3 :Float32; # m
|
||||
|
||||
# speed
|
||||
speed @4 :Float32; # m/s
|
||||
|
||||
# NED velocity components
|
||||
vNED @5 :List(Float32);
|
||||
|
||||
# roll, pitch, heading (x,y,z)
|
||||
roll @6 :Float32; # WRT to center of earth?
|
||||
pitch @7 :Float32; # WRT to center of earth?
|
||||
heading @8 :Float32; # WRT to north?
|
||||
|
||||
# what are these?
|
||||
wanderAngle @9 :Float32;
|
||||
trackAngle @10 :Float32;
|
||||
|
||||
# car frame -- https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png
|
||||
|
||||
# gyro, in car frame, deg/s
|
||||
gyro @11 :List(Float32);
|
||||
|
||||
# accel, in car frame, m/s^2
|
||||
accel @12 :List(Float32);
|
||||
|
||||
accuracy @13 :Accuracy;
|
||||
|
||||
source @14 :SensorSource;
|
||||
# if we are fixing a location in the past
|
||||
fixMonoTime @15 :UInt64;
|
||||
|
||||
gpsWeek @16 :Int32;
|
||||
timeOfWeek @17 :Float64;
|
||||
|
||||
positionECEF @18 :List(Float64);
|
||||
poseQuatECEF @19 :List(Float32);
|
||||
pitchCalibration @20 :Float32;
|
||||
yawCalibration @21 :Float32;
|
||||
imuFrame @22 :List(Float32);
|
||||
|
||||
struct Accuracy @0x943dc4625473b03f {
|
||||
pNEDError @0 :List(Float32);
|
||||
vNEDError @1 :List(Float32);
|
||||
rollError @2 :Float32;
|
||||
pitchError @3 :Float32;
|
||||
headingError @4 :Float32;
|
||||
ellipsoidSemiMajorError @5 :Float32;
|
||||
ellipsoidSemiMinorError @6 :Float32;
|
||||
ellipsoidOrientationError @7 :Float32;
|
||||
}
|
||||
|
||||
enum SensorSource @0xc871d3cc252af657 {
|
||||
applanix @0;
|
||||
kalman @1;
|
||||
orbslam @2;
|
||||
timing @3;
|
||||
dummy @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbOdometry @0xd7700859ed1f5b76 {
|
||||
# timing first
|
||||
startMonoTime @0 :UInt64;
|
||||
endMonoTime @1 :UInt64;
|
||||
|
||||
# fundamental matrix and error
|
||||
f @2: List(Float64);
|
||||
err @3: Float64;
|
||||
|
||||
# number of inlier points
|
||||
inliers @4: Int32;
|
||||
|
||||
# for debug only
|
||||
# indexed by endMonoTime features
|
||||
# value is startMonoTime feature match
|
||||
# -1 if no match
|
||||
matches @5: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeatures @0xcd60164a8a0159ef {
|
||||
timestampEof @0 :UInt64;
|
||||
# transposed arrays of normalized image coordinates
|
||||
# len(xs) == len(ys) == len(descriptors) * 32
|
||||
xs @1 :List(Float32);
|
||||
ys @2 :List(Float32);
|
||||
descriptors @3 :Data;
|
||||
octaves @4 :List(Int8);
|
||||
|
||||
# match index to last OrbFeatures
|
||||
# -1 if no match
|
||||
timestampLastEof @5 :UInt64;
|
||||
matches @6: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeaturesSummary @0xd500d30c5803fa4f {
|
||||
timestampEof @0 :UInt64;
|
||||
timestampLastEof @1 :UInt64;
|
||||
|
||||
featureCount @2 :UInt16;
|
||||
matchCount @3 :UInt16;
|
||||
computeNs @4 :UInt64;
|
||||
}
|
||||
|
||||
struct OrbKeyFrame @0xc8233c0345e27e24 {
|
||||
# this is a globally unique id for the KeyFrame
|
||||
id @0: UInt64;
|
||||
|
||||
# this is the location of the KeyFrame
|
||||
pos @1: ECEFPoint;
|
||||
|
||||
# these are the features in the world
|
||||
# len(dpos) == len(descriptors) * 32
|
||||
dpos @2 :List(ECEFPoint);
|
||||
descriptors @3 :Data;
|
||||
}
|
||||
|
||||
struct KalmanOdometry @0x92e21bb7ea38793a {
|
||||
trans @0 :List(Float32); # m/s in device frame
|
||||
rot @1 :List(Float32); # rad/s in device frame
|
||||
transStd @2 :List(Float32); # std m/s in device frame
|
||||
rotStd @3 :List(Float32); # std rad/s in device frame
|
||||
}
|
||||
|
||||
struct OrbObservation @0x9b326d4e436afec7 {
|
||||
observationMonoTime @0 :UInt64;
|
||||
normalizedCoordinates @1 :List(Float32);
|
||||
locationECEF @2 :List(Float64);
|
||||
matchDistance @3: UInt32;
|
||||
}
|
||||
|
||||
struct CalibrationFeatures @0x8fdfadb254ea867a {
|
||||
frameId @0 :UInt32;
|
||||
|
||||
p0 @1 :List(Float32);
|
||||
p1 @2 :List(Float32);
|
||||
status @3 :List(Int8);
|
||||
}
|
||||
|
||||
struct NavStatus @0xbd8822120928120c {
|
||||
isNavigating @0 :Bool;
|
||||
currentAddress @1 :Address;
|
||||
|
||||
struct Address @0xce7cd672cacc7814 {
|
||||
title @0 :Text;
|
||||
lat @1 :Float64;
|
||||
lng @2 :Float64;
|
||||
house @3 :Text;
|
||||
address @4 :Text;
|
||||
street @5 :Text;
|
||||
city @6 :Text;
|
||||
state @7 :Text;
|
||||
country @8 :Text;
|
||||
}
|
||||
}
|
||||
|
||||
struct NavUpdate @0xdb98be6565516acb {
|
||||
isNavigating @0 :Bool;
|
||||
curSegment @1 :Int32;
|
||||
segments @2 :List(Segment);
|
||||
|
||||
struct LatLng @0x9eaef9187cadbb9b {
|
||||
lat @0 :Float64;
|
||||
lng @1 :Float64;
|
||||
}
|
||||
|
||||
struct Segment @0xa5b39b4fc4d7da3f {
|
||||
from @0 :LatLng;
|
||||
to @1 :LatLng;
|
||||
updateTime @2 :Int32;
|
||||
distance @3 :Int32;
|
||||
crossTime @4 :Int32;
|
||||
exitNo @5 :Int32;
|
||||
instruction @6 :Instruction;
|
||||
|
||||
parts @7 :List(LatLng);
|
||||
|
||||
enum Instruction @0xc5417a637451246f {
|
||||
turnLeft @0;
|
||||
turnRight @1;
|
||||
keepLeft @2;
|
||||
keepRight @3;
|
||||
straight @4;
|
||||
roundaboutExitNumber @5;
|
||||
roundaboutExit @6;
|
||||
roundaboutTurnLeft @7;
|
||||
unkn8 @8;
|
||||
roundaboutStraight @9;
|
||||
unkn10 @10;
|
||||
roundaboutTurnRight @11;
|
||||
unkn12 @12;
|
||||
roundaboutUturn @13;
|
||||
unkn14 @14;
|
||||
arrive @15;
|
||||
exitLeft @16;
|
||||
exitRight @17;
|
||||
unkn18 @18;
|
||||
uturn @19;
|
||||
# ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TrafficEvent @0xacfa74a094e62626 {
|
||||
type @0 :Type;
|
||||
distance @1 :Float32;
|
||||
action @2 :Action;
|
||||
resuming @3 :Bool;
|
||||
|
||||
enum Type @0xd85d75253435bf4b {
|
||||
stopSign @0;
|
||||
lightRed @1;
|
||||
lightYellow @2;
|
||||
lightGreen @3;
|
||||
stopLight @4;
|
||||
}
|
||||
|
||||
enum Action @0xa6f6ce72165ccb49 {
|
||||
none @0;
|
||||
yield @1;
|
||||
stop @2;
|
||||
resumeReady @3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct AndroidGnss @0xdfdf30d03fc485bd {
|
||||
union {
|
||||
measurements @0 :Measurements;
|
||||
navigationMessage @1 :NavigationMessage;
|
||||
}
|
||||
|
||||
struct Measurements @0xa20710d4f428d6cd {
|
||||
clock @0 :Clock;
|
||||
measurements @1 :List(Measurement);
|
||||
|
||||
struct Clock @0xa0e27b453a38f450 {
|
||||
timeNanos @0 :Int64;
|
||||
hardwareClockDiscontinuityCount @1 :Int32;
|
||||
|
||||
hasTimeUncertaintyNanos @2 :Bool;
|
||||
timeUncertaintyNanos @3 :Float64;
|
||||
|
||||
hasLeapSecond @4 :Bool;
|
||||
leapSecond @5 :Int32;
|
||||
|
||||
hasFullBiasNanos @6 :Bool;
|
||||
fullBiasNanos @7 :Int64;
|
||||
|
||||
hasBiasNanos @8 :Bool;
|
||||
biasNanos @9 :Float64;
|
||||
|
||||
hasBiasUncertaintyNanos @10 :Bool;
|
||||
biasUncertaintyNanos @11 :Float64;
|
||||
|
||||
hasDriftNanosPerSecond @12 :Bool;
|
||||
driftNanosPerSecond @13 :Float64;
|
||||
|
||||
hasDriftUncertaintyNanosPerSecond @14 :Bool;
|
||||
driftUncertaintyNanosPerSecond @15 :Float64;
|
||||
}
|
||||
|
||||
struct Measurement @0xd949bf717d77614d {
|
||||
svId @0 :Int32;
|
||||
constellation @1 :Constellation;
|
||||
|
||||
timeOffsetNanos @2 :Float64;
|
||||
state @3 :Int32;
|
||||
receivedSvTimeNanos @4 :Int64;
|
||||
receivedSvTimeUncertaintyNanos @5 :Int64;
|
||||
cn0DbHz @6 :Float64;
|
||||
pseudorangeRateMetersPerSecond @7 :Float64;
|
||||
pseudorangeRateUncertaintyMetersPerSecond @8 :Float64;
|
||||
accumulatedDeltaRangeState @9 :Int32;
|
||||
accumulatedDeltaRangeMeters @10 :Float64;
|
||||
accumulatedDeltaRangeUncertaintyMeters @11 :Float64;
|
||||
|
||||
hasCarrierFrequencyHz @12 :Bool;
|
||||
carrierFrequencyHz @13 :Float32;
|
||||
hasCarrierCycles @14 :Bool;
|
||||
carrierCycles @15 :Int64;
|
||||
hasCarrierPhase @16 :Bool;
|
||||
carrierPhase @17 :Float64;
|
||||
hasCarrierPhaseUncertainty @18 :Bool;
|
||||
carrierPhaseUncertainty @19 :Float64;
|
||||
hasSnrInDb @20 :Bool;
|
||||
snrInDb @21 :Float64;
|
||||
|
||||
multipathIndicator @22 :MultipathIndicator;
|
||||
|
||||
enum Constellation @0x9ef1f3ff0deb5ffb {
|
||||
unknown @0;
|
||||
gps @1;
|
||||
sbas @2;
|
||||
glonass @3;
|
||||
qzss @4;
|
||||
beidou @5;
|
||||
galileo @6;
|
||||
}
|
||||
|
||||
enum State @0xcbb9490adce12d72 {
|
||||
unknown @0;
|
||||
codeLock @1;
|
||||
bitSync @2;
|
||||
subframeSync @3;
|
||||
towDecoded @4;
|
||||
msecAmbiguous @5;
|
||||
symbolSync @6;
|
||||
gloStringSync @7;
|
||||
gloTodDecoded @8;
|
||||
bdsD2BitSync @9;
|
||||
bdsD2SubframeSync @10;
|
||||
galE1bcCodeLock @11;
|
||||
galE1c2ndCodeLock @12;
|
||||
galE1bPageSync @13;
|
||||
sbasSync @14;
|
||||
}
|
||||
|
||||
enum MultipathIndicator @0xc04e7b6231d4caa8 {
|
||||
unknown @0;
|
||||
detected @1;
|
||||
notDetected @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NavigationMessage @0xe2517b083095fd4e {
|
||||
type @0 :Int32;
|
||||
svId @1 :Int32;
|
||||
messageId @2 :Int32;
|
||||
submessageId @3 :Int32;
|
||||
data @4 :Data;
|
||||
status @5 :Status;
|
||||
|
||||
enum Status @0xec1ff7996b35366f {
|
||||
unknown @0;
|
||||
parityPassed @1;
|
||||
parityRebuilt @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LidarPts @0xe3d6685d4e9d8f7a {
|
||||
r @0 :List(UInt16); # uint16 m*500.0
|
||||
theta @1 :List(UInt16); # uint16 deg*100.0
|
||||
reflect @2 :List(UInt8); # uint8 0-255
|
||||
|
||||
# For storing out of file.
|
||||
idx @3 :UInt64;
|
||||
|
||||
# For storing in file
|
||||
pkt @4 :Data;
|
||||
}
|
||||
|
||||
|
||||
+777
-686
File diff suppressed because it is too large
Load Diff
+163
-68
@@ -8,7 +8,7 @@
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000002
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
@@ -650,7 +650,7 @@ struct CarParams::LateralTorqueTuning {
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(80366e0e804ecc1d, 4, 0)
|
||||
CAPNP_DECLARE_STRUCT_HEADER(80366e0e804ecc1d, 5, 0)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
@@ -891,7 +891,7 @@ public:
|
||||
inline bool hasWheelSpeeds() const;
|
||||
inline ::cereal::CarState::WheelSpeeds::Reader getWheelSpeeds() const;
|
||||
|
||||
inline float getGas() const;
|
||||
inline float getGasDEPRECATED() const;
|
||||
|
||||
inline bool getGasPressed() const;
|
||||
|
||||
@@ -945,7 +945,7 @@ public:
|
||||
|
||||
inline float getSteeringTorqueEps() const;
|
||||
|
||||
inline bool getClutchPressed() const;
|
||||
inline bool getClutchPressedDEPRECATED() const;
|
||||
|
||||
inline bool getSteeringRateLimitedDEPRECATED() const;
|
||||
|
||||
@@ -981,7 +981,7 @@ public:
|
||||
|
||||
inline bool getRegenBraking() const;
|
||||
|
||||
inline float getEngineRpm() const;
|
||||
inline float getEngineRpmDEPRECATED() const;
|
||||
|
||||
inline bool getCarFaultedNonCritical() const;
|
||||
|
||||
@@ -1005,6 +1005,12 @@ public:
|
||||
|
||||
inline bool getButtonEnable() const;
|
||||
|
||||
inline bool getSteeringDisengage() const;
|
||||
|
||||
inline bool getStockLkas() const;
|
||||
|
||||
inline bool getBlockPcmEnable() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -1051,8 +1057,8 @@ public:
|
||||
inline void adoptWheelSpeeds(::capnp::Orphan< ::cereal::CarState::WheelSpeeds>&& value);
|
||||
inline ::capnp::Orphan< ::cereal::CarState::WheelSpeeds> disownWheelSpeeds();
|
||||
|
||||
inline float getGas();
|
||||
inline void setGas(float value);
|
||||
inline float getGasDEPRECATED();
|
||||
inline void setGasDEPRECATED(float value);
|
||||
|
||||
inline bool getGasPressed();
|
||||
inline void setGasPressed(bool value);
|
||||
@@ -1143,8 +1149,8 @@ public:
|
||||
inline float getSteeringTorqueEps();
|
||||
inline void setSteeringTorqueEps(float value);
|
||||
|
||||
inline bool getClutchPressed();
|
||||
inline void setClutchPressed(bool value);
|
||||
inline bool getClutchPressedDEPRECATED();
|
||||
inline void setClutchPressedDEPRECATED(bool value);
|
||||
|
||||
inline bool getSteeringRateLimitedDEPRECATED();
|
||||
inline void setSteeringRateLimitedDEPRECATED(bool value);
|
||||
@@ -1197,8 +1203,8 @@ public:
|
||||
inline bool getRegenBraking();
|
||||
inline void setRegenBraking(bool value);
|
||||
|
||||
inline float getEngineRpm();
|
||||
inline void setEngineRpm(float value);
|
||||
inline float getEngineRpmDEPRECATED();
|
||||
inline void setEngineRpmDEPRECATED(float value);
|
||||
|
||||
inline bool getCarFaultedNonCritical();
|
||||
inline void setCarFaultedNonCritical(bool value);
|
||||
@@ -1233,6 +1239,15 @@ public:
|
||||
inline bool getButtonEnable();
|
||||
inline void setButtonEnable(bool value);
|
||||
|
||||
inline bool getSteeringDisengage();
|
||||
inline void setSteeringDisengage(bool value);
|
||||
|
||||
inline bool getStockLkas();
|
||||
inline void setStockLkas(bool value);
|
||||
|
||||
inline bool getBlockPcmEnable();
|
||||
inline void setBlockPcmEnable(bool value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -1375,7 +1390,7 @@ public:
|
||||
|
||||
inline bool getAvailable() const;
|
||||
|
||||
inline float getSpeedOffset() const;
|
||||
inline float getSpeedOffsetDEPRECATED() const;
|
||||
|
||||
inline bool getStandstill() const;
|
||||
|
||||
@@ -1420,8 +1435,8 @@ public:
|
||||
inline bool getAvailable();
|
||||
inline void setAvailable(bool value);
|
||||
|
||||
inline float getSpeedOffset();
|
||||
inline void setSpeedOffset(float value);
|
||||
inline float getSpeedOffsetDEPRECATED();
|
||||
inline void setSpeedOffsetDEPRECATED(float value);
|
||||
|
||||
inline bool getStandstill();
|
||||
inline void setStandstill(bool value);
|
||||
@@ -2496,7 +2511,7 @@ public:
|
||||
|
||||
inline bool getEnableCameraDEPRECATED() const;
|
||||
|
||||
inline bool getEnableDsu() const;
|
||||
inline bool getEnableDsuDEPRECATED() const;
|
||||
|
||||
inline bool getEnableApgsDEPRECATED() const;
|
||||
|
||||
@@ -2633,7 +2648,7 @@ public:
|
||||
|
||||
inline bool getStartingState() const;
|
||||
|
||||
inline bool getExperimentalLongitudinalAvailable() const;
|
||||
inline bool getAlphaLongitudinalAvailable() const;
|
||||
|
||||
inline float getTireStiffnessFactor() const;
|
||||
|
||||
@@ -2645,6 +2660,8 @@ public:
|
||||
|
||||
inline bool getSecOcKeyAvailable() const;
|
||||
|
||||
inline bool getSteerAtStandstill() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -2696,8 +2713,8 @@ public:
|
||||
inline bool getEnableCameraDEPRECATED();
|
||||
inline void setEnableCameraDEPRECATED(bool value);
|
||||
|
||||
inline bool getEnableDsu();
|
||||
inline void setEnableDsu(bool value);
|
||||
inline bool getEnableDsuDEPRECATED();
|
||||
inline void setEnableDsuDEPRECATED(bool value);
|
||||
|
||||
inline bool getEnableApgsDEPRECATED();
|
||||
inline void setEnableApgsDEPRECATED(bool value);
|
||||
@@ -2935,8 +2952,8 @@ public:
|
||||
inline bool getStartingState();
|
||||
inline void setStartingState(bool value);
|
||||
|
||||
inline bool getExperimentalLongitudinalAvailable();
|
||||
inline void setExperimentalLongitudinalAvailable(bool value);
|
||||
inline bool getAlphaLongitudinalAvailable();
|
||||
inline void setAlphaLongitudinalAvailable(bool value);
|
||||
|
||||
inline float getTireStiffnessFactor();
|
||||
inline void setTireStiffnessFactor(float value);
|
||||
@@ -2953,6 +2970,9 @@ public:
|
||||
inline bool getSecOcKeyAvailable();
|
||||
inline void setSecOcKeyAvailable(bool value);
|
||||
|
||||
inline bool getSteerAtStandstill();
|
||||
inline void setSteerAtStandstill(bool value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -3303,15 +3323,15 @@ public:
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool getUseSteeringAngle() const;
|
||||
inline bool getUseSteeringAngleDEPRECATED() const;
|
||||
|
||||
inline float getKp() const;
|
||||
inline float getKpDEPRECATED() const;
|
||||
|
||||
inline float getKi() const;
|
||||
inline float getKiDEPRECATED() const;
|
||||
|
||||
inline float getFriction() const;
|
||||
|
||||
inline float getKf() const;
|
||||
inline float getKfDEPRECATED() const;
|
||||
|
||||
inline float getSteeringAngleDeadzoneDeg() const;
|
||||
|
||||
@@ -3319,6 +3339,8 @@ public:
|
||||
|
||||
inline float getLatAccelOffset() const;
|
||||
|
||||
inline float getKdDEPRECATED() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -3347,20 +3369,20 @@ public:
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline bool getUseSteeringAngle();
|
||||
inline void setUseSteeringAngle(bool value);
|
||||
inline bool getUseSteeringAngleDEPRECATED();
|
||||
inline void setUseSteeringAngleDEPRECATED(bool value);
|
||||
|
||||
inline float getKp();
|
||||
inline void setKp(float value);
|
||||
inline float getKpDEPRECATED();
|
||||
inline void setKpDEPRECATED(float value);
|
||||
|
||||
inline float getKi();
|
||||
inline void setKi(float value);
|
||||
inline float getKiDEPRECATED();
|
||||
inline void setKiDEPRECATED(float value);
|
||||
|
||||
inline float getFriction();
|
||||
inline void setFriction(float value);
|
||||
|
||||
inline float getKf();
|
||||
inline void setKf(float value);
|
||||
inline float getKfDEPRECATED();
|
||||
inline void setKfDEPRECATED(float value);
|
||||
|
||||
inline float getSteeringAngleDeadzoneDeg();
|
||||
inline void setSteeringAngleDeadzoneDeg(float value);
|
||||
@@ -3371,6 +3393,9 @@ public:
|
||||
inline float getLatAccelOffset();
|
||||
inline void setLatAccelOffset(float value);
|
||||
|
||||
inline float getKdDEPRECATED();
|
||||
inline void setKdDEPRECATED(float value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -3432,7 +3457,7 @@ public:
|
||||
inline bool hasDeadzoneVDEPRECATED() const;
|
||||
inline ::capnp::List<float, ::capnp::Kind::PRIMITIVE>::Reader getDeadzoneVDEPRECATED() const;
|
||||
|
||||
inline float getKf() const;
|
||||
inline float getKfDEPRECATED() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
@@ -3510,8 +3535,8 @@ public:
|
||||
inline void adoptDeadzoneVDEPRECATED(::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>> disownDeadzoneVDEPRECATED();
|
||||
|
||||
inline float getKf();
|
||||
inline void setKf(float value);
|
||||
inline float getKfDEPRECATED();
|
||||
inline void setKfDEPRECATED(float value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
@@ -4364,16 +4389,16 @@ inline ::capnp::Orphan< ::cereal::CarState::WheelSpeeds> CarState::Builder::diso
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline float CarState::Reader::getGas() const {
|
||||
inline float CarState::Reader::getGasDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarState::Builder::getGas() {
|
||||
inline float CarState::Builder::getGasDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setGas(float value) {
|
||||
inline void CarState::Builder::setGasDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -4803,16 +4828,16 @@ inline void CarState::Builder::setSteeringTorqueEps(float value) {
|
||||
::capnp::bounded<10>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarState::Reader::getClutchPressed() const {
|
||||
inline bool CarState::Reader::getClutchPressedDEPRECATED() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<75>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarState::Builder::getClutchPressed() {
|
||||
inline bool CarState::Builder::getClutchPressedDEPRECATED() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<75>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setClutchPressed(bool value) {
|
||||
inline void CarState::Builder::setClutchPressedDEPRECATED(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<75>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -5055,16 +5080,16 @@ inline void CarState::Builder::setRegenBraking(bool value) {
|
||||
::capnp::bounded<361>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarState::Reader::getEngineRpm() const {
|
||||
inline float CarState::Reader::getEngineRpmDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<15>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarState::Builder::getEngineRpm() {
|
||||
inline float CarState::Builder::getEngineRpmDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<15>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setEngineRpm(float value) {
|
||||
inline void CarState::Builder::setEngineRpmDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<15>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -5223,6 +5248,48 @@ inline void CarState::Builder::setButtonEnable(bool value) {
|
||||
::capnp::bounded<368>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarState::Reader::getSteeringDisengage() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<369>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarState::Builder::getSteeringDisengage() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<369>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setSteeringDisengage(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<369>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarState::Reader::getStockLkas() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<370>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarState::Builder::getStockLkas() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<370>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setStockLkas(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<370>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarState::Reader::getBlockPcmEnable() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<371>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarState::Builder::getBlockPcmEnable() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<371>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::Builder::setBlockPcmEnable(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<371>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarState::WheelSpeeds::Reader::getFl() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
@@ -5321,16 +5388,16 @@ inline void CarState::CruiseState::Builder::setAvailable(bool value) {
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarState::CruiseState::Reader::getSpeedOffset() const {
|
||||
inline float CarState::CruiseState::Reader::getSpeedOffsetDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarState::CruiseState::Builder::getSpeedOffset() {
|
||||
inline float CarState::CruiseState::Builder::getSpeedOffsetDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarState::CruiseState::Builder::setSpeedOffset(float value) {
|
||||
inline void CarState::CruiseState::Builder::setSpeedOffsetDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -6607,16 +6674,16 @@ inline void CarParams::Builder::setEnableCameraDEPRECATED(bool value) {
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::Reader::getEnableDsu() const {
|
||||
inline bool CarParams::Reader::getEnableDsuDEPRECATED() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarParams::Builder::getEnableDsu() {
|
||||
inline bool CarParams::Builder::getEnableDsuDEPRECATED() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::Builder::setEnableDsu(bool value) {
|
||||
inline void CarParams::Builder::setEnableDsuDEPRECATED(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -7745,16 +7812,16 @@ inline void CarParams::Builder::setStartingState(bool value) {
|
||||
::capnp::bounded<994>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::Reader::getExperimentalLongitudinalAvailable() const {
|
||||
inline bool CarParams::Reader::getAlphaLongitudinalAvailable() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<995>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarParams::Builder::getExperimentalLongitudinalAvailable() {
|
||||
inline bool CarParams::Builder::getAlphaLongitudinalAvailable() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<995>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::Builder::setExperimentalLongitudinalAvailable(bool value) {
|
||||
inline void CarParams::Builder::setAlphaLongitudinalAvailable(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<995>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -7829,6 +7896,20 @@ inline void CarParams::Builder::setSecOcKeyAvailable(bool value) {
|
||||
::capnp::bounded<998>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::Reader::getSteerAtStandstill() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<999>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarParams::Builder::getSteerAtStandstill() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<999>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::Builder::setSteerAtStandstill(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<999>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline ::cereal::CarParams::SafetyModel CarParams::SafetyConfig::Reader::getSafetyModel() const {
|
||||
return _reader.getDataField< ::cereal::CarParams::SafetyModel>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
@@ -8127,44 +8208,44 @@ inline void CarParams::LateralPIDTuning::Builder::setKf(float value) {
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::LateralTorqueTuning::Reader::getUseSteeringAngle() const {
|
||||
inline bool CarParams::LateralTorqueTuning::Reader::getUseSteeringAngleDEPRECATED() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool CarParams::LateralTorqueTuning::Builder::getUseSteeringAngle() {
|
||||
inline bool CarParams::LateralTorqueTuning::Builder::getUseSteeringAngleDEPRECATED() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setUseSteeringAngle(bool value) {
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setUseSteeringAngleDEPRECATED(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKp() const {
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKpDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKp() {
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKpDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKp(float value) {
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKpDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKi() const {
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKiDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKi() {
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKiDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKi(float value) {
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKiDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<2>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -8183,16 +8264,16 @@ inline void CarParams::LateralTorqueTuning::Builder::setFriction(float value) {
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKf() const {
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKfDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKf() {
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKfDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKf(float value) {
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKfDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -8239,6 +8320,20 @@ inline void CarParams::LateralTorqueTuning::Builder::setLatAccelOffset(float val
|
||||
::capnp::bounded<7>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKdDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKdDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKdDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::LongitudinalPIDTuning::Reader::hasKpBP() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
@@ -8467,16 +8562,16 @@ inline ::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>> CarPara
|
||||
::capnp::bounded<5>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline float CarParams::LongitudinalPIDTuning::Reader::getKf() const {
|
||||
inline float CarParams::LongitudinalPIDTuning::Reader::getKfDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LongitudinalPIDTuning::Builder::getKf() {
|
||||
inline float CarParams::LongitudinalPIDTuning::Builder::getKfDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LongitudinalPIDTuning::Builder::setKf(float value) {
|
||||
inline void CarParams::LongitudinalPIDTuning::Builder::setKfDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#ifndef CAPNP_VERSION
|
||||
#error "CAPNP_VERSION is not defined, is capnp/generated-header-support.h missing?"
|
||||
#elif CAPNP_VERSION != 1000002
|
||||
#elif CAPNP_VERSION != 1000001
|
||||
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2830
-1896
File diff suppressed because it is too large
Load Diff
+1848
-380
File diff suppressed because it is too large
Load Diff
@@ -1,574 +0,0 @@
|
||||
using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
@0x80ef1ec4889c2a63;
|
||||
|
||||
# legacy.capnp: a home for deprecated structs
|
||||
|
||||
struct LogRotate @0x9811e1f38f62f2d1 {
|
||||
segmentNum @0 :Int32;
|
||||
path @1 :Text;
|
||||
}
|
||||
|
||||
struct LiveUI @0xc08240f996aefced {
|
||||
rearViewCam @0 :Bool;
|
||||
alertText1 @1 :Text;
|
||||
alertText2 @2 :Text;
|
||||
awarenessStatus @3 :Float32;
|
||||
}
|
||||
|
||||
struct UiLayoutState @0x88dcce08ad29dda0 {
|
||||
activeApp @0 :App;
|
||||
sidebarCollapsed @1 :Bool;
|
||||
mapEnabled @2 :Bool;
|
||||
mockEngaged @3 :Bool;
|
||||
|
||||
enum App @0x9917470acf94d285 {
|
||||
home @0;
|
||||
music @1;
|
||||
nav @2;
|
||||
settings @3;
|
||||
none @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbslamCorrection @0x8afd33dc9b35e1aa {
|
||||
correctionMonoTime @0 :UInt64;
|
||||
prePositionECEF @1 :List(Float64);
|
||||
postPositionECEF @2 :List(Float64);
|
||||
prePoseQuatECEF @3 :List(Float32);
|
||||
postPoseQuatECEF @4 :List(Float32);
|
||||
numInliers @5 :UInt32;
|
||||
}
|
||||
|
||||
struct EthernetPacket @0xa99a9d5b33cf5859 {
|
||||
pkt @0 :Data;
|
||||
ts @1 :Float32;
|
||||
}
|
||||
|
||||
struct CellInfo @0xcff7566681c277ce {
|
||||
timestamp @0 :UInt64;
|
||||
repr @1 :Text; # android toString() for now
|
||||
}
|
||||
|
||||
struct WifiScan @0xd4df5a192382ba0b {
|
||||
bssid @0 :Text;
|
||||
ssid @1 :Text;
|
||||
capabilities @2 :Text;
|
||||
frequency @3 :Int32;
|
||||
level @4 :Int32;
|
||||
timestamp @5 :Int64;
|
||||
|
||||
centerFreq0 @6 :Int32;
|
||||
centerFreq1 @7 :Int32;
|
||||
channelWidth @8 :ChannelWidth;
|
||||
operatorFriendlyName @9 :Text;
|
||||
venueName @10 :Text;
|
||||
is80211mcResponder @11 :Bool;
|
||||
passpoint @12 :Bool;
|
||||
|
||||
distanceCm @13 :Int32;
|
||||
distanceSdCm @14 :Int32;
|
||||
|
||||
enum ChannelWidth @0xcb6a279f015f6b51 {
|
||||
w20Mhz @0;
|
||||
w40Mhz @1;
|
||||
w80Mhz @2;
|
||||
w160Mhz @3;
|
||||
w80Plus80Mhz @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveEventData @0x94b7baa90c5c321e {
|
||||
name @0 :Text;
|
||||
value @1 :Int32;
|
||||
}
|
||||
|
||||
struct ModelData @0xb8aad62cffef28a9 {
|
||||
frameId @0 :UInt32;
|
||||
frameAge @12 :UInt32;
|
||||
frameDropPerc @13 :Float32;
|
||||
timestampEof @9 :UInt64;
|
||||
modelExecutionTime @14 :Float32;
|
||||
gpuExecutionTime @16 :Float32;
|
||||
rawPred @15 :Data;
|
||||
|
||||
path @1 :PathData;
|
||||
leftLane @2 :PathData;
|
||||
rightLane @3 :PathData;
|
||||
lead @4 :LeadData;
|
||||
freePath @6 :List(Float32);
|
||||
|
||||
settings @5 :ModelSettings;
|
||||
leadFuture @7 :LeadData;
|
||||
speed @8 :List(Float32);
|
||||
meta @10 :MetaData;
|
||||
longitudinal @11 :LongitudinalData;
|
||||
|
||||
struct PathData @0x8817eeea389e9f08 {
|
||||
points @0 :List(Float32);
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
stds @3 :List(Float32);
|
||||
poly @4 :List(Float32);
|
||||
validLen @5 :Float32;
|
||||
}
|
||||
|
||||
struct LeadData @0xd1c9bef96d26fa91 {
|
||||
dist @0 :Float32;
|
||||
prob @1 :Float32;
|
||||
std @2 :Float32;
|
||||
relVel @3 :Float32;
|
||||
relVelStd @4 :Float32;
|
||||
relY @5 :Float32;
|
||||
relYStd @6 :Float32;
|
||||
relA @7 :Float32;
|
||||
relAStd @8 :Float32;
|
||||
}
|
||||
|
||||
struct ModelSettings @0xa26e3710efd3e914 {
|
||||
bigBoxX @0 :UInt16;
|
||||
bigBoxY @1 :UInt16;
|
||||
bigBoxWidth @2 :UInt16;
|
||||
bigBoxHeight @3 :UInt16;
|
||||
boxProjection @4 :List(Float32);
|
||||
yuvCorrection @5 :List(Float32);
|
||||
inputTransform @6 :List(Float32);
|
||||
}
|
||||
|
||||
struct MetaData @0x9744f25fb60f2bf8 {
|
||||
engagedProb @0 :Float32;
|
||||
desirePrediction @1 :List(Float32);
|
||||
brakeDisengageProb @2 :Float32;
|
||||
gasDisengageProb @3 :Float32;
|
||||
steerOverrideProb @4 :Float32;
|
||||
desireState @5 :List(Float32);
|
||||
}
|
||||
|
||||
struct LongitudinalData @0xf98f999c6a071122 {
|
||||
distances @2 :List(Float32);
|
||||
speeds @0 :List(Float32);
|
||||
accelerations @1 :List(Float32);
|
||||
}
|
||||
}
|
||||
|
||||
struct ECEFPoint @0xc25bbbd524983447 {
|
||||
x @0 :Float64;
|
||||
y @1 :Float64;
|
||||
z @2 :Float64;
|
||||
}
|
||||
|
||||
struct ECEFPointDEPRECATED @0xe10e21168db0c7f7 {
|
||||
x @0 :Float32;
|
||||
y @1 :Float32;
|
||||
z @2 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPoints @0xab54c59699f8f9f3 {
|
||||
curPosDEPRECATED @0 :ECEFPointDEPRECATED;
|
||||
pointsDEPRECATED @1 :List(ECEFPointDEPRECATED);
|
||||
curPos @6 :ECEFPoint;
|
||||
points @7 :List(ECEFPoint);
|
||||
valid @2 :Bool;
|
||||
trackName @3 :Text;
|
||||
speedLimit @4 :Float32;
|
||||
accelTarget @5 :Float32;
|
||||
}
|
||||
|
||||
struct GPSPlannerPlan @0xf5ad1d90cdc1dd6b {
|
||||
valid @0 :Bool;
|
||||
poly @1 :List(Float32);
|
||||
trackName @2 :Text;
|
||||
speed @3 :Float32;
|
||||
acceleration @4 :Float32;
|
||||
pointsDEPRECATED @5 :List(ECEFPointDEPRECATED);
|
||||
points @6 :List(ECEFPoint);
|
||||
xLookahead @7 :Float32;
|
||||
}
|
||||
|
||||
struct UiNavigationEvent @0x90c8426c3eaddd3b {
|
||||
type @0: Type;
|
||||
status @1: Status;
|
||||
distanceTo @2: Float32;
|
||||
endRoadPointDEPRECATED @3: ECEFPointDEPRECATED;
|
||||
endRoadPoint @4: ECEFPoint;
|
||||
|
||||
enum Type @0xe8db07dcf8fcea05 {
|
||||
none @0;
|
||||
laneChangeLeft @1;
|
||||
laneChangeRight @2;
|
||||
mergeLeft @3;
|
||||
mergeRight @4;
|
||||
turnLeft @5;
|
||||
turnRight @6;
|
||||
}
|
||||
|
||||
enum Status @0xb9aa88c75ef99a1f {
|
||||
none @0;
|
||||
passive @1;
|
||||
approaching @2;
|
||||
active @3;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveLocationData @0xb99b2bc7a57e8128 {
|
||||
status @0 :UInt8;
|
||||
|
||||
# 3D fix
|
||||
lat @1 :Float64;
|
||||
lon @2 :Float64;
|
||||
alt @3 :Float32; # m
|
||||
|
||||
# speed
|
||||
speed @4 :Float32; # m/s
|
||||
|
||||
# NED velocity components
|
||||
vNED @5 :List(Float32);
|
||||
|
||||
# roll, pitch, heading (x,y,z)
|
||||
roll @6 :Float32; # WRT to center of earth?
|
||||
pitch @7 :Float32; # WRT to center of earth?
|
||||
heading @8 :Float32; # WRT to north?
|
||||
|
||||
# what are these?
|
||||
wanderAngle @9 :Float32;
|
||||
trackAngle @10 :Float32;
|
||||
|
||||
# car frame -- https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png
|
||||
|
||||
# gyro, in car frame, deg/s
|
||||
gyro @11 :List(Float32);
|
||||
|
||||
# accel, in car frame, m/s^2
|
||||
accel @12 :List(Float32);
|
||||
|
||||
accuracy @13 :Accuracy;
|
||||
|
||||
source @14 :SensorSource;
|
||||
# if we are fixing a location in the past
|
||||
fixMonoTime @15 :UInt64;
|
||||
|
||||
gpsWeek @16 :Int32;
|
||||
timeOfWeek @17 :Float64;
|
||||
|
||||
positionECEF @18 :List(Float64);
|
||||
poseQuatECEF @19 :List(Float32);
|
||||
pitchCalibration @20 :Float32;
|
||||
yawCalibration @21 :Float32;
|
||||
imuFrame @22 :List(Float32);
|
||||
|
||||
struct Accuracy @0x943dc4625473b03f {
|
||||
pNEDError @0 :List(Float32);
|
||||
vNEDError @1 :List(Float32);
|
||||
rollError @2 :Float32;
|
||||
pitchError @3 :Float32;
|
||||
headingError @4 :Float32;
|
||||
ellipsoidSemiMajorError @5 :Float32;
|
||||
ellipsoidSemiMinorError @6 :Float32;
|
||||
ellipsoidOrientationError @7 :Float32;
|
||||
}
|
||||
|
||||
enum SensorSource @0xc871d3cc252af657 {
|
||||
applanix @0;
|
||||
kalman @1;
|
||||
orbslam @2;
|
||||
timing @3;
|
||||
dummy @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct OrbOdometry @0xd7700859ed1f5b76 {
|
||||
# timing first
|
||||
startMonoTime @0 :UInt64;
|
||||
endMonoTime @1 :UInt64;
|
||||
|
||||
# fundamental matrix and error
|
||||
f @2: List(Float64);
|
||||
err @3: Float64;
|
||||
|
||||
# number of inlier points
|
||||
inliers @4: Int32;
|
||||
|
||||
# for debug only
|
||||
# indexed by endMonoTime features
|
||||
# value is startMonoTime feature match
|
||||
# -1 if no match
|
||||
matches @5: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeatures @0xcd60164a8a0159ef {
|
||||
timestampEof @0 :UInt64;
|
||||
# transposed arrays of normalized image coordinates
|
||||
# len(xs) == len(ys) == len(descriptors) * 32
|
||||
xs @1 :List(Float32);
|
||||
ys @2 :List(Float32);
|
||||
descriptors @3 :Data;
|
||||
octaves @4 :List(Int8);
|
||||
|
||||
# match index to last OrbFeatures
|
||||
# -1 if no match
|
||||
timestampLastEof @5 :UInt64;
|
||||
matches @6: List(Int16);
|
||||
}
|
||||
|
||||
struct OrbFeaturesSummary @0xd500d30c5803fa4f {
|
||||
timestampEof @0 :UInt64;
|
||||
timestampLastEof @1 :UInt64;
|
||||
|
||||
featureCount @2 :UInt16;
|
||||
matchCount @3 :UInt16;
|
||||
computeNs @4 :UInt64;
|
||||
}
|
||||
|
||||
struct OrbKeyFrame @0xc8233c0345e27e24 {
|
||||
# this is a globally unique id for the KeyFrame
|
||||
id @0: UInt64;
|
||||
|
||||
# this is the location of the KeyFrame
|
||||
pos @1: ECEFPoint;
|
||||
|
||||
# these are the features in the world
|
||||
# len(dpos) == len(descriptors) * 32
|
||||
dpos @2 :List(ECEFPoint);
|
||||
descriptors @3 :Data;
|
||||
}
|
||||
|
||||
struct KalmanOdometry @0x92e21bb7ea38793a {
|
||||
trans @0 :List(Float32); # m/s in device frame
|
||||
rot @1 :List(Float32); # rad/s in device frame
|
||||
transStd @2 :List(Float32); # std m/s in device frame
|
||||
rotStd @3 :List(Float32); # std rad/s in device frame
|
||||
}
|
||||
|
||||
struct OrbObservation @0x9b326d4e436afec7 {
|
||||
observationMonoTime @0 :UInt64;
|
||||
normalizedCoordinates @1 :List(Float32);
|
||||
locationECEF @2 :List(Float64);
|
||||
matchDistance @3: UInt32;
|
||||
}
|
||||
|
||||
struct CalibrationFeatures @0x8fdfadb254ea867a {
|
||||
frameId @0 :UInt32;
|
||||
|
||||
p0 @1 :List(Float32);
|
||||
p1 @2 :List(Float32);
|
||||
status @3 :List(Int8);
|
||||
}
|
||||
|
||||
struct NavStatus @0xbd8822120928120c {
|
||||
isNavigating @0 :Bool;
|
||||
currentAddress @1 :Address;
|
||||
|
||||
struct Address @0xce7cd672cacc7814 {
|
||||
title @0 :Text;
|
||||
lat @1 :Float64;
|
||||
lng @2 :Float64;
|
||||
house @3 :Text;
|
||||
address @4 :Text;
|
||||
street @5 :Text;
|
||||
city @6 :Text;
|
||||
state @7 :Text;
|
||||
country @8 :Text;
|
||||
}
|
||||
}
|
||||
|
||||
struct NavUpdate @0xdb98be6565516acb {
|
||||
isNavigating @0 :Bool;
|
||||
curSegment @1 :Int32;
|
||||
segments @2 :List(Segment);
|
||||
|
||||
struct LatLng @0x9eaef9187cadbb9b {
|
||||
lat @0 :Float64;
|
||||
lng @1 :Float64;
|
||||
}
|
||||
|
||||
struct Segment @0xa5b39b4fc4d7da3f {
|
||||
from @0 :LatLng;
|
||||
to @1 :LatLng;
|
||||
updateTime @2 :Int32;
|
||||
distance @3 :Int32;
|
||||
crossTime @4 :Int32;
|
||||
exitNo @5 :Int32;
|
||||
instruction @6 :Instruction;
|
||||
|
||||
parts @7 :List(LatLng);
|
||||
|
||||
enum Instruction @0xc5417a637451246f {
|
||||
turnLeft @0;
|
||||
turnRight @1;
|
||||
keepLeft @2;
|
||||
keepRight @3;
|
||||
straight @4;
|
||||
roundaboutExitNumber @5;
|
||||
roundaboutExit @6;
|
||||
roundaboutTurnLeft @7;
|
||||
unkn8 @8;
|
||||
roundaboutStraight @9;
|
||||
unkn10 @10;
|
||||
roundaboutTurnRight @11;
|
||||
unkn12 @12;
|
||||
roundaboutUturn @13;
|
||||
unkn14 @14;
|
||||
arrive @15;
|
||||
exitLeft @16;
|
||||
exitRight @17;
|
||||
unkn18 @18;
|
||||
uturn @19;
|
||||
# ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TrafficEvent @0xacfa74a094e62626 {
|
||||
type @0 :Type;
|
||||
distance @1 :Float32;
|
||||
action @2 :Action;
|
||||
resuming @3 :Bool;
|
||||
|
||||
enum Type @0xd85d75253435bf4b {
|
||||
stopSign @0;
|
||||
lightRed @1;
|
||||
lightYellow @2;
|
||||
lightGreen @3;
|
||||
stopLight @4;
|
||||
}
|
||||
|
||||
enum Action @0xa6f6ce72165ccb49 {
|
||||
none @0;
|
||||
yield @1;
|
||||
stop @2;
|
||||
resumeReady @3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct AndroidGnss @0xdfdf30d03fc485bd {
|
||||
union {
|
||||
measurements @0 :Measurements;
|
||||
navigationMessage @1 :NavigationMessage;
|
||||
}
|
||||
|
||||
struct Measurements @0xa20710d4f428d6cd {
|
||||
clock @0 :Clock;
|
||||
measurements @1 :List(Measurement);
|
||||
|
||||
struct Clock @0xa0e27b453a38f450 {
|
||||
timeNanos @0 :Int64;
|
||||
hardwareClockDiscontinuityCount @1 :Int32;
|
||||
|
||||
hasTimeUncertaintyNanos @2 :Bool;
|
||||
timeUncertaintyNanos @3 :Float64;
|
||||
|
||||
hasLeapSecond @4 :Bool;
|
||||
leapSecond @5 :Int32;
|
||||
|
||||
hasFullBiasNanos @6 :Bool;
|
||||
fullBiasNanos @7 :Int64;
|
||||
|
||||
hasBiasNanos @8 :Bool;
|
||||
biasNanos @9 :Float64;
|
||||
|
||||
hasBiasUncertaintyNanos @10 :Bool;
|
||||
biasUncertaintyNanos @11 :Float64;
|
||||
|
||||
hasDriftNanosPerSecond @12 :Bool;
|
||||
driftNanosPerSecond @13 :Float64;
|
||||
|
||||
hasDriftUncertaintyNanosPerSecond @14 :Bool;
|
||||
driftUncertaintyNanosPerSecond @15 :Float64;
|
||||
}
|
||||
|
||||
struct Measurement @0xd949bf717d77614d {
|
||||
svId @0 :Int32;
|
||||
constellation @1 :Constellation;
|
||||
|
||||
timeOffsetNanos @2 :Float64;
|
||||
state @3 :Int32;
|
||||
receivedSvTimeNanos @4 :Int64;
|
||||
receivedSvTimeUncertaintyNanos @5 :Int64;
|
||||
cn0DbHz @6 :Float64;
|
||||
pseudorangeRateMetersPerSecond @7 :Float64;
|
||||
pseudorangeRateUncertaintyMetersPerSecond @8 :Float64;
|
||||
accumulatedDeltaRangeState @9 :Int32;
|
||||
accumulatedDeltaRangeMeters @10 :Float64;
|
||||
accumulatedDeltaRangeUncertaintyMeters @11 :Float64;
|
||||
|
||||
hasCarrierFrequencyHz @12 :Bool;
|
||||
carrierFrequencyHz @13 :Float32;
|
||||
hasCarrierCycles @14 :Bool;
|
||||
carrierCycles @15 :Int64;
|
||||
hasCarrierPhase @16 :Bool;
|
||||
carrierPhase @17 :Float64;
|
||||
hasCarrierPhaseUncertainty @18 :Bool;
|
||||
carrierPhaseUncertainty @19 :Float64;
|
||||
hasSnrInDb @20 :Bool;
|
||||
snrInDb @21 :Float64;
|
||||
|
||||
multipathIndicator @22 :MultipathIndicator;
|
||||
|
||||
enum Constellation @0x9ef1f3ff0deb5ffb {
|
||||
unknown @0;
|
||||
gps @1;
|
||||
sbas @2;
|
||||
glonass @3;
|
||||
qzss @4;
|
||||
beidou @5;
|
||||
galileo @6;
|
||||
}
|
||||
|
||||
enum State @0xcbb9490adce12d72 {
|
||||
unknown @0;
|
||||
codeLock @1;
|
||||
bitSync @2;
|
||||
subframeSync @3;
|
||||
towDecoded @4;
|
||||
msecAmbiguous @5;
|
||||
symbolSync @6;
|
||||
gloStringSync @7;
|
||||
gloTodDecoded @8;
|
||||
bdsD2BitSync @9;
|
||||
bdsD2SubframeSync @10;
|
||||
galE1bcCodeLock @11;
|
||||
galE1c2ndCodeLock @12;
|
||||
galE1bPageSync @13;
|
||||
sbasSync @14;
|
||||
}
|
||||
|
||||
enum MultipathIndicator @0xc04e7b6231d4caa8 {
|
||||
unknown @0;
|
||||
detected @1;
|
||||
notDetected @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NavigationMessage @0xe2517b083095fd4e {
|
||||
type @0 :Int32;
|
||||
svId @1 :Int32;
|
||||
messageId @2 :Int32;
|
||||
submessageId @3 :Int32;
|
||||
data @4 :Data;
|
||||
status @5 :Status;
|
||||
|
||||
enum Status @0xec1ff7996b35366f {
|
||||
unknown @0;
|
||||
parityPassed @1;
|
||||
parityRebuilt @2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LidarPts @0xe3d6685d4e9d8f7a {
|
||||
r @0 :List(UInt16); # uint16 m*500.0
|
||||
theta @1 :List(UInt16); # uint16 deg*100.0
|
||||
reflect @2 :List(UInt8); # uint8 0-255
|
||||
|
||||
# For storing out of file.
|
||||
idx @3 :UInt64;
|
||||
|
||||
# For storing in file
|
||||
pkt @4 :Data;
|
||||
}
|
||||
|
||||
|
||||
+136
-60
@@ -2,7 +2,7 @@ using Cxx = import "./include/c++.capnp";
|
||||
$Cxx.namespace("cereal");
|
||||
|
||||
using Car = import "car.capnp";
|
||||
using Legacy = import "legacy.capnp";
|
||||
using Deprecated = import "deprecated.capnp";
|
||||
using Custom = import "custom.capnp";
|
||||
|
||||
@0xf3b1f17e25a4285b;
|
||||
@@ -48,6 +48,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
preEnableStandstill @12; # added during pre-enable state with brake
|
||||
gasPressedOverride @13; # added when user is pressing gas with no disengage on gas
|
||||
steerOverride @14;
|
||||
steerDisengage @94; # exits active state
|
||||
cruiseDisabled @15;
|
||||
speedTooLow @16;
|
||||
outOfSpace @17;
|
||||
@@ -67,12 +68,12 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
longitudinalManeuver @30;
|
||||
steerTempUnavailableSilent @31;
|
||||
resumeRequired @32;
|
||||
preDriverDistracted @33;
|
||||
promptDriverDistracted @34;
|
||||
driverDistracted @35;
|
||||
preDriverUnresponsive @36;
|
||||
promptDriverUnresponsive @37;
|
||||
driverUnresponsive @38;
|
||||
driverDistracted1 @33;
|
||||
driverDistracted2 @34;
|
||||
driverDistracted3 @35;
|
||||
driverUnresponsive1 @36;
|
||||
driverUnresponsive2 @37;
|
||||
driverUnresponsive3 @38;
|
||||
belowSteerSpeed @39;
|
||||
lowBattery @40;
|
||||
accFaulted @41;
|
||||
@@ -86,6 +87,8 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
laneChange @50;
|
||||
lowMemory @51;
|
||||
stockAeb @52;
|
||||
stockLkas @98;
|
||||
lateralManeuver @99;
|
||||
ldw @53;
|
||||
carUnrecognized @54;
|
||||
invalidLkasSetting @55;
|
||||
@@ -126,6 +129,9 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
espActive @90;
|
||||
personalityChanged @91;
|
||||
aeb @92;
|
||||
userBookmark @95;
|
||||
excessiveActuation @96;
|
||||
audioFeedback @97;
|
||||
|
||||
soundsUnavailableDEPRECATED @47;
|
||||
}
|
||||
@@ -488,13 +494,14 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
||||
# device thermals
|
||||
cpuTempC @26 :List(Float32);
|
||||
gpuTempC @27 :List(Float32);
|
||||
dspTempC @49 :Float32;
|
||||
memoryTempC @28 :Float32;
|
||||
nvmeTempC @35 :List(Float32);
|
||||
modemTempC @36 :List(Float32);
|
||||
pmicTempC @39 :List(Float32);
|
||||
intakeTempC @46 :Float32;
|
||||
exhaustTempC @47 :Float32;
|
||||
caseTempC @48 :Float32;
|
||||
gnssTempC @48 :Float32;
|
||||
bottomSocTempC @50 :Float32;
|
||||
maxTempC @44 :Float32; # max of other temps, used to control fan
|
||||
thermalZones @38 :List(ThermalZone);
|
||||
thermalStatus @14 :ThermalStatus;
|
||||
@@ -565,6 +572,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
|
||||
chargingDisabledDEPRECATED @18 :Bool;
|
||||
usbOnlineDEPRECATED @12 :Bool;
|
||||
ambientTempCDEPRECATED @30 :Float32;
|
||||
nvmeTempCDEPRECATED @35 :List(Float32);
|
||||
}
|
||||
|
||||
struct PandaState @0xa7649e2575e4591e {
|
||||
@@ -580,13 +588,13 @@ struct PandaState @0xa7649e2575e4591e {
|
||||
heartbeatLost @22 :Bool;
|
||||
interruptLoad @25 :Float32;
|
||||
fanPower @28 :UInt8;
|
||||
fanStallCount @34 :UInt8;
|
||||
|
||||
spiChecksumErrorCount @33 :UInt16;
|
||||
spiErrorCount @33 :UInt16;
|
||||
|
||||
harnessStatus @21 :HarnessStatus;
|
||||
sbu1Voltage @35 :Float32;
|
||||
sbu2Voltage @36 :Float32;
|
||||
soundOutputLevel @37 :UInt16;
|
||||
|
||||
# can health
|
||||
canState0 @29 :PandaCanState;
|
||||
@@ -605,6 +613,11 @@ struct PandaState @0xa7649e2575e4591e {
|
||||
voltage @0 :UInt32;
|
||||
current @1 :UInt32;
|
||||
|
||||
# these fields are not used by openpilot, but they're
|
||||
# reserved for forks building alternate experiences.
|
||||
controlsAllowedRESERVED1 @38 :Bool;
|
||||
controlsAllowedRESERVED2 @39 :Bool;
|
||||
|
||||
enum FaultStatus {
|
||||
none @0;
|
||||
faultTemp @1;
|
||||
@@ -709,6 +722,7 @@ struct PandaState @0xa7649e2575e4591e {
|
||||
usbPowerModeDEPRECATED @12 :PeripheralState.UsbPowerModeDEPRECATED;
|
||||
safetyParamDEPRECATED @20 :Int16;
|
||||
safetyParam2DEPRECATED @26 :UInt32;
|
||||
fanStallCountDEPRECATED @34 :UInt8;
|
||||
}
|
||||
|
||||
struct PeripheralState {
|
||||
@@ -913,6 +927,8 @@ struct ControlsState @0x97ff69c53601abf1 {
|
||||
saturated @7 :Bool;
|
||||
actualLateralAccel @9 :Float32;
|
||||
desiredLateralAccel @10 :Float32;
|
||||
desiredLateralJerk @11 :Float32;
|
||||
version @12 :Int32;
|
||||
}
|
||||
|
||||
struct LateralLQRState {
|
||||
@@ -1080,7 +1096,7 @@ struct ModelDataV2 {
|
||||
confidence @23: ConfidenceClass;
|
||||
|
||||
# Model perceived motion
|
||||
temporalPose @21 :Pose;
|
||||
temporalPoseDEPRECATED @21 :Pose;
|
||||
|
||||
# e2e lateral planner
|
||||
action @26: Action;
|
||||
@@ -1174,6 +1190,8 @@ struct ModelDataV2 {
|
||||
|
||||
struct Action {
|
||||
desiredCurvature @0 :Float32;
|
||||
desiredAcceleration @1 :Float32;
|
||||
shouldStop @2 :Bool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1229,6 +1247,10 @@ struct DriverAssistance {
|
||||
# FCW, AEB, etc. will go here
|
||||
}
|
||||
|
||||
struct LateralManeuverPlan {
|
||||
desiredCurvature @0 :Float32; # 1/m
|
||||
}
|
||||
|
||||
struct LongitudinalPlan @0xe00b5b3eba12876c {
|
||||
modelMonoTime @9 :UInt64;
|
||||
hasLead @7 :Bool;
|
||||
@@ -1414,6 +1436,8 @@ struct LivePose {
|
||||
posenetOK @5 :Bool = false;
|
||||
sensorsOK @6 :Bool = false;
|
||||
|
||||
timestamp @8 :UInt64;
|
||||
|
||||
debugFilterState @7 :FilterState;
|
||||
|
||||
struct XYZMeasurement {
|
||||
@@ -1468,6 +1492,11 @@ struct ProcLog {
|
||||
|
||||
cmdline @15 :List(Text);
|
||||
exe @16 :Text;
|
||||
|
||||
# from /proc/<pid>/smaps_rollup (proportional/private memory)
|
||||
memPss @17 :UInt64; # Pss — shared pages split by mapper count
|
||||
memPssAnon @18 :UInt64; # Pss_Anon — private anonymous (heap, stack)
|
||||
memPssShmem @19 :UInt64; # Pss_Shmem — proportional MSGQ/tmpfs share
|
||||
}
|
||||
|
||||
struct CPUTimes {
|
||||
@@ -1586,6 +1615,10 @@ struct UbloxGnss {
|
||||
svId @0 :UInt8;
|
||||
gnssId @1 :UInt8;
|
||||
flagsBitfield @2 :UInt32;
|
||||
cno @3 :UInt8;
|
||||
elevationDeg @4 :Int8;
|
||||
azimuthDeg @5 :Int16;
|
||||
pseudorangeResidual @6 :Float32;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2135,13 +2168,10 @@ struct Joystick {
|
||||
struct DriverStateV2 {
|
||||
frameId @0 :UInt32;
|
||||
modelExecutionTime @1 :Float32;
|
||||
dspExecutionTimeDEPRECATED @2 :Float32;
|
||||
gpuExecutionTime @8 :Float32;
|
||||
rawPredictions @3 :Data;
|
||||
|
||||
poorVisionProb @4 :Float32;
|
||||
wheelOnRightProb @5 :Float32;
|
||||
|
||||
leftDriverData @6 :DriverData;
|
||||
rightDriverData @7 :DriverData;
|
||||
|
||||
@@ -2151,15 +2181,21 @@ struct DriverStateV2 {
|
||||
facePosition @2 :List(Float32);
|
||||
facePositionStd @3 :List(Float32);
|
||||
faceProb @4 :Float32;
|
||||
leftEyeProb @5 :Float32;
|
||||
rightEyeProb @6 :Float32;
|
||||
leftBlinkProb @7 :Float32;
|
||||
rightBlinkProb @8 :Float32;
|
||||
sunglassesProb @9 :Float32;
|
||||
occludedProb @10 :Float32;
|
||||
readyProb @11 :List(Float32);
|
||||
notReadyProb @12 :List(Float32);
|
||||
eyesVisibleProb @14 :Float32;
|
||||
eyesClosedProb @15 :Float32;
|
||||
phoneProb @13 :Float32;
|
||||
leftEyeProbDEPRECATED @5 :Float32;
|
||||
rightEyeProbDEPRECATED @6 :Float32;
|
||||
leftBlinkProbDEPRECATED @7 :Float32;
|
||||
rightBlinkProbDEPRECATED @8 :Float32;
|
||||
sunglassesProbDEPRECATED @9 :Float32;
|
||||
notReadyProbDEPRECATED @12 :List(Float32);
|
||||
occludedProbDEPRECATED @10 :Float32;
|
||||
readyProbDEPRECATED @11 :List(Float32);
|
||||
}
|
||||
|
||||
dspExecutionTimeDEPRECATED @2 :Float32;
|
||||
poorVisionProbDEPRECATED @4 :Float32;
|
||||
}
|
||||
|
||||
struct DriverStateDEPRECATED @0xb83c6cc593ed0a00 {
|
||||
@@ -2211,7 +2247,10 @@ struct DriverMonitoringState @0xb83cda094a1da284 {
|
||||
hiStdCount @14 :UInt32;
|
||||
isActiveMode @16 :Bool;
|
||||
isRHD @4 :Bool;
|
||||
uncertainCount @19 :UInt32;
|
||||
|
||||
phoneProbOffsetDEPRECATED @20 :Float32;
|
||||
phoneProbValidCountDEPRECATED @21 :UInt32;
|
||||
isPreviewDEPRECATED @15 :Bool;
|
||||
rhdCheckedDEPRECATED @5 :Bool;
|
||||
eventsDEPRECATED @0 :List(Car.OnroadEventDEPRECATED);
|
||||
@@ -2272,6 +2311,24 @@ struct LiveTorqueParametersData {
|
||||
points @10 :List(List(Float32));
|
||||
version @11 :Int32;
|
||||
useParams @12 :Bool;
|
||||
calPerc @13 :Int8;
|
||||
}
|
||||
|
||||
struct LiveDelayData {
|
||||
lateralDelay @0 :Float32;
|
||||
validBlocks @1 :Int32;
|
||||
status @2 :Status;
|
||||
|
||||
lateralDelayEstimate @3 :Float32;
|
||||
lateralDelayEstimateStd @5 :Float32;
|
||||
points @4 :List(Float32);
|
||||
calPerc @6 :Int8;
|
||||
|
||||
enum Status {
|
||||
unestimated @0;
|
||||
estimated @1;
|
||||
invalid @2;
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveMapDataDEPRECATED {
|
||||
@@ -2440,16 +2497,27 @@ struct DebugAlert {
|
||||
alertText2 @1 :Text;
|
||||
}
|
||||
|
||||
struct UserFlag {
|
||||
struct UserBookmark @0xfe346a9de48d9b50 {
|
||||
}
|
||||
|
||||
struct Microphone {
|
||||
struct SoundPressure @0xdc24138990726023 {
|
||||
soundPressure @0 :Float32;
|
||||
|
||||
# uncalibrated, A-weighted
|
||||
soundPressureWeighted @3 :Float32;
|
||||
soundPressureWeightedDb @1 :Float32;
|
||||
filteredSoundPressureWeightedDb @2 :Float32;
|
||||
|
||||
filteredSoundPressureWeightedDbDEPRECATED @2 :Float32;
|
||||
}
|
||||
|
||||
struct AudioData {
|
||||
data @0 :Data;
|
||||
sampleRate @1 :UInt32;
|
||||
}
|
||||
|
||||
struct AudioFeedback {
|
||||
audio @0 :AudioData;
|
||||
blockNum @1 :UInt16;
|
||||
}
|
||||
|
||||
struct Touch {
|
||||
@@ -2478,13 +2546,10 @@ struct Event {
|
||||
controlsState @7 :ControlsState;
|
||||
selfdriveState @130 :SelfdriveState;
|
||||
gyroscope @99 :SensorEventData;
|
||||
gyroscope2 @100 :SensorEventData;
|
||||
accelerometer @98 :SensorEventData;
|
||||
accelerometer2 @101 :SensorEventData;
|
||||
magnetometer @95 :SensorEventData;
|
||||
lightSensor @96 :SensorEventData;
|
||||
temperatureSensor @97 :SensorEventData;
|
||||
temperatureSensor2 @123 :SensorEventData;
|
||||
pandaStates @81 :List(PandaState);
|
||||
peripheralState @80 :PeripheralState;
|
||||
radarState @13 :RadarState;
|
||||
@@ -2504,6 +2569,7 @@ struct Event {
|
||||
gnssMeasurements @91 :GnssMeasurements;
|
||||
liveParameters @61 :LiveParametersData;
|
||||
liveTorqueParameters @94 :LiveTorqueParametersData;
|
||||
liveDelay @146 : LiveDelayData;
|
||||
cameraOdometry @63 :CameraOdometry;
|
||||
thumbnail @66: Thumbnail;
|
||||
onroadEvents @134: List(OnroadEvent);
|
||||
@@ -2528,7 +2594,8 @@ struct Event {
|
||||
livestreamDriverEncodeIdx @119 :EncodeIndex;
|
||||
|
||||
# microphone data
|
||||
microphone @103 :Microphone;
|
||||
soundPressure @103 :SoundPressure;
|
||||
rawAudioData @147 :AudioData;
|
||||
|
||||
# systems stuff
|
||||
androidLog @20 :AndroidLogEntry;
|
||||
@@ -2550,9 +2617,15 @@ struct Event {
|
||||
mapRenderState @105: MapRenderState;
|
||||
|
||||
# UI services
|
||||
userFlag @93 :UserFlag;
|
||||
uiDebug @102 :UIDebug;
|
||||
|
||||
# driving feedback
|
||||
userBookmark @93 :UserBookmark;
|
||||
bookmarkButton @148 :UserBookmark;
|
||||
audioFeedback @149 :AudioFeedback;
|
||||
|
||||
lateralManeuverPlan @150 :LateralManeuverPlan;
|
||||
|
||||
# *********** debug ***********
|
||||
testJoystick @52 :Joystick;
|
||||
roadEncodeData @86 :EncodeData;
|
||||
@@ -2598,40 +2671,40 @@ struct Event {
|
||||
customReserved19 @145 :Custom.CustomReserved19;
|
||||
|
||||
# *********** legacy + deprecated ***********
|
||||
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
||||
model @9 :Deprecated.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
||||
liveMpcDEPRECATED @36 :LiveMpcData;
|
||||
liveLongitudinalMpcDEPRECATED @37 :LiveLongitudinalMpcData;
|
||||
liveLocationKalmanLegacyDEPRECATED @51 :Legacy.LiveLocationData;
|
||||
orbslamCorrectionDEPRECATED @45 :Legacy.OrbslamCorrection;
|
||||
liveUIDEPRECATED @14 :Legacy.LiveUI;
|
||||
liveLocationKalmanDeprecatedDEPRECATED @51 :Deprecated.LiveLocationData;
|
||||
orbslamCorrectionDEPRECATED @45 :Deprecated.OrbslamCorrection;
|
||||
liveUIDEPRECATED @14 :Deprecated.LiveUI;
|
||||
sensorEventDEPRECATED @4 :SensorEventData;
|
||||
liveEventDEPRECATED @8 :List(Legacy.LiveEventData);
|
||||
liveLocationDEPRECATED @25 :Legacy.LiveLocationData;
|
||||
ethernetDataDEPRECATED @26 :List(Legacy.EthernetPacket);
|
||||
cellInfoDEPRECATED @28 :List(Legacy.CellInfo);
|
||||
wifiScanDEPRECATED @29 :List(Legacy.WifiScan);
|
||||
uiNavigationEventDEPRECATED @50 :Legacy.UiNavigationEvent;
|
||||
liveEventDEPRECATED @8 :List(Deprecated.LiveEventData);
|
||||
liveLocationDEPRECATED @25 :Deprecated.LiveLocationData;
|
||||
ethernetDataDEPRECATED @26 :List(Deprecated.EthernetPacket);
|
||||
cellInfoDEPRECATED @28 :List(Deprecated.CellInfo);
|
||||
wifiScanDEPRECATED @29 :List(Deprecated.WifiScan);
|
||||
uiNavigationEventDEPRECATED @50 :Deprecated.UiNavigationEvent;
|
||||
liveMapDataDEPRECATED @62 :LiveMapDataDEPRECATED;
|
||||
gpsPlannerPointsDEPRECATED @40 :Legacy.GPSPlannerPoints;
|
||||
gpsPlannerPlanDEPRECATED @41 :Legacy.GPSPlannerPlan;
|
||||
gpsPlannerPointsDEPRECATED @40 :Deprecated.GPSPlannerPoints;
|
||||
gpsPlannerPlanDEPRECATED @41 :Deprecated.GPSPlannerPlan;
|
||||
applanixRawDEPRECATED @42 :Data;
|
||||
androidGnssDEPRECATED @30 :Legacy.AndroidGnss;
|
||||
lidarPtsDEPRECATED @32 :Legacy.LidarPts;
|
||||
navStatusDEPRECATED @38 :Legacy.NavStatus;
|
||||
trafficEventsDEPRECATED @43 :List(Legacy.TrafficEvent);
|
||||
liveLocationTimingDEPRECATED @44 :Legacy.LiveLocationData;
|
||||
liveLocationCorrectedDEPRECATED @46 :Legacy.LiveLocationData;
|
||||
navUpdateDEPRECATED @27 :Legacy.NavUpdate;
|
||||
orbObservationDEPRECATED @47 :List(Legacy.OrbObservation);
|
||||
locationDEPRECATED @49 :Legacy.LiveLocationData;
|
||||
orbOdometryDEPRECATED @53 :Legacy.OrbOdometry;
|
||||
orbFeaturesDEPRECATED @54 :Legacy.OrbFeatures;
|
||||
applanixLocationDEPRECATED @55 :Legacy.LiveLocationData;
|
||||
orbKeyFrameDEPRECATED @56 :Legacy.OrbKeyFrame;
|
||||
orbFeaturesSummaryDEPRECATED @58 :Legacy.OrbFeaturesSummary;
|
||||
featuresDEPRECATED @10 :Legacy.CalibrationFeatures;
|
||||
kalmanOdometryDEPRECATED @65 :Legacy.KalmanOdometry;
|
||||
uiLayoutStateDEPRECATED @57 :Legacy.UiLayoutState;
|
||||
androidGnssDEPRECATED @30 :Deprecated.AndroidGnss;
|
||||
lidarPtsDEPRECATED @32 :Deprecated.LidarPts;
|
||||
navStatusDEPRECATED @38 :Deprecated.NavStatus;
|
||||
trafficEventsDEPRECATED @43 :List(Deprecated.TrafficEvent);
|
||||
liveLocationTimingDEPRECATED @44 :Deprecated.LiveLocationData;
|
||||
liveLocationCorrectedDEPRECATED @46 :Deprecated.LiveLocationData;
|
||||
navUpdateDEPRECATED @27 :Deprecated.NavUpdate;
|
||||
orbObservationDEPRECATED @47 :List(Deprecated.OrbObservation);
|
||||
locationDEPRECATED @49 :Deprecated.LiveLocationData;
|
||||
orbOdometryDEPRECATED @53 :Deprecated.OrbOdometry;
|
||||
orbFeaturesDEPRECATED @54 :Deprecated.OrbFeatures;
|
||||
applanixLocationDEPRECATED @55 :Deprecated.LiveLocationData;
|
||||
orbKeyFrameDEPRECATED @56 :Deprecated.OrbKeyFrame;
|
||||
orbFeaturesSummaryDEPRECATED @58 :Deprecated.OrbFeaturesSummary;
|
||||
featuresDEPRECATED @10 :Deprecated.CalibrationFeatures;
|
||||
kalmanOdometryDEPRECATED @65 :Deprecated.KalmanOdometry;
|
||||
uiLayoutStateDEPRECATED @57 :Deprecated.UiLayoutState;
|
||||
pandaStateDEPRECATED @12 :PandaState;
|
||||
driverStateDEPRECATED @59 :DriverStateDEPRECATED;
|
||||
sensorEventsDEPRECATED @11 :List(SensorEventData);
|
||||
@@ -2641,5 +2714,8 @@ struct Event {
|
||||
liveLocationKalmanDEPRECATED @72 :LiveLocationKalman;
|
||||
liveTracksDEPRECATED @16 :List(LiveTracksDEPRECATED);
|
||||
onroadEventsDEPRECATED @68: List(Car.OnroadEventDEPRECATED);
|
||||
gyroscope2DEPRECATED @100 :SensorEventData;
|
||||
accelerometer2DEPRECATED @101 :SensorEventData;
|
||||
temperatureSensor2DEPRECATED @123 :SensorEventData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# must be built with scons
|
||||
from msgq.ipc_pyx import Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
|
||||
set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
|
||||
from msgq.ipc_pyx import MultiplePublishersError, IpcError
|
||||
from msgq import fake_event_handle, pub_sock, sub_sock, drain_sock_raw
|
||||
from msgq import fake_event_handle, drain_sock_raw, MultiplePublishersError, IpcError, \
|
||||
Context, Poller, SubSocket, PubSocket, SocketEventHandle, toggle_fake_events, \
|
||||
set_fake_prefix, get_fake_prefix, delete_fake_prefix, wait_for_one_event
|
||||
import msgq
|
||||
|
||||
import os
|
||||
import capnp
|
||||
import time
|
||||
@@ -13,11 +11,25 @@ from typing import Optional, List, Union, Dict
|
||||
|
||||
from cereal import log
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.util import MovingAverage
|
||||
from openpilot.common.utils import MovingAverage
|
||||
|
||||
NO_TRAVERSAL_LIMIT = 2**64-1
|
||||
|
||||
|
||||
def pub_sock(endpoint: str) -> PubSocket:
|
||||
service = SERVICE_LIST.get(endpoint)
|
||||
segment_size = service.queue_size if service else 0
|
||||
return msgq.pub_sock(endpoint, segment_size)
|
||||
|
||||
|
||||
def sub_sock(endpoint: str, poller: Optional[Poller] = None, addr: str = "127.0.0.1",
|
||||
conflate: bool = False, timeout: Optional[int] = None) -> SubSocket:
|
||||
service = SERVICE_LIST.get(endpoint)
|
||||
segment_size = service.queue_size if service else 0
|
||||
return msgq.sub_sock(endpoint, poller=poller, addr=addr, conflate=conflate,
|
||||
timeout=timeout, segment_size=segment_size)
|
||||
|
||||
|
||||
def reset_context():
|
||||
msgq.context = Context()
|
||||
|
||||
@@ -145,12 +157,16 @@ class SubMaster:
|
||||
self.updated = {s: False for s in services}
|
||||
self.recv_time = {s: 0. for s in services}
|
||||
self.recv_frame = {s: 0 for s in services}
|
||||
self.alive = {s: False for s in services}
|
||||
self.freq_ok = {s: False for s in services}
|
||||
self.sock = {}
|
||||
self.data = {}
|
||||
self.valid = {}
|
||||
self.logMonoTime = {}
|
||||
self.logMonoTime = {s: 0 for s in services}
|
||||
|
||||
# zero-frequency / on-demand services are always alive and presumed valid; all others must pass checks
|
||||
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in services}
|
||||
self.static_freq_services = set(s for s in services if not on_demand[s])
|
||||
self.alive = {s: on_demand[s] for s in services}
|
||||
self.freq_ok = {s: on_demand[s] for s in services}
|
||||
self.valid = {s: on_demand[s] for s in services}
|
||||
|
||||
self.freq_tracker: Dict[str, FrequencyTracker] = {}
|
||||
self.poller = Poller()
|
||||
@@ -177,8 +193,6 @@ class SubMaster:
|
||||
data = new_message(s, 0) # lists
|
||||
|
||||
self.data[s] = getattr(data.as_reader(), s)
|
||||
self.logMonoTime[s] = 0
|
||||
self.valid[s] = False
|
||||
self.freq_tracker[s] = FrequencyTracker(SERVICE_LIST[s].frequency, self.update_freq, s == poll)
|
||||
|
||||
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
|
||||
@@ -215,14 +229,10 @@ class SubMaster:
|
||||
self.logMonoTime[s] = msg.logMonoTime
|
||||
self.valid[s] = msg.valid
|
||||
|
||||
for s in self.services:
|
||||
if SERVICE_LIST[s].frequency > 1e-5 and not self.simulation:
|
||||
# alive if delay is within 10x the expected frequency
|
||||
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency)
|
||||
self.freq_ok[s] = self.freq_tracker[s].valid
|
||||
else:
|
||||
self.freq_ok[s] = True
|
||||
self.alive[s] = self.seen[s] if self.simulation else True
|
||||
for s in self.static_freq_services:
|
||||
# alive if delay is within 10x the expected frequency; checks relaxed in simulator
|
||||
self.alive[s] = (cur_time - self.recv_time[s]) < (10. / SERVICE_LIST[s].frequency) or (self.seen[s] and self.simulation)
|
||||
self.freq_ok[s] = self.freq_tracker[s].valid or self.simulation
|
||||
|
||||
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
|
||||
return all(self.alive[s] for s in (service_list or self.services) if s not in self.ignore_alive)
|
||||
|
||||
Binary file not shown.
@@ -25,15 +25,16 @@ void msgq_to_zmq(const std::vector<std::string> &endpoints, const std::string &i
|
||||
}
|
||||
|
||||
void zmq_to_msgq(const std::vector<std::string> &endpoints, const std::string &ip) {
|
||||
auto poller = std::make_unique<ZMQPoller>();
|
||||
auto pub_context = std::make_unique<MSGQContext>();
|
||||
auto sub_context = std::make_unique<ZMQContext>();
|
||||
std::map<SubSocket *, PubSocket *> sub2pub;
|
||||
auto poller = std::make_unique<BridgeZmqPoller>();
|
||||
auto pub_context = std::make_unique<Context>();
|
||||
auto sub_context = std::make_unique<BridgeZmqContext>();
|
||||
std::map<BridgeZmqSubSocket *, PubSocket *> sub2pub;
|
||||
|
||||
for (auto endpoint : endpoints) {
|
||||
auto pub_sock = new MSGQPubSocket();
|
||||
auto sub_sock = new ZMQSubSocket();
|
||||
pub_sock->connect(pub_context.get(), endpoint);
|
||||
auto pub_sock = new PubSocket();
|
||||
auto sub_sock = new BridgeZmqSubSocket();
|
||||
size_t queue_size = services.at(endpoint).queue_size;
|
||||
pub_sock->connect(pub_context.get(), endpoint, true, queue_size);
|
||||
sub_sock->connect(sub_context.get(), endpoint, ip, false);
|
||||
|
||||
poller->registerSocket(sub_sock);
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#include "cereal/messaging/bridge_zmq.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
|
||||
static size_t fnv1a_hash(const std::string &str) {
|
||||
const size_t fnv_prime = 0x100000001b3;
|
||||
size_t hash_value = 0xcbf29ce484222325;
|
||||
for (char c : str) {
|
||||
hash_value ^= (unsigned char)c;
|
||||
hash_value *= fnv_prime;
|
||||
}
|
||||
return hash_value;
|
||||
}
|
||||
|
||||
// FIXME: This is a hack to get the port number from the socket name, might have collisions.
|
||||
static int get_port(std::string endpoint) {
|
||||
size_t hash_value = fnv1a_hash(endpoint);
|
||||
int start_port = 8023;
|
||||
int max_port = 65535;
|
||||
return start_port + (hash_value % (max_port - start_port));
|
||||
}
|
||||
|
||||
BridgeZmqContext::BridgeZmqContext() {
|
||||
context = zmq_ctx_new();
|
||||
}
|
||||
|
||||
BridgeZmqContext::~BridgeZmqContext() {
|
||||
if (context != nullptr) {
|
||||
zmq_ctx_term(context);
|
||||
}
|
||||
}
|
||||
|
||||
void BridgeZmqMessage::init(size_t sz) {
|
||||
size = sz;
|
||||
data = new char[size];
|
||||
}
|
||||
|
||||
void BridgeZmqMessage::init(char *d, size_t sz) {
|
||||
size = sz;
|
||||
data = new char[size];
|
||||
memcpy(data, d, size);
|
||||
}
|
||||
|
||||
void BridgeZmqMessage::close() {
|
||||
if (size > 0) {
|
||||
delete[] data;
|
||||
}
|
||||
data = nullptr;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
BridgeZmqMessage::~BridgeZmqMessage() {
|
||||
close();
|
||||
}
|
||||
|
||||
int BridgeZmqSubSocket::connect(BridgeZmqContext *context, std::string endpoint, std::string address, bool conflate, bool check_endpoint) {
|
||||
sock = zmq_socket(context->getRawContext(), ZMQ_SUB);
|
||||
if (sock == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0);
|
||||
|
||||
if (conflate) {
|
||||
int arg = 1;
|
||||
zmq_setsockopt(sock, ZMQ_CONFLATE, &arg, sizeof(int));
|
||||
}
|
||||
|
||||
int reconnect_ivl = 500;
|
||||
zmq_setsockopt(sock, ZMQ_RECONNECT_IVL_MAX, &reconnect_ivl, sizeof(reconnect_ivl));
|
||||
|
||||
full_endpoint = "tcp://" + address + ":";
|
||||
if (check_endpoint) {
|
||||
full_endpoint += std::to_string(get_port(endpoint));
|
||||
} else {
|
||||
full_endpoint += endpoint;
|
||||
}
|
||||
|
||||
return zmq_connect(sock, full_endpoint.c_str());
|
||||
}
|
||||
|
||||
void BridgeZmqSubSocket::setTimeout(int timeout) {
|
||||
zmq_setsockopt(sock, ZMQ_RCVTIMEO, &timeout, sizeof(int));
|
||||
}
|
||||
|
||||
Message *BridgeZmqSubSocket::receive(bool non_blocking) {
|
||||
zmq_msg_t msg;
|
||||
assert(zmq_msg_init(&msg) == 0);
|
||||
|
||||
int flags = non_blocking ? ZMQ_DONTWAIT : 0;
|
||||
int rc = zmq_msg_recv(&msg, sock, flags);
|
||||
|
||||
Message *ret = nullptr;
|
||||
if (rc >= 0) {
|
||||
ret = new BridgeZmqMessage;
|
||||
ret->init((char *)zmq_msg_data(&msg), zmq_msg_size(&msg));
|
||||
}
|
||||
|
||||
zmq_msg_close(&msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BridgeZmqSubSocket::~BridgeZmqSubSocket() {
|
||||
if (sock != nullptr) {
|
||||
zmq_close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
int BridgeZmqPubSocket::connect(BridgeZmqContext *context, std::string endpoint, bool check_endpoint) {
|
||||
sock = zmq_socket(context->getRawContext(), ZMQ_PUB);
|
||||
if (sock == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
full_endpoint = "tcp://*:";
|
||||
if (check_endpoint) {
|
||||
full_endpoint += std::to_string(get_port(endpoint));
|
||||
} else {
|
||||
full_endpoint += endpoint;
|
||||
}
|
||||
|
||||
// ZMQ pub sockets cannot be shared between processes, so we need to ensure pid stays the same.
|
||||
pid = getpid();
|
||||
|
||||
return zmq_bind(sock, full_endpoint.c_str());
|
||||
}
|
||||
|
||||
int BridgeZmqPubSocket::sendMessage(Message *message) {
|
||||
assert(pid == getpid());
|
||||
return zmq_send(sock, message->getData(), message->getSize(), ZMQ_DONTWAIT);
|
||||
}
|
||||
|
||||
int BridgeZmqPubSocket::send(char *data, size_t size) {
|
||||
assert(pid == getpid());
|
||||
return zmq_send(sock, data, size, ZMQ_DONTWAIT);
|
||||
}
|
||||
|
||||
BridgeZmqPubSocket::~BridgeZmqPubSocket() {
|
||||
if (sock != nullptr) {
|
||||
zmq_close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void BridgeZmqPoller::registerSocket(BridgeZmqSubSocket *socket) {
|
||||
assert(num_polls + 1 < (sizeof(polls) / sizeof(polls[0])));
|
||||
polls[num_polls].socket = socket->getRawSocket();
|
||||
polls[num_polls].events = ZMQ_POLLIN;
|
||||
|
||||
sockets.push_back(socket);
|
||||
num_polls++;
|
||||
}
|
||||
|
||||
std::vector<BridgeZmqSubSocket *> BridgeZmqPoller::poll(int timeout) {
|
||||
std::vector<BridgeZmqSubSocket *> ret;
|
||||
|
||||
int rc = zmq_poll(polls, num_polls, timeout);
|
||||
if (rc < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_polls; i++) {
|
||||
if (polls[i].revents) {
|
||||
ret.push_back(sockets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
#include "msgq/ipc.h"
|
||||
|
||||
class BridgeZmqContext {
|
||||
public:
|
||||
BridgeZmqContext();
|
||||
void *getRawContext() { return context; }
|
||||
~BridgeZmqContext();
|
||||
|
||||
private:
|
||||
void *context = nullptr;
|
||||
};
|
||||
|
||||
class BridgeZmqMessage : public Message {
|
||||
public:
|
||||
void init(size_t size);
|
||||
void init(char *data, size_t size);
|
||||
void close();
|
||||
size_t getSize() { return size; }
|
||||
char *getData() { return data; }
|
||||
~BridgeZmqMessage();
|
||||
|
||||
private:
|
||||
char *data = nullptr;
|
||||
size_t size = 0;
|
||||
};
|
||||
|
||||
class BridgeZmqSubSocket {
|
||||
public:
|
||||
int connect(BridgeZmqContext *context, std::string endpoint, std::string address, bool conflate = false, bool check_endpoint = true);
|
||||
void setTimeout(int timeout);
|
||||
Message *receive(bool non_blocking = false);
|
||||
void *getRawSocket() { return sock; }
|
||||
~BridgeZmqSubSocket();
|
||||
|
||||
private:
|
||||
void *sock = nullptr;
|
||||
std::string full_endpoint;
|
||||
};
|
||||
|
||||
class BridgeZmqPubSocket {
|
||||
public:
|
||||
int connect(BridgeZmqContext *context, std::string endpoint, bool check_endpoint = true);
|
||||
int sendMessage(Message *message);
|
||||
int send(char *data, size_t size);
|
||||
void *getRawSocket() { return sock; }
|
||||
~BridgeZmqPubSocket();
|
||||
|
||||
private:
|
||||
void *sock = nullptr;
|
||||
std::string full_endpoint;
|
||||
int pid = -1;
|
||||
};
|
||||
|
||||
class BridgeZmqPoller {
|
||||
public:
|
||||
void registerSocket(BridgeZmqSubSocket *socket);
|
||||
std::vector<BridgeZmqSubSocket *> poll(int timeout);
|
||||
|
||||
private:
|
||||
static constexpr size_t MAX_BRIDGE_ZMQ_POLLERS = 128;
|
||||
std::vector<BridgeZmqSubSocket *> sockets;
|
||||
zmq_pollitem_t polls[MAX_BRIDGE_ZMQ_POLLERS] = {};
|
||||
size_t num_polls = 0;
|
||||
};
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "cereal/services.h"
|
||||
#include "common/util.h"
|
||||
|
||||
extern ExitHandler do_exit;
|
||||
@@ -21,14 +22,14 @@ static std::string recv_zmq_msg(void *sock) {
|
||||
}
|
||||
|
||||
void MsgqToZmq::run(const std::vector<std::string> &endpoints, const std::string &ip) {
|
||||
zmq_context = std::make_unique<ZMQContext>();
|
||||
msgq_context = std::make_unique<MSGQContext>();
|
||||
zmq_context = std::make_unique<BridgeZmqContext>();
|
||||
msgq_context = std::make_unique<Context>();
|
||||
|
||||
// Create ZMQPubSockets for each endpoint
|
||||
for (const auto &endpoint : endpoints) {
|
||||
auto &socket_pair = socket_pairs.emplace_back();
|
||||
socket_pair.endpoint = endpoint;
|
||||
socket_pair.pub_sock = std::make_unique<ZMQPubSocket>();
|
||||
socket_pair.pub_sock = std::make_unique<BridgeZmqPubSocket>();
|
||||
int ret = socket_pair.pub_sock->connect(zmq_context.get(), endpoint);
|
||||
if (ret != 0) {
|
||||
printf("Failed to create ZMQ publisher for [%s]: %s\n", endpoint.c_str(), zmq_strerror(zmq_errno()));
|
||||
@@ -48,7 +49,7 @@ void MsgqToZmq::run(const std::vector<std::string> &endpoints, const std::string
|
||||
|
||||
for (auto sub_sock : msgq_poller->poll(100)) {
|
||||
// Process messages for each socket
|
||||
ZMQPubSocket *pub_sock = sub2pub.at(sub_sock);
|
||||
BridgeZmqPubSocket *pub_sock = sub2pub.at(sub_sock);
|
||||
for (int i = 0; i < MAX_MESSAGES_PER_SOCKET; ++i) {
|
||||
auto msg = std::unique_ptr<Message>(sub_sock->receive(true));
|
||||
if (!msg) break;
|
||||
@@ -71,7 +72,7 @@ void MsgqToZmq::zmqMonitorThread() {
|
||||
// Set up ZMQ monitor for each pub socket
|
||||
for (int i = 0; i < socket_pairs.size(); ++i) {
|
||||
std::string addr = "inproc://op-bridge-monitor-" + std::to_string(i);
|
||||
zmq_socket_monitor(socket_pairs[i].pub_sock->sock, addr.c_str(), ZMQ_EVENT_ACCEPTED | ZMQ_EVENT_DISCONNECTED);
|
||||
zmq_socket_monitor(socket_pairs[i].pub_sock->getRawSocket(), addr.c_str(), ZMQ_EVENT_ACCEPTED | ZMQ_EVENT_DISCONNECTED);
|
||||
|
||||
void *monitor_socket = zmq_socket(zmq_context->getRawContext(), ZMQ_PAIR);
|
||||
zmq_connect(monitor_socket, addr.c_str());
|
||||
@@ -108,7 +109,8 @@ void MsgqToZmq::zmqMonitorThread() {
|
||||
if (++pair.connected_clients == 1) {
|
||||
// Create new MSGQ subscriber socket and map to ZMQ publisher
|
||||
pair.sub_sock = std::make_unique<MSGQSubSocket>();
|
||||
pair.sub_sock->connect(msgq_context.get(), pair.endpoint, "127.0.0.1");
|
||||
size_t queue_size = services.at(pair.endpoint).queue_size;
|
||||
pair.sub_sock->connect(msgq_context.get(), pair.endpoint, "127.0.0.1", false, true, queue_size);
|
||||
sub2pub[pair.sub_sock.get()] = pair.pub_sock.get();
|
||||
registerSockets();
|
||||
}
|
||||
@@ -128,7 +130,7 @@ void MsgqToZmq::zmqMonitorThread() {
|
||||
|
||||
// Clean up monitor sockets
|
||||
for (int i = 0; i < pollitems.size(); ++i) {
|
||||
zmq_socket_monitor(socket_pairs[i].pub_sock->sock, nullptr, 0);
|
||||
zmq_socket_monitor(socket_pairs[i].pub_sock->getRawSocket(), nullptr, 0);
|
||||
zmq_close(pollitems[i].socket);
|
||||
}
|
||||
cv.notify_one();
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define private public
|
||||
#include "msgq/impl_msgq.h"
|
||||
#include "msgq/impl_zmq.h"
|
||||
#include "cereal/messaging/bridge_zmq.h"
|
||||
|
||||
class MsgqToZmq {
|
||||
public:
|
||||
@@ -22,16 +21,16 @@ protected:
|
||||
|
||||
struct SocketPair {
|
||||
std::string endpoint;
|
||||
std::unique_ptr<ZMQPubSocket> pub_sock;
|
||||
std::unique_ptr<BridgeZmqPubSocket> pub_sock;
|
||||
std::unique_ptr<MSGQSubSocket> sub_sock;
|
||||
int connected_clients = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<MSGQContext> msgq_context;
|
||||
std::unique_ptr<ZMQContext> zmq_context;
|
||||
std::unique_ptr<Context> msgq_context;
|
||||
std::unique_ptr<BridgeZmqContext> zmq_context;
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
std::unique_ptr<MSGQPoller> msgq_poller;
|
||||
std::map<SubSocket *, ZMQPubSocket *> sub2pub;
|
||||
std::map<SubSocket *, BridgeZmqPubSocket *> sub2pub;
|
||||
std::vector<SocketPair> socket_pairs;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ MessageContext message_context;
|
||||
struct SubMaster::SubMessage {
|
||||
std::string name;
|
||||
SubSocket *socket = nullptr;
|
||||
int freq = 0;
|
||||
float freq = 0.0f;
|
||||
bool updated = false, alive = false, valid = false, ignore_alive;
|
||||
uint64_t rcv_time = 0, rcv_frame = 0;
|
||||
void *allocated_msg_reader = nullptr;
|
||||
@@ -50,7 +50,7 @@ SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::v
|
||||
assert(services.count(std::string(name)) > 0);
|
||||
|
||||
service serv = services.at(std::string(name));
|
||||
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true);
|
||||
SubSocket *socket = SubSocket::create(message_context.context(), name, address ? address : "127.0.0.1", true, true, serv.queue_size);
|
||||
assert(socket != 0);
|
||||
bool is_polled = inList(poll, name) || poll.empty();
|
||||
if (is_polled) poller_->registerSocket(socket);
|
||||
@@ -187,7 +187,8 @@ SubMaster::~SubMaster() {
|
||||
PubMaster::PubMaster(const std::vector<const char *> &service_list) {
|
||||
for (auto name : service_list) {
|
||||
assert(services.count(name) > 0);
|
||||
PubSocket *socket = PubSocket::create(message_context.context(), name);
|
||||
service serv = services.at(std::string(name));
|
||||
PubSocket *socket = PubSocket::create(message_context.context(), name, true, serv.queue_size);
|
||||
assert(socket);
|
||||
sockets_[name] = socket;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import numbers
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from parameterized import parameterized
|
||||
from openpilot.common.parameterized import parameterized
|
||||
import pytest
|
||||
|
||||
from cereal import log, car
|
||||
@@ -30,7 +30,7 @@ def zmq_sleep(t=1):
|
||||
|
||||
# TODO: this should take any capnp struct and returrn a msg with random populated data
|
||||
def random_carstate():
|
||||
fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"]
|
||||
fields = ["vEgo", "aEgo", "brake", "steeringAngleDeg"]
|
||||
msg = messaging.new_message("carState")
|
||||
cs = msg.carState
|
||||
for f in fields:
|
||||
@@ -177,8 +177,8 @@ class TestMessaging:
|
||||
|
||||
# wait 5 socket timeouts before sending
|
||||
msg = random_carstate()
|
||||
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
|
||||
start_time = time.monotonic()
|
||||
delayed_send(sock_timeout*5, pub_sock, msg.to_bytes())
|
||||
recvd = messaging.recv_one_retry(sub_sock)
|
||||
assert (time.monotonic() - start_time) >= sock_timeout*5
|
||||
assert isinstance(recvd, capnp._DynamicStructReader)
|
||||
|
||||
@@ -6,6 +6,7 @@ import cereal.messaging as messaging
|
||||
from cereal.messaging.tests.test_messaging import events, random_sock, random_socks, \
|
||||
random_bytes, random_carstate, assert_carstate, \
|
||||
zmq_sleep
|
||||
from cereal.services import SERVICE_LIST
|
||||
|
||||
|
||||
class TestSubMaster:
|
||||
@@ -26,7 +27,9 @@ class TestSubMaster:
|
||||
sm = messaging.SubMaster(socks)
|
||||
assert sm.frame == -1
|
||||
assert not any(sm.updated.values())
|
||||
assert not any(sm.alive.values())
|
||||
assert not any(sm.seen.values())
|
||||
on_demand = {s: SERVICE_LIST[s].frequency <= 1e-5 for s in sm.services}
|
||||
assert all(sm.alive[s] == sm.valid[s] == sm.freq_ok[s] == on_demand[s] for s in sm.services)
|
||||
assert all(t == 0. for t in sm.recv_time.values())
|
||||
assert all(f == 0 for f in sm.recv_frame.values())
|
||||
assert all(t == 0 for t in sm.logMonoTime.values())
|
||||
@@ -83,6 +86,7 @@ class TestSubMaster:
|
||||
"cameraOdometry": (20, 10),
|
||||
"liveCalibration": (4, 4),
|
||||
"carParams": (None, None),
|
||||
"userBookmark": (None, None),
|
||||
}
|
||||
|
||||
for service, (max_freq, min_freq) in checks.items():
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import tempfile
|
||||
from typing import Dict
|
||||
from parameterized import parameterized
|
||||
from openpilot.common.parameterized import parameterized
|
||||
|
||||
import cereal.services as services
|
||||
from cereal.services import SERVICE_LIST
|
||||
|
||||
+80
-78
@@ -3,85 +3,87 @@
|
||||
#define __SERVICES_H
|
||||
#include <map>
|
||||
#include <string>
|
||||
struct service { std::string name; bool should_log; int frequency; int decimation; };
|
||||
struct service { std::string name; bool should_log; float frequency; int decimation; size_t queue_size; };
|
||||
static std::map<std::string, service> services = {
|
||||
{ "gyroscope", {"gyroscope", true, 104, 104}},
|
||||
{ "gyroscope2", {"gyroscope2", true, 100, 100}},
|
||||
{ "accelerometer", {"accelerometer", true, 104, 104}},
|
||||
{ "accelerometer2", {"accelerometer2", true, 100, 100}},
|
||||
{ "magnetometer", {"magnetometer", true, 25, -1}},
|
||||
{ "lightSensor", {"lightSensor", true, 100, 100}},
|
||||
{ "temperatureSensor", {"temperatureSensor", true, 2, 200}},
|
||||
{ "temperatureSensor2", {"temperatureSensor2", true, 2, 200}},
|
||||
{ "gpsNMEA", {"gpsNMEA", true, 9, -1}},
|
||||
{ "deviceState", {"deviceState", true, 2, 1}},
|
||||
{ "touch", {"touch", true, 20, 1}},
|
||||
{ "can", {"can", true, 100, 2053}},
|
||||
{ "controlsState", {"controlsState", true, 100, 10}},
|
||||
{ "selfdriveState", {"selfdriveState", true, 100, 10}},
|
||||
{ "pandaStates", {"pandaStates", true, 10, 1}},
|
||||
{ "peripheralState", {"peripheralState", true, 2, 1}},
|
||||
{ "radarState", {"radarState", true, 20, 5}},
|
||||
{ "roadEncodeIdx", {"roadEncodeIdx", false, 20, 1}},
|
||||
{ "liveTracks", {"liveTracks", true, 20, -1}},
|
||||
{ "sendcan", {"sendcan", true, 100, 139}},
|
||||
{ "logMessage", {"logMessage", true, 0, -1}},
|
||||
{ "errorLogMessage", {"errorLogMessage", true, 0, 1}},
|
||||
{ "liveCalibration", {"liveCalibration", true, 4, 4}},
|
||||
{ "liveTorqueParameters", {"liveTorqueParameters", true, 4, 1}},
|
||||
{ "androidLog", {"androidLog", true, 0, -1}},
|
||||
{ "carState", {"carState", true, 100, 10}},
|
||||
{ "carControl", {"carControl", true, 100, 10}},
|
||||
{ "carOutput", {"carOutput", true, 100, 10}},
|
||||
{ "longitudinalPlan", {"longitudinalPlan", true, 20, 10}},
|
||||
{ "driverAssistance", {"driverAssistance", true, 20, 20}},
|
||||
{ "procLog", {"procLog", true, 0, 15}},
|
||||
{ "gpsLocationExternal", {"gpsLocationExternal", true, 10, 10}},
|
||||
{ "gpsLocation", {"gpsLocation", true, 1, 1}},
|
||||
{ "ubloxGnss", {"ubloxGnss", true, 10, -1}},
|
||||
{ "qcomGnss", {"qcomGnss", true, 2, -1}},
|
||||
{ "gnssMeasurements", {"gnssMeasurements", true, 10, 10}},
|
||||
{ "clocks", {"clocks", true, 0, 1}},
|
||||
{ "ubloxRaw", {"ubloxRaw", true, 20, -1}},
|
||||
{ "livePose", {"livePose", true, 20, 4}},
|
||||
{ "liveParameters", {"liveParameters", true, 20, 5}},
|
||||
{ "cameraOdometry", {"cameraOdometry", true, 20, 10}},
|
||||
{ "thumbnail", {"thumbnail", true, 0, 1}},
|
||||
{ "onroadEvents", {"onroadEvents", true, 1, 1}},
|
||||
{ "carParams", {"carParams", true, 0, 1}},
|
||||
{ "roadCameraState", {"roadCameraState", true, 20, 20}},
|
||||
{ "driverCameraState", {"driverCameraState", true, 20, 20}},
|
||||
{ "driverEncodeIdx", {"driverEncodeIdx", false, 20, 1}},
|
||||
{ "driverStateV2", {"driverStateV2", true, 20, 10}},
|
||||
{ "driverMonitoringState", {"driverMonitoringState", true, 20, 10}},
|
||||
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", false, 20, 1}},
|
||||
{ "wideRoadCameraState", {"wideRoadCameraState", true, 20, 20}},
|
||||
{ "drivingModelData", {"drivingModelData", true, 20, 10}},
|
||||
{ "modelV2", {"modelV2", true, 20, -1}},
|
||||
{ "managerState", {"managerState", true, 2, 1}},
|
||||
{ "uploaderState", {"uploaderState", true, 0, 1}},
|
||||
{ "navInstruction", {"navInstruction", true, 1, 10}},
|
||||
{ "navRoute", {"navRoute", true, 0, -1}},
|
||||
{ "navThumbnail", {"navThumbnail", true, 0, -1}},
|
||||
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", false, 20, -1}},
|
||||
{ "userFlag", {"userFlag", true, 0, 1}},
|
||||
{ "microphone", {"microphone", true, 10, 10}},
|
||||
{ "uiDebug", {"uiDebug", true, 0, 1}},
|
||||
{ "testJoystick", {"testJoystick", true, 0, -1}},
|
||||
{ "alertDebug", {"alertDebug", true, 20, 5}},
|
||||
{ "roadEncodeData", {"roadEncodeData", false, 20, -1}},
|
||||
{ "driverEncodeData", {"driverEncodeData", false, 20, -1}},
|
||||
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20, -1}},
|
||||
{ "qRoadEncodeData", {"qRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", false, 20, -1}},
|
||||
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20, -1}},
|
||||
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20, -1}},
|
||||
{ "customReservedRawData0", {"customReservedRawData0", true, 0, -1}},
|
||||
{ "customReservedRawData1", {"customReservedRawData1", true, 0, -1}},
|
||||
{ "customReservedRawData2", {"customReservedRawData2", true, 0, -1}},
|
||||
{ "gyroscope", {"gyroscope", true, 104.000000, 104, 256000}},
|
||||
{ "accelerometer", {"accelerometer", true, 104.000000, 104, 256000}},
|
||||
{ "magnetometer", {"magnetometer", true, 25.000000, -1, 256000}},
|
||||
{ "lightSensor", {"lightSensor", true, 100.000000, 100, 256000}},
|
||||
{ "temperatureSensor", {"temperatureSensor", true, 2.000000, 200, 256000}},
|
||||
{ "gpsNMEA", {"gpsNMEA", true, 9.000000, -1, 256000}},
|
||||
{ "deviceState", {"deviceState", true, 2.000000, 1, 256000}},
|
||||
{ "touch", {"touch", true, 20.000000, 1, 256000}},
|
||||
{ "can", {"can", true, 100.000000, 2053, 10485760}},
|
||||
{ "controlsState", {"controlsState", true, 100.000000, 10, 2097152}},
|
||||
{ "selfdriveState", {"selfdriveState", true, 100.000000, 10, 256000}},
|
||||
{ "pandaStates", {"pandaStates", true, 10.000000, 1, 256000}},
|
||||
{ "peripheralState", {"peripheralState", true, 2.000000, 1, 256000}},
|
||||
{ "radarState", {"radarState", true, 20.000000, 5, 256000}},
|
||||
{ "roadEncodeIdx", {"roadEncodeIdx", false, 20.000000, 1, 256000}},
|
||||
{ "liveTracks", {"liveTracks", true, 20.000000, -1, 256000}},
|
||||
{ "sendcan", {"sendcan", true, 100.000000, 139, 2097152}},
|
||||
{ "logMessage", {"logMessage", true, 0.000000, -1, 10485760}},
|
||||
{ "errorLogMessage", {"errorLogMessage", true, 0.000000, 1, 10485760}},
|
||||
{ "liveCalibration", {"liveCalibration", true, 4.000000, 4, 256000}},
|
||||
{ "liveTorqueParameters", {"liveTorqueParameters", true, 4.000000, 1, 256000}},
|
||||
{ "liveDelay", {"liveDelay", true, 4.000000, 1, 256000}},
|
||||
{ "androidLog", {"androidLog", true, 0.000000, -1, 256000}},
|
||||
{ "carState", {"carState", true, 100.000000, 10, 256000}},
|
||||
{ "carControl", {"carControl", true, 100.000000, 10, 256000}},
|
||||
{ "carOutput", {"carOutput", true, 100.000000, 10, 256000}},
|
||||
{ "longitudinalPlan", {"longitudinalPlan", true, 20.000000, 10, 256000}},
|
||||
{ "lateralManeuverPlan", {"lateralManeuverPlan", true, 20.000000, -1, 256000}},
|
||||
{ "driverAssistance", {"driverAssistance", true, 20.000000, 20, 256000}},
|
||||
{ "procLog", {"procLog", true, 0.500000, 15, 10485760}},
|
||||
{ "gpsLocationExternal", {"gpsLocationExternal", true, 10.000000, 10, 256000}},
|
||||
{ "gpsLocation", {"gpsLocation", true, 1.000000, 1, 256000}},
|
||||
{ "ubloxGnss", {"ubloxGnss", true, 10.000000, -1, 256000}},
|
||||
{ "qcomGnss", {"qcomGnss", true, 2.000000, -1, 256000}},
|
||||
{ "gnssMeasurements", {"gnssMeasurements", true, 10.000000, 10, 256000}},
|
||||
{ "clocks", {"clocks", true, 0.100000, 1, 256000}},
|
||||
{ "ubloxRaw", {"ubloxRaw", true, 20.000000, -1, 256000}},
|
||||
{ "livePose", {"livePose", true, 20.000000, 4, 256000}},
|
||||
{ "liveParameters", {"liveParameters", true, 20.000000, 5, 256000}},
|
||||
{ "cameraOdometry", {"cameraOdometry", true, 20.000000, 10, 256000}},
|
||||
{ "thumbnail", {"thumbnail", true, 0.016667, 1, 256000}},
|
||||
{ "onroadEvents", {"onroadEvents", true, 1.000000, 1, 256000}},
|
||||
{ "carParams", {"carParams", true, 0.020000, 1, 256000}},
|
||||
{ "roadCameraState", {"roadCameraState", true, 20.000000, 20, 256000}},
|
||||
{ "driverCameraState", {"driverCameraState", true, 20.000000, 20, 256000}},
|
||||
{ "driverEncodeIdx", {"driverEncodeIdx", false, 20.000000, 1, 256000}},
|
||||
{ "driverStateV2", {"driverStateV2", true, 20.000000, 10, 256000}},
|
||||
{ "driverMonitoringState", {"driverMonitoringState", true, 20.000000, 10, 256000}},
|
||||
{ "wideRoadEncodeIdx", {"wideRoadEncodeIdx", false, 20.000000, 1, 256000}},
|
||||
{ "wideRoadCameraState", {"wideRoadCameraState", true, 20.000000, 20, 256000}},
|
||||
{ "drivingModelData", {"drivingModelData", true, 20.000000, 10, 256000}},
|
||||
{ "modelV2", {"modelV2", true, 20.000000, -1, 10485760}},
|
||||
{ "managerState", {"managerState", true, 2.000000, 1, 256000}},
|
||||
{ "uploaderState", {"uploaderState", true, 0.000000, 1, 256000}},
|
||||
{ "navInstruction", {"navInstruction", true, 1.000000, 10, 256000}},
|
||||
{ "navRoute", {"navRoute", true, 0.000000, -1, 256000}},
|
||||
{ "navThumbnail", {"navThumbnail", true, 0.000000, -1, 256000}},
|
||||
{ "qRoadEncodeIdx", {"qRoadEncodeIdx", false, 20.000000, -1, 256000}},
|
||||
{ "userBookmark", {"userBookmark", true, 0.000000, 1, 256000}},
|
||||
{ "soundPressure", {"soundPressure", true, 10.000000, 10, 256000}},
|
||||
{ "rawAudioData", {"rawAudioData", false, 20.000000, -1, 256000}},
|
||||
{ "bookmarkButton", {"bookmarkButton", true, 0.000000, 1, 256000}},
|
||||
{ "audioFeedback", {"audioFeedback", true, 0.000000, 1, 256000}},
|
||||
{ "roadEncodeData", {"roadEncodeData", false, 20.000000, -1, 10485760}},
|
||||
{ "driverEncodeData", {"driverEncodeData", false, 20.000000, -1, 10485760}},
|
||||
{ "wideRoadEncodeData", {"wideRoadEncodeData", false, 20.000000, -1, 10485760}},
|
||||
{ "qRoadEncodeData", {"qRoadEncodeData", false, 20.000000, -1, 10485760}},
|
||||
{ "uiDebug", {"uiDebug", true, 0.000000, 1, 256000}},
|
||||
{ "testJoystick", {"testJoystick", true, 0.000000, -1, 256000}},
|
||||
{ "alertDebug", {"alertDebug", true, 20.000000, 5, 256000}},
|
||||
{ "livestreamWideRoadEncodeIdx", {"livestreamWideRoadEncodeIdx", false, 20.000000, -1, 256000}},
|
||||
{ "livestreamRoadEncodeIdx", {"livestreamRoadEncodeIdx", false, 20.000000, -1, 256000}},
|
||||
{ "livestreamDriverEncodeIdx", {"livestreamDriverEncodeIdx", false, 20.000000, -1, 256000}},
|
||||
{ "livestreamWideRoadEncodeData", {"livestreamWideRoadEncodeData", false, 20.000000, -1, 2097152}},
|
||||
{ "livestreamRoadEncodeData", {"livestreamRoadEncodeData", false, 20.000000, -1, 2097152}},
|
||||
{ "livestreamDriverEncodeData", {"livestreamDriverEncodeData", false, 20.000000, -1, 2097152}},
|
||||
{ "customReservedRawData0", {"customReservedRawData0", true, 0.000000, -1, 256000}},
|
||||
{ "customReservedRawData1", {"customReservedRawData1", true, 0.000000, -1, 256000}},
|
||||
{ "customReservedRawData2", {"customReservedRawData2", true, 0.000000, -1, 256000}},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
+35
-23
@@ -1,48 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
from enum import IntEnum
|
||||
from typing import Optional
|
||||
|
||||
|
||||
# TODO: this should be automatically determined using the capnp schema
|
||||
class QueueSize(IntEnum):
|
||||
BIG = 10 * 1024 * 1024 # 10MB - video frames, large AI outputs
|
||||
MEDIUM = 2 * 1024 * 1024 # 2MB - high freq (CAN), livestream
|
||||
SMALL = 250 * 1024 # 250KB - most services
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None):
|
||||
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None,
|
||||
queue_size: QueueSize = QueueSize.SMALL):
|
||||
self.should_log = should_log
|
||||
self.frequency = frequency
|
||||
self.decimation = decimation
|
||||
self.queue_size = queue_size
|
||||
|
||||
|
||||
_services: dict[str, tuple] = {
|
||||
# service: (should_log, frequency, qlog decimation (optional))
|
||||
# note: the "EncodeIdx" packets will still be in the log
|
||||
"gyroscope": (True, 104., 104),
|
||||
"gyroscope2": (True, 100., 100),
|
||||
"accelerometer": (True, 104., 104),
|
||||
"accelerometer2": (True, 100., 100),
|
||||
"magnetometer": (True, 25.),
|
||||
"lightSensor": (True, 100., 100),
|
||||
"temperatureSensor": (True, 2., 200),
|
||||
"temperatureSensor2": (True, 2., 200),
|
||||
"gpsNMEA": (True, 9.),
|
||||
"deviceState": (True, 2., 1),
|
||||
"touch": (True, 20., 1),
|
||||
"can": (True, 100., 2053), # decimation gives ~3 msgs in a full segment
|
||||
"controlsState": (True, 100., 10),
|
||||
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
||||
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
||||
"selfdriveState": (True, 100., 10),
|
||||
"pandaStates": (True, 10., 1),
|
||||
"peripheralState": (True, 2., 1),
|
||||
"radarState": (True, 20., 5),
|
||||
"roadEncodeIdx": (False, 20., 1),
|
||||
"liveTracks": (True, 20.),
|
||||
"sendcan": (True, 100., 139),
|
||||
"logMessage": (True, 0.),
|
||||
"errorLogMessage": (True, 0., 1),
|
||||
"sendcan": (True, 100., 139, QueueSize.MEDIUM),
|
||||
"logMessage": (True, 0., None, QueueSize.BIG),
|
||||
"errorLogMessage": (True, 0., 1, QueueSize.BIG),
|
||||
"liveCalibration": (True, 4., 4),
|
||||
"liveTorqueParameters": (True, 4., 1),
|
||||
"liveDelay": (True, 4., 1),
|
||||
"androidLog": (True, 0.),
|
||||
"carState": (True, 100., 10),
|
||||
"carControl": (True, 100., 10),
|
||||
"carOutput": (True, 100., 10),
|
||||
"longitudinalPlan": (True, 20., 10),
|
||||
"lateralManeuverPlan": (True, 20.),
|
||||
"driverAssistance": (True, 20., 20),
|
||||
"procLog": (True, 0.5, 15),
|
||||
"procLog": (True, 0.5, 15, QueueSize.BIG),
|
||||
"gpsLocationExternal": (True, 10., 10),
|
||||
"gpsLocation": (True, 1., 1),
|
||||
"ubloxGnss": (True, 10.),
|
||||
@@ -64,30 +73,33 @@ _services: dict[str, tuple] = {
|
||||
"wideRoadEncodeIdx": (False, 20., 1),
|
||||
"wideRoadCameraState": (True, 20., 20),
|
||||
"drivingModelData": (True, 20., 10),
|
||||
"modelV2": (True, 20.),
|
||||
"modelV2": (True, 20., None, QueueSize.BIG),
|
||||
"managerState": (True, 2., 1),
|
||||
"uploaderState": (True, 0., 1),
|
||||
"navInstruction": (True, 1., 10),
|
||||
"navRoute": (True, 0.),
|
||||
"navThumbnail": (True, 0.),
|
||||
"qRoadEncodeIdx": (False, 20.),
|
||||
"userFlag": (True, 0., 1),
|
||||
"microphone": (True, 10., 10),
|
||||
"userBookmark": (True, 0., 1),
|
||||
"soundPressure": (True, 10., 10),
|
||||
"rawAudioData": (False, 20.),
|
||||
"bookmarkButton": (True, 0., 1),
|
||||
"audioFeedback": (True, 0., 1),
|
||||
"roadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||
"driverEncodeData": (False, 20., None, QueueSize.BIG),
|
||||
"wideRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||
"qRoadEncodeData": (False, 20., None, QueueSize.BIG),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
"testJoystick": (True, 0.),
|
||||
"alertDebug": (True, 20., 5),
|
||||
"roadEncodeData": (False, 20.),
|
||||
"driverEncodeData": (False, 20.),
|
||||
"wideRoadEncodeData": (False, 20.),
|
||||
"qRoadEncodeData": (False, 20.),
|
||||
"livestreamWideRoadEncodeIdx": (False, 20.),
|
||||
"livestreamRoadEncodeIdx": (False, 20.),
|
||||
"livestreamDriverEncodeIdx": (False, 20.),
|
||||
"livestreamWideRoadEncodeData": (False, 20.),
|
||||
"livestreamRoadEncodeData": (False, 20.),
|
||||
"livestreamDriverEncodeData": (False, 20.),
|
||||
"livestreamWideRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||
"livestreamRoadEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||
"livestreamDriverEncodeData": (False, 20., None, QueueSize.MEDIUM),
|
||||
"customReservedRawData0": (True, 0.),
|
||||
"customReservedRawData1": (True, 0.),
|
||||
"customReservedRawData2": (True, 0.),
|
||||
@@ -105,13 +117,13 @@ def build_header():
|
||||
h += "#include <map>\n"
|
||||
h += "#include <string>\n"
|
||||
|
||||
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\n"
|
||||
h += "struct service { std::string name; bool should_log; float frequency; int decimation; size_t queue_size; };\n"
|
||||
h += "static std::map<std::string, service> services = {\n"
|
||||
for k, v in SERVICE_LIST.items():
|
||||
should_log = "true" if v.should_log else "false"
|
||||
decimation = -1 if v.decimation is None else v.decimation
|
||||
h += ' { "%s", {"%s", %s, %d, %d}},\n' % \
|
||||
(k, k, should_log, v.frequency, decimation)
|
||||
h += ' { "%s", {"%s", %s, %f, %d, %d}},\n' % \
|
||||
(k, k, should_log, v.frequency, decimation, v.queue_size)
|
||||
h += "};\n"
|
||||
|
||||
h += "#endif\n"
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
comment: false
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
patch: off
|
||||
|
||||
ignore:
|
||||
- "**/test_*.py"
|
||||
- "selfdrive/test/**"
|
||||
- "system/version.py" # codecov changes depending on if we are in a branch or not
|
||||
- "tools"
|
||||
@@ -1 +0,0 @@
|
||||
*.cpp
|
||||
+4
-20
@@ -1,25 +1,14 @@
|
||||
Import('env', 'envCython', 'arch')
|
||||
Import('env', 'envCython')
|
||||
|
||||
common_libs = [
|
||||
'params.cc',
|
||||
'swaglog.cc',
|
||||
'util.cc',
|
||||
'i2c.cc',
|
||||
'watchdog.cc',
|
||||
'ratekeeper.cc'
|
||||
'ratekeeper.cc',
|
||||
]
|
||||
|
||||
if arch != "Darwin":
|
||||
common_libs.append('gpio.cc')
|
||||
|
||||
_common = env.Library('common', common_libs, LIBS="json11")
|
||||
|
||||
files = [
|
||||
'clutil.cc',
|
||||
]
|
||||
|
||||
_gpucommon = env.Library('gpucommon', files)
|
||||
Export('_common', '_gpucommon')
|
||||
Export('_common')
|
||||
|
||||
if GetOption('extras'):
|
||||
env.Program('tests/test_common',
|
||||
@@ -29,11 +18,6 @@ if GetOption('extras'):
|
||||
# Cython bindings
|
||||
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
|
||||
|
||||
SConscript([
|
||||
'transformations/SConscript',
|
||||
])
|
||||
|
||||
Import('transformations_python')
|
||||
common_python = [params_python, transformations_python]
|
||||
common_python = [params_python]
|
||||
|
||||
Export('common_python')
|
||||
|
||||
+22
-6
@@ -7,11 +7,15 @@ from openpilot.system.version import get_version
|
||||
|
||||
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
|
||||
|
||||
# name: jwt signature algorithm
|
||||
KEYS = {"id_rsa": "RS256",
|
||||
"id_ecdsa": "ES256"}
|
||||
|
||||
|
||||
class Api:
|
||||
def __init__(self, dongle_id):
|
||||
self.dongle_id = dongle_id
|
||||
with open(Paths.persist_root()+'/comma/id_rsa') as f:
|
||||
self.private_key = f.read()
|
||||
self.jwt_algorithm, self.private_key, _ = get_key_pair()
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return self.request('GET', *args, **kwargs)
|
||||
@@ -22,7 +26,7 @@ class Api:
|
||||
def request(self, method, endpoint, timeout=None, access_token=None, **params):
|
||||
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
|
||||
|
||||
def get_token(self, expiry_hours=1):
|
||||
def get_token(self, payload_extra=None, expiry_hours=1):
|
||||
now = datetime.now(UTC).replace(tzinfo=None)
|
||||
payload = {
|
||||
'identity': self.dongle_id,
|
||||
@@ -30,17 +34,29 @@ class Api:
|
||||
'iat': now,
|
||||
'exp': now + timedelta(hours=expiry_hours)
|
||||
}
|
||||
token = jwt.encode(payload, self.private_key, algorithm='RS256')
|
||||
if payload_extra is not None:
|
||||
payload.update(payload_extra)
|
||||
token = jwt.encode(payload, self.private_key, algorithm=self.jwt_algorithm)
|
||||
if isinstance(token, bytes):
|
||||
token = token.decode('utf8')
|
||||
return token
|
||||
|
||||
|
||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
|
||||
def api_get(endpoint, method='GET', timeout=None, access_token=None, session=None, **params):
|
||||
headers = {}
|
||||
if access_token is not None:
|
||||
headers['Authorization'] = "JWT " + access_token
|
||||
|
||||
headers['User-Agent'] = "openpilot-" + get_version()
|
||||
|
||||
return requests.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
|
||||
# TODO: add session to Api
|
||||
req = requests if session is None else session
|
||||
return req.request(method, API_HOST + "/" + endpoint, timeout=timeout, headers=headers, params=params)
|
||||
|
||||
|
||||
def get_key_pair() -> tuple[str, str, str] | tuple[None, None, None]:
|
||||
for key in KEYS:
|
||||
if os.path.isfile(Paths.persist_root() + f'/comma/{key}') and os.path.isfile(Paths.persist_root() + f'/comma/{key}.pub'):
|
||||
with open(Paths.persist_root() + f'/comma/{key}') as private, open(Paths.persist_root() + f'/comma/{key}.pub') as public:
|
||||
return KEYS[key], private.read(), public.read()
|
||||
return None, None, None
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#include "common/clutil.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/swaglog.h"
|
||||
|
||||
namespace { // helper functions
|
||||
|
||||
template <typename Func, typename Id, typename Name>
|
||||
std::string get_info(Func get_info_func, Id id, Name param_name) {
|
||||
size_t size = 0;
|
||||
CL_CHECK(get_info_func(id, param_name, 0, NULL, &size));
|
||||
std::string info(size, '\0');
|
||||
CL_CHECK(get_info_func(id, param_name, size, info.data(), NULL));
|
||||
return info;
|
||||
}
|
||||
inline std::string get_platform_info(cl_platform_id id, cl_platform_info name) { return get_info(&clGetPlatformInfo, id, name); }
|
||||
inline std::string get_device_info(cl_device_id id, cl_device_info name) { return get_info(&clGetDeviceInfo, id, name); }
|
||||
|
||||
void cl_print_info(cl_platform_id platform, cl_device_id device) {
|
||||
size_t work_group_size = 0;
|
||||
cl_device_type device_type = 0;
|
||||
clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(work_group_size), &work_group_size, NULL);
|
||||
clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(device_type), &device_type, NULL);
|
||||
const char *type_str = "Other...";
|
||||
switch (device_type) {
|
||||
case CL_DEVICE_TYPE_CPU: type_str ="CL_DEVICE_TYPE_CPU"; break;
|
||||
case CL_DEVICE_TYPE_GPU: type_str = "CL_DEVICE_TYPE_GPU"; break;
|
||||
case CL_DEVICE_TYPE_ACCELERATOR: type_str = "CL_DEVICE_TYPE_ACCELERATOR"; break;
|
||||
}
|
||||
|
||||
LOGD("vendor: %s", get_platform_info(platform, CL_PLATFORM_VENDOR).c_str());
|
||||
LOGD("platform version: %s", get_platform_info(platform, CL_PLATFORM_VERSION).c_str());
|
||||
LOGD("profile: %s", get_platform_info(platform, CL_PLATFORM_PROFILE).c_str());
|
||||
LOGD("extensions: %s", get_platform_info(platform, CL_PLATFORM_EXTENSIONS).c_str());
|
||||
LOGD("name: %s", get_device_info(device, CL_DEVICE_NAME).c_str());
|
||||
LOGD("device version: %s", get_device_info(device, CL_DEVICE_VERSION).c_str());
|
||||
LOGD("max work group size: %zu", work_group_size);
|
||||
LOGD("type = %d, %s", (int)device_type, type_str);
|
||||
}
|
||||
|
||||
void cl_print_build_errors(cl_program program, cl_device_id device) {
|
||||
cl_build_status status;
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_STATUS, sizeof(status), &status, NULL);
|
||||
size_t log_size;
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
|
||||
std::string log(log_size, '\0');
|
||||
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, &log[0], NULL);
|
||||
|
||||
LOGE("build failed; status=%d, log: %s", status, log.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
cl_device_id cl_get_device_id(cl_device_type device_type) {
|
||||
cl_uint num_platforms = 0;
|
||||
CL_CHECK(clGetPlatformIDs(0, NULL, &num_platforms));
|
||||
std::unique_ptr<cl_platform_id[]> platform_ids = std::make_unique<cl_platform_id[]>(num_platforms);
|
||||
CL_CHECK(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL));
|
||||
|
||||
for (size_t i = 0; i < num_platforms; ++i) {
|
||||
LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, get_platform_info(platform_ids[i], CL_PLATFORM_NAME).c_str());
|
||||
|
||||
// Get first device
|
||||
if (cl_device_id device_id = NULL; clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL) == 0 && device_id) {
|
||||
cl_print_info(platform_ids[i], device_id);
|
||||
return device_id;
|
||||
}
|
||||
}
|
||||
LOGE("No valid openCL platform found");
|
||||
assert(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cl_context cl_create_context(cl_device_id device_id) {
|
||||
return CL_CHECK_ERR(clCreateContext(NULL, 1, &device_id, NULL, NULL, &err));
|
||||
}
|
||||
|
||||
void cl_release_context(cl_context context) {
|
||||
clReleaseContext(context);
|
||||
}
|
||||
|
||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args) {
|
||||
return cl_program_from_source(ctx, device_id, util::read_file(path), args);
|
||||
}
|
||||
|
||||
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args) {
|
||||
const char *csrc = src.c_str();
|
||||
cl_program prg = CL_CHECK_ERR(clCreateProgramWithSource(ctx, 1, &csrc, NULL, &err));
|
||||
if (int err = clBuildProgram(prg, 1, &device_id, args, NULL, NULL); err != 0) {
|
||||
cl_print_build_errors(prg, device_id);
|
||||
assert(0);
|
||||
}
|
||||
return prg;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenCL/cl.h>
|
||||
#else
|
||||
#include <CL/cl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#define CL_CHECK(_expr) \
|
||||
do { \
|
||||
assert(CL_SUCCESS == (_expr)); \
|
||||
} while (0)
|
||||
|
||||
#define CL_CHECK_ERR(_expr) \
|
||||
({ \
|
||||
cl_int err = CL_INVALID_VALUE; \
|
||||
__typeof__(_expr) _ret = _expr; \
|
||||
assert(_ret&& err == CL_SUCCESS); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
cl_device_id cl_get_device_id(cl_device_type device_type);
|
||||
cl_context cl_create_context(cl_device_id device_id);
|
||||
void cl_release_context(cl_context context);
|
||||
cl_program cl_program_from_source(cl_context ctx, cl_device_id device_id, const std::string& src, const char* args = nullptr);
|
||||
cl_program cl_program_from_file(cl_context ctx, cl_device_id device_id, const char* path, const char* args);
|
||||
@@ -0,0 +1,23 @@
|
||||
import numpy as np
|
||||
|
||||
# conversions
|
||||
class CV:
|
||||
# Speed
|
||||
MPH_TO_KPH = 1.609344
|
||||
KPH_TO_MPH = 1. / MPH_TO_KPH
|
||||
MS_TO_KPH = 3.6
|
||||
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
|
||||
MS_TO_KNOTS = 1.9438
|
||||
KNOTS_TO_MS = 1. / MS_TO_KNOTS
|
||||
|
||||
# Angle
|
||||
DEG_TO_RAD = np.pi / 180.
|
||||
RAD_TO_DEG = 1. / DEG_TO_RAD
|
||||
|
||||
# Mass
|
||||
LB_TO_KG = 0.453592
|
||||
|
||||
|
||||
ACCELERATION_DUE_TO_GRAVITY = 9.81 # m/s^2
|
||||
@@ -1,19 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
class Conversions:
|
||||
# Speed
|
||||
MPH_TO_KPH = 1.609344
|
||||
KPH_TO_MPH = 1. / MPH_TO_KPH
|
||||
MS_TO_KPH = 3.6
|
||||
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
|
||||
MS_TO_KNOTS = 1.9438
|
||||
KNOTS_TO_MS = 1. / MS_TO_KNOTS
|
||||
|
||||
# Angle
|
||||
DEG_TO_RAD = np.pi / 180.
|
||||
RAD_TO_DEG = 1. / DEG_TO_RAD
|
||||
|
||||
# Mass
|
||||
LB_TO_KG = 0.453592
|
||||
@@ -1,9 +0,0 @@
|
||||
# remove all keys that end in DEPRECATED
|
||||
def strip_deprecated_keys(d):
|
||||
for k in list(d.keys()):
|
||||
if isinstance(k, str):
|
||||
if k.endswith('DEPRECATED'):
|
||||
d.pop(k)
|
||||
elif isinstance(d[k], dict):
|
||||
strip_deprecated_keys(d[k])
|
||||
return d
|
||||
@@ -1,8 +0,0 @@
|
||||
import platform
|
||||
|
||||
|
||||
def suffix():
|
||||
if platform.system() == "Darwin":
|
||||
return ".dylib"
|
||||
else:
|
||||
return ".so"
|
||||
@@ -0,0 +1,37 @@
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
CHUNK_SIZE = 45 * 1024 * 1024 # 45MB, under GitHub's 50MB limit
|
||||
|
||||
def get_chunk_name(name, idx, num_chunks):
|
||||
return f"{name}.chunk{idx+1:02d}of{num_chunks:02d}"
|
||||
|
||||
def get_manifest_path(name):
|
||||
return f"{name}.chunkmanifest"
|
||||
|
||||
def get_chunk_paths(path, file_size):
|
||||
num_chunks = math.ceil(file_size / CHUNK_SIZE)
|
||||
return [get_manifest_path(path)] + [get_chunk_name(path, i, num_chunks) for i in range(num_chunks)]
|
||||
|
||||
def chunk_file(path, targets):
|
||||
manifest_path, *chunk_paths = targets
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read()
|
||||
actual_num_chunks = max(1, math.ceil(len(data) / CHUNK_SIZE))
|
||||
assert len(chunk_paths) >= actual_num_chunks, f"Allowed {len(chunk_paths)} chunks but needs at least {actual_num_chunks}, for path {path}"
|
||||
for i, chunk_path in enumerate(chunk_paths):
|
||||
with open(chunk_path, 'wb') as f:
|
||||
f.write(data[i * CHUNK_SIZE:(i + 1) * CHUNK_SIZE])
|
||||
Path(manifest_path).write_text(str(len(chunk_paths)))
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def read_file_chunked(path):
|
||||
manifest_path = get_manifest_path(path)
|
||||
if os.path.isfile(manifest_path):
|
||||
num_chunks = int(Path(manifest_path).read_text().strip())
|
||||
return b''.join(Path(get_chunk_name(path, i, num_chunks)).read_bytes() for i in range(num_chunks))
|
||||
if os.path.isfile(path):
|
||||
return Path(path).read_bytes()
|
||||
raise FileNotFoundError(path)
|
||||
@@ -1,58 +0,0 @@
|
||||
import io
|
||||
import os
|
||||
import tempfile
|
||||
import contextlib
|
||||
import zstandard as zstd
|
||||
|
||||
LOG_COMPRESSION_LEVEL = 10 # little benefit up to level 15. level ~17 is a small step change
|
||||
|
||||
|
||||
class CallbackReader:
|
||||
"""Wraps a file, but overrides the read method to also
|
||||
call a callback function with the number of bytes read so far."""
|
||||
def __init__(self, f, callback, *args):
|
||||
self.f = f
|
||||
self.callback = callback
|
||||
self.cb_args = args
|
||||
self.total_read = 0
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.f, attr)
|
||||
|
||||
def read(self, *args, **kwargs):
|
||||
chunk = self.f.read(*args, **kwargs)
|
||||
self.total_read += len(chunk)
|
||||
self.callback(*self.cb_args, self.total_read)
|
||||
return chunk
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def atomic_write_in_dir(path: str, mode: str = 'w', buffering: int = -1, encoding: str = None, newline: str = None,
|
||||
overwrite: bool = False):
|
||||
"""Write to a file atomically using a temporary file in the same directory as the destination file."""
|
||||
dir_name = os.path.dirname(path)
|
||||
|
||||
if not overwrite and os.path.exists(path):
|
||||
raise FileExistsError(f"File '{path}' already exists. To overwrite it, set 'overwrite' to True.")
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode=mode, buffering=buffering, encoding=encoding, newline=newline, dir=dir_name, delete=False) as tmp_file:
|
||||
yield tmp_file
|
||||
tmp_file_name = tmp_file.name
|
||||
os.replace(tmp_file_name, path)
|
||||
|
||||
|
||||
def get_upload_stream(filepath: str, should_compress: bool) -> tuple[io.BufferedIOBase, int]:
|
||||
if not should_compress:
|
||||
file_size = os.path.getsize(filepath)
|
||||
file_stream = open(filepath, "rb")
|
||||
return file_stream, file_size
|
||||
|
||||
# Compress the file on the fly
|
||||
compressed_stream = io.BytesIO()
|
||||
compressor = zstd.ZstdCompressor(level=LOG_COMPRESSION_LEVEL)
|
||||
|
||||
with open(filepath, "rb") as f:
|
||||
compressor.copy_stream(f, compressed_stream)
|
||||
compressed_size = compressed_stream.tell()
|
||||
compressed_stream.seek(0)
|
||||
return compressed_stream, compressed_size
|
||||
+17
-1
@@ -1,5 +1,4 @@
|
||||
class FirstOrderFilter:
|
||||
# first order filter
|
||||
def __init__(self, x0, rc, dt, initialized=True):
|
||||
self.x = x0
|
||||
self.dt = dt
|
||||
@@ -16,3 +15,20 @@ class FirstOrderFilter:
|
||||
self.initialized = True
|
||||
self.x = x
|
||||
return self.x
|
||||
|
||||
|
||||
class BounceFilter(FirstOrderFilter):
|
||||
def __init__(self, x0, rc, dt, initialized=True, bounce=2):
|
||||
self.velocity = FirstOrderFilter(0.0, 0.15, dt)
|
||||
self.bounce = bounce
|
||||
super().__init__(x0, rc, dt, initialized)
|
||||
|
||||
def update(self, x):
|
||||
super().update(x)
|
||||
scale = self.dt / (1.0 / 60.0) # tuned at 60 fps
|
||||
self.velocity.x += (x - self.x) * self.bounce * scale * self.dt
|
||||
self.velocity.update(0.0)
|
||||
if abs(self.velocity.x) < 1e-3:
|
||||
self.velocity.x = 0.0
|
||||
self.x += self.velocity.x
|
||||
return self.x
|
||||
|
||||
+7
-7
@@ -1,30 +1,30 @@
|
||||
from functools import cache
|
||||
import subprocess
|
||||
from openpilot.common.run import run_cmd, run_cmd_default
|
||||
from openpilot.common.utils import run_cmd, run_cmd_default
|
||||
|
||||
|
||||
@cache
|
||||
def get_commit(cwd: str = None, branch: str = "HEAD") -> str:
|
||||
def get_commit(cwd: str | None = None, branch: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "rev-parse", branch], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_commit_date(cwd: str = None, commit: str = "HEAD") -> str:
|
||||
def get_commit_date(cwd: str | None = None, commit: str = "HEAD") -> str:
|
||||
return run_cmd_default(["git", "show", "--no-patch", "--format='%ct %ci'", commit], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_short_branch(cwd: str = None) -> str:
|
||||
def get_short_branch(cwd: str | None = None) -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_branch(cwd: str = None) -> str:
|
||||
def get_branch(cwd: str | None = None) -> str:
|
||||
return run_cmd_default(["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], cwd=cwd)
|
||||
|
||||
|
||||
@cache
|
||||
def get_origin(cwd: str = None) -> str:
|
||||
def get_origin(cwd: str | None = None) -> str:
|
||||
try:
|
||||
local_branch = run_cmd(["git", "name-rev", "--name-only", "HEAD"], cwd=cwd)
|
||||
tracking_remote = run_cmd(["git", "config", "branch." + local_branch + ".remote"], cwd=cwd)
|
||||
@@ -34,7 +34,7 @@ def get_origin(cwd: str = None) -> str:
|
||||
|
||||
|
||||
@cache
|
||||
def get_normalized_origin(cwd: str = None) -> str:
|
||||
def get_normalized_origin(cwd: str | None = None) -> str:
|
||||
return get_origin(cwd) \
|
||||
.replace("git@", "", 1) \
|
||||
.replace(".git", "", 1) \
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
#include "common/gpio.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __APPLE__
|
||||
int gpio_init(int pin_nr, bool output) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_set(int pin_nr, bool high) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <linux/gpio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/swaglog.h"
|
||||
|
||||
int gpio_init(int pin_nr, bool output) {
|
||||
char pin_dir_path[50];
|
||||
int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path),
|
||||
"/sys/class/gpio/gpio%d/direction", pin_nr);
|
||||
if (pin_dir_path_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
const char *value = output ? "out" : "in";
|
||||
return util::write_file(pin_dir_path, (void*)value, strlen(value));
|
||||
}
|
||||
|
||||
int gpio_set(int pin_nr, bool high) {
|
||||
char pin_val_path[50];
|
||||
int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path),
|
||||
"/sys/class/gpio/gpio%d/value", pin_nr);
|
||||
if (pin_val_path_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return util::write_file(pin_val_path, (void*)(high ? "1" : "0"), 1);
|
||||
}
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr) {
|
||||
|
||||
// Assumed that all interrupt pins are unexported and rights are given to
|
||||
// read from gpiochip0.
|
||||
std::string gpiochip_path = "/dev/gpiochip" + std::to_string(gpiochiop_id);
|
||||
int fd = open(gpiochip_path.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
LOGE("Error opening gpiochip0 fd");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Setup event
|
||||
struct gpioevent_request rq;
|
||||
rq.lineoffset = pin_nr;
|
||||
rq.handleflags = GPIOHANDLE_REQUEST_INPUT;
|
||||
|
||||
/* Requesting both edges as the data ready pulse from the lsm6ds sensor is
|
||||
very short(75us) and is mostly detected as falling edge instead of rising.
|
||||
So if it is detected as rising the following falling edge is skipped. */
|
||||
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
|
||||
|
||||
strncpy(rq.consumer_label, consumer_label, std::size(rq.consumer_label) - 1);
|
||||
int ret = util::safe_ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq);
|
||||
if (ret == -1) {
|
||||
LOGE("Unable to get line event from ioctl : %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return rq.fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Pin definitions
|
||||
#ifdef QCOM2
|
||||
#define GPIO_HUB_RST_N 30
|
||||
#define GPIO_UBLOX_RST_N 32
|
||||
#define GPIO_UBLOX_SAFEBOOT_N 33
|
||||
#define GPIO_GNSS_PWR_EN 34 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||
#define GPIO_STM_RST_N 124
|
||||
#define GPIO_STM_BOOT0 134
|
||||
#define GPIO_BMX_ACCEL_INT 21
|
||||
#define GPIO_BMX_GYRO_INT 23
|
||||
#define GPIO_BMX_MAGN_INT 87
|
||||
#define GPIO_LSM_INT 84
|
||||
#define GPIOCHIP_INT 0
|
||||
#else
|
||||
#define GPIO_HUB_RST_N 0
|
||||
#define GPIO_UBLOX_RST_N 0
|
||||
#define GPIO_UBLOX_SAFEBOOT_N 0
|
||||
#define GPIO_GNSS_PWR_EN 0 /* SCHEMATIC LABEL: GPIO_UBLOX_PWR_EN */
|
||||
#define GPIO_STM_RST_N 0
|
||||
#define GPIO_STM_BOOT0 0
|
||||
#define GPIO_BMX_ACCEL_INT 0
|
||||
#define GPIO_BMX_GYRO_INT 0
|
||||
#define GPIO_BMX_MAGN_INT 0
|
||||
#define GPIO_LSM_INT 0
|
||||
#define GPIOCHIP_INT 0
|
||||
#endif
|
||||
|
||||
int gpio_init(int pin_nr, bool output);
|
||||
int gpio_set(int pin_nr, bool high);
|
||||
|
||||
int gpiochip_get_ro_value_fd(const char* consumer_label, int gpiochiop_id, int pin_nr);
|
||||
@@ -1,4 +1,6 @@
|
||||
import os
|
||||
import fcntl
|
||||
import ctypes
|
||||
from functools import cache
|
||||
|
||||
def gpio_init(pin: int, output: bool) -> None:
|
||||
@@ -52,3 +54,36 @@ def get_irqs_for_action(action: str) -> list[str]:
|
||||
if irq.isdigit() and action in get_irq_action(irq):
|
||||
ret.append(irq)
|
||||
return ret
|
||||
|
||||
# *** gpiochip ***
|
||||
|
||||
class gpioevent_data(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("timestamp", ctypes.c_uint64),
|
||||
("id", ctypes.c_uint32),
|
||||
]
|
||||
|
||||
class gpioevent_request(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("lineoffset", ctypes.c_uint32),
|
||||
("handleflags", ctypes.c_uint32),
|
||||
("eventflags", ctypes.c_uint32),
|
||||
("label", ctypes.c_char * 32),
|
||||
("fd", ctypes.c_int)
|
||||
]
|
||||
|
||||
def gpiochip_get_ro_value_fd(label: str, gpiochip_id: int, pin: int) -> int:
|
||||
GPIOEVENT_REQUEST_BOTH_EDGES = 0x3
|
||||
GPIOHANDLE_REQUEST_INPUT = 0x1
|
||||
GPIO_GET_LINEEVENT_IOCTL = 0xc030b404
|
||||
|
||||
rq = gpioevent_request()
|
||||
rq.lineoffset = pin
|
||||
rq.handleflags = GPIOHANDLE_REQUEST_INPUT
|
||||
rq.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES
|
||||
rq.label = label.encode('utf-8')[:31] + b'\0'
|
||||
|
||||
fd = os.open(f"/dev/gpiochip{gpiochip_id}", os.O_RDONLY)
|
||||
fcntl.ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, rq)
|
||||
os.close(fd)
|
||||
return int(rq.fd)
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#include "common/i2c.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "common/swaglog.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#ifdef QCOM2
|
||||
// TODO: decide if we want to install libi2c-dev everywhere
|
||||
extern "C" {
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <i2c/smbus.h>
|
||||
}
|
||||
|
||||
I2CBus::I2CBus(uint8_t bus_id) {
|
||||
char bus_name[20];
|
||||
snprintf(bus_name, 20, "/dev/i2c-%d", bus_id);
|
||||
|
||||
i2c_fd = HANDLE_EINTR(open(bus_name, O_RDWR));
|
||||
if (i2c_fd < 0) {
|
||||
throw std::runtime_error("Failed to open I2C bus");
|
||||
}
|
||||
}
|
||||
|
||||
I2CBus::~I2CBus() {
|
||||
if (i2c_fd >= 0) {
|
||||
close(i2c_fd);
|
||||
}
|
||||
}
|
||||
|
||||
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||
std::lock_guard lk(m);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(i2c_fd, register_address, len, buffer);
|
||||
if ((ret < 0) || (ret != len)) { goto fail; }
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||
std::lock_guard lk(m);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = HANDLE_EINTR(ioctl(i2c_fd, I2C_SLAVE, device_address));
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
ret = i2c_smbus_write_byte_data(i2c_fd, register_address, data);
|
||||
if (ret < 0) { goto fail; }
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
I2CBus::I2CBus(uint8_t bus_id) {
|
||||
UNUSED(bus_id);
|
||||
i2c_fd = -1;
|
||||
}
|
||||
|
||||
I2CBus::~I2CBus() {}
|
||||
|
||||
int I2CBus::read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len) {
|
||||
UNUSED(device_address);
|
||||
UNUSED(register_address);
|
||||
UNUSED(buffer);
|
||||
UNUSED(len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int I2CBus::set_register(uint8_t device_address, uint register_address, uint8_t data) {
|
||||
UNUSED(device_address);
|
||||
UNUSED(register_address);
|
||||
UNUSED(data);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
class I2CBus {
|
||||
private:
|
||||
int i2c_fd;
|
||||
std::mutex m;
|
||||
|
||||
public:
|
||||
I2CBus(uint8_t bus_id);
|
||||
~I2CBus();
|
||||
|
||||
int read_register(uint8_t device_address, uint register_address, uint8_t *buffer, uint8_t len);
|
||||
int set_register(uint8_t device_address, uint register_address, uint8_t data);
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import os
|
||||
import fcntl
|
||||
import ctypes
|
||||
|
||||
# I2C constants from /usr/include/linux/i2c-dev.h
|
||||
I2C_SLAVE = 0x0703
|
||||
I2C_SLAVE_FORCE = 0x0706
|
||||
I2C_SMBUS = 0x0720
|
||||
|
||||
# SMBus transfer types
|
||||
I2C_SMBUS_READ = 1
|
||||
I2C_SMBUS_WRITE = 0
|
||||
I2C_SMBUS_BYTE_DATA = 2
|
||||
I2C_SMBUS_I2C_BLOCK_DATA = 8
|
||||
|
||||
I2C_SMBUS_BLOCK_MAX = 32
|
||||
|
||||
|
||||
class _I2cSmbusData(ctypes.Union):
|
||||
_fields_ = [
|
||||
("byte", ctypes.c_uint8),
|
||||
("word", ctypes.c_uint16),
|
||||
("block", ctypes.c_uint8 * (I2C_SMBUS_BLOCK_MAX + 2)),
|
||||
]
|
||||
|
||||
|
||||
class _I2cSmbusIoctlData(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("read_write", ctypes.c_uint8),
|
||||
("command", ctypes.c_uint8),
|
||||
("size", ctypes.c_uint32),
|
||||
("data", ctypes.POINTER(_I2cSmbusData)),
|
||||
]
|
||||
|
||||
|
||||
class SMBus:
|
||||
def __init__(self, bus: int):
|
||||
self._fd = os.open(f'/dev/i2c-{bus}', os.O_RDWR)
|
||||
|
||||
def __enter__(self) -> 'SMBus':
|
||||
return self
|
||||
|
||||
def __exit__(self, *args) -> None:
|
||||
self.close()
|
||||
|
||||
def close(self) -> None:
|
||||
if hasattr(self, '_fd') and self._fd >= 0:
|
||||
os.close(self._fd)
|
||||
self._fd = -1
|
||||
|
||||
def _set_address(self, addr: int, force: bool = False) -> None:
|
||||
ioctl_arg = I2C_SLAVE_FORCE if force else I2C_SLAVE
|
||||
fcntl.ioctl(self._fd, ioctl_arg, addr)
|
||||
|
||||
def _smbus_access(self, read_write: int, command: int, size: int, data: _I2cSmbusData) -> None:
|
||||
ioctl_data = _I2cSmbusIoctlData(read_write, command, size, ctypes.pointer(data))
|
||||
fcntl.ioctl(self._fd, I2C_SMBUS, ioctl_data)
|
||||
|
||||
def read_byte_data(self, addr: int, register: int, force: bool = False) -> int:
|
||||
self._set_address(addr, force)
|
||||
data = _I2cSmbusData()
|
||||
self._smbus_access(I2C_SMBUS_READ, register, I2C_SMBUS_BYTE_DATA, data)
|
||||
return int(data.byte)
|
||||
|
||||
def write_byte_data(self, addr: int, register: int, value: int, force: bool = False) -> None:
|
||||
self._set_address(addr, force)
|
||||
data = _I2cSmbusData()
|
||||
data.byte = value & 0xFF
|
||||
self._smbus_access(I2C_SMBUS_WRITE, register, I2C_SMBUS_BYTE_DATA, data)
|
||||
|
||||
def read_i2c_block_data(self, addr: int, register: int, length: int, force: bool = False) -> list[int]:
|
||||
self._set_address(addr, force)
|
||||
if not (0 <= length <= I2C_SMBUS_BLOCK_MAX):
|
||||
raise ValueError(f"length must be 0..{I2C_SMBUS_BLOCK_MAX}")
|
||||
|
||||
data = _I2cSmbusData()
|
||||
data.block[0] = length
|
||||
self._smbus_access(I2C_SMBUS_READ, register, I2C_SMBUS_I2C_BLOCK_DATA, data)
|
||||
read_len = int(data.block[0]) or length
|
||||
read_len = min(read_len, length)
|
||||
return [int(b) for b in data.block[1 : read_len + 1]]
|
||||
@@ -199,7 +199,6 @@ class SwagLogger(logging.Logger):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
|
||||
# TODO: is this pylint exception correct?
|
||||
if filename == _srcfile:
|
||||
f = f.f_back
|
||||
continue
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct vec3 {
|
||||
float v[3];
|
||||
} vec3;
|
||||
|
||||
typedef struct vec4 {
|
||||
float v[4];
|
||||
} vec4;
|
||||
|
||||
typedef struct mat3 {
|
||||
float v[3*3];
|
||||
} mat3;
|
||||
|
||||
typedef struct mat4 {
|
||||
float v[4*4];
|
||||
} mat4;
|
||||
|
||||
static inline mat3 matmul3(const mat3 &a, const mat3 &b) {
|
||||
mat3 ret = {{0.0}};
|
||||
for (int r=0; r<3; r++) {
|
||||
for (int c=0; c<3; c++) {
|
||||
float v = 0.0;
|
||||
for (int k=0; k<3; k++) {
|
||||
v += a.v[r*3+k] * b.v[k*3+c];
|
||||
}
|
||||
ret.v[r*3+c] = v;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline vec3 matvecmul3(const mat3 &a, const vec3 &b) {
|
||||
vec3 ret = {{0.0}};
|
||||
for (int r=0; r<3; r++) {
|
||||
for (int c=0; c<3; c++) {
|
||||
ret.v[r] += a.v[r*3+c] * b.v[c];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline mat4 matmul(const mat4 &a, const mat4 &b) {
|
||||
mat4 ret = {{0.0}};
|
||||
for (int r=0; r<4; r++) {
|
||||
for (int c=0; c<4; c++) {
|
||||
float v = 0.0;
|
||||
for (int k=0; k<4; k++) {
|
||||
v += a.v[r*4+k] * b.v[k*4+c];
|
||||
}
|
||||
ret.v[r*4+c] = v;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline vec4 matvecmul(const mat4 &a, const vec4 &b) {
|
||||
vec4 ret = {{0.0}};
|
||||
for (int r=0; r<4; r++) {
|
||||
for (int c=0; c<4; c++) {
|
||||
ret.v[r] += a.v[r*4+c] * b.v[c];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// scales the input and output space of a transformation matrix
|
||||
// that assumes pixel-center origin.
|
||||
static inline mat3 transform_scale_buffer(const mat3 &in, float s) {
|
||||
// in_pt = ( transform(out_pt/s + 0.5) - 0.5) * s
|
||||
|
||||
mat3 transform_out = {{
|
||||
1.0f/s, 0.0f, 0.5f,
|
||||
0.0f, 1.0f/s, 0.5f,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
}};
|
||||
|
||||
mat3 transform_in = {{
|
||||
s, 0.0f, -0.5f*s,
|
||||
0.0f, s, -0.5f*s,
|
||||
0.0f, 0.0f, 1.0f,
|
||||
}};
|
||||
|
||||
return matmul3(transform_in, matmul3(in, transform_out));
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import sys
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
class parameterized:
|
||||
@staticmethod
|
||||
def expand(cases):
|
||||
cases = list(cases)
|
||||
|
||||
if not cases:
|
||||
return lambda func: pytest.mark.skip("no parameterized cases")(func)
|
||||
|
||||
def decorator(func):
|
||||
params = [p for p in inspect.signature(func).parameters if p != 'self']
|
||||
normalized = [c if isinstance(c, tuple) else (c,) for c in cases]
|
||||
# Infer arg count from first case so extra params (e.g. from @given) are left untouched
|
||||
expand_params = params[: len(normalized[0])]
|
||||
if len(expand_params) == 1:
|
||||
return pytest.mark.parametrize(expand_params[0], [c[0] for c in normalized])(func)
|
||||
return pytest.mark.parametrize(', '.join(expand_params), normalized)(func)
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def parameterized_class(attrs, input_list=None):
|
||||
if isinstance(attrs, list) and (not attrs or isinstance(attrs[0], dict)):
|
||||
params_list = attrs
|
||||
else:
|
||||
assert input_list is not None
|
||||
attr_names = (attrs,) if isinstance(attrs, str) else tuple(attrs)
|
||||
params_list = [dict(zip(attr_names, v if isinstance(v, (tuple, list)) else (v,), strict=False)) for v in input_list]
|
||||
|
||||
def decorator(cls):
|
||||
globs = sys._getframe(1).f_globals
|
||||
for i, params in enumerate(params_list):
|
||||
name = f"{cls.__name__}_{i}"
|
||||
new_cls = type(name, (cls,), dict(params))
|
||||
new_cls.__module__ = cls.__module__
|
||||
new_cls.__test__ = True # override inherited False so pytest collects this subclass
|
||||
globs[name] = new_cls
|
||||
# Don't collect the un-parametrised base, but return it so outer decorators
|
||||
# (e.g. @pytest.mark.skip) land on it and propagate to subclasses via MRO.
|
||||
cls.__test__ = False
|
||||
return cls
|
||||
|
||||
return decorator
|
||||
+13
-5
@@ -115,8 +115,16 @@ bool Params::checkKey(const std::string &key) {
|
||||
return keys.find(key) != keys.end();
|
||||
}
|
||||
|
||||
ParamKeyFlag Params::getKeyFlag(const std::string &key) {
|
||||
return static_cast<ParamKeyFlag>(keys[key].flags);
|
||||
}
|
||||
|
||||
ParamKeyType Params::getKeyType(const std::string &key) {
|
||||
return static_cast<ParamKeyType>(keys[key]);
|
||||
return keys[key].type;
|
||||
}
|
||||
|
||||
std::optional<std::string> Params::getKeyDefaultValue(const std::string &key) {
|
||||
return keys[key].default_value;
|
||||
}
|
||||
|
||||
int Params::put(const char* key, const char* value, size_t value_size) {
|
||||
@@ -140,7 +148,7 @@ int Params::put(const char* key, const char* value, size_t value_size) {
|
||||
}
|
||||
|
||||
// fsync to force persist the changes.
|
||||
if ((result = fsync(tmp_fd)) < 0) break;
|
||||
if ((result = HANDLE_EINTR(fsync(tmp_fd))) < 0) break;
|
||||
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
|
||||
@@ -195,17 +203,17 @@ std::map<std::string, std::string> Params::readAll() {
|
||||
return util::read_files_in_dir(getParamPath());
|
||||
}
|
||||
|
||||
void Params::clearAll(ParamKeyType key_type) {
|
||||
void Params::clearAll(ParamKeyFlag key_flag) {
|
||||
FileLock file_lock(params_path + "/.lock");
|
||||
|
||||
// 1) delete params of key_type
|
||||
// 1) delete params of key_flag
|
||||
// 2) delete files that are not defined in the keys.
|
||||
if (DIR *d = opendir(getParamPath().c_str())) {
|
||||
struct dirent *de = NULL;
|
||||
while ((de = readdir(d))) {
|
||||
if (de->d_type != DT_DIR) {
|
||||
auto it = keys.find(de->d_name);
|
||||
if (it == keys.end() || (it->second & key_type)) {
|
||||
if (it == keys.end() || (it->second.flags & key_flag)) {
|
||||
unlink(getParamPath(de->d_name).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
+22
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@@ -9,16 +10,33 @@
|
||||
|
||||
#include "common/queue.h"
|
||||
|
||||
enum ParamKeyType {
|
||||
enum ParamKeyFlag {
|
||||
PERSISTENT = 0x02,
|
||||
CLEAR_ON_MANAGER_START = 0x04,
|
||||
CLEAR_ON_ONROAD_TRANSITION = 0x08,
|
||||
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
|
||||
DONT_LOG = 0x20,
|
||||
DEVELOPMENT_ONLY = 0x40,
|
||||
CLEAR_ON_IGNITION_ON = 0x80,
|
||||
ALL = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum ParamKeyType {
|
||||
STRING = 0, // must be utf-8 decodable
|
||||
BOOL = 1,
|
||||
INT = 2,
|
||||
FLOAT = 3,
|
||||
TIME = 4, // ISO 8601
|
||||
JSON = 5,
|
||||
BYTES = 6
|
||||
};
|
||||
|
||||
struct ParamKeyAttributes {
|
||||
uint32_t flags;
|
||||
ParamKeyType type;
|
||||
std::optional<std::string> default_value = std::nullopt;
|
||||
};
|
||||
|
||||
class Params {
|
||||
public:
|
||||
explicit Params(const std::string &path = {});
|
||||
@@ -29,14 +47,16 @@ public:
|
||||
|
||||
std::vector<std::string> allKeys() const;
|
||||
bool checkKey(const std::string &key);
|
||||
ParamKeyFlag getKeyFlag(const std::string &key);
|
||||
ParamKeyType getKeyType(const std::string &key);
|
||||
std::optional<std::string> getKeyDefaultValue(const std::string &key);
|
||||
inline std::string getParamPath(const std::string &key = {}) {
|
||||
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
|
||||
}
|
||||
|
||||
// Delete a value
|
||||
int remove(const std::string &key);
|
||||
void clearAll(ParamKeyType type);
|
||||
void clearAll(ParamKeyFlag flag);
|
||||
|
||||
// helpers for reading values
|
||||
std::string get(const std::string &key, bool block = false);
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
|
||||
from openpilot.common.params_pyx import Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
|
||||
assert Params
|
||||
assert ParamKeyFlag
|
||||
assert ParamKeyType
|
||||
assert UnknownKeyName
|
||||
|
||||
|
||||
+127
-114
@@ -3,118 +3,131 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
inline static std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||
{"AdbEnabled", PERSISTENT},
|
||||
{"AlwaysOnDM", PERSISTENT},
|
||||
{"ApiCache_Device", PERSISTENT},
|
||||
{"ApiCache_FirehoseStats", PERSISTENT},
|
||||
{"AssistNowToken", PERSISTENT},
|
||||
{"AthenadPid", PERSISTENT},
|
||||
{"AthenadUploadQueue", PERSISTENT},
|
||||
{"AthenadRecentlyViewedRoutes", PERSISTENT},
|
||||
{"BootCount", PERSISTENT},
|
||||
{"CalibrationParams", PERSISTENT},
|
||||
{"CameraDebugExpGain", CLEAR_ON_MANAGER_START},
|
||||
{"CameraDebugExpTime", CLEAR_ON_MANAGER_START},
|
||||
{"CarBatteryCapacity", PERSISTENT},
|
||||
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CarParamsCache", CLEAR_ON_MANAGER_START},
|
||||
{"CarParamsPersistent", PERSISTENT},
|
||||
{"CarParamsPrevRoute", PERSISTENT},
|
||||
{"CompletedTrainingVersion", PERSISTENT},
|
||||
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CurrentBootlog", PERSISTENT},
|
||||
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"DisablePowerDown", PERSISTENT},
|
||||
{"DisableUpdates", PERSISTENT},
|
||||
{"DisengageOnAccelerator", PERSISTENT},
|
||||
{"DongleId", PERSISTENT},
|
||||
{"DoReboot", CLEAR_ON_MANAGER_START},
|
||||
{"DoShutdown", CLEAR_ON_MANAGER_START},
|
||||
{"DoUninstall", CLEAR_ON_MANAGER_START},
|
||||
{"ExperimentalLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY},
|
||||
{"ExperimentalMode", PERSISTENT},
|
||||
{"ExperimentalModeConfirmed", PERSISTENT},
|
||||
{"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ForcePowerDown", PERSISTENT},
|
||||
{"GitBranch", PERSISTENT},
|
||||
{"GitCommit", PERSISTENT},
|
||||
{"GitCommitDate", PERSISTENT},
|
||||
{"GitDiff", PERSISTENT},
|
||||
{"GithubSshKeys", PERSISTENT},
|
||||
{"GithubUsername", PERSISTENT},
|
||||
{"GitRemote", PERSISTENT},
|
||||
{"GsmApn", PERSISTENT},
|
||||
{"GsmMetered", PERSISTENT},
|
||||
{"GsmRoaming", PERSISTENT},
|
||||
{"HardwareSerial", PERSISTENT},
|
||||
{"HasAcceptedTerms", PERSISTENT},
|
||||
{"InstallDate", PERSISTENT},
|
||||
{"IsDriverViewEnabled", CLEAR_ON_MANAGER_START},
|
||||
{"IsEngaged", PERSISTENT},
|
||||
{"IsLdwEnabled", PERSISTENT},
|
||||
{"IsMetric", PERSISTENT},
|
||||
{"IsOffroad", CLEAR_ON_MANAGER_START},
|
||||
{"IsOnroad", PERSISTENT},
|
||||
{"IsRhdDetected", PERSISTENT},
|
||||
{"IsReleaseBranch", CLEAR_ON_MANAGER_START},
|
||||
{"IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"IsTestedBranch", CLEAR_ON_MANAGER_START},
|
||||
{"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LanguageSetting", PERSISTENT},
|
||||
{"LastAthenaPingTime", CLEAR_ON_MANAGER_START},
|
||||
{"LastGPSPosition", PERSISTENT},
|
||||
{"LastManagerExitReason", CLEAR_ON_MANAGER_START},
|
||||
{"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LastPowerDropDetected", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateException", CLEAR_ON_MANAGER_START},
|
||||
{"LastUpdateTime", PERSISTENT},
|
||||
{"LiveParameters", PERSISTENT},
|
||||
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
|
||||
{"LocationFilterInitialState", PERSISTENT},
|
||||
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"LongitudinalPersonality", PERSISTENT},
|
||||
{"NetworkMetered", PERSISTENT},
|
||||
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_BadNvme", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"Offroad_StorageMissing", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START},
|
||||
{"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START},
|
||||
{"OpenpilotEnabledToggle", PERSISTENT},
|
||||
{"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"PandaSignatures", CLEAR_ON_MANAGER_START},
|
||||
{"PrimeType", PERSISTENT},
|
||||
{"RecordFront", PERSISTENT},
|
||||
{"RecordFrontLock", PERSISTENT}, // for the internal fleet
|
||||
{"SecOCKey", PERSISTENT | DONT_LOG},
|
||||
{"RouteCount", PERSISTENT},
|
||||
{"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
|
||||
{"SshEnabled", PERSISTENT},
|
||||
{"TermsVersion", PERSISTENT},
|
||||
{"TrainingVersion", PERSISTENT},
|
||||
{"UbloxAvailable", PERSISTENT},
|
||||
{"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"UpdateFailedCount", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterAvailableBranches", PERSISTENT},
|
||||
{"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterNewDescription", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterState", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterTargetBranch", CLEAR_ON_MANAGER_START},
|
||||
{"UpdaterLastFetchTime", PERSISTENT},
|
||||
{"Version", PERSISTENT},
|
||||
#include "cereal/gen/cpp/log.capnp.h"
|
||||
|
||||
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
|
||||
{"AdbEnabled", {PERSISTENT, BOOL}},
|
||||
{"AlwaysOnDM", {PERSISTENT, BOOL}},
|
||||
{"ApiCache_Device", {PERSISTENT, STRING}},
|
||||
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
|
||||
{"AssistNowToken", {PERSISTENT, STRING}},
|
||||
{"AthenadPid", {PERSISTENT, INT}},
|
||||
{"AthenadUploadQueue", {PERSISTENT, JSON}},
|
||||
{"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}},
|
||||
{"BootCount", {PERSISTENT, INT}},
|
||||
{"CalibrationParams", {PERSISTENT, BYTES}},
|
||||
{"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"CarBatteryCapacity", {PERSISTENT, INT}},
|
||||
{"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}},
|
||||
{"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||
{"CarParamsPersistent", {PERSISTENT, BYTES}},
|
||||
{"CarParamsPrevRoute", {PERSISTENT, BYTES}},
|
||||
{"CompletedTrainingVersion", {PERSISTENT, STRING, "0"}},
|
||||
{"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"CurrentBootlog", {PERSISTENT, STRING}},
|
||||
{"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}},
|
||||
{"DisableLogging", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"DisablePowerDown", {PERSISTENT, BOOL}},
|
||||
{"DisableUpdates", {PERSISTENT, BOOL}},
|
||||
{"DisengageOnAccelerator", {PERSISTENT, BOOL, "0"}},
|
||||
{"DongleId", {PERSISTENT, STRING}},
|
||||
{"DoReboot", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
|
||||
{"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY, BOOL}},
|
||||
{"ExperimentalMode", {PERSISTENT, BOOL}},
|
||||
{"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
|
||||
{"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"ForcePowerDown", {PERSISTENT, BOOL}},
|
||||
{"GitBranch", {PERSISTENT, STRING}},
|
||||
{"GitCommit", {PERSISTENT, STRING}},
|
||||
{"GitCommitDate", {PERSISTENT, STRING}},
|
||||
{"GitDiff", {PERSISTENT, STRING}},
|
||||
{"GithubSshKeys", {PERSISTENT, STRING}},
|
||||
{"GithubUsername", {PERSISTENT, STRING}},
|
||||
{"GitRemote", {PERSISTENT, STRING}},
|
||||
{"GsmApn", {PERSISTENT, STRING}},
|
||||
{"GsmMetered", {PERSISTENT, BOOL, "1"}},
|
||||
{"GsmRoaming", {PERSISTENT, BOOL}},
|
||||
{"HardwareSerial", {PERSISTENT, STRING}},
|
||||
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
|
||||
{"InstallDate", {PERSISTENT, TIME}},
|
||||
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsEngaged", {PERSISTENT, BOOL}},
|
||||
{"IsLdwEnabled", {PERSISTENT, BOOL}},
|
||||
{"IsMetric", {PERSISTENT, BOOL}},
|
||||
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsOnroad", {PERSISTENT, BOOL}},
|
||||
{"IsRhdDetected", {PERSISTENT, BOOL}},
|
||||
{"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"LanguageSetting", {PERSISTENT, STRING, "en"}},
|
||||
{"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}},
|
||||
{"LastGPSPosition", {PERSISTENT, STRING}},
|
||||
{"LastManagerExitReason", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}},
|
||||
{"LastAgnosPowerMonitorShutdown", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"LastUpdateRouteCount", {PERSISTENT, INT, "0"}},
|
||||
{"LastUpdateTime", {PERSISTENT, TIME}},
|
||||
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||
{"LiveDelay", {PERSISTENT, BYTES}},
|
||||
{"LiveParameters", {PERSISTENT, JSON}},
|
||||
{"LiveParametersV2", {PERSISTENT, BYTES}},
|
||||
{"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}},
|
||||
{"LocationFilterInitialState", {PERSISTENT, BYTES}},
|
||||
{"LateralManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"LongitudinalManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"LongitudinalPersonality", {PERSISTENT, INT, std::to_string(static_cast<int>(cereal::LongitudinalPersonality::STANDARD))}},
|
||||
{"NetworkMetered", {PERSISTENT, BOOL}},
|
||||
{"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||
{"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_ExcessiveActuation", {PERSISTENT, JSON}},
|
||||
{"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||
{"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||
{"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}},
|
||||
{"Offroad_DriverMonitoringUncertain", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
|
||||
{"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"OpenpilotEnabledToggle", {PERSISTENT, BOOL, "1"}},
|
||||
{"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||
{"PrimeType", {PERSISTENT, INT}},
|
||||
{"RecordAudio", {PERSISTENT, BOOL}},
|
||||
{"RecordAudioFeedback", {PERSISTENT, BOOL, "0"}},
|
||||
{"RecordFront", {PERSISTENT, BOOL}},
|
||||
{"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet
|
||||
{"SecOCKey", {PERSISTENT | DONT_LOG, STRING}},
|
||||
{"ShowDebugInfo", {PERSISTENT, BOOL}},
|
||||
{"RouteCount", {PERSISTENT, INT, "0"}},
|
||||
{"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}},
|
||||
{"SshEnabled", {PERSISTENT, BOOL}},
|
||||
{"UbloxAvailable", {PERSISTENT, BOOL}},
|
||||
{"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
|
||||
{"UpdateFailedCount", {CLEAR_ON_MANAGER_START, INT}},
|
||||
{"UpdaterAvailableBranches", {PERSISTENT, STRING}},
|
||||
{"UpdaterCurrentDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"UpdaterCurrentReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||
{"UpdaterFetchAvailable", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"UpdaterNewDescription", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"UpdaterNewReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}},
|
||||
{"UpdaterState", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"UpdaterTargetBranch", {CLEAR_ON_MANAGER_START, STRING}},
|
||||
{"UpdaterLastFetchTime", {PERSISTENT, TIME}},
|
||||
{"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||
{"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
|
||||
{"Version", {PERSISTENT, STRING}},
|
||||
};
|
||||
|
||||
+9901
-10076
File diff suppressed because it is too large
Load Diff
+83
-10
@@ -1,18 +1,34 @@
|
||||
# distutils: language = c++
|
||||
# cython: language_level = 3
|
||||
import builtins
|
||||
import datetime
|
||||
import json
|
||||
from libcpp cimport bool
|
||||
from libcpp.string cimport string
|
||||
from libcpp.vector cimport vector
|
||||
from libcpp.optional cimport optional
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
cdef extern from "common/params.h":
|
||||
cpdef enum ParamKeyType:
|
||||
cpdef enum ParamKeyFlag:
|
||||
PERSISTENT
|
||||
CLEAR_ON_MANAGER_START
|
||||
CLEAR_ON_ONROAD_TRANSITION
|
||||
CLEAR_ON_OFFROAD_TRANSITION
|
||||
DEVELOPMENT_ONLY
|
||||
CLEAR_ON_IGNITION_ON
|
||||
ALL
|
||||
|
||||
cpdef enum ParamKeyType:
|
||||
STRING
|
||||
BOOL
|
||||
INT
|
||||
FLOAT
|
||||
TIME
|
||||
JSON
|
||||
BYTES
|
||||
|
||||
cdef cppclass c_Params "Params":
|
||||
c_Params(string) except + nogil
|
||||
string get(string, bool) nogil
|
||||
@@ -23,10 +39,31 @@ cdef extern from "common/params.h":
|
||||
void putBoolNonBlocking(string, bool) nogil
|
||||
int putBool(string, bool) nogil
|
||||
bool checkKey(string) nogil
|
||||
ParamKeyType getKeyType(string) nogil
|
||||
optional[string] getKeyDefaultValue(string) nogil
|
||||
string getParamPath(string) nogil
|
||||
void clearAll(ParamKeyType)
|
||||
void clearAll(ParamKeyFlag)
|
||||
vector[string] allKeys()
|
||||
|
||||
PYTHON_2_CPP = {
|
||||
(str, STRING): lambda v: v,
|
||||
(builtins.bool, BOOL): lambda v: "1" if v else "0",
|
||||
(int, INT): str,
|
||||
(float, FLOAT): str,
|
||||
(datetime.datetime, TIME): lambda v: v.isoformat(),
|
||||
(dict, JSON): json.dumps,
|
||||
(list, JSON): json.dumps,
|
||||
(bytes, BYTES): lambda v: v,
|
||||
}
|
||||
CPP_2_PYTHON = {
|
||||
STRING: lambda v: v.decode("utf-8"),
|
||||
BOOL: lambda v: v == b"1",
|
||||
INT: int,
|
||||
FLOAT: float,
|
||||
TIME: lambda v: datetime.datetime.fromisoformat(v.decode("utf-8")),
|
||||
JSON: json.loads,
|
||||
BYTES: lambda v: v,
|
||||
}
|
||||
|
||||
def ensure_bytes(v):
|
||||
return v.encode() if isinstance(v, str) else v
|
||||
@@ -50,8 +87,8 @@ cdef class Params:
|
||||
def __dealloc__(self):
|
||||
del self.p
|
||||
|
||||
def clear_all(self, tx_type=ParamKeyType.ALL):
|
||||
self.p.clearAll(tx_type)
|
||||
def clear_all(self, tx_flag=ParamKeyFlag.ALL):
|
||||
self.p.clearAll(tx_flag)
|
||||
|
||||
def check_key(self, key):
|
||||
key = ensure_bytes(key)
|
||||
@@ -59,21 +96,38 @@ cdef class Params:
|
||||
raise UnknownKeyName(key)
|
||||
return key
|
||||
|
||||
def get(self, key, bool block=False, encoding=None):
|
||||
def python2cpp(self, proposed_type, expected_type, value, key):
|
||||
cast = PYTHON_2_CPP.get((proposed_type, expected_type))
|
||||
if cast:
|
||||
return cast(value)
|
||||
raise TypeError(f"Type mismatch while writing param {key}: {proposed_type=} {expected_type=} {value=}")
|
||||
|
||||
def _cpp2python(self, t, value, default, key):
|
||||
if value is None:
|
||||
return None
|
||||
try:
|
||||
return CPP_2_PYTHON[t](value)
|
||||
except (KeyError, TypeError, ValueError):
|
||||
cloudlog.warning(f"Failed to cast param {key} with {value=} from type {t=}")
|
||||
return self._cpp2python(t, default, None, key)
|
||||
|
||||
def get(self, key, bool block=False, bool return_default=False):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
||||
cdef optional[string] default = self.p.getKeyDefaultValue(k)
|
||||
cdef string val
|
||||
with nogil:
|
||||
val = self.p.get(k, block)
|
||||
|
||||
default_val = (default.value() if default.has_value() else None) if return_default else None
|
||||
if val == b"":
|
||||
if block:
|
||||
# If we got no value while running in blocked mode
|
||||
# it means we got an interrupt while waiting
|
||||
raise KeyboardInterrupt
|
||||
else:
|
||||
return None
|
||||
|
||||
return val if encoding is None else val.decode(encoding)
|
||||
return self._cpp2python(t, default_val, None, key)
|
||||
return self._cpp2python(t, val, default_val, key)
|
||||
|
||||
def get_bool(self, key, bool block=False):
|
||||
cdef string k = self.check_key(key)
|
||||
@@ -82,6 +136,11 @@ cdef class Params:
|
||||
r = self.p.getBool(k, block)
|
||||
return r
|
||||
|
||||
def _put_cast(self, key, dat):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
||||
return ensure_bytes(self.python2cpp(type(dat), t, dat, key))
|
||||
|
||||
def put(self, key, dat):
|
||||
"""
|
||||
Warning: This function blocks until the param is written to disk!
|
||||
@@ -90,7 +149,7 @@ cdef class Params:
|
||||
in general try to avoid writing params as much as possible.
|
||||
"""
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
cdef string dat_bytes = self._put_cast(key, dat)
|
||||
with nogil:
|
||||
self.p.put(k, dat_bytes)
|
||||
|
||||
@@ -101,7 +160,7 @@ cdef class Params:
|
||||
|
||||
def put_nonblocking(self, key, dat):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef string dat_bytes = ensure_bytes(dat)
|
||||
cdef string dat_bytes = self._put_cast(key, dat)
|
||||
with nogil:
|
||||
self.p.putNonBlocking(k, dat_bytes)
|
||||
|
||||
@@ -119,5 +178,19 @@ cdef class Params:
|
||||
cdef string key_bytes = ensure_bytes(key)
|
||||
return self.p.getParamPath(key_bytes).decode("utf-8")
|
||||
|
||||
def get_type(self, key):
|
||||
return self.p.getKeyType(self.check_key(key))
|
||||
|
||||
def all_keys(self):
|
||||
return self.p.allKeys()
|
||||
|
||||
def get_default_value(self, key):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
||||
cdef optional[string] default = self.p.getKeyDefaultValue(k)
|
||||
return self._cpp2python(t, default.value(), None, key) if default.has_value() else None
|
||||
|
||||
def cpp2python(self, key, value):
|
||||
cdef string k = self.check_key(key)
|
||||
cdef ParamKeyType t = self.p.getKeyType(k)
|
||||
return self._cpp2python(t, value, None, key)
|
||||
|
||||
Binary file not shown.
+21
-34
@@ -2,23 +2,14 @@ import numpy as np
|
||||
from numbers import Number
|
||||
|
||||
class PIDController:
|
||||
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
|
||||
self._k_p = k_p
|
||||
self._k_i = k_i
|
||||
self._k_d = k_d
|
||||
self.k_f = k_f # feedforward gain
|
||||
if isinstance(self._k_p, Number):
|
||||
self._k_p = [[0], [self._k_p]]
|
||||
if isinstance(self._k_i, Number):
|
||||
self._k_i = [[0], [self._k_i]]
|
||||
if isinstance(self._k_d, Number):
|
||||
self._k_d = [[0], [self._k_d]]
|
||||
def __init__(self, k_p, k_i, k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
|
||||
self._k_p: list[list[float]] = [[0], [k_p]] if isinstance(k_p, Number) else k_p
|
||||
self._k_i: list[list[float]] = [[0], [k_i]] if isinstance(k_i, Number) else k_i
|
||||
self._k_d: list[list[float]] = [[0], [k_d]] if isinstance(k_d, Number) else k_d
|
||||
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
self.set_limits(pos_limit, neg_limit)
|
||||
|
||||
self.i_unwind_rate = 0.3 / rate
|
||||
self.i_rate = 1.0 / rate
|
||||
self.i_dt = 1.0 / rate
|
||||
self.speed = 0.0
|
||||
|
||||
self.reset()
|
||||
@@ -35,10 +26,6 @@ class PIDController:
|
||||
def k_d(self):
|
||||
return np.interp(self.speed, self._k_d[0], self._k_d[1])
|
||||
|
||||
@property
|
||||
def error_integral(self):
|
||||
return self.i/self.k_i
|
||||
|
||||
def reset(self):
|
||||
self.p = 0.0
|
||||
self.i = 0.0
|
||||
@@ -46,25 +33,25 @@ class PIDController:
|
||||
self.f = 0.0
|
||||
self.control = 0
|
||||
|
||||
def update(self, error, error_rate=0.0, speed=0.0, override=False, feedforward=0., freeze_integrator=False):
|
||||
def set_limits(self, pos_limit, neg_limit):
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
|
||||
def update(self, error, error_rate=0.0, speed=0.0, feedforward=0., freeze_integrator=False):
|
||||
self.speed = speed
|
||||
self.p = self.k_p * float(error)
|
||||
self.d = self.k_d * error_rate
|
||||
self.f = feedforward
|
||||
|
||||
self.p = float(error) * self.k_p
|
||||
self.f = feedforward * self.k_f
|
||||
self.d = error_rate * self.k_d
|
||||
if not freeze_integrator:
|
||||
i = self.i + self.k_i * self.i_dt * error
|
||||
|
||||
if override:
|
||||
self.i -= self.i_unwind_rate * float(np.sign(self.i))
|
||||
else:
|
||||
if not freeze_integrator:
|
||||
self.i = self.i + error * self.k_i * self.i_rate
|
||||
|
||||
# Clip i to prevent exceeding control limits
|
||||
control_no_i = self.p + self.d + self.f
|
||||
control_no_i = np.clip(control_no_i, self.neg_limit, self.pos_limit)
|
||||
self.i = np.clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
|
||||
# Don't allow windup if already clipping
|
||||
test_control = self.p + i + self.d + self.f
|
||||
i_upperbound = self.i if test_control > self.pos_limit else self.pos_limit
|
||||
i_lowerbound = self.i if test_control < self.neg_limit else self.neg_limit
|
||||
self.i = np.clip(i, i_lowerbound, i_upperbound)
|
||||
|
||||
control = self.p + self.i + self.d + self.f
|
||||
|
||||
self.control = np.clip(control, self.neg_limit, self.pos_limit)
|
||||
return self.control
|
||||
|
||||
+9
-5
@@ -13,7 +13,11 @@ public:
|
||||
if (prefix.empty()) {
|
||||
prefix = util::random_string(15);
|
||||
}
|
||||
msgq_path = Path::shm_path() + "/" + prefix;
|
||||
#ifdef __APPLE__
|
||||
msgq_path = "/tmp/msgq_" + prefix;
|
||||
#else
|
||||
msgq_path = "/dev/shm/msgq_" + prefix;
|
||||
#endif
|
||||
bool ret = util::create_directories(msgq_path, 0777);
|
||||
assert(ret);
|
||||
setenv("OPENPILOT_PREFIX", prefix.c_str(), 1);
|
||||
@@ -23,14 +27,14 @@ public:
|
||||
auto param_path = Params().getParamPath();
|
||||
if (util::file_exists(param_path)) {
|
||||
std::string real_path = util::readlink(param_path);
|
||||
system(util::string_format("rm %s -rf", real_path.c_str()).c_str());
|
||||
util::check_system(util::string_format("rm %s -rf", real_path.c_str()));
|
||||
unlink(param_path.c_str());
|
||||
}
|
||||
if (getenv("COMMA_CACHE") == nullptr) {
|
||||
system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()).c_str());
|
||||
util::check_system(util::string_format("rm %s -rf", Path::download_cache_root().c_str()));
|
||||
}
|
||||
system(util::string_format("rm %s -rf", Path::comma_home().c_str()).c_str());
|
||||
system(util::string_format("rm %s -rf", msgq_path.c_str()).c_str());
|
||||
util::check_system(util::string_format("rm %s -rf", Path::comma_home().c_str()));
|
||||
util::check_system(util::string_format("rm %s -rf", msgq_path.c_str()));
|
||||
unsetenv("OPENPILOT_PREFIX");
|
||||
}
|
||||
|
||||
|
||||
+15
-7
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import uuid
|
||||
|
||||
@@ -9,20 +10,20 @@ from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
|
||||
class OpenpilotPrefix:
|
||||
def __init__(self, prefix: str = None, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||
def __init__(self, prefix: str | None = None, create_dirs_on_enter: bool = True, clean_dirs_on_exit: bool = True, shared_download_cache: bool = False):
|
||||
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
|
||||
self.msgq_path = os.path.join(Paths.shm_path(), self.prefix)
|
||||
shm_path = "/tmp" if platform.system() == "Darwin" else "/dev/shm"
|
||||
self.msgq_path = os.path.join(shm_path, "msgq_" + self.prefix)
|
||||
self.create_dirs_on_enter = create_dirs_on_enter
|
||||
self.clean_dirs_on_exit = clean_dirs_on_exit
|
||||
self.shared_download_cache = shared_download_cache
|
||||
|
||||
def __enter__(self):
|
||||
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
|
||||
os.environ['OPENPILOT_PREFIX'] = self.prefix
|
||||
try:
|
||||
os.mkdir(self.msgq_path)
|
||||
except FileExistsError:
|
||||
pass
|
||||
os.makedirs(Paths.log_root(), exist_ok=True)
|
||||
|
||||
if self.create_dirs_on_enter:
|
||||
self.create_dirs()
|
||||
|
||||
if self.shared_download_cache:
|
||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
@@ -40,6 +41,13 @@ class OpenpilotPrefix:
|
||||
pass
|
||||
return False
|
||||
|
||||
def create_dirs(self):
|
||||
try:
|
||||
os.mkdir(self.msgq_path)
|
||||
except FileExistsError:
|
||||
pass
|
||||
os.makedirs(Paths.log_root(), exist_ok=True)
|
||||
|
||||
def clean_dirs(self):
|
||||
symlink_path = Params().get_param_path()
|
||||
if os.path.exists(symlink_path):
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#include "common/timing.h"
|
||||
#include "common/util.h"
|
||||
|
||||
RateKeeper::RateKeeper(const std::string &name, float rate, float print_delay_threshold)
|
||||
: name(name),
|
||||
print_delay_threshold(std::max(0.f, print_delay_threshold)) {
|
||||
RateKeeper::RateKeeper(const std::string &name_, float rate, float print_delay_threshold_)
|
||||
: name(name_),
|
||||
print_delay_threshold(std::max(0.f, print_delay_threshold_)) {
|
||||
interval = 1 / rate;
|
||||
last_monitor_time = seconds_since_boot();
|
||||
next_frame_time = last_monitor_time + interval;
|
||||
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
"""Utilities for reading real time clocks and keeping soft real time constraints."""
|
||||
import gc
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from setproctitle import getproctitle
|
||||
|
||||
from openpilot.common.util import MovingAverage
|
||||
from openpilot.common.utils import MovingAverage
|
||||
from openpilot.system.hardware import PC
|
||||
|
||||
|
||||
@@ -28,13 +29,13 @@ class Priority:
|
||||
|
||||
|
||||
def set_core_affinity(cores: list[int]) -> None:
|
||||
if not PC:
|
||||
if sys.platform == 'linux' and not PC:
|
||||
os.sched_setaffinity(0, cores)
|
||||
|
||||
|
||||
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
||||
gc.disable()
|
||||
if not PC:
|
||||
if sys.platform == 'linux' and not PC:
|
||||
os.sched_setscheduler(0, os.SCHED_FIFO, os.sched_param(priority))
|
||||
c = cores if isinstance(cores, list) else [cores, ]
|
||||
set_core_affinity(c)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import time
|
||||
import functools
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
|
||||
def retry(attempts=3, delay=1.0, ignore_failure=False):
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for _ in range(attempts):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception:
|
||||
cloudlog.exception(f"{func.__name__} failed, trying again")
|
||||
time.sleep(delay)
|
||||
|
||||
if ignore_failure:
|
||||
cloudlog.error(f"{func.__name__} failed after retry")
|
||||
else:
|
||||
raise Exception(f"{func.__name__} failed after retry")
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@retry(attempts=10)
|
||||
def abc():
|
||||
raise ValueError("abc failed :(")
|
||||
abc()
|
||||
@@ -1,13 +0,0 @@
|
||||
import subprocess
|
||||
|
||||
|
||||
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
|
||||
return subprocess.check_output(cmd, encoding='utf8', cwd=cwd, env=env).strip()
|
||||
|
||||
|
||||
def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> str:
|
||||
try:
|
||||
return run_cmd(cmd, cwd=cwd, env=env)
|
||||
except subprocess.CalledProcessError:
|
||||
return default
|
||||
|
||||
Regular → Executable
+2
-2
@@ -6,9 +6,9 @@ from openpilot.common.basedir import BASEDIR
|
||||
class Spinner:
|
||||
def __init__(self):
|
||||
try:
|
||||
self.spinner_proc = subprocess.Popen(["./spinner"],
|
||||
self.spinner_proc = subprocess.Popen(["./spinner.py"],
|
||||
stdin=subprocess.PIPE,
|
||||
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
||||
cwd=os.path.join(BASEDIR, "system", "ui"),
|
||||
close_fds=True)
|
||||
except OSError:
|
||||
self.spinner_proc = None
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
from uuid import uuid4
|
||||
|
||||
from openpilot.common.file_helpers import atomic_write_in_dir
|
||||
from openpilot.common.utils import atomic_write
|
||||
|
||||
|
||||
class TestFileHelpers:
|
||||
@@ -15,5 +15,5 @@ class TestFileHelpers:
|
||||
assert f.read() == "test"
|
||||
os.remove(path)
|
||||
|
||||
def test_atomic_write_in_dir(self):
|
||||
self.run_atomic_write_func(atomic_write_in_dir)
|
||||
def test_atomic_write(self):
|
||||
self.run_atomic_write_func(atomic_write)
|
||||
|
||||
+44
-12
@@ -1,10 +1,11 @@
|
||||
import pytest
|
||||
import datetime
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from openpilot.common.params import Params, ParamKeyType, UnknownKeyName
|
||||
from openpilot.common.params import Params, ParamKeyFlag, UnknownKeyName
|
||||
|
||||
class TestParams:
|
||||
def setup_method(self):
|
||||
@@ -12,7 +13,7 @@ class TestParams:
|
||||
|
||||
def test_params_put_and_get(self):
|
||||
self.params.put("DongleId", "cb38263377b873ee")
|
||||
assert self.params.get("DongleId") == b"cb38263377b873ee"
|
||||
assert self.params.get("DongleId") == "cb38263377b873ee"
|
||||
|
||||
def test_params_non_ascii(self):
|
||||
st = b"\xe1\x90\xff"
|
||||
@@ -20,7 +21,7 @@ class TestParams:
|
||||
assert self.params.get("CarParams") == st
|
||||
|
||||
def test_params_get_cleared_manager_start(self):
|
||||
self.params.put("CarParams", "test")
|
||||
self.params.put("CarParams", b"test")
|
||||
self.params.put("DongleId", "cb38263377b873ee")
|
||||
assert self.params.get("CarParams") == b"test"
|
||||
|
||||
@@ -29,24 +30,24 @@ class TestParams:
|
||||
f.write("test")
|
||||
assert os.path.isfile(undefined_param)
|
||||
|
||||
self.params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START)
|
||||
self.params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START)
|
||||
assert self.params.get("CarParams") is None
|
||||
assert self.params.get("DongleId") is not None
|
||||
assert not os.path.isfile(undefined_param)
|
||||
|
||||
def test_params_two_things(self):
|
||||
self.params.put("DongleId", "bob")
|
||||
self.params.put("AthenadPid", "123")
|
||||
assert self.params.get("DongleId") == b"bob"
|
||||
assert self.params.get("AthenadPid") == b"123"
|
||||
self.params.put("AthenadPid", 123)
|
||||
assert self.params.get("DongleId") == "bob"
|
||||
assert self.params.get("AthenadPid") == 123
|
||||
|
||||
def test_params_get_block(self):
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
self.params.put("CarParams", "test")
|
||||
self.params.put("CarParams", b"test")
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert self.params.get("CarParams") is None
|
||||
assert self.params.get("CarParams", True) == b"test"
|
||||
assert self.params.get("CarParams", block=True) == b"test"
|
||||
|
||||
def test_params_unknown_key_fails(self):
|
||||
with pytest.raises(UnknownKeyName):
|
||||
@@ -76,17 +77,17 @@ class TestParams:
|
||||
self.params.put_bool("IsMetric", False)
|
||||
assert not self.params.get_bool("IsMetric")
|
||||
|
||||
self.params.put("IsMetric", "1")
|
||||
self.params.put("IsMetric", True)
|
||||
assert self.params.get_bool("IsMetric")
|
||||
|
||||
self.params.put("IsMetric", "0")
|
||||
self.params.put("IsMetric", False)
|
||||
assert not self.params.get_bool("IsMetric")
|
||||
|
||||
def test_put_non_blocking_with_get_block(self):
|
||||
q = Params()
|
||||
def _delayed_writer():
|
||||
time.sleep(0.1)
|
||||
Params().put_nonblocking("CarParams", "test")
|
||||
Params().put_nonblocking("CarParams", b"test")
|
||||
threading.Thread(target=_delayed_writer).start()
|
||||
assert q.get("CarParams") is None
|
||||
assert q.get("CarParams", True) == b"test"
|
||||
@@ -107,3 +108,34 @@ class TestParams:
|
||||
assert len(keys) > 20
|
||||
assert len(keys) == len(set(keys))
|
||||
assert b"CarParams" in keys
|
||||
|
||||
def test_params_default_value(self):
|
||||
self.params.remove("LanguageSetting")
|
||||
self.params.remove("LongitudinalPersonality")
|
||||
self.params.remove("LiveParameters")
|
||||
|
||||
assert self.params.get("LanguageSetting") is None
|
||||
assert self.params.get("LanguageSetting", return_default=False) is None
|
||||
assert isinstance(self.params.get("LanguageSetting", return_default=True), str)
|
||||
assert isinstance(self.params.get("LongitudinalPersonality", return_default=True), int)
|
||||
assert self.params.get("LiveParameters") is None
|
||||
assert self.params.get("LiveParameters", return_default=True) is None
|
||||
|
||||
def test_params_get_type(self):
|
||||
# json
|
||||
self.params.put("ApiCache_FirehoseStats", {"a": 0})
|
||||
assert self.params.get("ApiCache_FirehoseStats") == {"a": 0}
|
||||
|
||||
# int
|
||||
self.params.put("BootCount", 1441)
|
||||
assert self.params.get("BootCount") == 1441
|
||||
|
||||
# bool
|
||||
self.params.put("AdbEnabled", True)
|
||||
assert self.params.get("AdbEnabled")
|
||||
assert isinstance(self.params.get("AdbEnabled"), bool)
|
||||
|
||||
# time
|
||||
now = datetime.datetime.now(datetime.UTC)
|
||||
self.params.put("InstallDate", now)
|
||||
assert self.params.get("InstallDate") == now
|
||||
|
||||
@@ -24,6 +24,6 @@ class TestSimpleKalman:
|
||||
self.kf.set_x([[1.0], [1.0]])
|
||||
assert self.kf.x == [[1.0], [1.0]]
|
||||
|
||||
def update_returns_state(self):
|
||||
def test_update_returns_state(self):
|
||||
x = self.kf.update(100)
|
||||
assert x == self.kf.x
|
||||
assert x == [i[0] for i in self.kf.x]
|
||||
|
||||
@@ -36,7 +36,7 @@ TEST_CASE("util::read_file") {
|
||||
REQUIRE(util::read_file(filename).empty());
|
||||
|
||||
std::string content = random_bytes(64 * 1024);
|
||||
write(fd, content.c_str(), content.size());
|
||||
REQUIRE(write(fd, content.c_str(), content.size()) == (ssize_t)content.size());
|
||||
std::string ret = util::read_file(filename);
|
||||
bool equal = (ret == content);
|
||||
REQUIRE(equal);
|
||||
@@ -114,12 +114,12 @@ TEST_CASE("util::safe_fwrite") {
|
||||
}
|
||||
|
||||
TEST_CASE("util::create_directories") {
|
||||
system("rm /tmp/test_create_directories -rf");
|
||||
REQUIRE(system("rm /tmp/test_create_directories -rf") == 0);
|
||||
std::string dir = "/tmp/test_create_directories/a/b/c/d/e/f";
|
||||
|
||||
auto check_dir_permissions = [](const std::string &dir, mode_t mode) -> bool {
|
||||
auto check_dir_permissions = [](const std::string &path, mode_t mode) -> bool {
|
||||
struct stat st = {};
|
||||
return stat(dir.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR && (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == mode;
|
||||
return stat(path.c_str(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR && (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) == mode;
|
||||
};
|
||||
|
||||
SECTION("create_directories") {
|
||||
@@ -132,7 +132,7 @@ TEST_CASE("util::create_directories") {
|
||||
}
|
||||
SECTION("a file exists with the same name") {
|
||||
REQUIRE(util::create_directories(dir, 0755));
|
||||
int f = open((dir + "/file").c_str(), O_RDWR | O_CREAT);
|
||||
int f = open((dir + "/file").c_str(), O_RDWR | O_CREAT, 0644);
|
||||
REQUIRE(f != -1);
|
||||
close(f);
|
||||
REQUIRE(util::create_directories(dir + "/file", 0755) == false);
|
||||
|
||||
@@ -8,9 +8,9 @@ from openpilot.common.basedir import BASEDIR
|
||||
class TextWindow:
|
||||
def __init__(self, text):
|
||||
try:
|
||||
self.text_proc = subprocess.Popen(["./text", text],
|
||||
self.text_proc = subprocess.Popen(["./text.py", text],
|
||||
stdin=subprocess.PIPE,
|
||||
cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
|
||||
cwd=os.path.join(BASEDIR, "system", "ui"),
|
||||
close_fds=True)
|
||||
except OSError:
|
||||
self.text_proc = None
|
||||
|
||||
@@ -2,6 +2,7 @@ import datetime
|
||||
from pathlib import Path
|
||||
|
||||
MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
|
||||
MAX_DATE = datetime.datetime(year=2035, month=1, day=1)
|
||||
|
||||
def min_date():
|
||||
# on systemd systems, the default time is the systemd build time
|
||||
@@ -12,4 +13,4 @@ def min_date():
|
||||
return MIN_DATE
|
||||
|
||||
def system_time_valid():
|
||||
return datetime.datetime.now() > min_date()
|
||||
return min_date() < datetime.datetime.now() < MAX_DATE
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
transformations
|
||||
transformations.cpp
|
||||
@@ -1,5 +0,0 @@
|
||||
Import('env', 'envCython')
|
||||
|
||||
transformations = env.Library('transformations', ['orientation.cc', 'coordinates.cc'])
|
||||
transformations_python = envCython.Program('transformations.so', 'transformations.pyx')
|
||||
Export('transformations', 'transformations_python')
|
||||
@@ -1,100 +0,0 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include "common/transformations/coordinates.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
double a = 6378137; // lgtm [cpp/short-global-name]
|
||||
double b = 6356752.3142; // lgtm [cpp/short-global-name]
|
||||
double esq = 6.69437999014 * 0.001; // lgtm [cpp/short-global-name]
|
||||
double e1sq = 6.73949674228 * 0.001;
|
||||
|
||||
|
||||
static Geodetic to_degrees(Geodetic geodetic){
|
||||
geodetic.lat = RAD2DEG(geodetic.lat);
|
||||
geodetic.lon = RAD2DEG(geodetic.lon);
|
||||
return geodetic;
|
||||
}
|
||||
|
||||
static Geodetic to_radians(Geodetic geodetic){
|
||||
geodetic.lat = DEG2RAD(geodetic.lat);
|
||||
geodetic.lon = DEG2RAD(geodetic.lon);
|
||||
return geodetic;
|
||||
}
|
||||
|
||||
|
||||
ECEF geodetic2ecef(const Geodetic &geodetic) {
|
||||
auto g = to_radians(geodetic);
|
||||
double xi = sqrt(1.0 - esq * pow(sin(g.lat), 2));
|
||||
double x = (a / xi + g.alt) * cos(g.lat) * cos(g.lon);
|
||||
double y = (a / xi + g.alt) * cos(g.lat) * sin(g.lon);
|
||||
double z = (a / xi * (1.0 - esq) + g.alt) * sin(g.lat);
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
Geodetic ecef2geodetic(const ECEF &e) {
|
||||
// Convert from ECEF to geodetic using Ferrari's methods
|
||||
// https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
|
||||
double x = e.x;
|
||||
double y = e.y;
|
||||
double z = e.z;
|
||||
|
||||
double r = sqrt(x * x + y * y);
|
||||
double Esq = a * a - b * b;
|
||||
double F = 54 * b * b * z * z;
|
||||
double G = r * r + (1 - esq) * z * z - esq * Esq;
|
||||
double C = (esq * esq * F * r * r) / (pow(G, 3));
|
||||
double S = cbrt(1 + C + sqrt(C * C + 2 * C));
|
||||
double P = F / (3 * pow((S + 1 / S + 1), 2) * G * G);
|
||||
double Q = sqrt(1 + 2 * esq * esq * P);
|
||||
double r_0 = -(P * esq * r) / (1 + Q) + sqrt(0.5 * a * a*(1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
|
||||
double U = sqrt(pow((r - esq * r_0), 2) + z * z);
|
||||
double V = sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z);
|
||||
double Z_0 = b * b * z / (a * V);
|
||||
double h = U * (1 - b * b / (a * V));
|
||||
|
||||
double lat = atan((z + e1sq * Z_0) / r);
|
||||
double lon = atan2(y, x);
|
||||
|
||||
return to_degrees({lat, lon, h});
|
||||
}
|
||||
|
||||
LocalCoord::LocalCoord(const Geodetic &geodetic, const ECEF &e) {
|
||||
init_ecef << e.x, e.y, e.z;
|
||||
|
||||
auto g = to_radians(geodetic);
|
||||
|
||||
ned2ecef_matrix <<
|
||||
-sin(g.lat)*cos(g.lon), -sin(g.lon), -cos(g.lat)*cos(g.lon),
|
||||
-sin(g.lat)*sin(g.lon), cos(g.lon), -cos(g.lat)*sin(g.lon),
|
||||
cos(g.lat), 0, -sin(g.lat);
|
||||
ecef2ned_matrix = ned2ecef_matrix.transpose();
|
||||
}
|
||||
|
||||
NED LocalCoord::ecef2ned(const ECEF &e) {
|
||||
Eigen::Vector3d ecef;
|
||||
ecef << e.x, e.y, e.z;
|
||||
|
||||
Eigen::Vector3d ned = (ecef2ned_matrix * (ecef - init_ecef));
|
||||
return {ned[0], ned[1], ned[2]};
|
||||
}
|
||||
|
||||
ECEF LocalCoord::ned2ecef(const NED &n) {
|
||||
Eigen::Vector3d ned;
|
||||
ned << n.n, n.e, n.d;
|
||||
|
||||
Eigen::Vector3d ecef = (ned2ecef_matrix * ned) + init_ecef;
|
||||
return {ecef[0], ecef[1], ecef[2]};
|
||||
}
|
||||
|
||||
NED LocalCoord::geodetic2ned(const Geodetic &g) {
|
||||
ECEF e = ::geodetic2ecef(g);
|
||||
return ecef2ned(e);
|
||||
}
|
||||
|
||||
Geodetic LocalCoord::ned2geodetic(const NED &n) {
|
||||
ECEF e = ned2ecef(n);
|
||||
return ::ecef2geodetic(e);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
#define DEG2RAD(x) ((x) * M_PI / 180.0)
|
||||
#define RAD2DEG(x) ((x) * 180.0 / M_PI)
|
||||
|
||||
struct ECEF {
|
||||
double x, y, z;
|
||||
Eigen::Vector3d to_vector() const {
|
||||
return Eigen::Vector3d(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
struct NED {
|
||||
double n, e, d;
|
||||
Eigen::Vector3d to_vector() const {
|
||||
return Eigen::Vector3d(n, e, d);
|
||||
}
|
||||
};
|
||||
|
||||
struct Geodetic {
|
||||
double lat, lon, alt;
|
||||
bool radians=false;
|
||||
};
|
||||
|
||||
ECEF geodetic2ecef(const Geodetic &g);
|
||||
Geodetic ecef2geodetic(const ECEF &e);
|
||||
|
||||
class LocalCoord {
|
||||
public:
|
||||
Eigen::Matrix3d ned2ecef_matrix;
|
||||
Eigen::Matrix3d ecef2ned_matrix;
|
||||
Eigen::Vector3d init_ecef;
|
||||
LocalCoord(const Geodetic &g, const ECEF &e);
|
||||
LocalCoord(const Geodetic &g) : LocalCoord(g, ::geodetic2ecef(g)) {}
|
||||
LocalCoord(const ECEF &e) : LocalCoord(::ecef2geodetic(e), e) {}
|
||||
|
||||
NED ecef2ned(const ECEF &e);
|
||||
ECEF ned2ecef(const NED &n);
|
||||
NED geodetic2ned(const Geodetic &g);
|
||||
Geodetic ned2geodetic(const NED &n);
|
||||
};
|
||||
@@ -1,144 +0,0 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
#include "common/transformations/orientation.hpp"
|
||||
#include "common/transformations/coordinates.hpp"
|
||||
|
||||
Eigen::Quaterniond ensure_unique(const Eigen::Quaterniond &quat) {
|
||||
if (quat.w() > 0){
|
||||
return quat;
|
||||
} else {
|
||||
return Eigen::Quaterniond(-quat.w(), -quat.x(), -quat.y(), -quat.z());
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::Quaterniond euler2quat(const Eigen::Vector3d &euler) {
|
||||
Eigen::Quaterniond q;
|
||||
|
||||
q = Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitZ())
|
||||
* Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY())
|
||||
* Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitX());
|
||||
return ensure_unique(q);
|
||||
}
|
||||
|
||||
|
||||
Eigen::Vector3d quat2euler(const Eigen::Quaterniond &quat) {
|
||||
// TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore
|
||||
// Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0);
|
||||
// return {euler(2), euler(1), euler(0)};
|
||||
double gamma = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2 * (quat.x()*quat.x() + quat.y()*quat.y()));
|
||||
double asin_arg_clipped = std::clamp(2 * (quat.w() * quat.y() - quat.z() * quat.x()), -1.0, 1.0);
|
||||
double theta = asin(asin_arg_clipped);
|
||||
double psi = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2 * (quat.y()*quat.y() + quat.z()*quat.z()));
|
||||
return {gamma, theta, psi};
|
||||
}
|
||||
|
||||
Eigen::Matrix3d quat2rot(const Eigen::Quaterniond &quat) {
|
||||
return quat.toRotationMatrix();
|
||||
}
|
||||
|
||||
Eigen::Quaterniond rot2quat(const Eigen::Matrix3d &rot) {
|
||||
return ensure_unique(Eigen::Quaterniond(rot));
|
||||
}
|
||||
|
||||
Eigen::Matrix3d euler2rot(const Eigen::Vector3d &euler) {
|
||||
return quat2rot(euler2quat(euler));
|
||||
}
|
||||
|
||||
Eigen::Vector3d rot2euler(const Eigen::Matrix3d &rot) {
|
||||
return quat2euler(rot2quat(rot));
|
||||
}
|
||||
|
||||
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw) {
|
||||
return euler2rot({roll, pitch, yaw});
|
||||
}
|
||||
|
||||
Eigen::Matrix3d rot(const Eigen::Vector3d &axis, double angle) {
|
||||
Eigen::Quaterniond q;
|
||||
q = Eigen::AngleAxisd(angle, axis);
|
||||
return q.toRotationMatrix();
|
||||
}
|
||||
|
||||
|
||||
Eigen::Vector3d ecef_euler_from_ned(const ECEF &ecef_init, const Eigen::Vector3d &ned_pose) {
|
||||
/*
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
Don Koks
|
||||
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
|
||||
*/
|
||||
LocalCoord converter = LocalCoord(ecef_init);
|
||||
Eigen::Vector3d zero = ecef_init.to_vector();
|
||||
|
||||
Eigen::Vector3d x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
|
||||
Eigen::Vector3d y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
|
||||
Eigen::Vector3d z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
|
||||
|
||||
Eigen::Vector3d x1 = rot(z0, ned_pose(2)) * x0;
|
||||
Eigen::Vector3d y1 = rot(z0, ned_pose(2)) * y0;
|
||||
Eigen::Vector3d z1 = rot(z0, ned_pose(2)) * z0;
|
||||
|
||||
Eigen::Vector3d x2 = rot(y1, ned_pose(1)) * x1;
|
||||
Eigen::Vector3d y2 = rot(y1, ned_pose(1)) * y1;
|
||||
Eigen::Vector3d z2 = rot(y1, ned_pose(1)) * z1;
|
||||
|
||||
Eigen::Vector3d x3 = rot(x2, ned_pose(0)) * x2;
|
||||
Eigen::Vector3d y3 = rot(x2, ned_pose(0)) * y2;
|
||||
|
||||
|
||||
x0 = Eigen::Vector3d(1, 0, 0);
|
||||
y0 = Eigen::Vector3d(0, 1, 0);
|
||||
z0 = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
double psi = atan2(x3.dot(y0), x3.dot(x0));
|
||||
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
|
||||
|
||||
y2 = rot(z0, psi) * y0;
|
||||
z2 = rot(y2, theta) * z0;
|
||||
|
||||
double phi = atan2(y3.dot(z2), y3.dot(y2));
|
||||
|
||||
return {phi, theta, psi};
|
||||
}
|
||||
|
||||
Eigen::Vector3d ned_euler_from_ecef(const ECEF &ecef_init, const Eigen::Vector3d &ecef_pose) {
|
||||
/*
|
||||
Using Rotations to Build Aerospace Coordinate Systems
|
||||
Don Koks
|
||||
https://apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
|
||||
*/
|
||||
LocalCoord converter = LocalCoord(ecef_init);
|
||||
|
||||
Eigen::Vector3d x0 = Eigen::Vector3d(1, 0, 0);
|
||||
Eigen::Vector3d y0 = Eigen::Vector3d(0, 1, 0);
|
||||
Eigen::Vector3d z0 = Eigen::Vector3d(0, 0, 1);
|
||||
|
||||
Eigen::Vector3d x1 = rot(z0, ecef_pose(2)) * x0;
|
||||
Eigen::Vector3d y1 = rot(z0, ecef_pose(2)) * y0;
|
||||
Eigen::Vector3d z1 = rot(z0, ecef_pose(2)) * z0;
|
||||
|
||||
Eigen::Vector3d x2 = rot(y1, ecef_pose(1)) * x1;
|
||||
Eigen::Vector3d y2 = rot(y1, ecef_pose(1)) * y1;
|
||||
Eigen::Vector3d z2 = rot(y1, ecef_pose(1)) * z1;
|
||||
|
||||
Eigen::Vector3d x3 = rot(x2, ecef_pose(0)) * x2;
|
||||
Eigen::Vector3d y3 = rot(x2, ecef_pose(0)) * y2;
|
||||
|
||||
Eigen::Vector3d zero = ecef_init.to_vector();
|
||||
x0 = converter.ned2ecef({1, 0, 0}).to_vector() - zero;
|
||||
y0 = converter.ned2ecef({0, 1, 0}).to_vector() - zero;
|
||||
z0 = converter.ned2ecef({0, 0, 1}).to_vector() - zero;
|
||||
|
||||
double psi = atan2(x3.dot(y0), x3.dot(x0));
|
||||
double theta = atan2(-x3.dot(z0), sqrt(pow(x3.dot(x0), 2) + pow(x3.dot(y0), 2)));
|
||||
|
||||
y2 = rot(z0, psi) * y0;
|
||||
z2 = rot(y2, theta) * z0;
|
||||
|
||||
double phi = atan2(y3.dot(z2), y3.dot(y2));
|
||||
|
||||
return {phi, theta, psi};
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
#include <eigen3/Eigen/Dense>
|
||||
#include "common/transformations/coordinates.hpp"
|
||||
|
||||
|
||||
Eigen::Quaterniond ensure_unique(const Eigen::Quaterniond &quat);
|
||||
|
||||
Eigen::Quaterniond euler2quat(const Eigen::Vector3d &euler);
|
||||
Eigen::Vector3d quat2euler(const Eigen::Quaterniond &quat);
|
||||
Eigen::Matrix3d quat2rot(const Eigen::Quaterniond &quat);
|
||||
Eigen::Quaterniond rot2quat(const Eigen::Matrix3d &rot);
|
||||
Eigen::Matrix3d euler2rot(const Eigen::Vector3d &euler);
|
||||
Eigen::Vector3d rot2euler(const Eigen::Matrix3d &rot);
|
||||
Eigen::Matrix3d rot_matrix(double roll, double pitch, double yaw);
|
||||
Eigen::Matrix3d rot(const Eigen::Vector3d &axis, double angle);
|
||||
Eigen::Vector3d ecef_euler_from_ned(const ECEF &ecef_init, const Eigen::Vector3d &ned_pose);
|
||||
Eigen::Vector3d ned_euler_from_ecef(const ECEF &ecef_init, const Eigen::Vector3d &ecef_pose);
|
||||
@@ -102,3 +102,36 @@ class TestNED:
|
||||
np.testing.assert_allclose(converter.ned2ecef(ned_offsets_batch),
|
||||
ecef_positions_offset_batch,
|
||||
rtol=1e-9, atol=1e-7)
|
||||
|
||||
def test_errors(self):
|
||||
# Test wrong shape/type for geodetic2ecef
|
||||
# numpy_wrap raises IndexError for scalar input
|
||||
with np.testing.assert_raises(IndexError):
|
||||
coord.geodetic2ecef(1.0)
|
||||
|
||||
with np.testing.assert_raises_regex(ValueError, "Geodetic must be size 3"):
|
||||
coord.geodetic2ecef([0, 0])
|
||||
|
||||
with np.testing.assert_raises_regex(ValueError, "Geodetic must be size 3"):
|
||||
coord.geodetic2ecef([0, 0, 0, 0])
|
||||
|
||||
with np.testing.assert_raises(TypeError):
|
||||
coord.geodetic2ecef(['a', 'b', 'c'])
|
||||
|
||||
# Test LocalCoord constructor errors
|
||||
with np.testing.assert_raises(ValueError):
|
||||
coord.LocalCoord.from_geodetic([0, 0])
|
||||
|
||||
with np.testing.assert_raises(ValueError):
|
||||
coord.LocalCoord.from_geodetic(1)
|
||||
|
||||
with np.testing.assert_raises(TypeError):
|
||||
coord.LocalCoord.from_geodetic(['a', 'b', 'c'])
|
||||
|
||||
# Test wrong shape/type for ecef2geodetic
|
||||
with np.testing.assert_raises(ValueError):
|
||||
coord.ecef2geodetic([1, 2])
|
||||
with np.testing.assert_raises(ValueError):
|
||||
coord.ecef2geodetic([1, 2, 3, 4])
|
||||
with np.testing.assert_raises(IndexError):
|
||||
coord.ecef2geodetic(1.0)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \
|
||||
rot2quat, quat2rot, \
|
||||
@@ -59,3 +60,32 @@ class TestOrientation:
|
||||
np.testing.assert_allclose(ned_eulers[i], ned_euler_from_ecef(ecef_positions[i], eulers[i]), rtol=1e-7)
|
||||
#np.testing.assert_allclose(eulers[i], ecef_euler_from_ned(ecef_positions[i], ned_eulers[i]), rtol=1e-7)
|
||||
# np.testing.assert_allclose(ned_eulers, ned_euler_from_ecef(ecef_positions, eulers), rtol=1e-7)
|
||||
|
||||
def test_inputs(self):
|
||||
with pytest.raises(ValueError):
|
||||
euler2quat([1, 2])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
quat2rot([1, 2, 3])
|
||||
|
||||
with pytest.raises(IndexError):
|
||||
rot2quat(np.zeros((2, 2)))
|
||||
|
||||
def test_euler_rot_consistency(self):
|
||||
rpy = [0.1, 0.2, 0.3]
|
||||
R = euler2rot(rpy)
|
||||
|
||||
# R -> q -> R
|
||||
q = rot2quat(R)
|
||||
R_new = quat2rot(q)
|
||||
np.testing.assert_allclose(R, R_new, atol=1e-15)
|
||||
|
||||
# q -> R -> Euler (quat2euler) -> R
|
||||
rpy_new = quat2euler(q)
|
||||
R_new2 = euler2rot(rpy_new)
|
||||
np.testing.assert_allclose(R, R_new2, atol=1e-15)
|
||||
|
||||
# R -> Euler (rot2euler) -> R
|
||||
rpy_from_rot = rot2euler(R)
|
||||
R_new3 = euler2rot(rpy_from_rot)
|
||||
np.testing.assert_allclose(R, R_new3, atol=1e-15)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
||||
# cython: language_level=3
|
||||
from libcpp cimport bool
|
||||
|
||||
cdef extern from "orientation.cc":
|
||||
pass
|
||||
|
||||
cdef extern from "orientation.hpp":
|
||||
cdef cppclass Quaternion "Eigen::Quaterniond":
|
||||
Quaternion()
|
||||
Quaternion(double, double, double, double)
|
||||
double w()
|
||||
double x()
|
||||
double y()
|
||||
double z()
|
||||
|
||||
cdef cppclass Vector3 "Eigen::Vector3d":
|
||||
Vector3()
|
||||
Vector3(double, double, double)
|
||||
double operator()(int)
|
||||
|
||||
cdef cppclass Matrix3 "Eigen::Matrix3d":
|
||||
Matrix3()
|
||||
Matrix3(double*)
|
||||
|
||||
double operator()(int, int)
|
||||
|
||||
Quaternion euler2quat(const Vector3 &)
|
||||
Vector3 quat2euler(const Quaternion &)
|
||||
Matrix3 quat2rot(const Quaternion &)
|
||||
Quaternion rot2quat(const Matrix3 &)
|
||||
Vector3 rot2euler(const Matrix3 &)
|
||||
Matrix3 euler2rot(const Vector3 &)
|
||||
Matrix3 rot_matrix(double, double, double)
|
||||
Vector3 ecef_euler_from_ned(const ECEF &, const Vector3 &)
|
||||
Vector3 ned_euler_from_ecef(const ECEF &, const Vector3 &)
|
||||
|
||||
|
||||
cdef extern from "coordinates.cc":
|
||||
cdef struct ECEF:
|
||||
double x
|
||||
double y
|
||||
double z
|
||||
|
||||
cdef struct NED:
|
||||
double n
|
||||
double e
|
||||
double d
|
||||
|
||||
cdef struct Geodetic:
|
||||
double lat
|
||||
double lon
|
||||
double alt
|
||||
bool radians
|
||||
|
||||
ECEF geodetic2ecef(const Geodetic &)
|
||||
Geodetic ecef2geodetic(const ECEF &)
|
||||
|
||||
cdef cppclass LocalCoord_c "LocalCoord":
|
||||
Matrix3 ned2ecef_matrix
|
||||
Matrix3 ecef2ned_matrix
|
||||
|
||||
LocalCoord_c(const Geodetic &, const ECEF &)
|
||||
LocalCoord_c(const Geodetic &)
|
||||
LocalCoord_c(const ECEF &)
|
||||
|
||||
NED ecef2ned(const ECEF &)
|
||||
ECEF ned2ecef(const NED &)
|
||||
NED geodetic2ned(const Geodetic &)
|
||||
Geodetic ned2geodetic(const NED &)
|
||||
|
||||
cdef extern from "coordinates.hpp":
|
||||
pass
|
||||
@@ -0,0 +1,342 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
# Constants
|
||||
a = 6378137.0
|
||||
b = 6356752.3142
|
||||
esq = 6.69437999014e-3
|
||||
e1sq = 6.73949674228e-3
|
||||
|
||||
|
||||
def geodetic2ecef_single(g):
|
||||
"""
|
||||
Convert geodetic coordinates (latitude, longitude, altitude) to ECEF.
|
||||
"""
|
||||
try:
|
||||
if len(g) != 3:
|
||||
raise ValueError("Geodetic must be size 3")
|
||||
except TypeError:
|
||||
raise ValueError("Geodetic must be a sequence of length 3") from None
|
||||
|
||||
lat, lon, alt = g
|
||||
lat = np.radians(lat)
|
||||
lon = np.radians(lon)
|
||||
xi = np.sqrt(1.0 - esq * np.sin(lat)**2)
|
||||
x = (a / xi + alt) * np.cos(lat) * np.cos(lon)
|
||||
y = (a / xi + alt) * np.cos(lat) * np.sin(lon)
|
||||
z = (a / xi * (1.0 - esq) + alt) * np.sin(lat)
|
||||
return np.array([x, y, z])
|
||||
|
||||
|
||||
def ecef2geodetic_single(e):
|
||||
"""
|
||||
Convert ECEF to geodetic coordinates using Ferrari's solution.
|
||||
"""
|
||||
x, y, z = e
|
||||
r = np.sqrt(x**2 + y**2)
|
||||
Esq = a**2 - b**2
|
||||
F = 54 * b**2 * z**2
|
||||
G = r**2 + (1 - esq) * z**2 - esq * Esq
|
||||
C = (esq**2 * F * r**2) / (G**3)
|
||||
S = np.cbrt(1 + C + np.sqrt(C**2 + 2 * C))
|
||||
P = F / (3 * (S + 1 / S + 1)**2 * G**2)
|
||||
Q = np.sqrt(1 + 2 * esq**2 * P)
|
||||
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a**2 * (1 + 1.0 / Q) - P * (1 - esq) * z**2 / (Q * (1 + Q)) - 0.5 * P * r**2)
|
||||
U = np.sqrt((r - esq * r_0)**2 + z**2)
|
||||
V = np.sqrt((r - esq * r_0)**2 + (1 - esq) * z**2)
|
||||
Z_0 = b**2 * z / (a * V)
|
||||
h = U * (1 - b**2 / (a * V))
|
||||
lat = np.arctan((z + e1sq * Z_0) / r)
|
||||
lon = np.arctan2(y, x)
|
||||
return np.array([np.degrees(lat), np.degrees(lon), h])
|
||||
|
||||
|
||||
def euler2quat_single(euler):
|
||||
"""
|
||||
Convert Euler angles (roll, pitch, yaw) to a quaternion.
|
||||
Rotation order: Z-Y-X (yaw, pitch, roll).
|
||||
"""
|
||||
phi, theta, psi = euler
|
||||
|
||||
c_phi, s_phi = np.cos(phi / 2), np.sin(phi / 2)
|
||||
c_theta, s_theta = np.cos(theta / 2), np.sin(theta / 2)
|
||||
c_psi, s_psi = np.cos(psi / 2), np.sin(psi / 2)
|
||||
|
||||
w = c_phi * c_theta * c_psi + s_phi * s_theta * s_psi
|
||||
x = s_phi * c_theta * c_psi - c_phi * s_theta * s_psi
|
||||
y = c_phi * s_theta * c_psi + s_phi * c_theta * s_psi
|
||||
z = c_phi * c_theta * s_psi - s_phi * s_theta * c_psi
|
||||
|
||||
if w < 0:
|
||||
return np.array([-w, -x, -y, -z])
|
||||
return np.array([w, x, y, z])
|
||||
|
||||
|
||||
def quat2euler_single(q):
|
||||
"""
|
||||
Convert a quaternion to Euler angles (roll, pitch, yaw).
|
||||
"""
|
||||
w, x, y, z = q
|
||||
gamma = np.arctan2(2 * (w * x + y * z), 1 - 2 * (x**2 + y**2))
|
||||
sin_arg = 2 * (w * y - z * x)
|
||||
sin_arg = np.clip(sin_arg, -1.0, 1.0)
|
||||
theta = np.arcsin(sin_arg)
|
||||
psi = np.arctan2(2 * (w * z + x * y), 1 - 2 * (y**2 + z**2))
|
||||
return np.array([gamma, theta, psi])
|
||||
|
||||
|
||||
def quat2rot_single(q):
|
||||
"""
|
||||
Convert a quaternion to a 3x3 rotation matrix.
|
||||
"""
|
||||
w, x, y, z = q
|
||||
xx, yy, zz = x * x, y * y, z * z
|
||||
xy, xz, yz = x * y, x * z, y * z
|
||||
wx, wy, wz = w * x, w * y, w * z
|
||||
|
||||
mat = np.array([
|
||||
[1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy)],
|
||||
[2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx)],
|
||||
[2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy)]
|
||||
])
|
||||
return mat
|
||||
|
||||
|
||||
def rot2quat_single(rot):
|
||||
"""
|
||||
Convert a 3x3 rotation matrix to a quaternion.
|
||||
"""
|
||||
trace = np.trace(rot)
|
||||
if trace > 0:
|
||||
s = 0.5 / np.sqrt(trace + 1.0)
|
||||
w = 0.25 / s
|
||||
x = (rot[2, 1] - rot[1, 2]) * s
|
||||
y = (rot[0, 2] - rot[2, 0]) * s
|
||||
z = (rot[1, 0] - rot[0, 1]) * s
|
||||
else:
|
||||
if rot[0, 0] > rot[1, 1] and rot[0, 0] > rot[2, 2]:
|
||||
s = 2.0 * np.sqrt(1.0 + rot[0, 0] - rot[1, 1] - rot[2, 2])
|
||||
w = (rot[2, 1] - rot[1, 2]) / s
|
||||
x = 0.25 * s
|
||||
y = (rot[0, 1] + rot[1, 0]) / s
|
||||
z = (rot[0, 2] + rot[2, 0]) / s
|
||||
elif rot[1, 1] > rot[2, 2]:
|
||||
s = 2.0 * np.sqrt(1.0 + rot[1, 1] - rot[0, 0] - rot[2, 2])
|
||||
w = (rot[0, 2] - rot[2, 0]) / s
|
||||
x = (rot[0, 1] + rot[1, 0]) / s
|
||||
y = 0.25 * s
|
||||
z = (rot[1, 2] + rot[2, 1]) / s
|
||||
else:
|
||||
s = 2.0 * np.sqrt(1.0 + rot[2, 2] - rot[0, 0] - rot[1, 1])
|
||||
w = (rot[1, 0] - rot[0, 1]) / s
|
||||
x = (rot[0, 2] + rot[2, 0]) / s
|
||||
y = (rot[1, 2] + rot[2, 1]) / s
|
||||
z = 0.25 * s
|
||||
|
||||
if w < 0:
|
||||
return np.array([-w, -x, -y, -z])
|
||||
return np.array([w, x, y, z])
|
||||
|
||||
|
||||
def euler2rot_single(euler):
|
||||
"""
|
||||
Convert Euler angles (roll, pitch, yaw) to a 3x3 rotation matrix.
|
||||
Rotation order: Z-Y-X (yaw, pitch, roll).
|
||||
"""
|
||||
phi, theta, psi = euler
|
||||
|
||||
cx, sx = np.cos(phi), np.sin(phi)
|
||||
cy, sy = np.cos(theta), np.sin(theta)
|
||||
cz, sz = np.cos(psi), np.sin(psi)
|
||||
|
||||
Rx = np.array([[1, 0, 0], [0, cx, -sx], [0, sx, cx]])
|
||||
Ry = np.array([[cy, 0, sy], [0, 1, 0], [-sy, 0, cy]])
|
||||
Rz = np.array([[cz, -sz, 0], [sz, cz, 0], [0, 0, 1]])
|
||||
|
||||
return Rz @ Ry @ Rx
|
||||
|
||||
|
||||
def rot2euler_single(rot):
|
||||
"""
|
||||
Convert a 3x3 rotation matrix to Euler angles (roll, pitch, yaw).
|
||||
"""
|
||||
return quat2euler_single(rot2quat_single(rot))
|
||||
|
||||
|
||||
def rot_matrix(roll, pitch, yaw):
|
||||
"""
|
||||
Create a 3x3 rotation matrix from roll, pitch, and yaw angles.
|
||||
"""
|
||||
return euler2rot_single([roll, pitch, yaw])
|
||||
|
||||
|
||||
def axis_angle_to_rot(axis, angle):
|
||||
"""
|
||||
Convert an axis-angle representation to a 3x3 rotation matrix.
|
||||
"""
|
||||
c = np.cos(angle / 2)
|
||||
s = np.sin(angle / 2)
|
||||
q = np.array([c, s*axis[0], s*axis[1], s*axis[2]])
|
||||
return quat2rot_single(q)
|
||||
|
||||
|
||||
class LocalCoord:
|
||||
"""
|
||||
A class to handle conversions between ECEF and local NED coordinates.
|
||||
"""
|
||||
def __init__(self, geodetic=None, ecef=None):
|
||||
"""
|
||||
Initialize LocalCoord with either geodetic or ECEF coordinates.
|
||||
"""
|
||||
if geodetic is not None:
|
||||
self.init_ecef = geodetic2ecef_single(geodetic)
|
||||
lat, lon, _ = geodetic
|
||||
elif ecef is not None:
|
||||
self.init_ecef = np.array(ecef)
|
||||
lat, lon, _ = ecef2geodetic_single(ecef)
|
||||
else:
|
||||
raise ValueError("Must provide geodetic or ecef")
|
||||
|
||||
lat = np.radians(lat)
|
||||
lon = np.radians(lon)
|
||||
|
||||
self.ned2ecef_matrix = np.array([
|
||||
[-np.sin(lat) * np.cos(lon), -np.sin(lon), -np.cos(lat) * np.cos(lon)],
|
||||
[-np.sin(lat) * np.sin(lon), np.cos(lon), -np.cos(lat) * np.sin(lon)],
|
||||
[np.cos(lat), 0, -np.sin(lat)]
|
||||
])
|
||||
self.ecef2ned_matrix = self.ned2ecef_matrix.T
|
||||
|
||||
@classmethod
|
||||
def from_geodetic(cls, geodetic):
|
||||
"""
|
||||
Create a LocalCoord instance from geodetic coordinates.
|
||||
"""
|
||||
return cls(geodetic=geodetic)
|
||||
|
||||
@classmethod
|
||||
def from_ecef(cls, ecef):
|
||||
"""
|
||||
Create a LocalCoord instance from ECEF coordinates.
|
||||
"""
|
||||
return cls(ecef=ecef)
|
||||
|
||||
def ecef2ned_single(self, ecef):
|
||||
"""
|
||||
Convert a single ECEF point to NED coordinates relative to the origin.
|
||||
"""
|
||||
return self.ecef2ned_matrix @ (ecef - self.init_ecef)
|
||||
|
||||
def ned2ecef_single(self, ned):
|
||||
"""
|
||||
Convert a single NED point to ECEF coordinates.
|
||||
"""
|
||||
return self.ned2ecef_matrix @ ned + self.init_ecef
|
||||
|
||||
def geodetic2ned_single(self, geodetic):
|
||||
"""
|
||||
Convert a single geodetic point to NED coordinates.
|
||||
"""
|
||||
ecef = geodetic2ecef_single(geodetic)
|
||||
return self.ecef2ned_single(ecef)
|
||||
|
||||
def ned2geodetic_single(self, ned):
|
||||
"""
|
||||
Convert a single NED point to geodetic coordinates.
|
||||
"""
|
||||
ecef = self.ned2ecef_single(ned)
|
||||
return ecef2geodetic_single(ecef)
|
||||
|
||||
@property
|
||||
def ned_from_ecef_matrix(self):
|
||||
"""
|
||||
Returns the rotation matrix from ECEF to NED coordinates.
|
||||
"""
|
||||
return self.ecef2ned_matrix
|
||||
|
||||
@property
|
||||
def ecef_from_ned_matrix(self):
|
||||
"""
|
||||
Returns the rotation matrix from NED to ECEF coordinates.
|
||||
"""
|
||||
return self.ned2ecef_matrix
|
||||
|
||||
|
||||
def ecef_euler_from_ned_single(ecef_init, ned_pose):
|
||||
"""
|
||||
Convert NED Euler angles (roll, pitch, yaw) at a given ECEF origin
|
||||
to equivalent ECEF Euler angles.
|
||||
"""
|
||||
converter = LocalCoord(ecef=ecef_init)
|
||||
zero = np.array(ecef_init)
|
||||
|
||||
x0 = converter.ned2ecef_single([1, 0, 0]) - zero
|
||||
y0 = converter.ned2ecef_single([0, 1, 0]) - zero
|
||||
z0 = converter.ned2ecef_single([0, 0, 1]) - zero
|
||||
|
||||
phi, theta, psi = ned_pose
|
||||
|
||||
x1 = axis_angle_to_rot(z0, psi) @ x0
|
||||
y1 = axis_angle_to_rot(z0, psi) @ y0
|
||||
z1 = axis_angle_to_rot(z0, psi) @ z0
|
||||
|
||||
x2 = axis_angle_to_rot(y1, theta) @ x1
|
||||
y2 = axis_angle_to_rot(y1, theta) @ y1
|
||||
z2 = axis_angle_to_rot(y1, theta) @ z1
|
||||
|
||||
x3 = axis_angle_to_rot(x2, phi) @ x2
|
||||
y3 = axis_angle_to_rot(x2, phi) @ y2
|
||||
|
||||
x0 = np.array([1.0, 0, 0])
|
||||
y0 = np.array([0, 1.0, 0])
|
||||
z0 = np.array([0, 0, 1.0])
|
||||
|
||||
psi_out = np.arctan2(np.dot(x3, y0), np.dot(x3, x0))
|
||||
theta_out = np.arctan2(-np.dot(x3, z0), np.sqrt(np.dot(x3, x0)**2 + np.dot(x3, y0)**2))
|
||||
|
||||
y2 = axis_angle_to_rot(z0, psi_out) @ y0
|
||||
z2 = axis_angle_to_rot(y2, theta_out) @ z0
|
||||
|
||||
phi_out = np.arctan2(np.dot(y3, z2), np.dot(y3, y2))
|
||||
|
||||
return np.array([phi_out, theta_out, psi_out])
|
||||
|
||||
|
||||
def ned_euler_from_ecef_single(ecef_init, ecef_pose):
|
||||
"""
|
||||
Convert ECEF Euler angles (roll, pitch, yaw) at a given ECEF origin
|
||||
to equivalent NED Euler angles.
|
||||
"""
|
||||
converter = LocalCoord(ecef=ecef_init)
|
||||
|
||||
x0 = np.array([1.0, 0, 0])
|
||||
y0 = np.array([0, 1.0, 0])
|
||||
z0 = np.array([0, 0, 1.0])
|
||||
|
||||
phi, theta, psi = ecef_pose
|
||||
|
||||
x1 = axis_angle_to_rot(z0, psi) @ x0
|
||||
y1 = axis_angle_to_rot(z0, psi) @ y0
|
||||
z1 = axis_angle_to_rot(z0, psi) @ z0
|
||||
|
||||
x2 = axis_angle_to_rot(y1, theta) @ x1
|
||||
y2 = axis_angle_to_rot(y1, theta) @ y1
|
||||
z2 = axis_angle_to_rot(y1, theta) @ z1
|
||||
|
||||
x3 = axis_angle_to_rot(x2, phi) @ x2
|
||||
y3 = axis_angle_to_rot(x2, phi) @ y2
|
||||
|
||||
zero = np.array(ecef_init)
|
||||
x0 = converter.ned2ecef_single([1, 0, 0]) - zero
|
||||
y0 = converter.ned2ecef_single([0, 1, 0]) - zero
|
||||
z0 = converter.ned2ecef_single([0, 0, 1]) - zero
|
||||
|
||||
psi_out = np.arctan2(np.dot(x3, y0), np.dot(x3, x0))
|
||||
theta_out = np.arctan2(-np.dot(x3, z0), np.sqrt(np.dot(x3, x0)**2 + np.dot(x3, y0)**2))
|
||||
|
||||
y2 = axis_angle_to_rot(z0, psi_out) @ y0
|
||||
z2 = axis_angle_to_rot(y2, theta_out) @ z0
|
||||
|
||||
phi_out = np.arctan2(np.dot(y3, z2), np.dot(y3, y2))
|
||||
|
||||
return np.array([phi_out, theta_out, psi_out])
|
||||
@@ -1,173 +0,0 @@
|
||||
# distutils: language = c++
|
||||
# cython: language_level = 3
|
||||
from openpilot.common.transformations.transformations cimport Matrix3, Vector3, Quaternion
|
||||
from openpilot.common.transformations.transformations cimport ECEF, NED, Geodetic
|
||||
|
||||
from openpilot.common.transformations.transformations cimport euler2quat as euler2quat_c
|
||||
from openpilot.common.transformations.transformations cimport quat2euler as quat2euler_c
|
||||
from openpilot.common.transformations.transformations cimport quat2rot as quat2rot_c
|
||||
from openpilot.common.transformations.transformations cimport rot2quat as rot2quat_c
|
||||
from openpilot.common.transformations.transformations cimport euler2rot as euler2rot_c
|
||||
from openpilot.common.transformations.transformations cimport rot2euler as rot2euler_c
|
||||
from openpilot.common.transformations.transformations cimport rot_matrix as rot_matrix_c
|
||||
from openpilot.common.transformations.transformations cimport ecef_euler_from_ned as ecef_euler_from_ned_c
|
||||
from openpilot.common.transformations.transformations cimport ned_euler_from_ecef as ned_euler_from_ecef_c
|
||||
from openpilot.common.transformations.transformations cimport geodetic2ecef as geodetic2ecef_c
|
||||
from openpilot.common.transformations.transformations cimport ecef2geodetic as ecef2geodetic_c
|
||||
from openpilot.common.transformations.transformations cimport LocalCoord_c
|
||||
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as np
|
||||
|
||||
cdef np.ndarray[double, ndim=2] matrix2numpy(Matrix3 m):
|
||||
return np.array([
|
||||
[m(0, 0), m(0, 1), m(0, 2)],
|
||||
[m(1, 0), m(1, 1), m(1, 2)],
|
||||
[m(2, 0), m(2, 1), m(2, 2)],
|
||||
])
|
||||
|
||||
cdef Matrix3 numpy2matrix(np.ndarray[double, ndim=2, mode="fortran"] m):
|
||||
assert m.shape[0] == 3
|
||||
assert m.shape[1] == 3
|
||||
return Matrix3(<double*>m.data)
|
||||
|
||||
cdef ECEF list2ecef(ecef):
|
||||
cdef ECEF e
|
||||
e.x = ecef[0]
|
||||
e.y = ecef[1]
|
||||
e.z = ecef[2]
|
||||
return e
|
||||
|
||||
cdef NED list2ned(ned):
|
||||
cdef NED n
|
||||
n.n = ned[0]
|
||||
n.e = ned[1]
|
||||
n.d = ned[2]
|
||||
return n
|
||||
|
||||
cdef Geodetic list2geodetic(geodetic):
|
||||
cdef Geodetic g
|
||||
g.lat = geodetic[0]
|
||||
g.lon = geodetic[1]
|
||||
g.alt = geodetic[2]
|
||||
return g
|
||||
|
||||
def euler2quat_single(euler):
|
||||
cdef Vector3 e = Vector3(euler[0], euler[1], euler[2])
|
||||
cdef Quaternion q = euler2quat_c(e)
|
||||
return [q.w(), q.x(), q.y(), q.z()]
|
||||
|
||||
def quat2euler_single(quat):
|
||||
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
|
||||
cdef Vector3 e = quat2euler_c(q)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def quat2rot_single(quat):
|
||||
cdef Quaternion q = Quaternion(quat[0], quat[1], quat[2], quat[3])
|
||||
cdef Matrix3 r = quat2rot_c(q)
|
||||
return matrix2numpy(r)
|
||||
|
||||
def rot2quat_single(rot):
|
||||
cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double))
|
||||
cdef Quaternion q = rot2quat_c(r)
|
||||
return [q.w(), q.x(), q.y(), q.z()]
|
||||
|
||||
def euler2rot_single(euler):
|
||||
cdef Vector3 e = Vector3(euler[0], euler[1], euler[2])
|
||||
cdef Matrix3 r = euler2rot_c(e)
|
||||
return matrix2numpy(r)
|
||||
|
||||
def rot2euler_single(rot):
|
||||
cdef Matrix3 r = numpy2matrix(np.asfortranarray(rot, dtype=np.double))
|
||||
cdef Vector3 e = rot2euler_c(r)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def rot_matrix(roll, pitch, yaw):
|
||||
return matrix2numpy(rot_matrix_c(roll, pitch, yaw))
|
||||
|
||||
def ecef_euler_from_ned_single(ecef_init, ned_pose):
|
||||
cdef ECEF init = list2ecef(ecef_init)
|
||||
cdef Vector3 pose = Vector3(ned_pose[0], ned_pose[1], ned_pose[2])
|
||||
|
||||
cdef Vector3 e = ecef_euler_from_ned_c(init, pose)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def ned_euler_from_ecef_single(ecef_init, ecef_pose):
|
||||
cdef ECEF init = list2ecef(ecef_init)
|
||||
cdef Vector3 pose = Vector3(ecef_pose[0], ecef_pose[1], ecef_pose[2])
|
||||
|
||||
cdef Vector3 e = ned_euler_from_ecef_c(init, pose)
|
||||
return [e(0), e(1), e(2)]
|
||||
|
||||
def geodetic2ecef_single(geodetic):
|
||||
cdef Geodetic g = list2geodetic(geodetic)
|
||||
cdef ECEF e = geodetic2ecef_c(g)
|
||||
return [e.x, e.y, e.z]
|
||||
|
||||
def ecef2geodetic_single(ecef):
|
||||
cdef ECEF e = list2ecef(ecef)
|
||||
cdef Geodetic g = ecef2geodetic_c(e)
|
||||
return [g.lat, g.lon, g.alt]
|
||||
|
||||
|
||||
cdef class LocalCoord:
|
||||
cdef LocalCoord_c * lc
|
||||
|
||||
def __init__(self, geodetic=None, ecef=None):
|
||||
assert (geodetic is not None) or (ecef is not None)
|
||||
if geodetic is not None:
|
||||
self.lc = new LocalCoord_c(list2geodetic(geodetic))
|
||||
elif ecef is not None:
|
||||
self.lc = new LocalCoord_c(list2ecef(ecef))
|
||||
|
||||
@property
|
||||
def ned2ecef_matrix(self):
|
||||
return matrix2numpy(self.lc.ned2ecef_matrix)
|
||||
|
||||
@property
|
||||
def ecef2ned_matrix(self):
|
||||
return matrix2numpy(self.lc.ecef2ned_matrix)
|
||||
|
||||
@property
|
||||
def ned_from_ecef_matrix(self):
|
||||
return self.ecef2ned_matrix
|
||||
|
||||
@property
|
||||
def ecef_from_ned_matrix(self):
|
||||
return self.ned2ecef_matrix
|
||||
|
||||
@classmethod
|
||||
def from_geodetic(cls, geodetic):
|
||||
return cls(geodetic=geodetic)
|
||||
|
||||
@classmethod
|
||||
def from_ecef(cls, ecef):
|
||||
return cls(ecef=ecef)
|
||||
|
||||
def ecef2ned_single(self, ecef):
|
||||
assert self.lc
|
||||
cdef ECEF e = list2ecef(ecef)
|
||||
cdef NED n = self.lc.ecef2ned(e)
|
||||
return [n.n, n.e, n.d]
|
||||
|
||||
def ned2ecef_single(self, ned):
|
||||
assert self.lc
|
||||
cdef NED n = list2ned(ned)
|
||||
cdef ECEF e = self.lc.ned2ecef(n)
|
||||
return [e.x, e.y, e.z]
|
||||
|
||||
def geodetic2ned_single(self, geodetic):
|
||||
assert self.lc
|
||||
cdef Geodetic g = list2geodetic(geodetic)
|
||||
cdef NED n = self.lc.geodetic2ned(g)
|
||||
return [n.n, n.e, n.d]
|
||||
|
||||
def ned2geodetic_single(self, ned):
|
||||
assert self.lc
|
||||
cdef NED n = list2ned(ned)
|
||||
cdef Geodetic g = self.lc.ned2geodetic(n)
|
||||
return [g.lat, g.lon, g.alt]
|
||||
|
||||
def __dealloc__(self):
|
||||
del self.lc
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user