Sync: `sunnypilot/sunnypilot:master` into `sunnypilot/openpilot-special:master-priv`

This commit is contained in:
Jason Wen 2024-06-12 21:14:31 -04:00
commit c55d11a865
No known key found for this signature in database
GPG Key ID: EF8EA444C1E7B69C
249 changed files with 7629 additions and 2579 deletions

View File

@ -26,7 +26,9 @@ env:
jobs:
build_release:
name: build release
runs-on: ubuntu-latest
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-amd64-8x16' || 'ubuntu-latest' }}
env:
STRIPPED_DIR: /tmp/releasepilot
steps:
@ -116,6 +118,8 @@ jobs:
submodules: true
- uses: ./.github/workflows/setup-pre-commit
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: pre-commit
timeout-minutes: 4
run: ${{ env.RUN }} "unset PYTHONWARNINGS && pre-commit run --all && chmod -R 777 /tmp/pre-commit"
@ -143,7 +147,7 @@ jobs:
$PYTEST --timeout 60 -m 'not slow' && \
./selfdrive/ui/tests/create_test_translations.sh && \
QT_QPA_PLATFORM=offscreen ./selfdrive/ui/tests/test_translations && \
./selfdrive/ui/tests/test_translations.py"
pytest ./selfdrive/ui/tests/test_translations.py"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4
with:

View File

@ -20,25 +20,6 @@ env:
jobs:
simulator_build:
name: simulator docker build
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
- name: Setup to push to repo
if: github.ref == 'refs/heads/master' && github.repository == 'commaai/openpilot'
run: |
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
$DOCKER_LOGIN
- name: Build and push sim image
run: |
selfdrive/test/docker_build.sh sim
simulator_driving:
name: simulator driving
runs-on: ubuntu-latest
@ -47,7 +28,6 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
- run: git lfs pull
- uses: ./.github/workflows/setup-with-retry
- name: Build openpilot
run: |

5
.gitignore vendored
View File

@ -40,8 +40,9 @@ compile_commands.json
compare_runtime*.html
persist
board/obj/
selfdrive/boardd/boardd
selfdrive/pandad/pandad
cereal/services.h
cereal/gen
selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd

6
.gitmodules vendored
View File

@ -4,9 +4,9 @@
[submodule "opendbc"]
path = opendbc
url = https://github.com/sunnyhaibin/opendbc.git
[submodule "cereal"]
path = cereal
url = https://github.com/sunnyhaibin/cereal.git
[submodule "msgq"]
path = msgq_repo
url = https://github.com/commaai/msgq.git
[submodule "rednose_repo"]
path = rednose_repo
url = https://github.com/commaai/rednose.git

View File

@ -24,19 +24,19 @@ repos:
- --maxkb=120
- --enforce-all
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
rev: v2.3.0
hooks:
- id: codespell
exclude: '^(third_party/)|(body/)|(cereal/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
exclude: '^(third_party/)|(body/)|(msgq/)|(panda/)|(opendbc/)|(rednose/)|(rednose_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(selfdrive/ui/translations/.*.ts)|(poetry.lock)'
args:
# if you've got a short variable name that's getting flagged, add it here
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
rev: v0.4.8
hooks:
- id: ruff
exclude: '^(third_party/)|(cereal/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
- repo: local
hooks:
- id: mypy
@ -47,7 +47,7 @@ repos:
args:
- --local-partial-types
- --explicit-package-bases
exclude: '^(third_party/)|(body/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
exclude: '^(third_party/)|(body/)|(msgq/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
- repo: local
hooks:
- id: cppcheck
@ -55,7 +55,7 @@ repos:
entry: cppcheck
language: system
types: [c++]
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)'
exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(tools/)|(selfdrive/modeld/thneed/debug/)|(selfdrive/modeld/test/)|(selfdrive/camerad/test/)|(installer/)'
args:
- --error-exitcode=1
- --language=c++
@ -66,7 +66,7 @@ repos:
rev: 1.6.1
hooks:
- id: cpplint
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
args:
- --quiet
- --counting=total
@ -78,7 +78,7 @@ repos:
rev: v0.16.2
hooks:
- id: cython-lint
exclude: '^(third_party/)|(cereal/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
exclude: '^(third_party/)|(msgq/)|(body/)|(rednose/)|(rednose_repo/)|(opendbc/)|(panda/)|(generated/)'
args:
- --max-line-length=240
- --ignore=E111, E302, E305
@ -86,8 +86,8 @@ repos:
hooks:
- id: test_translations
name: test translations
entry: selfdrive/ui/tests/test_translations.py
language: script
entry: pytest selfdrive/ui/tests/test_translations.py
language: system
pass_filenames: false
files: '^selfdrive/ui/translations/'
- repo: https://github.com/python-poetry/poetry
@ -98,6 +98,6 @@ repos:
args:
- --lock
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.28.3
rev: 0.28.4
hooks:
- id: check-github-workflows

View File

@ -20,6 +20,8 @@ COPY ./release ${OPENPILOT_PATH}/release
COPY ./common ${OPENPILOT_PATH}/common
COPY ./opendbc ${OPENPILOT_PATH}/opendbc
COPY ./cereal ${OPENPILOT_PATH}/cereal
COPY ./msgq_repo ${OPENPILOT_PATH}/msgq_repo
COPY ./msgq ${OPENPILOT_PATH}/msgq
COPY ./panda ${OPENPILOT_PATH}/panda
COPY ./selfdrive ${OPENPILOT_PATH}/selfdrive
COPY ./system ${OPENPILOT_PATH}/system

10
Jenkinsfile vendored
View File

@ -192,7 +192,7 @@ node {
'HW + Unit Tests': {
deviceStage("tici-hardware", "tici-common", ["UNSAFE=1"], [
["build", "cd system/manager && ./build.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test power draw", "pytest -s system/hardware/tici/tests/test_power_draw.py"],
["test encoder", "LD_LIBRARY_PATH=/usr/local/lib pytest system/loggerd/tests/test_encoder.py"],
["test pigeond", "pytest system/ubloxd/tests/test_pigeond.py"],
@ -202,7 +202,7 @@ node {
'loopback': {
deviceStage("loopback", "tici-loopback", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"],
["test boardd loopback", "pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test pandad loopback", "pytest selfdrive/pandad/tests/test_pandad_loopback.py"],
])
},
'camerad': {
@ -236,9 +236,9 @@ node {
'tizi': {
deviceStage("tizi", "tizi", ["UNSAFE=1"], [
["build openpilot", "cd system/manager && ./build.py"],
["test boardd loopback", "SINGLE_PANDA=1 pytest selfdrive/boardd/tests/test_boardd_loopback.py"],
["test boardd spi", "pytest selfdrive/boardd/tests/test_boardd_spi.py"],
["test pandad", "pytest selfdrive/boardd/tests/test_pandad.py"],
["test pandad loopback", "SINGLE_PANDA=1 pytest selfdrive/pandad/tests/test_pandad_loopback.py"],
["test pandad spi", "pytest selfdrive/pandad/tests/test_pandad_spi.py"],
["test pandad", "pytest selfdrive/pandad/tests/test_pandad.py"],
["test amp", "pytest system/hardware/tici/tests/test_amplifier.py"],
["test hw", "pytest system/hardware/tici/tests/test_hardware.py"],
["test qcomgpsd", "pytest system/qcomgpsd/tests/test_qcomgpsd.py"],

View File

@ -1,6 +1,13 @@
Version 0.9.8 (2024-XX-XX)
========================
* Always on driver monitoring toggle
Version 0.9.7 (2024-06-11)
========================
* New driving model
* Inputs the past curvature for smoother and more accurate lateral control
* Simplified neural network architecture in the model's last layers
* Minor fixes to desire augmentation and weight decay
* Adjust driving personality with the follow distance button
* Added toggle to enable driver monitoring even when openpilot is not engaged
* Support for hybrid variants of supported Ford models
@ -634,7 +641,7 @@ Version 0.5.13 (2019-05-31)
* Reduce CPU utilization by 20% and improve stability
* Temporarily remove mapd functionalities to improve stability
* Add openpilot record-only mode for unsupported cars
* Synchronize controlsd to boardd to reduce latency
* Synchronize controlsd to pandad to reduce latency
* Remove panda support for Subaru giraffe
Version 0.5.12 (2019-05-16)
@ -970,7 +977,7 @@ Version 0.2.8 (2017-02-27)
Version 0.2.7 (2017-02-08)
===========================
* Better performance and pictures at night
* Fix ptr alignment issue in boardd
* Fix ptr alignment issue in pandad
* Fix brake error light, fix crash if too cold
Version 0.2.6 (2017-01-31)
@ -1002,7 +1009,7 @@ Version 0.2.2 (2017-01-10)
Version 0.2.1 (2016-12-14)
===========================
* Performance improvements, removal of more numpy
* Fix boardd process priority
* Fix pandad process priority
* Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12)

View File

@ -67,7 +67,7 @@ AddOption('--pc-thneed',
AddOption('--minimal',
action='store_false',
dest='extras',
default=os.path.islink(Dir('#rednose/').abspath), # minimal by default on release branch (where rednose is not a link)
default=os.path.exists(File('#.lfsconfig').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)
@ -209,6 +209,7 @@ env = Environment(
"#third_party/qrcode",
"#third_party",
"#cereal",
"#msgq",
"#opendbc/can",
"#third_party/maplibre-native-qt/include",
f"#third_party/maplibre-native-qt/{arch}/include"
@ -223,10 +224,9 @@ env = Environment(
CFLAGS=["-std=gnu11"] + cflags,
CXXFLAGS=["-std=c++1z"] + cxxflags,
LIBPATH=libpath + [
"#cereal",
"#msgq_repo",
"#third_party",
"#opendbc/can",
"#selfdrive/boardd",
"#selfdrive/pandad",
"#common",
"#rednose/helpers",
],
@ -357,8 +357,13 @@ gpucommon = [_gpucommon]
Export('common', 'gpucommon')
# Build cereal and messaging
# Build messaging (cereal + msgq + socketmaster + their dependencies)
SConscript(['msgq_repo/SConscript'])
SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
messaging = [socketmaster, msgq, 'zmq', 'capnp', 'kj',]
Export('messaging')
# Build other submodules
SConscript([

1
cereal

@ -1 +0,0 @@
Subproject commit bda2b7a4a2e3a9de3dddf8ea8ddbc890d9e7a3ea

60
cereal/README.md Normal file
View File

@ -0,0 +1,60 @@
# What is cereal? [![cereal tests](https://github.com/commaai/cereal/workflows/tests/badge.svg?event=push)](https://github.com/commaai/cereal/actions) [![codecov](https://codecov.io/gh/commaai/cereal/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/cereal)
cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers.
Imagine this use case:
* A sensor process reads gyro measurements directly from an IMU and publishes a `sensorEvents` packet
* A calibration process subscribes to the `sensorEvents` packet to use the IMU
* A localization process subscribes to the `sensorEvents` packet to use the IMU also
## Messaging Spec
You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called `Event`.
All `Events` have a `logMonoTime` and a `valid`. Then a big union defines the packet type.
### Best Practices
- **All fields must describe quantities in SI units**, unless otherwise specified in the field name.
- In the context of the message they are in, field names should be completely unambiguous.
- All values should be easy to plot and be human-readable with minimal parsing.
### Maintaining backwards-compatibility
When making changes to the messaging spec you want to maintain backwards-compatibility, such that old logs can
be parsed with a new version of cereal. Adding structs and adding members to structs is generally safe, most other
things are not. Read more details [here](https://capnproto.org/language.html).
### Custom forks
Forks of [openpilot](https://github.com/commaai/openpilot) might want to add things to the messaging
spec, however this could conflict with future changes made in mainline cereal/openpilot. Rebasing against mainline openpilot
then means breaking backwards-compatibility with all old logs of your fork. So we added reserved events in
[custom.capnp](custom.capnp) that we will leave empty in mainline cereal/openpilot. **If you only modify those, you can ensure your
fork will remain backwards-compatible with all versions of mainline cereal/openpilot and your fork.**
## Pub Sub Backends
cereal supports two backends, one based on [zmq](https://zeromq.org/) and another called [msgq](messaging/msgq.cc), a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel.
Example
---
```python
import cereal.messaging as messaging
# in subscriber
sm = messaging.SubMaster(['sensorEvents'])
while 1:
sm.update()
print(sm['sensorEvents'])
```
```python
# in publisher
pm = messaging.PubMaster(['sensorEvents'])
dat = messaging.new_message('sensorEvents', size=1)
dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}}
pm.send('sensorEvents', dat)
```

31
cereal/SConscript Normal file
View File

@ -0,0 +1,31 @@
Import('env', 'envCython', 'arch', 'common', 'msgq')
import shutil
cereal_dir = Dir('.')
gen_dir = Dir('gen')
other_dir = Dir('#msgq')
# Build cereal
schema_files = ['log.capnp', 'car.capnp', 'legacy.capnp', 'custom.capnp']
env.Command(["gen/c/include/c++.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS")
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/")
# TODO: remove non shared cereal and messaging
cereal_objects = env.SharedObject([f'gen/cpp/{s}.c++' for s in schema_files])
cereal = env.Library('cereal', cereal_objects)
env.SharedLibrary('cereal_shared', cereal_objects)
# Build messaging
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[msgq, 'zmq', common])
socketmaster = env.SharedObject(['messaging/socketmaster.cc'])
socketmaster = env.Library('socketmaster', socketmaster)
Export('cereal', 'socketmaster')

9
cereal/__init__.py Normal file
View File

@ -0,0 +1,9 @@
import os
import capnp
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"))

757
cereal/car.capnp Normal file
View File

@ -0,0 +1,757 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0x8e2af1e708af8b8d;
# ******* events causing controls state machine transition *******
struct CarEvent @0x9b1657f34caf3ad3 {
name @0 :EventName;
# event types
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool; # alerts presented only when enabled or soft disabling
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool; # alerts presented regardless of openpilot state
overrideLateral @10 :Bool;
overrideLongitudinal @9 :Bool;
enum EventName @0xbaa8c5d505f727de {
canError @0;
steerUnavailable @1;
wrongGear @4;
doorOpen @5;
seatbeltNotLatched @6;
espDisabled @7;
wrongCarMode @8;
steerTempUnavailable @9;
reverseGear @10;
buttonCancel @11;
buttonEnable @12;
pedalPressed @13; # exits active state
preEnableStandstill @73; # added during pre-enable state with brake
gasPressedOverride @108; # added when user is pressing gas with no disengage on gas
steerOverride @114;
cruiseDisabled @14;
speedTooLow @17;
outOfSpace @18;
overheat @19;
calibrationIncomplete @20;
calibrationInvalid @21;
calibrationRecalibrating @117;
controlsMismatch @22;
pcmEnable @23;
pcmDisable @24;
radarFault @26;
brakeHold @28;
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
joystickDebug @34;
steerTempUnavailableSilent @35;
resumeRequired @36;
preDriverDistracted @37;
promptDriverDistracted @38;
driverDistracted @39;
preDriverUnresponsive @43;
promptDriverUnresponsive @44;
driverUnresponsive @45;
belowSteerSpeed @46;
lowBattery @48;
accFaulted @51;
sensorDataInvalid @52;
commIssue @53;
commIssueAvgFreq @109;
tooDistracted @54;
posenetInvalid @55;
soundsUnavailable @56;
preLaneChangeLeft @57;
preLaneChangeRight @58;
laneChange @59;
lowMemory @63;
stockAeb @64;
ldw @65;
carUnrecognized @66;
invalidLkasSetting @69;
speedTooHigh @70;
laneChangeBlocked @71;
relayMalfunction @72;
stockFcw @74;
startup @75;
startupNoCar @76;
startupNoControl @77;
startupMaster @78;
startupNoFw @104;
fcw @79;
steerSaturated @80;
belowEngageSpeed @84;
noGps @85;
wrongCruiseMode @87;
modeldLagging @89;
deviceFalling @90;
fanMalfunction @91;
cameraMalfunction @92;
cameraFrameRate @110;
processNotRunning @95;
dashcamMode @96;
controlsInitializing @98;
usbError @99;
roadCameraError @100;
driverCameraError @101;
wideRoadCameraError @102;
highCpuUsage @105;
cruiseMismatch @106;
lkasDisabled @107;
canBusMissing @111;
controlsdLagging @112;
resumeBlocked @113;
steerTimeLimit @115;
vehicleSensorsInvalid @116;
locationdTemporaryError @103;
locationdPermanentError @118;
paramsdTemporaryError @50;
paramsdPermanentError @119;
actuatorsApiUnavailable @120;
manualSteeringRequired @121;
manualLongitudinalRequired @122;
silentPedalPressed @123;
silentButtonEnable @124;
silentBrakeHold @125;
silentWrongGear @126;
spReverseGear @127;
preKeepHandsOnWheel @128;
promptKeepHandsOnWheel @129;
keepHandsOnWheel @130;
speedLimitActive @131;
speedLimitValueChange @132;
e2eLongStop @133;
e2eLongStart @134;
controlsMismatchLong @135;
cruiseEngageBlocked @136;
laneChangeRoadEdge @137;
speedLimitPreActive @138;
speedLimitConfirmed @139;
torqueNNLoad @140;
radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62;
radarCommIssueDEPRECATED @67;
driverMonitorLowAccDEPRECATED @68;
gasUnavailableDEPRECATED @3;
dataNeededDEPRECATED @16;
modelCommIssueDEPRECATED @27;
ipasOverrideDEPRECATED @33;
geofenceDEPRECATED @40;
driverMonitorOnDEPRECATED @41;
driverMonitorOffDEPRECATED @42;
calibrationProgressDEPRECATED @47;
invalidGiraffeHondaDEPRECATED @49;
invalidGiraffeToyotaDEPRECATED @60;
internetConnectivityNeededDEPRECATED @61;
whitePandaUnsupportedDEPRECATED @81;
commIssueWarningDEPRECATED @83;
focusRecoverActiveDEPRECATED @86;
neosUpdateRequiredDEPRECATED @88;
modelLagWarningDEPRECATED @93;
startupOneplusDEPRECATED @82;
startupFuzzyFingerprintDEPRECATED @97;
noTargetDEPRECATED @25;
brakeUnavailableDEPRECATED @2;
plannerErrorDEPRECATED @32;
gpsMalfunctionDEPRECATED @94;
}
}
# ******* main car state @ 100hz *******
# all speeds in m/s
struct CarState {
events @13 :List(CarEvent);
# CAN health
canValid @26 :Bool; # invalid counter/checksums
canTimeout @40 :Bool; # CAN bus dropped out
canErrorCounter @48 :UInt32;
# car speed
vEgo @1 :Float32; # best estimate of speed
aEgo @16 :Float32; # best estimate of acceleration
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
vEgoCluster @44 :Float32; # best estimate of speed shown on car's instrument cluster, used for UI
yawRate @22 :Float32; # best estimate of yaw rate
standstill @18 :Bool;
wheelSpeeds @2 :WheelSpeeds;
# gas pedal, 0.0-1.0
gas @3 :Float32; # this is user pedal only
gasPressed @4 :Bool; # this is user pedal only
engineRpm @46 :Float32;
# brake pedal, 0.0-1.0
brake @5 :Float32; # this is user pedal only
brakePressed @6 :Bool; # this is user pedal only
regenBraking @45 :Bool; # this is user pedal only
parkingBrake @39 :Bool;
brakeHoldActive @38 :Bool;
# steering wheel
steeringAngleDeg @7 :Float32;
steeringAngleOffsetDeg @37 :Float32; # Offset betweens sensors in case there multiple
steeringRateDeg @15 :Float32;
steeringTorque @8 :Float32; # TODO: standardize units
steeringTorqueEps @27 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
steerFaultTemporary @35 :Bool; # temporary EPS fault
steerFaultPermanent @36 :Bool; # permanent EPS fault
stockAeb @30 :Bool;
stockFcw @31 :Bool;
espDisabled @32 :Bool;
accFaulted @42 :Bool;
carFaultedNonCritical @47 :Bool; # some ECU is faulted, but car remains controllable
# cruise state
cruiseState @10 :CruiseState;
# gear
gearShifter @14 :GearShifter;
# button presses
buttonEvents @11 :List(ButtonEvent);
leftBlinker @20 :Bool;
rightBlinker @21 :Bool;
genericToggle @23 :Bool;
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
# clutch (manual transmission only)
clutchPressed @28 :Bool;
madsEnabled @51 :Bool;
leftBlinkerOn @52 :Bool;
rightBlinkerOn @53 :Bool;
disengageByBrake @54 :Bool;
belowLaneChangeSpeed @55 :Bool;
accEnabled @56 :Bool;
latActive @57 :Bool;
gapAdjustCruiseTr @58 :Int32;
endToEndLong @59 :Bool;
customStockLong @60 :CustomStockLong;
struct CustomStockLong {
cruiseButton @0 :Int16;
finalSpeedKph @1 :Float32;
vCruiseKphPrev @2 :Float32;
targetSpeed @3 :Float32;
vSetDis @4 :Float32;
speedDiff @5 :Float32;
buttonType @6 :Int16;
}
# blindspot sensors
leftBlindspot @33 :Bool; # Is there something blocking the left lane change
rightBlindspot @34 :Bool; # Is there something blocking the right lane change
fuelGauge @41 :Float32; # battery or fuel tank level from 0.0 to 1.0
charging @43 :Bool;
# process meta
cumLagMs @50 :Float32;
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
fr @1 :Float32;
rl @2 :Float32;
rr @3 :Float32;
}
struct CruiseState {
enabled @0 :Bool;
speed @1 :Float32;
speedCluster @6 :Float32; # Set speed as shown on instrument cluster
available @2 :Bool;
speedOffset @3 :Float32;
standstill @4 :Bool;
nonAdaptive @5 :Bool;
speedLimit @7 :Float32;
}
enum GearShifter {
unknown @0;
park @1;
drive @2;
neutral @3;
reverse @4;
sport @5;
low @6;
brake @7;
eco @8;
manumatic @9;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
type @1 :Type;
enum Type {
unknown @0;
leftBlinker @1;
rightBlinker @2;
accelCruise @3;
decelCruise @4;
cancel @5;
altButton1 @6;
altButton2 @7;
altButton3 @8;
setCruise @9;
resumeCruise @10;
gapAdjustCruise @11;
}
}
# deprecated
errorsDEPRECATED @0 :List(CarEvent.EventName);
brakeLightsDEPRECATED @19 :Bool;
steeringRateLimitedDEPRECATED @29 :Bool;
canMonoTimesDEPRECATED @12: List(UInt64);
canRcvTimeoutDEPRECATED @49 :Bool;
}
# ******* radar state @ 20hz *******
struct RadarData @0x888ad6581cf0aacb {
errors @0 :List(Error);
points @1 :List(RadarPoint);
enum Error {
canError @0;
fault @1;
wrongConfig @2;
}
# similar to LiveTracks
# is one timestamp valid for all? I think so
struct RadarPoint {
trackId @0 :UInt64; # no trackId reuse
# these 3 are the minimum required
dRel @1 :Float32; # m from the front bumper of the car
yRel @2 :Float32; # m
vRel @3 :Float32; # m/s
# these are optional and valid if they are not NaN
aRel @4 :Float32; # m/s^2
yvRel @5 :Float32; # m/s
# some radars flag measurements VS estimates
measured @6 :Bool;
}
# deprecated
canMonoTimesDEPRECATED @2 :List(UInt64);
}
# ******* car controls @ 100hz *******
struct CarControl {
# must be true for any actuator commands to work
enabled @0 :Bool;
latActive @11: Bool;
longActive @12: Bool;
vCruise @17 :Float32; # actual set speed
# Actuator commands as computed by controlsd
actuators @6 :Actuators;
# moved to CarOutput
actuatorsOutputDEPRECATED @10 :Actuators;
leftBlinker @15: Bool;
rightBlinker @16: Bool;
orientationNED @13 :List(Float32);
angularVelocity @14 :List(Float32);
cruiseControl @4 :CruiseControl;
hudControl @5 :HUDControl;
struct Actuators {
# range from 0.0 - 1.0
gas @0: Float32;
brake @1: Float32;
# range from -1.0 - 1.0
steer @2: Float32;
# value sent over can to the car
steerOutputCan @8: Float32;
steeringAngleDeg @3: Float32;
curvature @7: Float32;
speed @6: Float32; # m/s
accel @4: Float32; # m/s^2
longControlState @5: LongControlState;
enum LongControlState @0xe40f3a917d908282{
off @0;
pid @1;
stopping @2;
starting @3;
}
}
struct CruiseControl {
cancel @0: Bool;
resume @1: Bool;
override @4: Bool;
speedOverrideDEPRECATED @2: Float32;
accelOverrideDEPRECATED @3: Float32;
}
struct HUDControl {
speedVisible @0: Bool;
setSpeed @1: Float32;
lanesVisible @2: Bool;
leadVisible @3: Bool;
visualAlert @4: VisualAlert;
audibleAlert @5: AudibleAlert;
rightLaneVisible @6: Bool;
leftLaneVisible @7: Bool;
rightLaneDepart @8: Bool;
leftLaneDepart @9: Bool;
leadDistanceBars @10: Int8; # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead
enum VisualAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
fcw @1;
steerRequired @2;
brakePressed @3;
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
ldw @7;
}
enum AudibleAlert {
none @0;
engage @1;
disengage @2;
refuse @3;
warningSoft @4;
warningImmediate @5;
prompt @6;
promptRepeat @7;
promptDistracted @8;
promptStarting @9;
promptSingleLow @10;
promptSingleHigh @11;
}
}
gasDEPRECATED @1 :Float32;
brakeDEPRECATED @2 :Float32;
steeringTorqueDEPRECATED @3 :Float32;
activeDEPRECATED @7 :Bool;
rollDEPRECATED @8 :Float32;
pitchDEPRECATED @9 :Float32;
}
struct CarOutput {
# Any car specific rate limits or quirks applied by
# the CarController are reflected in actuatorsOutput
# and matches what is sent to the car
actuatorsOutput @0 :CarControl.Actuators;
}
# ****** car param ******
struct CarParams {
carName @0 :Text;
carFingerprint @1 :Text;
fuzzyFingerprint @55 :Bool;
notCar @66 :Bool; # flag for non-car robotics platforms
pcmCruise @3 :Bool; # is openpilot's state tied to the PCM's cruise state?
enableDsu @5 :Bool; # driving support unit
enableBsm @56 :Bool; # blind spot monitoring
flags @64 :UInt32; # flags for car specific quirks
experimentalLongitudinalAvailable @71 :Bool;
pcmCruiseSpeed @74 :Bool; # is openpilot's state tied to the PCM's cruise speed?
customStockLongAvailable @75 :Bool;
spFlags @76 :UInt32; # flags for car specific quirks in sunnypilot
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
safetyConfigs @62 :List(SafetyConfig);
alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas
# Car docs fields
maxLateralAccel @68 :Float32;
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
# things about the car in the manual
mass @17 :Float32; # [kg] curb weight: all fluids no cargo
wheelbase @18 :Float32; # [m] distance from rear axle to front axle
centerToFront @19 :Float32; # [m] distance from center of mass to front axle
steerRatio @20 :Float32; # [] ratio of steering wheel angle to front wheel angle
steerRatioRear @21 :Float32; # [] ratio of steering wheel angle to rear wheel angle (usually 0)
# things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFactor @72 :Float32; # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
longitudinalTuning @25 :LongitudinalPIDTuning;
lateralParams @48 :LateralParams;
lateralTuning :union {
pid @26 :LateralPIDTuning;
indiDEPRECATED @27 :LateralINDITuning;
lqrDEPRECATED @40 :LateralLQRTuning;
torque @67 :LateralTorqueTuning;
}
steerLimitAlert @28 :Bool;
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
stoppingControl @31 :Bool; # Does the car allow full control even at lows speeds when stopping
steerControlType @34 :SteerControlType;
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
startAccel @32 :Float32; # Required acceleration to get car moving
startingState @70 :Bool; # Does this car make use of special starting state
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
longitudinalActuatorDelayLowerBound @61 :Float32; # Gas/Brake actuator delay in seconds, lower bound
longitudinalActuatorDelayUpperBound @58 :Float32; # Gas/Brake actuator delay in seconds, upper bound
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
dashcamOnly @41: Bool;
passive @73: Bool; # is openpilot in control?
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
fingerprintSource @49: FingerprintSource;
networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network
wheelSpeedFactor @63 :Float32; # Multiplier on wheels speeds to computer actual speeds
struct SafetyConfig {
safetyModel @0 :SafetyModel;
safetyParam @3 :UInt16;
safetyParamDEPRECATED @1 :Int16;
safetyParam2DEPRECATED @2 :UInt32;
}
struct LateralParams {
torqueBP @0 :List(Int32);
torqueV @1 :List(Int32);
}
struct LateralPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @4 :Float32;
}
struct LateralTorqueTuning {
useSteeringAngle @0 :Bool;
kp @1 :Float32;
ki @2 :Float32;
friction @3 :Float32;
kf @4 :Float32;
steeringAngleDeadzoneDeg @5 :Float32;
latAccelFactor @6 :Float32;
latAccelOffset @7 :Float32;
nnModelName @8 :Text;
nnModelFuzzyMatch @9 :Bool;
}
struct LongitudinalPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @6 :Float32;
deadzoneBP @4 :List(Float32);
deadzoneV @5 :List(Float32);
}
struct LateralINDITuning {
outerLoopGainBP @4 :List(Float32);
outerLoopGainV @5 :List(Float32);
innerLoopGainBP @6 :List(Float32);
innerLoopGainV @7 :List(Float32);
timeConstantBP @8 :List(Float32);
timeConstantV @9 :List(Float32);
actuatorEffectivenessBP @10 :List(Float32);
actuatorEffectivenessV @11 :List(Float32);
outerLoopGainDEPRECATED @0 :Float32;
innerLoopGainDEPRECATED @1 :Float32;
timeConstantDEPRECATED @2 :Float32;
actuatorEffectivenessDEPRECATED @3 :Float32;
}
struct LateralLQRTuning {
scale @0 :Float32;
ki @1 :Float32;
dcGain @2 :Float32;
# State space system
a @3 :List(Float32);
b @4 :List(Float32);
c @5 :List(Float32);
k @6 :List(Float32); # LQR gain
l @7 :List(Float32); # Kalman gain
}
enum SafetyModel {
silent @0;
hondaNidec @1;
toyota @2;
elm327 @3;
gm @4;
hondaBoschGiraffe @5;
ford @6;
cadillac @7;
hyundai @8;
chrysler @9;
tesla @10;
subaru @11;
gmPassive @12;
mazda @13;
nissan @14;
volkswagen @15;
toyotaIpas @16;
allOutput @17;
gmAscm @18;
noOutput @19; # like silent but without silent CAN TXs
hondaBosch @20;
volkswagenPq @21;
subaruPreglobal @22; # pre-Global platform
hyundaiLegacy @23;
hyundaiCommunity @24;
volkswagenMlb @25;
hongqi @26;
body @27;
hyundaiCanfd @28;
volkswagenMqbEvo @29;
chryslerCusw @30;
psa @31;
}
enum SteerControlType {
torque @0;
angle @1;
curvatureDEPRECATED @2;
}
enum TransmissionType {
unknown @0;
automatic @1; # Traditional auto, including DSG
manual @2; # True "stick shift" only
direct @3; # Electric vehicle or other direct drive
cvt @4;
}
struct CarFw {
ecu @0 :Ecu;
fwVersion @1 :Data;
address @2 :UInt32;
subAddress @3 :UInt8;
responseAddress @4 :UInt32;
request @5 :List(Data);
brand @6 :Text;
bus @7 :UInt8;
logging @8 :Bool;
obdMultiplexing @9 :Bool;
}
enum Ecu {
eps @0;
abs @1;
fwdRadar @2;
fwdCamera @3;
engine @4;
unknown @5;
transmission @8; # Transmission Control Module
hybrid @18; # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
srs @9; # airbag
gateway @10; # can gateway
hud @11; # heads up display
combinationMeter @12; # instrument cluster
electricBrakeBooster @15;
shiftByWire @16;
adas @19;
cornerRadar @21;
hvac @20;
parkingAdas @7; # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
epb @22; # electronic parking brake
telematics @23;
body @24; # body control module
# Toyota only
dsu @6;
# Honda only
vsa @13; # Vehicle Stability Assist
programmedFuelInjection @14;
debug @17;
}
enum FingerprintSource {
can @0;
fw @1;
fixed @2;
}
enum NetworkLocation {
fwdCamera @0; # Standard/default integration at LKAS camera
gateway @1; # Integration at vehicle's CAN gateway
}
enableGasInterceptorDEPRECATED @2 :Bool;
enableCameraDEPRECATED @4 :Bool;
enableApgsDEPRECATED @6 :Bool;
steerRateCostDEPRECATED @33 :Float32;
isPandaBlackDEPRECATED @39 :Bool;
hasStockCameraDEPRECATED @57 :Bool;
safetyParamDEPRECATED @10 :Int16;
safetyModelDEPRECATED @9 :SafetyModel;
safetyModelPassiveDEPRECATED @42 :SafetyModel = silent;
minSpeedCanDEPRECATED @51 :Float32;
communityFeatureDEPRECATED @46: Bool;
startingAccelRateDEPRECATED @53 :Float32;
steerMaxBPDEPRECATED @11 :List(Float32);
steerMaxVDEPRECATED @12 :List(Float32);
gasMaxBPDEPRECATED @13 :List(Float32);
gasMaxVDEPRECATED @14 :List(Float32);
brakeMaxBPDEPRECATED @15 :List(Float32);
brakeMaxVDEPRECATED @16 :List(Float32);
directAccelControlDEPRECATED @30 :Bool;
maxSteeringAngleDegDEPRECATED @54 :Float32;
}

192
cereal/custom.capnp Normal file
View File

@ -0,0 +1,192 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
using Car = import "car.capnp";
@0xb526ba661d550a59;
# custom.capnp: a home for empty structs reserved for custom forks
# These structs are guaranteed to remain reserved and empty in mainline
# cereal, so use these if you want custom events in your fork.
# you can rename the struct, but don't change the identifier
enum LongitudinalPersonalitySP {
aggressive @0;
moderate @1;
standard @2;
relaxed @3;
}
struct ControlsStateSP @0x81c2f05a394cf4af {
lateralState @0 :Text;
personality @8 :LongitudinalPersonalitySP;
lateralControlState :union {
indiState @1 :LateralINDIState;
pidState @2 :LateralPIDState;
angleState @3 :LateralAngleState;
debugState @4 :LateralDebugState;
torqueState @5 :LateralTorqueState;
curvatureState @6 :LateralCurvatureState;
lqrStateDEPRECATED @7 :LateralLQRState;
}
struct LateralINDIState {
}
struct LateralPIDState {
}
struct LateralAngleState {
}
struct LateralDebugState {
}
struct LateralTorqueState {
nnLog @0 :List(Float32);
}
struct LateralCurvatureState {
}
struct LateralLQRState {
}
}
struct LongitudinalPlanSP @0xaedffd8f31e7b55d {
visionTurnControllerState @0 :VisionTurnControllerState;
visionTurnSpeed @1 :Float32;
visionCurrentLatAcc @16 :Float32;
visionMaxPredLatAcc @17 :Float32;
speedLimitControlState @2 :SpeedLimitControlState;
speedLimit @3 :Float32;
speedLimitOffset @4 :Float32;
distToSpeedLimit @5 :Float32;
isMapSpeedLimit @6 :Bool;
speedLimitPercOffset @11 :Bool;
speedLimitValueOffset @12 :Float32;
desiredTF @13 :Float32;
notSpeedLimit @14 :Int16;
e2eX @15 :List(Float32);
e2eBlended @18 :Text;
e2eStatus @22 :Bool;
distToTurn @7 :Float32;
turnSpeed @8 :Float32;
turnSpeedControlState @9 :SpeedLimitControlState;
turnSign @10 :Int16;
events @19 :List(Car.CarEvent);
longitudinalPlanSource @20 :LongitudinalPlanSource;
personalityDEPRECATED @21 :LongitudinalPersonalitySP;
enum SpeedLimitControlState {
inactive @0; # No speed limit set or not enabled by parameter.
tempInactive @1; # User wants to ignore speed limit until it changes.
adapting @2; # Reducing speed to match new speed limit.
active @3; # Cruising at speed limit.
preActive @4;
}
enum VisionTurnControllerState {
disabled @0; # No predicted substantial turn on vision range or feature disabled.
entering @1; # A substantial turn is predicted ahead, adapting speed to turn comfort levels.
turning @2; # Actively turning. Managing acceleration to provide a roll on turn feeling.
leaving @3; # Road ahead straightens. Start to allow positive acceleration.
}
enum LongitudinalPlanSource {
cruise @0;
lead0 @1;
lead1 @2;
lead2 @3;
e2e @4;
turn @5;
limit @6;
turnlimit @7;
}
}
struct LateralPlanSP @0xf35cc4560bbf6ec2 {
laneWidth @0 :Float32;
lProb @1 :Float32;
rProb @2 :Float32;
dProb @3 :Float32;
dynamicLaneProfile @4 :Int8;
standstillElapsed @5 :Float32;
dynamicLaneProfileStatus @9 :Bool;
dPathWLinesXDEPRECATED @6 :List(Float32);
dPathWLinesYDEPRECATED @7 :List(Float32);
laneChangePrevDEPRECATED @8 :Bool;
laneChangeEdgeBlockDEPRECATED @10 :Bool;
}
struct DriverMonitoringStateSP @0xda96579883444c35 {
handsOnWheelState @0 :HandsOnWheelState;
notModified @1 :Float32;
enum HandsOnWheelState {
none @0; # hand on wheel monitoring inactive
ok @1; # driver has hands on steering wheel
minor @2; # hands off steering wheel for acceptable period
warning @3; # hands off steering wheel for warning period
critical @4; # # hands off steering wheel for critical period
terminal @5; # # hands off steering wheel for terminal period
}
}
struct LiveMapDataSP @0x80ae746ee2596b11 {
speedLimitValid @0 :Bool;
speedLimit @1 :Float32;
speedLimitAheadValid @2 :Bool;
speedLimitAhead @3 :Float32;
speedLimitAheadDistance @4 :Float32;
turnSpeedLimitValid @5 :Bool;
turnSpeedLimit @6 :Float32;
turnSpeedLimitEndDistance @7 :Float32;
turnSpeedLimitSign @8 :Int16;
turnSpeedLimitsAhead @9 :List(Float32);
turnSpeedLimitsAheadDistances @10 :List(Float32);
turnSpeedLimitsAheadSigns @11 :List(Int16);
lastGpsTimestamp @12 :Int64; # Milliseconds since January 1, 1970.
currentRoadName @13 :Text;
lastGpsLatitude @14 :Float64;
lastGpsLongitude @15 :Float64;
lastGpsSpeed @16 :Float32;
lastGpsBearingDeg @17 :Float32;
lastGpsAccuracy @18 :Float32;
lastGpsBearingAccuracyDeg @19 :Float32;
dataType @20 :DataType;
enum DataType {
default @0;
offline @1;
online @2;
}
}
struct E2eLongStateSP @0xa5cd762cd951a455 {
status @0 :UInt16;
}
struct ModelDataV2SP @0xf98d843bfd7004a3 {
laneChangePrev @0 :Bool;
laneChangeEdgeBlock @1 :Bool;
}
struct CustomReserved7 @0xb86e6369214c01c8 {
}
struct CustomReserved8 @0xf416ec09499d9d19 {
}
struct CustomReserved9 @0xa1680744031fdb2d {
}

26
cereal/include/c++.capnp Normal file
View File

@ -0,0 +1,26 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xbdf87d7bb8304e81;
$namespace("capnp::annotations");
annotation namespace(file): Text;
annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text;

574
cereal/legacy.capnp Normal file
View File

@ -0,0 +1,574 @@
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;
}

2369
cereal/log.capnp Normal file

File diff suppressed because it is too large Load Diff

49
cereal/maptile.capnp Normal file
View File

@ -0,0 +1,49 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
@0xa086df597ef5d7a0;
# Geometry
struct Point {
x @0: Float64;
y @1: Float64;
z @2: Float64;
}
struct PolyLine {
points @0: List(Point);
}
# Map features
struct Lane {
id @0 :Text;
leftBoundary @1 :LaneBoundary;
rightBoundary @2 :LaneBoundary;
leftAdjacentId @3 :Text;
rightAdjacentId @4 :Text;
inboundIds @5 :List(Text);
outboundIds @6 :List(Text);
struct LaneBoundary {
polyLine @0 :PolyLine;
startHeading @1 :Float32; # WRT north
}
}
# Map tiles
struct TileSummary {
version @0 :Text;
updatedAt @1 :UInt64; # Millis since epoch
level @2 :UInt8;
x @3 :UInt16;
y @4 :UInt16;
}
struct MapTile {
summary @0 :TileSummary;
lanes @1 :List(Lane);
}

10
cereal/messaging/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
demo
bridge
test_runner
*.o
*.os
*.d
*.a
*.so
messaging_pyx.cpp
build/

View File

@ -0,0 +1,252 @@
# 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, context
import os
import capnp
import time
from typing import Optional, List, Union, Dict, Deque
from collections import deque
from cereal import log
from cereal.services import SERVICE_LIST
NO_TRAVERSAL_LIMIT = 2**64-1
def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
with log.Event.from_bytes(dat, traversal_limit_in_words=NO_TRAVERSAL_LIMIT) as msg:
return msg
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
args = {
'valid': False,
'logMonoTime': int(time.monotonic() * 1e9),
**kwargs
}
dat = log.Event.new_message(**args)
if service is not None:
if size is None:
dat.init(service)
else:
dat.init(service, size)
return dat
def drain_sock(sock: SubSocket, wait_for_one: bool = False) -> List[capnp.lib.capnp._DynamicStructReader]:
"""Receive all message currently available on the queue"""
msgs = drain_sock_raw(sock, wait_for_one=wait_for_one)
return [log_from_bytes(m) for m in msgs]
# TODO: print when we drop packets?
def recv_sock(sock: SubSocket, wait: bool = False) -> Optional[capnp.lib.capnp._DynamicStructReader]:
"""Same as drain sock, but only returns latest message. Consider using conflate instead."""
dat = None
while 1:
if wait and dat is None:
recv = sock.receive()
else:
recv = sock.receive(non_blocking=True)
if recv is None: # Timeout hit
break
dat = recv
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
dat = sock.receive()
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one_or_none(sock: SubSocket) -> Optional[capnp.lib.capnp._DynamicStructReader]:
dat = sock.receive(non_blocking=True)
if dat is not None:
dat = log_from_bytes(dat)
return dat
def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
"""Keep receiving until we get a message"""
while True:
dat = sock.receive()
if dat is not None:
return log_from_bytes(dat)
class SubMaster:
def __init__(self, services: List[str], poll: Optional[str] = None,
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1", frequency: Optional[float] = None):
self.frame = -1
self.seen = {s: False for s in services}
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.recv_dts: Dict[str, Deque[float]] = {}
self.sock = {}
self.data = {}
self.valid = {}
self.logMonoTime = {}
self.max_freq = {}
self.min_freq = {}
self.poller = Poller()
polled_services = set([poll, ] if poll is not None else services)
self.non_polled_services = set(services) - polled_services
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
self.ignore_alive = [] if ignore_alive is None else ignore_alive
self.ignore_valid = [] if ignore_valid is None else ignore_valid
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
# if freq and poll aren't specified, assume the max to be conservative
assert frequency is None or poll is None, "Do not specify 'frequency' - frequency of the polled service will be used."
self.update_freq = frequency or max([SERVICE_LIST[s].frequency for s in polled_services])
for s in services:
p = self.poller if s not in self.non_polled_services else None
self.sock[s] = sub_sock(s, poller=p, addr=addr, conflate=True)
try:
data = new_message(s)
except capnp.lib.capnp.KjException:
data = new_message(s, 0) # lists
self.data[s] = getattr(data.as_reader(), s)
self.logMonoTime[s] = 0
self.valid[s] = True # FIXME: this should default to False
freq = max(min([SERVICE_LIST[s].frequency, self.update_freq]), 1.)
if s == poll:
max_freq = freq
min_freq = freq
else:
max_freq = min(freq, self.update_freq)
if SERVICE_LIST[s].frequency >= 2*self.update_freq:
min_freq = self.update_freq
elif self.update_freq >= 2*SERVICE_LIST[s].frequency:
min_freq = freq
else:
min_freq = min(freq, freq / 2.)
self.max_freq[s] = max_freq*1.2
self.min_freq[s] = min_freq*0.8
self.recv_dts[s] = deque(maxlen=int(10*freq))
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
return self.data[s]
def _check_avg_freq(self, s: str) -> bool:
return SERVICE_LIST[s].frequency > 0.99 and (s not in self.ignore_average_freq) and (s not in self.ignore_alive)
def update(self, timeout: int = 100) -> None:
msgs = []
for sock in self.poller.poll(timeout):
msgs.append(recv_one_or_none(sock))
# non-blocking receive for non-polled sockets
for s in self.non_polled_services:
msgs.append(recv_one_or_none(self.sock[s]))
self.update_msgs(time.monotonic(), msgs)
def update_msgs(self, cur_time: float, msgs: List[capnp.lib.capnp._DynamicStructReader]) -> None:
self.frame += 1
self.updated = dict.fromkeys(self.updated, False)
for msg in msgs:
if msg is None:
continue
s = msg.which()
self.seen[s] = True
self.updated[s] = True
if self.recv_time[s] > 1e-5:
self.recv_dts[s].append(cur_time - self.recv_time[s])
self.recv_time[s] = cur_time
self.recv_frame[s] = self.frame
self.data[s] = getattr(msg, s)
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
for s in self.data:
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)
# check average frequency; slow to fall, quick to recover
dts = self.recv_dts[s]
assert dts.maxlen is not None
recent_dts = list(dts)[-int(dts.maxlen / 10):]
try:
avg_freq = 1 / (sum(dts) / len(dts))
avg_freq_recent = 1 / (sum(recent_dts) / len(recent_dts))
except ZeroDivisionError:
avg_freq = 0
avg_freq_recent = 0
avg_freq_ok = self.min_freq[s] <= avg_freq <= self.max_freq[s]
recent_freq_ok = self.min_freq[s] <= avg_freq_recent <= self.max_freq[s]
self.freq_ok[s] = avg_freq_ok or recent_freq_ok
else:
self.freq_ok[s] = True
if self.simulation:
self.alive[s] = self.seen[s] # alive is defined as seen when simulation flag set
else:
self.alive[s] = True
def all_alive(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
def all_freq_ok(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.freq_ok[s] for s in service_list if self._check_avg_freq(s))
def all_valid(self, service_list: Optional[List[str]] = None) -> bool:
if service_list is None:
service_list = list(self.sock.keys())
return all(self.valid[s] for s in service_list if s not in self.ignore_valid)
def all_checks(self, service_list: Optional[List[str]] = None) -> bool:
return self.all_alive(service_list) and self.all_freq_ok(service_list) and self.all_valid(service_list)
class PubMaster:
def __init__(self, services: List[str]):
self.sock = {}
for s in services:
self.sock[s] = pub_sock(s)
def send(self, s: str, dat: Union[bytes, capnp.lib.capnp._DynamicStructBuilder]) -> None:
if not isinstance(dat, bytes):
dat = dat.to_bytes()
self.sock[s].send(dat)
def wait_for_readers_to_update(self, s: str, timeout: int, dt: float = 0.05) -> bool:
for _ in range(int(timeout*(1./dt))):
if self.sock[s].all_readers_updated():
return True
time.sleep(dt)
return False
def all_readers_updated(self, s: str) -> bool:
return self.sock[s].all_readers_updated() # type: ignore

View File

@ -0,0 +1,92 @@
#include <algorithm>
#include <cassert>
#include <csignal>
#include <iostream>
#include <map>
#include <string>
typedef void (*sighandler_t)(int sig);
#include "cereal/services.h"
#include "msgq/impl_msgq.h"
#include "msgq/impl_zmq.h"
std::atomic<bool> do_exit = false;
static void set_do_exit(int sig) {
do_exit = true;
}
void sigpipe_handler(int sig) {
assert(sig == SIGPIPE);
std::cout << "SIGPIPE received" << std::endl;
}
static std::vector<std::string> get_services(std::string whitelist_str, bool zmq_to_msgq) {
std::vector<std::string> service_list;
for (const auto& it : services) {
std::string name = it.second.name;
bool in_whitelist = whitelist_str.find(name) != std::string::npos;
if (name == "plusFrame" || name == "uiLayoutState" || (zmq_to_msgq && !in_whitelist)) {
continue;
}
service_list.push_back(name);
}
return service_list;
}
int main(int argc, char** argv) {
signal(SIGPIPE, (sighandler_t)sigpipe_handler);
signal(SIGINT, (sighandler_t)set_do_exit);
signal(SIGTERM, (sighandler_t)set_do_exit);
bool zmq_to_msgq = argc > 2;
std::string ip = zmq_to_msgq ? argv[1] : "127.0.0.1";
std::string whitelist_str = zmq_to_msgq ? std::string(argv[2]) : "";
Poller *poller;
Context *pub_context;
Context *sub_context;
if (zmq_to_msgq) { // republishes zmq debugging messages as msgq
poller = new ZMQPoller();
pub_context = new MSGQContext();
sub_context = new ZMQContext();
} else {
poller = new MSGQPoller();
pub_context = new ZMQContext();
sub_context = new MSGQContext();
}
std::map<SubSocket*, PubSocket*> sub2pub;
for (auto endpoint : get_services(whitelist_str, zmq_to_msgq)) {
PubSocket * pub_sock;
SubSocket * sub_sock;
if (zmq_to_msgq) {
pub_sock = new MSGQPubSocket();
sub_sock = new ZMQSubSocket();
} else {
pub_sock = new ZMQPubSocket();
sub_sock = new MSGQSubSocket();
}
pub_sock->connect(pub_context, endpoint);
sub_sock->connect(sub_context, endpoint, ip, false);
poller->registerSocket(sub_sock);
sub2pub[sub_sock] = pub_sock;
}
while (!do_exit) {
for (auto sub_sock : poller->poll(100)) {
Message * msg = sub_sock->receive();
if (msg == NULL) continue;
int ret;
do {
ret = sub2pub[sub_sock]->sendMessage(msg);
} while (ret == -1 && errno == EINTR && !do_exit);
assert(ret >= 0 || do_exit);
delete msg;
if (do_exit) break;
}
}
return 0;
}

View File

@ -0,0 +1,112 @@
#pragma once
#include <cstddef>
#include <map>
#include <string>
#include <vector>
#include <utility>
#include <time.h>
#include <capnp/serialize.h>
#include "cereal/gen/cpp/log.capnp.h"
#include "msgq/ipc.h"
#ifdef __APPLE__
#define CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
#define MSG_MULTIPLE_PUBLISHERS 100
class SubMaster {
public:
SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll = {},
const char *address = nullptr, const std::vector<const char *> &ignore_alive = {});
void update(int timeout = 1000);
void update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages);
inline bool allAlive(const std::vector<const char *> &service_list = {}) { return all_(service_list, false, true); }
inline bool allValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, false); }
inline bool allAliveAndValid(const std::vector<const char *> &service_list = {}) { return all_(service_list, true, true); }
void drain();
~SubMaster();
uint64_t frame = 0;
bool updated(const char *name) const;
bool alive(const char *name) const;
bool valid(const char *name) const;
uint64_t rcv_frame(const char *name) const;
uint64_t rcv_time(const char *name) const;
cereal::Event::Reader &operator[](const char *name) const;
private:
bool all_(const std::vector<const char *> &service_list, bool valid, bool alive);
Poller *poller_ = nullptr;
struct SubMessage;
std::map<SubSocket *, SubMessage *> messages_;
std::map<std::string, SubMessage *> services_;
};
class MessageBuilder : public capnp::MallocMessageBuilder {
public:
MessageBuilder() = default;
cereal::Event::Builder initEvent(bool valid = true) {
cereal::Event::Builder event = initRoot<cereal::Event>();
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
uint64_t current_time = t.tv_sec * 1000000000ULL + t.tv_nsec;
event.setLogMonoTime(current_time);
event.setValid(valid);
return event;
}
kj::ArrayPtr<capnp::byte> toBytes() {
heapArray_ = capnp::messageToFlatArray(*this);
return heapArray_.asBytes();
}
size_t getSerializedSize() {
return capnp::computeSerializedSizeInWords(*this) * sizeof(capnp::word);
}
int serializeToBuffer(unsigned char *buffer, size_t buffer_size) {
size_t serialized_size = getSerializedSize();
if (serialized_size > buffer_size) { return -1; }
kj::ArrayOutputStream out(kj::ArrayPtr<capnp::byte>(buffer, buffer_size));
capnp::writeMessage(out, *this);
return serialized_size;
}
private:
kj::Array<capnp::word> heapArray_;
};
class PubMaster {
public:
PubMaster(const std::vector<const char *> &service_list);
inline int send(const char *name, capnp::byte *data, size_t size) { return sockets_.at(name)->send((char *)data, size); }
int send(const char *name, MessageBuilder &msg);
~PubMaster();
private:
std::map<std::string, PubSocket *> sockets_;
};
class AlignedBuffer {
public:
kj::ArrayPtr<const capnp::word> align(const char *data, const size_t size) {
words_size = size / sizeof(capnp::word) + 1;
if (aligned_buf.size() < words_size) {
aligned_buf = kj::heapArray<capnp::word>(words_size < 512 ? 512 : words_size);
}
memcpy(aligned_buf.begin(), data, size);
return aligned_buf.slice(0, words_size);
}
inline kj::ArrayPtr<const capnp::word> align(Message *m) {
return align(m->getData(), m->getSize());
}
private:
kj::Array<capnp::word> aligned_buf;
size_t words_size;
};

View File

@ -0,0 +1,211 @@
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#include <string>
#include <mutex>
#include "cereal/services.h"
#include "cereal/messaging/messaging.h"
const bool SIMULATION = (getenv("SIMULATION") != nullptr) && (std::string(getenv("SIMULATION")) == "1");
static inline uint64_t nanos_since_boot() {
struct timespec t;
clock_gettime(CLOCK_BOOTTIME, &t);
return t.tv_sec * 1000000000ULL + t.tv_nsec;
}
static inline bool inList(const std::vector<const char *> &list, const char *value) {
for (auto &v : list) {
if (strcmp(value, v) == 0) return true;
}
return false;
}
class MessageContext {
public:
MessageContext() : ctx_(nullptr) {}
~MessageContext() { delete ctx_; }
inline Context *context() {
std::call_once(init_flag, [=]() { ctx_ = Context::create(); });
return ctx_;
}
private:
Context *ctx_;
std::once_flag init_flag;
};
MessageContext message_context;
struct SubMaster::SubMessage {
std::string name;
SubSocket *socket = nullptr;
int freq = 0;
bool updated = false, alive = false, valid = true, ignore_alive;
uint64_t rcv_time = 0, rcv_frame = 0;
void *allocated_msg_reader = nullptr;
bool is_polled = false;
capnp::FlatArrayMessageReader *msg_reader = nullptr;
AlignedBuffer aligned_buf;
cereal::Event::Reader event;
};
SubMaster::SubMaster(const std::vector<const char *> &service_list, const std::vector<const char *> &poll,
const char *address, const std::vector<const char *> &ignore_alive) {
poller_ = Poller::create();
for (auto name : service_list) {
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);
assert(socket != 0);
bool is_polled = inList(poll, name) || poll.empty();
if (is_polled) poller_->registerSocket(socket);
SubMessage *m = new SubMessage{
.name = name,
.socket = socket,
.freq = serv.frequency,
.ignore_alive = inList(ignore_alive, name),
.allocated_msg_reader = malloc(sizeof(capnp::FlatArrayMessageReader)),
.is_polled = is_polled};
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader({});
messages_[socket] = m;
services_[name] = m;
}
}
void SubMaster::update(int timeout) {
for (auto &kv : messages_) kv.second->updated = false;
auto sockets = poller_->poll(timeout);
// add non-polled sockets for non-blocking receive
for (auto &kv : messages_) {
SubMessage *m = kv.second;
SubSocket *s = kv.first;
if (!m->is_polled) sockets.push_back(s);
}
uint64_t current_time = nanos_since_boot();
std::vector<std::pair<std::string, cereal::Event::Reader>> messages;
for (auto s : sockets) {
Message *msg = s->receive(true);
if (msg == nullptr) continue;
SubMessage *m = messages_.at(s);
m->msg_reader->~FlatArrayMessageReader();
capnp::ReaderOptions options;
options.traversalLimitInWords = kj::maxValue; // Don't limit
m->msg_reader = new (m->allocated_msg_reader) capnp::FlatArrayMessageReader(m->aligned_buf.align(msg), options);
delete msg;
messages.push_back({m->name, m->msg_reader->getRoot<cereal::Event>()});
}
update_msgs(current_time, messages);
}
void SubMaster::update_msgs(uint64_t current_time, const std::vector<std::pair<std::string, cereal::Event::Reader>> &messages){
if (++frame == UINT64_MAX) frame = 1;
for (auto &kv : messages) {
auto m_find = services_.find(kv.first);
if (m_find == services_.end()){
continue;
}
SubMessage *m = m_find->second;
m->event = kv.second;
m->updated = true;
m->rcv_time = current_time;
m->rcv_frame = frame;
m->valid = m->event.getValid();
if (SIMULATION) m->alive = true;
}
if (!SIMULATION) {
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->alive = (m->freq <= (1e-5) || ((current_time - m->rcv_time) * (1e-9)) < (10.0 / m->freq));
}
}
}
bool SubMaster::all_(const std::vector<const char *> &service_list, bool valid, bool alive) {
int found = 0;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
if (service_list.size() == 0 || inList(service_list, m->name.c_str())) {
found += (!valid || m->valid) && (!alive || (m->alive || m->ignore_alive));
}
}
return service_list.size() == 0 ? found == messages_.size() : found == service_list.size();
}
void SubMaster::drain() {
while (true) {
auto polls = poller_->poll(0);
if (polls.size() == 0)
break;
for (auto sock : polls) {
Message *msg = sock->receive(true);
delete msg;
}
}
}
bool SubMaster::updated(const char *name) const {
return services_.at(name)->updated;
}
bool SubMaster::alive(const char *name) const {
return services_.at(name)->alive;
}
bool SubMaster::valid(const char *name) const {
return services_.at(name)->valid;
}
uint64_t SubMaster::rcv_frame(const char *name) const {
return services_.at(name)->rcv_frame;
}
uint64_t SubMaster::rcv_time(const char *name) const {
return services_.at(name)->rcv_time;
}
cereal::Event::Reader &SubMaster::operator[](const char *name) const {
return services_.at(name)->event;
}
SubMaster::~SubMaster() {
delete poller_;
for (auto &kv : messages_) {
SubMessage *m = kv.second;
m->msg_reader->~FlatArrayMessageReader();
free(m->allocated_msg_reader);
delete m->socket;
delete m;
}
}
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);
assert(socket);
sockets_[name] = socket;
}
}
int PubMaster::send(const char *name, MessageBuilder &msg) {
auto bytes = msg.toBytes();
return send(name, bytes.begin(), bytes.size());
}
PubMaster::~PubMaster() {
for (auto s : sockets_) delete s.second;
}

View File

@ -0,0 +1,195 @@
#!/usr/bin/env python3
import os
import capnp
import multiprocessing
import numbers
import random
import threading
import time
import unittest
from parameterized import parameterized
from cereal import log, car
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
events = [evt for evt in log.Event.schema.union_fields if evt in SERVICE_LIST.keys()]
def random_sock():
return random.choice(events)
def random_socks(num_socks=10):
return list({random_sock() for _ in range(num_socks)})
def random_bytes(length=1000):
return bytes([random.randrange(0xFF) for _ in range(length)])
def zmq_sleep(t=1):
if "ZMQ" in os.environ:
time.sleep(t)
def zmq_expected_failure(func):
if "ZMQ" in os.environ:
return unittest.expectedFailure(func)
else:
return func
# TODO: this should take any capnp struct and returrn a msg with random populated data
def random_carstate():
fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"]
msg = messaging.new_message("carState")
cs = msg.carState
for f in fields:
setattr(cs, f, random.random() * 10)
return msg
# TODO: this should compare any capnp structs
def assert_carstate(cs1, cs2):
for f in car.CarState.schema.non_union_fields:
# TODO: check all types
val1, val2 = getattr(cs1, f), getattr(cs2, f)
if isinstance(val1, numbers.Number):
assert val1 == val2, f"{f}: sent '{val1}' vs recvd '{val2}'"
def delayed_send(delay, sock, dat):
def send_func():
sock.send(dat)
threading.Timer(delay, send_func).start()
class TestMessaging(unittest.TestCase):
def setUp(self):
# TODO: ZMQ tests are too slow; all sleeps will need to be
# replaced with logic to block on the necessary condition
if "ZMQ" in os.environ:
raise unittest.SkipTest
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep()
@parameterized.expand(events)
def test_new_message(self, evt):
try:
msg = messaging.new_message(evt)
except capnp.lib.capnp.KjException:
msg = messaging.new_message(evt, random.randrange(200))
self.assertLess(time.monotonic() - msg.logMonoTime, 0.1)
self.assertFalse(msg.valid)
self.assertEqual(evt, msg.which())
@parameterized.expand(events)
def test_pub_sock(self, evt):
messaging.pub_sock(evt)
@parameterized.expand(events)
def test_sub_sock(self, evt):
messaging.sub_sock(evt)
@parameterized.expand([
(messaging.drain_sock, capnp._DynamicStructReader),
(messaging.drain_sock_raw, bytes),
])
def test_drain_sock(self, func, expected_type):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no wait and no msgs in queue
msgs = func(sub_sock)
self.assertIsInstance(msgs, list)
self.assertEqual(len(msgs), 0)
# no wait but msgs are queued up
num_msgs = random.randrange(3, 10)
for _ in range(num_msgs):
pub_sock.send(messaging.new_message(sock).to_bytes())
time.sleep(0.1)
msgs = func(sub_sock)
self.assertIsInstance(msgs, list)
self.assertTrue(all(isinstance(msg, expected_type) for msg in msgs))
self.assertEqual(len(msgs), num_msgs)
def test_recv_sock(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=100)
zmq_sleep()
# no wait and no msg in queue, socket should timeout
recvd = messaging.recv_sock(sub_sock)
self.assertTrue(recvd is None)
# no wait and one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
recvd = messaging.recv_sock(sub_sock)
self.assertIsInstance(recvd, capnp._DynamicStructReader)
# https://github.com/python/mypy/issues/13038
assert_carstate(msg.carState, recvd.carState)
def test_recv_one(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=1000)
zmq_sleep()
# no msg in queue, socket should timeout
recvd = messaging.recv_one(sub_sock)
self.assertTrue(recvd is None)
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one(sub_sock)
self.assertIsInstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
@zmq_expected_failure
def test_recv_one_or_none(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock)
zmq_sleep()
# no msg in queue, socket shouldn't block
recvd = messaging.recv_one_or_none(sub_sock)
self.assertTrue(recvd is None)
# one msg in queue
msg = random_carstate()
pub_sock.send(msg.to_bytes())
recvd = messaging.recv_one_or_none(sub_sock)
self.assertIsInstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
def test_recv_one_retry(self):
sock = "carState"
sock_timeout = 0.1
pub_sock = messaging.pub_sock(sock)
sub_sock = messaging.sub_sock(sock, timeout=round(sock_timeout*1000))
zmq_sleep()
# this test doesn't work with ZMQ since multiprocessing interrupts it
if "ZMQ" not in os.environ:
# wait 15 socket timeouts and make sure it's still retrying
p = multiprocessing.Process(target=messaging.recv_one_retry, args=(sub_sock,))
p.start()
time.sleep(sock_timeout*15)
self.assertTrue(p.is_alive())
p.terminate()
# wait 15 socket timeouts before sending
msg = random_carstate()
delayed_send(sock_timeout*15, pub_sock, msg.to_bytes())
start_time = time.monotonic()
recvd = messaging.recv_one_retry(sub_sock)
self.assertGreaterEqual(time.monotonic() - start_time, sock_timeout*15)
self.assertIsInstance(recvd, capnp._DynamicStructReader)
assert_carstate(msg.carState, recvd.carState)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
import random
import time
from typing import Sized, cast
import unittest
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
class TestSubMaster(unittest.TestCase):
def setUp(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
sm = messaging.SubMaster(events)
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
self.assertEqual(len(cast(Sized, p)), len(events))
def test_init_state(self):
socks = random_socks()
sm = messaging.SubMaster(socks)
self.assertEqual(sm.frame, -1)
self.assertFalse(any(sm.updated.values()))
self.assertFalse(any(sm.alive.values()))
self.assertTrue(all(t == 0. for t in sm.recv_time.values()))
self.assertTrue(all(f == 0 for f in sm.recv_frame.values()))
self.assertTrue(all(t == 0 for t in sm.logMonoTime.values()))
for p in [sm.updated, sm.recv_time, sm.recv_frame, sm.alive,
sm.sock, sm.data, sm.logMonoTime, sm.valid]:
self.assertEqual(len(cast(Sized, p)), len(socks))
def test_getitem(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
msg = random_carstate()
pub_sock.send(msg.to_bytes())
sm.update(1000)
assert_carstate(msg.carState, sm[sock])
# TODO: break this test up to individually test SubMaster.update and SubMaster.update_msgs
def test_update(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
zmq_sleep()
for i in range(10):
msg = messaging.new_message(sock)
pub_sock.send(msg.to_bytes())
sm.update(1000)
self.assertEqual(sm.frame, i)
self.assertTrue(all(sm.updated.values()))
def test_update_timeout(self):
sock = random_sock()
sm = messaging.SubMaster([sock,])
for _ in range(5):
timeout = random.randrange(1000, 5000)
start_time = time.monotonic()
sm.update(timeout)
t = time.monotonic() - start_time
self.assertGreaterEqual(t, timeout/1000.)
self.assertLess(t, 5)
self.assertFalse(any(sm.updated.values()))
def test_avg_frequency_checks(self):
for poll in (True, False):
sm = messaging.SubMaster(["modelV2", "carParams", "carState", "cameraOdometry", "liveCalibration"],
poll=("modelV2" if poll else None),
frequency=(20. if not poll else None))
checks = {
"carState": (20, 20),
"modelV2": (20, 20 if poll else 10),
"cameraOdometry": (20, 10),
"liveCalibration": (4, 4),
"carParams": (None, None),
}
for service, (max_freq, min_freq) in checks.items():
if max_freq is not None:
assert sm._check_avg_freq(service)
assert sm.max_freq[service] == max_freq*1.2
assert sm.min_freq[service] == min_freq*0.8
else:
assert not sm._check_avg_freq(service)
def test_alive(self):
pass
def test_ignore_alive(self):
pass
def test_valid(self):
pass
# SubMaster should always conflate
def test_conflate(self):
sock = "carState"
pub_sock = messaging.pub_sock(sock)
sm = messaging.SubMaster([sock,])
n = 10
for i in range(n+1):
msg = messaging.new_message(sock)
msg.carState.vEgo = i
pub_sock.send(msg.to_bytes())
time.sleep(0.01)
sm.update(1000)
self.assertEqual(sm[sock].vEgo, n)
class TestPubMaster(unittest.TestCase):
def setUp(self):
# ZMQ pub socket takes too long to die
# sleep to prevent multiple publishers error between tests
zmq_sleep(3)
def test_init(self):
messaging.PubMaster(events)
def test_send(self):
socks = random_socks()
pm = messaging.PubMaster(socks)
sub_socks = {s: messaging.sub_sock(s, conflate=True, timeout=1000) for s in socks}
zmq_sleep()
# PubMaster accepts either a capnp msg builder or bytes
for capnp in [True, False]:
for i in range(100):
sock = socks[i % len(socks)]
if capnp:
try:
msg = messaging.new_message(sock)
except Exception:
msg = messaging.new_message(sock, random.randrange(50))
else:
msg = random_bytes()
pm.send(sock, msg)
recvd = sub_socks[sock].receive()
if capnp:
msg.clear_write_flag()
msg = msg.to_bytes()
self.assertEqual(msg, recvd, i)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
import os
import tempfile
from typing import Dict
import unittest
from parameterized import parameterized
import cereal.services as services
from cereal.services import SERVICE_LIST
class TestServices(unittest.TestCase):
@parameterized.expand(SERVICE_LIST.keys())
def test_services(self, s):
service = SERVICE_LIST[s]
self.assertTrue(service.frequency <= 104)
def test_generated_header(self):
with tempfile.NamedTemporaryFile(suffix=".h") as f:
ret = os.system(f"python3 {services.__file__} > {f.name} && clang++ {f.name}")
self.assertEqual(ret, 0, "generated services header is not valid C")
if __name__ == "__main__":
unittest.main()

129
cereal/services.py Executable file
View File

@ -0,0 +1,129 @@
#!/usr/bin/env python3
from typing import Optional
class Service:
def __init__(self, should_log: bool, frequency: float, decimation: Optional[int] = None):
self.should_log = should_log
self.frequency = frequency
self.decimation = decimation
_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., 25),
"lightSensor": (True, 100., 100),
"temperatureSensor": (True, 2., 200),
"temperatureSensor2": (True, 2., 200),
"gpsNMEA": (True, 9.),
"deviceState": (True, 2., 1),
"can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment
"controlsState": (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),
"liveCalibration": (True, 4., 4),
"liveTorqueParameters": (True, 4., 1),
"androidLog": (True, 0.),
"carState": (True, 100., 10),
"carControl": (True, 100., 10),
"carOutput": (True, 100., 10),
"longitudinalPlan": (True, 20., 5),
"procLog": (True, 0.5, 15),
"gpsLocationExternal": (True, 10., 10),
"gpsLocation": (True, 1., 1),
"ubloxGnss": (True, 10.),
"qcomGnss": (True, 2.),
"gnssMeasurements": (True, 10., 10),
"clocks": (True, 0.1, 1),
"ubloxRaw": (True, 20.),
"liveLocationKalman": (True, 20., 5),
"liveParameters": (True, 20., 5),
"cameraOdometry": (True, 20., 5),
"lateralPlanDEPRECATED": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
"onroadEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),
"driverEncodeIdx": (False, 20., 1),
"driverStateV2": (True, 20., 10),
"driverMonitoringState": (True, 20., 10),
"wideRoadEncodeIdx": (False, 20., 1),
"wideRoadCameraState": (True, 20., 20),
"modelV2": (True, 20., 40),
"managerState": (True, 2., 1),
"uploaderState": (True, 0., 1),
"navInstruction": (True, 1., 10),
"navRoute": (True, 0.),
"navThumbnail": (True, 0.),
"navModelDEPRECATED": (True, 2., 4.),
"mapRenderState": (True, 2., 1.),
"uiPlan": (True, 20., 40.),
"qRoadEncodeIdx": (False, 20.),
"userFlag": (True, 0., 1),
"microphone": (True, 10., 10),
"controlsStateSP": (True, 100., 10),
"longitudinalPlanSP": (True, 20., 5),
"lateralPlanSPDEPRECATED": (True, 20., 5),
"driverMonitoringStateSP": (True, 20., 10),
"liveMapDataSP": (True, 0.),
"e2eLongStateSP": (True, 0.),
"modelV2SP": (True, 20., 40),
# debug
"uiDebug": (True, 0., 1),
"testJoystick": (True, 0.),
"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.),
"customReservedRawData0": (True, 0.),
"customReservedRawData1": (True, 0.),
"customReservedRawData2": (True, 0.),
}
SERVICE_LIST = {name: Service(*vals) for
idx, (name, vals) in enumerate(_services.items())}
def build_header():
h = ""
h += "/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT services.py */\n"
h += "#ifndef __SERVICES_H\n"
h += "#define __SERVICES_H\n"
h += "#include <map>\n"
h += "#include <string>\n"
h += "struct service { std::string name; bool should_log; int frequency; int decimation; };\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 += "};\n"
h += "#endif\n"
return h
if __name__ == "__main__":
print(build_header())

View File

@ -1,5 +1,5 @@
from functools import cache
import subprocess
from openpilot.common.utils import cache
from openpilot.common.run import run_cmd, run_cmd_default

45
common/markdown.py Normal file
View File

@ -0,0 +1,45 @@
HTML_REPLACEMENTS = [
(r'&', r'&amp;'),
(r'"', r'&quot;'),
]
def parse_markdown(text: str, tab_length: int = 2) -> str:
lines = text.split("\n")
output: list[str] = []
list_level = 0
def end_outstanding_lists(level: int, end_level: int) -> int:
while level > end_level:
level -= 1
output.append("</ul>")
if level > 0:
output.append("</li>")
return end_level
for i, line in enumerate(lines):
if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading
output.append(f"<h1>{line}</h1>")
elif line.startswith("==="):
pass
elif line.lstrip().startswith("* "): # list
line_level = 1 + line.count(" " * tab_length, 0, line.index("*"))
if list_level >= line_level:
list_level = end_outstanding_lists(list_level, line_level)
else:
list_level += 1
if list_level > 1:
output[-1] = output[-1].replace("</li>", "")
output.append("<ul>")
output.append(f"<li>{line.replace('*', '', 1).lstrip()}</li>")
else:
list_level = end_outstanding_lists(list_level, 0)
if len(line) > 0:
output.append(line)
end_outstanding_lists(list_level, 0)
output_str = "\n".join(output) + "\n"
for (fr, to) in HTML_REPLACEMENTS:
output_str = output_str.replace(fr, to)
return output_str

View File

@ -9,7 +9,7 @@ public:
~RateKeeper() {}
bool keepTime();
bool monitorTime();
inline double frame() const { return frame_; }
inline uint64_t frame() const { return frame_; }
inline double remaining() const { return remaining_; }
private:

View File

@ -14,7 +14,7 @@ from openpilot.system.hardware import PC
# time step for each process
DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model
DT_TRML = 0.5 # thermald and manager
DT_HW = 0.5 # hardwared and manager
DT_DMON = 0.05 # driver monitoring
@ -25,7 +25,7 @@ class Priority:
CTRL_LOW = 51 # plannerd & radard
# CORE 3
# - boardd = 55
# - pandad = 55
CTRL_HIGH = 53

View File

@ -0,0 +1,15 @@
import os
from openpilot.common.basedir import BASEDIR
from openpilot.common.markdown import parse_markdown
class TestMarkdown:
def test_all_release_notes(self):
with open(os.path.join(BASEDIR, "RELEASES.md")) as f:
release_notes = f.read().split("\n\n")
assert len(release_notes) > 10
for rn in release_notes:
md = parse_markdown(rn)
assert len(md) > 0

2
common/transformations/tests/test_coordinates.py Executable file → Normal file
View File

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import numpy as np
import openpilot.common.transformations.coordinates as coord

2
common/transformations/tests/test_orientation.py Executable file → Normal file
View File

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import numpy as np
from openpilot.common.transformations.orientation import euler2quat, quat2euler, euler2rot, rot2euler, \

View File

@ -1,11 +1,3 @@
from collections.abc import Callable
from functools import lru_cache
from typing import TypeVar
_RT = TypeVar("_RT")
class Freezable:
_frozen: bool = False
@ -17,7 +9,3 @@ class Freezable:
if self._frozen:
raise Exception("cannot modify frozen object")
super().__setattr__(*args, **kwargs)
def cache(user_function: Callable[..., _RT], /) -> Callable[..., _RT]:
return lru_cache(maxsize=None)(user_function)

View File

@ -1 +1 @@
#define COMMA_VERSION "0.9.7.0"
#define COMMA_VERSION "0.9.7.1"

View File

@ -57,10 +57,6 @@ The control doesn't have to be perfect, but it should generally do what it's sup
Get a Rivian driving with openpilot.
Requires a merged port with lateral control and at least a POC of longitudinal control.
#### Toyota SecOc - $5000
We're contributing $5k to the [community-organized bounty](https://github.com/commaai/openpilot/discussions/19932).
#### Chevy Bolt with SuperCruise - $2500
The Bolt is already supported on the trim with standard ACC. Get openpilot working on the trim with SuperCruise. It must be a normal install: no extra pandas or other hardware, no ECU reflashes, etc. The full bounty is for a port with lateral and longitudinal control. $1500 of the bounty can be claimed with a lateral-only port.

View File

@ -93,7 +93,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>||
|Hyundai|Ioniq 6 (with HDA II) 2023[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023">Buy Here</a></sub></details>||
|Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Hybrid 2017-19">Buy Here</a></sub></details>||
@ -185,8 +185,8 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lexus&model=UX Hybrid 2019-23">Buy Here</a></sub></details>||
|Lincoln|Aviator 2020-23|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator 2020-23">Buy Here</a></sub></details>||
|Lincoln|Aviator Plug-in Hybrid 2020-23|Co-Pilot360 Plus|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Lincoln&model=Aviator Plug-in Hybrid 2020-23">Buy Here</a></sub></details>||
|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-5 2022-24">Buy Here</a></sub></details>||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
@ -237,7 +237,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Cross Hybrid (Non-US only) 2020-22">Buy Here</a></sub></details>||
|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hatchback 2019-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=_66pXk0CBYA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid 2020-22">Buy Here</a></sub></details>||
|Toyota|Corolla Hybrid (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid (Non-US only) 2020-23">Buy Here</a></sub></details>||
|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Corolla Hybrid (South America only) 2020-23">Buy Here</a></sub></details>||
|Toyota|Highlander 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2017-19">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=0wS0wXSLzoo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander 2020-23">Buy Here</a></sub></details>||
|Toyota|Highlander Hybrid 2017-19|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Highlander Hybrid 2017-19">Buy Here</a></sub></details>||
@ -269,8 +269,8 @@ A supported vehicle is one that just works when you install a comma device. All
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
@ -279,7 +279,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-24">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-24">Buy Here</a></sub></details>||
|Volkswagen|Jetta GLI 2021-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-24">Buy Here</a></sub></details>||
|Volkswagen|Passat 2015-22[<sup>10</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||

View File

@ -14,12 +14,12 @@ cereal
messaging
^^^^^^^^^
.. autodoxygenindex::
:project: cereal_messaging
:project: msgq_repo_msgq
visionipc
^^^^^^^^^
.. autodoxygenindex::
:project: cereal_visionipc
:project: msgq_repo_msgq_visionipc
selfdrive
@ -77,10 +77,10 @@ sensorsd
.. autodoxygenindex::
:project: system_sensord_sensors
boardd
pandad
^^^^^^
.. autodoxygenindex::
:project: selfdrive_boardd
:project: selfdrive_pandad
rednose

1
msgq Symbolic link
View File

@ -0,0 +1 @@
msgq_repo/msgq

1
msgq_repo Submodule

@ -0,0 +1 @@
Subproject commit 381fc3d9dfe7d2ff40a075ff8c1f980ae2a62d19

@ -1 +1 @@
Subproject commit e2906791c67eeadc9dfc3c770a678f3b888137a8
Subproject commit e0b8c109cd3571c407cb09b5edacc223fb78be10

2
panda

@ -1 +1 @@
Subproject commit aaa6047409a13a9e5cd57d550e8d63a8cbab1068
Subproject commit b1eaf465019be0b76d208a820face2a62a711a8f

3173
poetry.lock generated

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,7 @@ markers = [
]
testpaths = [
"common",
"selfdrive/boardd",
"selfdrive/pandad",
"selfdrive/car",
"selfdrive/controls",
"selfdrive/locationd",
@ -29,10 +29,9 @@ testpaths = [
"selfdrive/test/longitudinal_maneuvers",
"selfdrive/test/process_replay/test_fuzzy.py",
"system/updated",
"system/thermald",
"system/athena",
"system/camerad",
"system/hardware/tici",
"system/hardware",
"system/loggerd",
"system/proclogd",
"system/tests",
@ -40,7 +39,8 @@ testpaths = [
"system/webrtc",
"tools/lib/tests",
"tools/replay",
"tools/cabana"
"tools/cabana",
"cereal/messaging/tests",
]
[tool.mypy]
@ -87,34 +87,47 @@ readme = "README.md"
repository = "https://github.com/commaai/openpilot"
documentation = "https://docs.comma.ai"
[tool.poetry.dependencies]
python = "~3.11"
# multiple users
sounddevice = "*" # micd + soundd
pyserial = "*" # pigeond + qcomgpsd
requests = "*" # many one-off uses
sympy = "*" # rednose + friends
crcmod = "*" # cars + qcomgpsd
# hardwared
smbus2 = "*" # configuring amp
# core
cffi = "*"
scons = "*"
pycapnp = "*"
Cython = "*"
numpy = "*"
# body / webrtcd
aiohttp = "*"
aiortc = "*"
cffi = "*"
crcmod = "*"
Cython = "*"
json-rpc = "*"
pyaudio = "*"
# panda
libusb1 = "*"
numpy = "*"
spidev = { version = "*", platform = "linux" }
# modeld
onnx = ">=1.14.0"
onnxruntime = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'aarch64'" }
onnxruntime-gpu = { version = ">=1.16.3", platform = "linux", markers = "platform_machine == 'x86_64'" }
psutil = "*"
pyaudio = "*"
pycapnp = "*"
pycryptodome = "*"
PyJWT = "*"
pyserial = "*"
# logging
pyzmq = "*"
requests = "*"
scons = "*"
sentry-sdk = "*"
smbus2 = "*"
sounddevice = "*"
spidev = { version = "*", platform = "linux" }
sympy = "*"
# athena
PyJWT = "*"
json-rpc = "*"
websocket_client = "*"
# acados deps
@ -122,9 +135,10 @@ casadi = "*"
future-fstrings = "*"
# these should be removed
markdown-it-py = "*"
timezonefinder = "*"
psutil = "*"
timezonefinder = "*" # just used for nav ETA
setproctitle = "*"
pycryptodome = "*" # used in updated/casync, panda, body, and a test
[tool.poetry.group.dev.dependencies]
av = "*"
@ -152,6 +166,7 @@ pprofile = "*"
polyline = "*"
pre-commit = "*"
pyautogui = "*"
pytools = "<=2024.1.3" # our pinned version of pyopencl use a broken version of pytools
pyopencl = "==2023.1.4" # 2024.1 is broken on arm64
pygame = "*"
pywinctl = "*"
@ -165,6 +180,7 @@ pytest-timeout = "*"
pytest-randomly = "*"
pytest-asyncio = "*"
pytest-mock = "*"
pytest-repeat = "*"
rerun-sdk = "*"
ruff = "*"
sphinx = "*"

View File

@ -105,9 +105,9 @@ git branch -m release-c3
#cd $SOURCE_DIR
#cp -pR -n --parents $TEST_FILES $BUILD_DIR/
#cd $BUILD_DIR
#RELEASE=1 selfdrive/test/test_onroad.py
#RELEASE=1 pytest -n0 -s selfdrive/test/test_onroad.py
#system/manager/test/test_manager.py
#selfdrive/car/tests/test_car_interfaces.py
#pytest selfdrive/car/tests/test_car_interfaces.py
#rm -rf $TEST_FILES
if [ ! -z "$RELEASE_BRANCH" ]; then

View File

@ -10,13 +10,25 @@ ROOT = HERE + "/.."
# - minimizing release download size
# - keeping the diff readable
blacklist = [
"^scripts/",
"body/STL/",
"tools/cabana/",
"panda/drivers/",
"panda/examples/",
"panda/tests/safety/",
"opendbc/.*.dbc$",
"opendbc/generator/",
"cereal/.*test.*",
"^common/tests/",
# particularly large text files
"poetry.lock",
"third_party/catch2",
"selfdrive/car/tests/test_models.*",
"^tools/",
"^scripts/",
"^tinygrad_repo/",
"matlab.*.md",
@ -97,7 +109,58 @@ whitelist = [
"tinygrad_repo/tinygrad/runtime/ops_disk.py",
"tinygrad_repo/tinygrad/runtime/ops_gpu.py",
"tinygrad_repo/tinygrad/shape/*",
"tinygrad_repo/tinygrad/.*.py$",
"tinygrad_repo/tinygrad/.*.py",
# TODO: do this automatically
"opendbc/comma_body.dbc",
"opendbc/chrysler_ram_hd_generated.dbc",
"opendbc/chrysler_ram_dt_generated.dbc",
"opendbc/chrysler_pacifica_2017_hybrid_generated.dbc",
"opendbc/chrysler_pacifica_2017_hybrid_private_fusion.dbc",
"opendbc/gm_global_a_powertrain_generated.dbc",
"opendbc/gm_global_a_object.dbc",
"opendbc/gm_global_a_chassis.dbc",
"opendbc/FORD_CADS.dbc",
"opendbc/ford_fusion_2018_adas.dbc",
"opendbc/ford_lincoln_base_pt.dbc",
"opendbc/honda_accord_2018_can_generated.dbc",
"opendbc/acura_ilx_2016_can_generated.dbc",
"opendbc/acura_rdx_2018_can_generated.dbc",
"opendbc/acura_rdx_2020_can_generated.dbc",
"opendbc/honda_civic_touring_2016_can_generated.dbc",
"opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc",
"opendbc/honda_crv_touring_2016_can_generated.dbc",
"opendbc/honda_crv_ex_2017_can_generated.dbc",
"opendbc/honda_crv_ex_2017_body_generated.dbc",
"opendbc/honda_crv_executive_2016_can_generated.dbc",
"opendbc/honda_fit_ex_2018_can_generated.dbc",
"opendbc/honda_odyssey_exl_2018_generated.dbc",
"opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc",
"opendbc/honda_insight_ex_2019_can_generated.dbc",
"opendbc/acura_ilx_2016_nidec.dbc",
"opendbc/honda_civic_ex_2022_can_generated.dbc",
"opendbc/hyundai_canfd.dbc",
"opendbc/hyundai_kia_generic.dbc",
"opendbc/hyundai_kia_mando_front_radar_generated.dbc",
"opendbc/mazda_2017.dbc",
"opendbc/nissan_x_trail_2017_generated.dbc",
"opendbc/nissan_leaf_2018_generated.dbc",
"opendbc/subaru_global_2017_generated.dbc",
"opendbc/subaru_global_2020_hybrid_generated.dbc",
"opendbc/subaru_outback_2015_generated.dbc",
"opendbc/subaru_outback_2019_generated.dbc",
"opendbc/subaru_forester_2017_generated.dbc",
"opendbc/toyota_tnga_k_pt_generated.dbc",
"opendbc/toyota_new_mc_pt_generated.dbc",
"opendbc/toyota_nodsu_pt_generated.dbc",
"opendbc/toyota_adas.dbc",
"opendbc/toyota_tss2_adas.dbc",
"opendbc/vw_golf_mk4.dbc",
"opendbc/vw_mqb_2010.dbc",
"opendbc/tesla_can.dbc",
"opendbc/tesla_radar_bosch_generated.dbc",
"opendbc/tesla_radar_continental_generated.dbc",
"opendbc/tesla_powertrain.dbc",
]
# Sunnypilot whitelist
@ -140,6 +203,7 @@ sunnypilot_whitelist = [
# Merge the whitelists
whitelist += sunnypilot_whitelist
if __name__ == "__main__":
for f in Path(ROOT).rglob("**/*"):
if not (f.is_file() or f.is_symlink()):

View File

@ -1,4 +1,4 @@
SConscript(['boardd/SConscript'])
SConscript(['pandad/SConscript'])
SConscript(['controls/lib/lateral_mpc_lib/SConscript'])
SConscript(['controls/lib/longitudinal_mpc_lib/SConscript'])
SConscript(['locationd/SConscript'])

View File

@ -1,3 +0,0 @@
boardd
boardd_api_impl.cpp
tests/test_boardd_usbprotocol

View File

@ -1,11 +0,0 @@
Import('env', 'envCython', 'common', 'cereal', 'messaging')
libs = ['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']
panda = env.Library('panda', ['panda.cc', 'panda_comms.cc', 'spi.cc'])
env.Program('boardd', ['main.cc', 'boardd.cc'], LIBS=[panda] + libs)
env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc'])
envCython.Program('boardd_api_impl.so', 'boardd_api_impl.pyx', LIBS=["can_list_to_can_capnp", 'capnp', 'kj'] + envCython["LIBS"])
if GetOption('extras'):
env.Program('tests/test_boardd_usbprotocol', ['tests/test_boardd_usbprotocol.cc'], LIBS=[panda] + libs)

View File

@ -11,7 +11,7 @@ from panda import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.selfdrive.car.car_helpers import get_car, get_one_can
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.controls.lib.events import Events
@ -29,8 +29,7 @@ class Car:
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'])
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput'])
self.can_rcv_timeout_counter = 0 # consecutive timeout count
self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count
self.can_rcv_cum_timeout_counter = 0
self.CC_prev = car.CarControl.new_message()
self.CS_prev = car.CarState.new_message()
@ -107,12 +106,7 @@ class Car:
# Check for CAN timeout
if not can_rcv_valid:
self.can_rcv_timeout_counter += 1
self.can_rcv_cum_timeout_counter += 1
else:
self.can_rcv_timeout_counter = 0
self.can_rcv_timeout = self.can_rcv_timeout_counter >= 5
if can_rcv_valid and REPLAY:
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
@ -155,7 +149,6 @@ class Car:
cs_send = messaging.new_message('carState')
cs_send.valid = CS.canValid
cs_send.carState = CS
cs_send.carState.canRcvTimeout = self.can_rcv_timeout
cs_send.carState.canErrorCounter = self.can_rcv_cum_timeout_counter
cs_send.carState.cumLagMs = -self.rk.remaining * 1000.
self.pm.send('carState', cs_send)
@ -167,7 +160,7 @@ class Car:
# Initialize CarInterface, once controls are ready
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
# signal boardd to switch to car safety mode
# signal pandad to switch to car safety mode
self.params.put_bool_nonblocking("ControlsReady", True)
if self.sm.all_alive(['carControl']):

View File

@ -410,6 +410,7 @@ FW_VERSIONS = {
b'68453483AD',
b'68453487AD',
b'68453491AC',
b'68453491AD',
b'68453499AD',
b'68453503AC',
b'68453503AD',
@ -557,6 +558,7 @@ FW_VERSIONS = {
b'68467936AC ',
b'68500630AD',
b'68500630AE',
b'68500631AE',
b'68502719AC ',
b'68502722AC ',
b'68502733AC ',
@ -603,6 +605,7 @@ FW_VERSIONS = {
b'68484467AC',
b'68484471AC',
b'68502994AD',
b'68502996AD',
b'68520867AE',
b'68520867AF',
b'68520870AC',

View File

@ -6,7 +6,7 @@ import cereal.messaging as messaging
from panda.python.uds import SERVICE_TYPE
from openpilot.selfdrive.car import make_can_msg
from openpilot.selfdrive.car.fw_query_definitions import EcuAddrBusType
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.common.swaglog import cloudlog

1
selfdrive/car/ford/tests/test_ford.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random
from collections.abc import Iterable

View File

@ -85,7 +85,7 @@ class Request:
auxiliary: bool = False
# FW responses from these queries will not be used for fingerprinting
logging: bool = False
# boardd toggles OBD multiplexing on/off as needed
# pandad toggles OBD multiplexing on/off as needed
obd_multiplexing: bool = True

View File

@ -352,7 +352,7 @@ if __name__ == "__main__":
pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan')
# Set up params for boardd
# Set up params for pandad
params = Params()
params.remove("FirmwareQueryDone")
params.put_bool("IsOnroad", False)

1
selfdrive/car/gm/tests/test_gm.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized
from openpilot.selfdrive.car.gm.fingerprints import FINGERPRINTS

View File

@ -11,43 +11,6 @@ Ecu = car.CarParams.Ecu
FW_VERSIONS = {
CAR.HONDA_ACCORD: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-6A0-8720\x00\x00',
b'37805-6A0-9520\x00\x00',
b'37805-6A0-9620\x00\x00',
b'37805-6A0-9720\x00\x00',
b'37805-6A0-A540\x00\x00',
b'37805-6A0-A550\x00\x00',
b'37805-6A0-A640\x00\x00',
b'37805-6A0-A650\x00\x00',
b'37805-6A0-A740\x00\x00',
b'37805-6A0-A750\x00\x00',
b'37805-6A0-A840\x00\x00',
b'37805-6A0-A850\x00\x00',
b'37805-6A0-A930\x00\x00',
b'37805-6A0-AF30\x00\x00',
b'37805-6A0-AG30\x00\x00',
b'37805-6A0-AJ10\x00\x00',
b'37805-6A0-C540\x00\x00',
b'37805-6A0-CG20\x00\x00',
b'37805-6A1-H650\x00\x00',
b'37805-6B2-A550\x00\x00',
b'37805-6B2-A560\x00\x00',
b'37805-6B2-A650\x00\x00',
b'37805-6B2-A660\x00\x00',
b'37805-6B2-A720\x00\x00',
b'37805-6B2-A810\x00\x00',
b'37805-6B2-A820\x00\x00',
b'37805-6B2-A920\x00\x00',
b'37805-6B2-A960\x00\x00',
b'37805-6B2-AA10\x00\x00',
b'37805-6B2-C520\x00\x00',
b'37805-6B2-C540\x00\x00',
b'37805-6B2-C560\x00\x00',
b'37805-6B2-M520\x00\x00',
b'37805-6B2-Y810\x00\x00',
b'37805-6M4-B730\x00\x00',
],
(Ecu.shiftByWire, 0x18da0bf1, None): [
b'54008-TVC-A910\x00\x00',
b'54008-TWA-A910\x00\x00',
@ -175,38 +138,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CIVIC: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5AA-A640\x00\x00',
b'37805-5AA-A650\x00\x00',
b'37805-5AA-A670\x00\x00',
b'37805-5AA-A680\x00\x00',
b'37805-5AA-A810\x00\x00',
b'37805-5AA-C640\x00\x00',
b'37805-5AA-C680\x00\x00',
b'37805-5AA-C820\x00\x00',
b'37805-5AA-L650\x00\x00',
b'37805-5AA-L660\x00\x00',
b'37805-5AA-L680\x00\x00',
b'37805-5AA-L690\x00\x00',
b'37805-5AA-L810\x00\x00',
b'37805-5AG-Q710\x00\x00',
b'37805-5AJ-A610\x00\x00',
b'37805-5AJ-A620\x00\x00',
b'37805-5AJ-L610\x00\x00',
b'37805-5BA-A310\x00\x00',
b'37805-5BA-A510\x00\x00',
b'37805-5BA-A740\x00\x00',
b'37805-5BA-A760\x00\x00',
b'37805-5BA-A930\x00\x00',
b'37805-5BA-A960\x00\x00',
b'37805-5BA-C640\x00\x00',
b'37805-5BA-C860\x00\x00',
b'37805-5BA-L410\x00\x00',
b'37805-5BA-L760\x00\x00',
b'37805-5BA-L930\x00\x00',
b'37805-5BA-L940\x00\x00',
b'37805-5BA-L960\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A040\x00\x00',
b'28101-5CG-A050\x00\x00',
@ -256,61 +187,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CIVIC_BOSCH: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5AA-A940\x00\x00',
b'37805-5AA-A950\x00\x00',
b'37805-5AA-C950\x00\x00',
b'37805-5AA-L940\x00\x00',
b'37805-5AA-L950\x00\x00',
b'37805-5AG-Z910\x00\x00',
b'37805-5AJ-A750\x00\x00',
b'37805-5AJ-L750\x00\x00',
b'37805-5AK-T530\x00\x00',
b'37805-5AN-A750\x00\x00',
b'37805-5AN-A830\x00\x00',
b'37805-5AN-A840\x00\x00',
b'37805-5AN-A930\x00\x00',
b'37805-5AN-A940\x00\x00',
b'37805-5AN-A950\x00\x00',
b'37805-5AN-AG20\x00\x00',
b'37805-5AN-AH20\x00\x00',
b'37805-5AN-AJ30\x00\x00',
b'37805-5AN-AK10\x00\x00',
b'37805-5AN-AK20\x00\x00',
b'37805-5AN-AR10\x00\x00',
b'37805-5AN-AR20\x00\x00',
b'37805-5AN-C650\x00\x00',
b'37805-5AN-CH20\x00\x00',
b'37805-5AN-E630\x00\x00',
b'37805-5AN-E720\x00\x00',
b'37805-5AN-E820\x00\x00',
b'37805-5AN-J820\x00\x00',
b'37805-5AN-L840\x00\x00',
b'37805-5AN-L930\x00\x00',
b'37805-5AN-L940\x00\x00',
b'37805-5AN-LF20\x00\x00',
b'37805-5AN-LH20\x00\x00',
b'37805-5AN-LJ20\x00\x00',
b'37805-5AN-LR20\x00\x00',
b'37805-5AN-LS20\x00\x00',
b'37805-5AW-G720\x00\x00',
b'37805-5AZ-E850\x00\x00',
b'37805-5AZ-G540\x00\x00',
b'37805-5AZ-G740\x00\x00',
b'37805-5AZ-G840\x00\x00',
b'37805-5BB-A530\x00\x00',
b'37805-5BB-A540\x00\x00',
b'37805-5BB-A620\x00\x00',
b'37805-5BB-A630\x00\x00',
b'37805-5BB-A640\x00\x00',
b'37805-5BB-C540\x00\x00',
b'37805-5BB-C630\x00\x00',
b'37805-5BB-C640\x00\x00',
b'37805-5BB-L540\x00\x00',
b'37805-5BB-L630\x00\x00',
b'37805-5BB-L640\x00\x00',
b'37805-5BF-J130\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5CG-A920\x00\x00',
b'28101-5CG-AB10\x00\x00',
@ -422,10 +298,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CIVIC_BOSCH_DIESEL: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-59N-G630\x00\x00',
b'37805-59N-G830\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-59Y-G220\x00\x00',
b'28101-59Y-G620\x00\x00',
@ -496,41 +368,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CRV_5G: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5PA-3060\x00\x00',
b'37805-5PA-3080\x00\x00',
b'37805-5PA-3180\x00\x00',
b'37805-5PA-4050\x00\x00',
b'37805-5PA-4150\x00\x00',
b'37805-5PA-6520\x00\x00',
b'37805-5PA-6530\x00\x00',
b'37805-5PA-6630\x00\x00',
b'37805-5PA-6640\x00\x00',
b'37805-5PA-7630\x00\x00',
b'37805-5PA-9530\x00\x00',
b'37805-5PA-9630\x00\x00',
b'37805-5PA-9640\x00\x00',
b'37805-5PA-9730\x00\x00',
b'37805-5PA-9830\x00\x00',
b'37805-5PA-9840\x00\x00',
b'37805-5PA-A650\x00\x00',
b'37805-5PA-A670\x00\x00',
b'37805-5PA-A680\x00\x00',
b'37805-5PA-A850\x00\x00',
b'37805-5PA-A870\x00\x00',
b'37805-5PA-A880\x00\x00',
b'37805-5PA-A890\x00\x00',
b'37805-5PA-AB10\x00\x00',
b'37805-5PA-AD10\x00\x00',
b'37805-5PA-AF20\x00\x00',
b'37805-5PA-AF30\x00\x00',
b'37805-5PA-AH20\x00\x00',
b'37805-5PA-BF10\x00\x00',
b'37805-5PA-C680\x00\x00',
b'37805-5PD-Q630\x00\x00',
b'37805-5PF-F730\x00\x00',
b'37805-5PF-M630\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-5RG-A020\x00\x00',
b'28101-5RG-A030\x00\x00',
@ -606,10 +443,6 @@ FW_VERSIONS = {
],
},
CAR.HONDA_CRV_EU: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-R5Z-G740\x00\x00',
b'37805-R5Z-G780\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T1V-G920\x00\x00',
],
@ -710,24 +543,6 @@ FW_VERSIONS = {
b'38897-THR-A010\x00\x00',
b'38897-THR-A020\x00\x00',
],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5MR-3050\x00\x00',
b'37805-5MR-3150\x00\x00',
b'37805-5MR-3250\x00\x00',
b'37805-5MR-4070\x00\x00',
b'37805-5MR-4080\x00\x00',
b'37805-5MR-4170\x00\x00',
b'37805-5MR-4180\x00\x00',
b'37805-5MR-A240\x00\x00',
b'37805-5MR-A250\x00\x00',
b'37805-5MR-A310\x00\x00',
b'37805-5MR-A740\x00\x00',
b'37805-5MR-A750\x00\x00',
b'37805-5MR-A840\x00\x00',
b'37805-5MR-C620\x00\x00',
b'37805-5MR-D530\x00\x00',
b'37805-5MR-K730\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-THR-A020\x00\x00',
b'39990-THR-A030\x00\x00',
@ -812,39 +627,6 @@ FW_VERSIONS = {
b'28101-5EZ-A700\x00\x00',
b'28103-5EY-A110\x00\x00',
],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-RLV-4060\x00\x00',
b'37805-RLV-4070\x00\x00',
b'37805-RLV-5140\x00\x00',
b'37805-RLV-5230\x00\x00',
b'37805-RLV-5250\x00\x00',
b'37805-RLV-A630\x00\x00',
b'37805-RLV-A830\x00\x00',
b'37805-RLV-A840\x00\x00',
b'37805-RLV-B210\x00\x00',
b'37805-RLV-B220\x00\x00',
b'37805-RLV-B420\x00\x00',
b'37805-RLV-B430\x00\x00',
b'37805-RLV-B620\x00\x00',
b'37805-RLV-B710\x00\x00',
b'37805-RLV-B720\x00\x00',
b'37805-RLV-C430\x00\x00',
b'37805-RLV-C510\x00\x00',
b'37805-RLV-C520\x00\x00',
b'37805-RLV-C530\x00\x00',
b'37805-RLV-C910\x00\x00',
b'37805-RLV-F120\x00\x00',
b'37805-RLV-L080\x00\x00',
b'37805-RLV-L090\x00\x00',
b'37805-RLV-L150\x00\x00',
b'37805-RLV-L160\x00\x00',
b'37805-RLV-L180\x00\x00',
b'37805-RLV-L350\x00\x00',
b'37805-RLV-L410\x00\x00',
b'37805-RLV-L430\x00\x00',
b'37805-RLV-L830\x00\x00',
b'37805-RLV-L850\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-TG7-A030\x00\x00',
b'38897-TG7-A040\x00\x00',
@ -922,26 +704,6 @@ FW_VERSIONS = {
],
},
CAR.ACURA_RDX_3G: {
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-5YF-A130\x00\x00',
b'37805-5YF-A230\x00\x00',
b'37805-5YF-A320\x00\x00',
b'37805-5YF-A330\x00\x00',
b'37805-5YF-A420\x00\x00',
b'37805-5YF-A430\x00\x00',
b'37805-5YF-A750\x00\x00',
b'37805-5YF-A760\x00\x00',
b'37805-5YF-A770\x00\x00',
b'37805-5YF-A850\x00\x00',
b'37805-5YF-A860\x00\x00',
b'37805-5YF-A870\x00\x00',
b'37805-5YF-AD20\x00\x00',
b'37805-5YF-C210\x00\x00',
b'37805-5YF-C220\x00\x00',
b'37805-5YF-C410\x00\x00',
b'37805-5YF-C420\x00\x00',
b'37805-5YF-C430\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-TJB-A030\x00\x00',
b'57114-TJB-A040\x00\x00',
@ -1096,10 +858,6 @@ FW_VERSIONS = {
b'28101-6EH-A010\x00\x00',
b'28101-6JC-M310\x00\x00',
],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-6CT-A710\x00\x00',
b'37805-6HZ-M630\x00\x00',
],
(Ecu.electricBrakeBooster, 0x18da2bf1, None): [
b'46114-3W0-A020\x00\x00',
],
@ -1180,14 +938,5 @@ FW_VERSIONS = {
b'28101-65H-A120\x00\x00',
b'28101-65J-N010\x00\x00',
],
(Ecu.programmedFuelInjection, 0x18da10f1, None): [
b'37805-64A-A540\x00\x00',
b'37805-64A-A620\x00\x00',
b'37805-64D-P510\x00\x00',
b'37805-64L-A540\x00\x00',
b'37805-64S-A540\x00\x00',
b'37805-64S-A720\x00\x00',
b'37805-64S-AA10\x00\x00',
],
},
}

1
selfdrive/car/honda/tests/test_honda.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import re
from openpilot.selfdrive.car.honda.fingerprints import FW_VERSIONS

View File

@ -318,6 +318,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
],
# We lose these ECUs without the comma power on these cars.
# Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_2022, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
@ -325,6 +326,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),
(Ecu.programmedFuelInjection, 0x18da10f1, None),
# The only other ECU on PT bus accessible by camera on radarless Civic
# This is likely a manufacturer-specific sub-address implementation: the camera responds to this and 0x18dab0f1
# Unclear what the part number refers to: 8S103 is 'Camera Set Mono', while 36160 is 'Camera Monocular - Honda'

View File

@ -23,9 +23,6 @@ FINGERPRINTS = {
CAR.GENESIS_G90: [{
67: 8, 68: 8, 127: 8, 304: 8, 320: 8, 339: 8, 356: 4, 358: 6, 359: 8, 544: 8, 593: 8, 608: 8, 688: 5, 809: 8, 854: 7, 870: 7, 871: 8, 872: 8, 897: 8, 902: 8, 903: 8, 916: 8, 1040: 8, 1056: 8, 1057: 8, 1078: 4, 1107: 5, 1136: 8, 1151: 6, 1162: 4, 1168: 7, 1170: 8, 1173: 8, 1184: 8, 1265: 4, 1280: 1, 1281: 3, 1287: 4, 1290: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1345: 8, 1348: 8, 1363: 8, 1369: 8, 1370: 8, 1371: 8, 1378: 4, 1384: 8, 1407: 8, 1419: 8, 1425: 2, 1427: 6, 1434: 2, 1456: 4, 1470: 8, 1988: 8, 2000: 8, 2003: 8, 2004: 8, 2005: 8, 2008: 8, 2011: 8, 2012: 8, 2013: 8
}],
CAR.HYUNDAI_IONIQ_EV_2020: [{
127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 524: 8, 544: 7, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1155: 8, 1156: 8, 1157: 4, 1164: 8, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1379: 8, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 1988: 8, 1996: 8, 2000: 8, 2004: 8, 2005: 8, 2008: 8, 2012: 8, 2013: 8
}],
CAR.HYUNDAI_KONA_EV: [{
127: 8, 304: 8, 320: 8, 339: 8, 352: 8, 356: 4, 544: 8, 549: 8, 593: 8, 688: 5, 832: 8, 881: 8, 882: 8, 897: 8, 902: 8, 903: 8, 905: 8, 909: 8, 916: 8, 1040: 8, 1042: 8, 1056: 8, 1057: 8, 1078: 4, 1136: 8, 1151: 6, 1168: 7, 1173: 8, 1183: 8, 1186: 2, 1191: 2, 1225: 8, 1265: 4, 1280: 1, 1287: 4, 1290: 8, 1291: 8, 1292: 8, 1294: 8, 1307: 8, 1312: 8, 1322: 8, 1342: 6, 1345: 8, 1348: 8, 1355: 8, 1363: 8, 1369: 8, 1378: 4, 1407: 8, 1419: 8, 1426: 8, 1427: 6, 1429: 8, 1430: 8, 1456: 4, 1470: 8, 1473: 8, 1507: 8, 1535: 8, 2000: 8, 2004: 8, 2008: 8, 2012: 8, 1157: 4, 1193: 8, 1379: 8, 1988: 8, 1996: 8
}],
@ -135,9 +132,12 @@ FW_VERSIONS = {
b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7200 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.00 99110-G7500 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7000 ',
b'\xf1\x00AEev SCC F-CUP 1.00 1.01 99110-G7100 ',
b'\xf1\x00AEev SCC FHCUP 1.00 1.01 99110-G7100 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7310 4APEC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7510 4APEC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G7560 4APEC101',
],
(Ecu.fwdCamera, 0x7c4, None): [
@ -146,6 +146,7 @@ FW_VERSIONS = {
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEE MFC AT EUR LHD 1.00 1.03 95740-G2500 190516',
b'\xf1\x00AEE MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEE MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
],
},
CAR.HYUNDAI_IONIQ_EV_LTD: {
@ -749,6 +750,7 @@ FW_VERSIONS = {
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DEhe SCC F-CUP 1.00 1.00 99110-G5600 ',
b'\xf1\x00DEhe SCC FHCUP 1.00 1.00 99110-G5600 ',
],
},
CAR.KIA_NIRO_HEV_2021: {
@ -877,6 +879,7 @@ FW_VERSIONS = {
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AA000 200819',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.03 99210-AB000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.07 99210-AA000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728',
],
(Ecu.abs, 0x7d1, None): [
@ -1001,6 +1004,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CE MFC AT CAN LHD 1.00 1.04 99211-KL000 221213',
b'\xf1\x00CE MFC AT EUR LHD 1.00 1.03 99211-KL000 221011',
b'\xf1\x00CE MFC AT EUR LHD 1.00 1.04 99211-KL000 221213',
b'\xf1\x00CE MFC AT USA LHD 1.00 1.04 99211-KL000 221213',
],
},
@ -1039,10 +1043,10 @@ FW_VERSIONS = {
CAR.KIA_SPORTAGE_5TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690',
],

View File

@ -86,6 +86,9 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 0.4
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate == CAR.KIA_OPTIMA_G4_FL:
ret.steerActuatorDelay = 0.2
# *** longitudinal control ***
if candidate in CANFD_CAR:
ret.longitudinalTuning.kpV = [0.1]

1
selfdrive/car/hyundai/tests/test_hyundai.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from hypothesis import settings, given, strategies as st
import pytest

View File

@ -328,7 +328,7 @@ class CAR(Platforms):
flags=HyundaiFlags.EV,
)
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
)
@ -529,7 +529,7 @@ class CAR(Platforms):
# TODO: From 3.3T Sport Advanced 2022 & Prestige 2023 Trim, 2.0T is unknown
HyundaiCarDocs("Genesis G70 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l])),
],
CarSpecs(mass=3673 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=12.9),
GENESIS_G70.specs,
flags=HyundaiFlags.MANDO_RADAR,
)
GENESIS_GV70_1ST_GEN = HyundaiCanFDPlatformConfig(

View File

@ -48,6 +48,18 @@ FORWARD_GEARS = [GearShifter.drive, GearShifter.low, GearShifter.eco,
def similarity(s1: str, s2: str) -> float:
return SequenceMatcher(None, s1, s2).ratio()
GEAR_SHIFTER_MAP: dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
'E': GearShifter.eco, 'ECO': GearShifter.eco,
'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic,
'D': GearShifter.drive, 'DRIVE': GearShifter.drive,
'S': GearShifter.sport, 'SPORT': GearShifter.sport,
'L': GearShifter.low, 'LOW': GearShifter.low,
'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
}
class LatControlInputs(NamedTuple):
lateral_acceleration: float
@ -60,29 +72,33 @@ TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.L
@cache
def get_torque_params(candidate):
def get_torque_params():
with open(TORQUE_SUBSTITUTE_PATH, 'rb') as f:
sub = tomllib.load(f)
if candidate in sub:
candidate = sub[candidate]
with open(TORQUE_PARAMS_PATH, 'rb') as f:
params = tomllib.load(f)
with open(TORQUE_OVERRIDE_PATH, 'rb') as f:
override = tomllib.load(f)
# Ensure no overlap
if sum([candidate in x for x in [sub, params, override]]) > 1:
raise RuntimeError(f'{candidate} is defined twice in torque config')
torque_params = {}
for candidate in (sub.keys() | params.keys() | override.keys()) - {'legend'}:
if sum([candidate in x for x in [sub, params, override]]) > 1:
raise RuntimeError(f'{candidate} is defined twice in torque config')
if candidate in override:
out = override[candidate]
elif candidate in params:
out = params[candidate]
else:
raise NotImplementedError(f"Did not find torque params for {candidate}")
return {key: out[i] for i, key in enumerate(params['legend'])}
sub_candidate = sub.get(candidate, candidate)
if sub_candidate in override:
out = override[sub_candidate]
elif sub_candidate in params:
out = params[sub_candidate]
else:
raise NotImplementedError(f"Did not find torque params for {sub_candidate}")
torque_params[sub_candidate] = {key: out[i] for i, key in enumerate(params['legend'])}
if candidate in sub:
torque_params[candidate] = torque_params[sub_candidate]
return torque_params
# lateral neural network feedforward
class FluxModel:
@ -344,7 +360,7 @@ class CarInterfaceBase(ABC):
ret.carFingerprint = candidate
# Car docs fields
ret.maxLateralAccel = get_torque_params(candidate)['MAX_LAT_ACCEL_MEASURED']
ret.maxLateralAccel = get_torque_params()[candidate]['MAX_LAT_ACCEL_MEASURED']
ret.autoResumeSng = True # describes whether car can resume from a stop automatically
# standard ALC params
@ -378,7 +394,7 @@ class CarInterfaceBase(ABC):
@staticmethod
def configure_torque_tune(candidate, tune, steering_angle_deadzone_deg=0.0, use_steering_angle=True):
params = get_torque_params(candidate)
params = get_torque_params()[candidate]
tune.init('torque')
tune.torque.useSteeringAngle = use_steering_angle
@ -840,19 +856,7 @@ class CarStateBase(ABC):
def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter:
if gear is None:
return GearShifter.unknown
d: dict[str, car.CarState.GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
'E': GearShifter.eco, 'ECO': GearShifter.eco,
'T': GearShifter.manumatic, 'MANUAL': GearShifter.manumatic,
'D': GearShifter.drive, 'DRIVE': GearShifter.drive,
'S': GearShifter.sport, 'SPORT': GearShifter.sport,
'L': GearShifter.low, 'LOW': GearShifter.low,
'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
}
return d.get(gear.upper(), GearShifter.unknown)
return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown)
@staticmethod
def get_can_parser(CP):

View File

@ -4,7 +4,7 @@ from functools import partial
import cereal.messaging as messaging
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
from openpilot.selfdrive.pandad import can_list_to_can_capnp
from openpilot.selfdrive.car.fw_query_definitions import AddrType
from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr

View File

@ -311,6 +311,7 @@ FW_VERSIONS = {
b'\x00\x00d\xd3\x1f@ \t',
],
(Ecu.engine, 0x7e0, None): [
b'\xa7"@0\x07',
b'\xa7"@p\x07',
b'\xa7)\xa0q\x07',
b'\xba"@@\x07',
@ -318,6 +319,7 @@ FW_VERSIONS = {
],
(Ecu.transmission, 0x7e1, None): [
b'\x1a\xf6F`\x00',
b'\xda\xf2`p\x00',
b'\xda\xf2`\x80\x00',
b'\xda\xfd\xe0\x80\x00',
b'\xdc\xf2@`\x00',

1
selfdrive/car/tests/test_can_fingerprint.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized
from cereal import log, messaging

1
selfdrive/car/tests/test_car_interfaces.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import os
import math
import hypothesis.strategies as st

1
selfdrive/car/tests/test_docs.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from collections import defaultdict
import os
import pytest

View File

@ -1,96 +0,0 @@
#!/usr/bin/env python3
import os
import sys
from openpilot.common.basedir import BASEDIR
# messages reserved for CAN based ignition (see can_ignition_hook function in panda/board/drivers/can)
# (addr, len)
CAN_IGNITION_MSGS = {
'gm': [(0x1F1, 8), (0x160, 5)],
#'tesla' : [(0x348, 8)],
}
def _get_fingerprints():
# read all the folders in selfdrive/car and return a dict where:
# - keys are all the car names that which we have a fingerprint dict for
# - values are dicts of fingeprints for each trim
fingerprints = {}
for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
car_name = car_folder.split('/')[-1]
try:
fingerprints[car_name] = __import__(f'selfdrive.car.{car_name}.values', fromlist=['FINGERPRINTS']).FINGERPRINTS
except (ImportError, OSError, AttributeError):
pass
return fingerprints
def check_fingerprint_consistency(f1, f2):
# return false if it finds a fingerprint fully included in another
# max message worth checking is 1800, as above that they usually come too infrequently and not
# usable for fingerprinting
max_msg = 1800
is_f1_in_f2 = True
for k in f1:
if (k not in f2 or f1[k] != f2[k]) and k < max_msg:
is_f1_in_f2 = False
is_f2_in_f1 = True
for k in f2:
if (k not in f1 or f2[k] != f1[k]) and k < max_msg:
is_f2_in_f1 = False
return not is_f1_in_f2 and not is_f2_in_f1
def check_can_ignition_conflicts(fingerprints, brands):
# loops through all the fingerprints and exits if CAN ignition dedicated messages
# are found in unexpected fingerprints
for brand_can, msgs_can in CAN_IGNITION_MSGS.items():
for i, f in enumerate(fingerprints):
for msg_can in msgs_can:
if brand_can != brands[i] and msg_can[0] in f and msg_can[1] == f[msg_can[0]]:
print("CAN ignition dedicated msg %d with len %d found in %s fingerprints!" % (msg_can[0], msg_can[1], brands[i]))
print("TEST FAILED")
sys.exit(1)
if __name__ == "__main__":
fingerprints = _get_fingerprints()
fingerprints_flat: list[dict] = []
car_names = []
brand_names = []
for brand in fingerprints:
for car in fingerprints[brand]:
fingerprints_flat += fingerprints[brand][car]
for _ in range(len(fingerprints[brand][car])):
car_names.append(car)
brand_names.append(brand)
# first check if CAN ignition specific messages are unexpectedly included in other fingerprints
check_can_ignition_conflicts(fingerprints_flat, brand_names)
valid = True
for idx1, f1 in enumerate(fingerprints_flat):
for idx2, f2 in enumerate(fingerprints_flat):
if idx1 < idx2 and not check_fingerprint_consistency(f1, f2):
valid = False
print(f"Those two fingerprints are inconsistent {car_names[idx1]} {car_names[idx2]}")
print("")
print(', '.join("%d: %d" % v for v in sorted(f1.items())))
print("")
print(', '.join("%d: %d" % v for v in sorted(f2.items())))
print("")
print(f"Found {len(fingerprints_flat)} individual fingerprints")
if not valid or len(fingerprints_flat) == 0:
print("TEST FAILED")
sys.exit(1)
else:
print("TEST SUCCESSFUL")

1
selfdrive/car/tests/test_fw_fingerprint.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest
import random
import time

View File

@ -3,6 +3,7 @@ from collections import defaultdict
import importlib
from parameterized import parameterized_class
import pytest
import sys
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.car.car_helpers import interfaces
@ -20,8 +21,6 @@ MAX_LAT_JERK_UP_TOLERANCE = 0.5 # m/s^3
# jerk is measured over half a second
JERK_MEAS_T = 0.5
car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
@parameterized_class('car_model', [(c,) for c in sorted(CAR_MODELS)])
class TestLateralLimits:
@ -44,7 +43,7 @@ class TestLateralLimits:
CarControllerParams = importlib.import_module(f'selfdrive.car.{CP.carName}.values').CarControllerParams
cls.control_params = CarControllerParams(CP)
cls.torque_params = get_torque_params(cls.car_model)
cls.torque_params = get_torque_params()[cls.car_model]
@staticmethod
def calculate_0_5s_jerk(control_params, torque_params):
@ -64,9 +63,36 @@ class TestLateralLimits:
def test_jerk_limits(self):
up_jerk, down_jerk = self.calculate_0_5s_jerk(self.control_params, self.torque_params)
car_model_jerks[self.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk}
assert up_jerk <= MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE
assert down_jerk <= MAX_LAT_JERK_DOWN
def test_max_lateral_accel(self):
assert self.torque_params["MAX_LAT_ACCEL_MEASURED"] <= MAX_LAT_ACCEL
class LatAccelReport:
car_model_jerks: defaultdict[str, dict[str, float]] = defaultdict(dict)
def pytest_sessionfinish(self):
print(f"\n\n---- Lateral limit report ({len(CAR_MODELS)} cars) ----\n")
max_car_model_len = max([len(car_model) for car_model in self.car_model_jerks])
for car_model, _jerks in sorted(self.car_model_jerks.items(), key=lambda i: i[1]['up_jerk'], reverse=True):
violation = _jerks["up_jerk"] > MAX_LAT_JERK_UP + MAX_LAT_JERK_UP_TOLERANCE or \
_jerks["down_jerk"] > MAX_LAT_JERK_DOWN
violation_str = " - VIOLATION" if violation else ""
print(f"{car_model:{max_car_model_len}} - up jerk: {round(_jerks['up_jerk'], 2):5} " +
f"m/s^3, down jerk: {round(_jerks['down_jerk'], 2):5} m/s^3{violation_str}")
@pytest.fixture(scope="class", autouse=True)
def class_setup(self, request):
yield
cls = request.cls
if hasattr(cls, "control_params"):
up_jerk, down_jerk = TestLateralLimits.calculate_0_5s_jerk(cls.control_params, cls.torque_params)
self.car_model_jerks[cls.car_model] = {"up_jerk": up_jerk, "down_jerk": down_jerk}
if __name__ == '__main__':
sys.exit(pytest.main([__file__, '-n0', '--no-summary'], plugins=[LatAccelReport()])) # noqa: TID251

1
selfdrive/car/tests/test_models.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import capnp
import os
import importlib

2
selfdrive/car/tests/test_platform_configs.py Executable file → Normal file
View File

@ -1,5 +1,3 @@
#!/usr/bin/env python3
from openpilot.selfdrive.car.values import PLATFORMS

View File

@ -61,7 +61,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GMC_ACADIA" = [1.6, 1.6, 0.2]
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005]
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]

View File

@ -41,7 +41,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745]
"JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048]
"JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003]
"KIA_EV6" = [3.2, 2.093457, 0.05]
"KIA_EV6" = [3.2, 2.093457, 0.005]
"KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716]
"KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267]
"KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558]

View File

@ -214,6 +214,7 @@ FW_VERSIONS = {
b'8646F0601400 ',
b'8646F0603400 ',
b'8646F0603500 ',
b'8646F0604000 ',
b'8646F0604100 ',
b'8646F0605000 ',
b'8646F0606000 ',

1
selfdrive/car/toyota/tests/test_toyota.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from hypothesis import given, settings, strategies as st
from cereal import car

View File

@ -165,7 +165,7 @@ class CAR(Platforms):
ToyotaCarDocs("Toyota Corolla Hatchback 2019-22", video_link="https://www.youtube.com/watch?v=_66pXk0CBYA"),
# Hybrid platforms
ToyotaCarDocs("Toyota Corolla Hybrid 2020-22"),
ToyotaCarDocs("Toyota Corolla Hybrid (Non-US only) 2020-23", min_enable_speed=7.5),
ToyotaCarDocs("Toyota Corolla Hybrid (South America only) 2020-23", min_enable_speed=7.5),
ToyotaCarDocs("Toyota Corolla Cross Hybrid (Non-US only) 2020-22", min_enable_speed=7.5),
ToyotaCarDocs("Lexus UX Hybrid 2019-23"),
],

View File

@ -119,6 +119,7 @@ FW_VERSIONS = {
b'\xf1\x8704L906056BP\xf1\x894729',
b'\xf1\x8704L906056EK\xf1\x896391',
b'\xf1\x8705L906023BC\xf1\x892688',
b'\xf1\x8705L906023MH\xf1\x892588',
],
(Ecu.srs, 0x715, None): [
b'\xf1\x873Q0959655AL\xf1\x890505\xf1\x82\x0e1411001413001203151311031100',
@ -128,6 +129,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x712, None): [
b'\xf1\x872N0909143D\x00\xf1\x897010\xf1\x82\x05183AZ306A2',
b'\xf1\x872N0909143E \xf1\x897021\xf1\x82\x05163AZ306A2',
b'\xf1\x872N0909143H \xf1\x897045\xf1\x82\x05263AZ309A2',
b'\xf1\x872N0909144K \xf1\x897045\xf1\x82\x05233AZ810A2',
],
(Ecu.fwdRadar, 0x757, None): [
@ -589,6 +591,7 @@ FW_VERSIONS = {
b'\xf1\x8783A907115Q \xf1\x890001',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x8709G927158DS\xf1\x893699',
b'\xf1\x8709G927158DT\xf1\x893698',
b'\xf1\x8709G927158FM\xf1\x893757',
b'\xf1\x8709G927158GC\xf1\x893821',

1
selfdrive/car/volkswagen/tests/test_volkswagen.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random
import re

View File

@ -261,14 +261,14 @@ class CAR(Platforms):
)
VOLKSWAGEN_CRAFTER_MK2 = VolkswagenMQBPlatformConfig(
[
VWCarDocs("Volkswagen Crafter 2017-23", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("Volkswagen e-Crafter 2018-23", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("Volkswagen Grand California 2019-23", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("MAN TGE 2017-23", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("MAN eTGE 2020-23", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("Volkswagen Crafter 2017-24", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("Volkswagen e-Crafter 2018-24", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("Volkswagen Grand California 2019-24", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("MAN TGE 2017-24", video_link="https://youtu.be/4100gLeabmo"),
VWCarDocs("MAN eTGE 2020-24", video_link="https://youtu.be/4100gLeabmo"),
],
VolkswagenCarSpecs(mass=2100, wheelbase=3.64, minSteerSpeed=50 * CV.KPH_TO_MS),
chassis_codes={"SY", "SZ"},
chassis_codes={"SY", "SZ", "UY", "UZ"},
wmis={WMI.VOLKSWAGEN_COMMERCIAL, WMI.MAN},
)
VOLKSWAGEN_GOLF_MK7 = VolkswagenMQBPlatformConfig(

View File

@ -8,7 +8,7 @@ from typing import SupportsFloat
import cereal.messaging as messaging
from cereal import car, log, custom
from cereal.visionipc import VisionIpcClient, VisionStreamType
from msgq.visionipc import VisionIpcClient, VisionStreamType
from openpilot.common.conversions import Conversions as CV
@ -323,7 +323,7 @@ class Controls:
else:
safety_mismatch = pandaState.safetyModel not in IGNORED_SAFETY_MODES
# safety mismatch allows some time for boardd to set the safety mode and publish it back from panda
# safety mismatch allows some time for pandad to set the safety mode and publish it back from panda
if (safety_mismatch and self.sm.frame*DT_CTRL > 10.) or pandaState.safetyRxChecksInvalid or self.mismatch_counter >= 200:
self.events.add(EventName.controlsMismatch)
@ -366,19 +366,18 @@ class Controls:
# generic catch-all. ideally, a more specific event should be added above instead
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
if (not self.sm.all_checks() or CS.canRcvTimeout) and no_system_errors:
if not self.sm.all_checks() and no_system_errors:
if not self.sm.all_alive():
self.events.add(EventName.commIssue)
elif not self.sm.all_freq_ok():
self.events.add(EventName.commIssueAvgFreq)
else: # invalid or can_rcv_timeout.
else:
self.events.add(EventName.commIssue)
logs = {
'invalid': [s for s, valid in self.sm.valid.items() if not valid],
'not_alive': [s for s, alive in self.sm.alive.items() if not alive],
'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
'can_rcv_timeout': CS.canRcvTimeout,
}
if logs != self.logged_comm_issue:
cloudlog.event("commIssue", error=True, **logs)

View File

@ -51,7 +51,7 @@ class Events:
def __init__(self):
self.events: list[int] = []
self.static_events: list[int] = []
self.events_prev = dict.fromkeys(EVENTS.keys(), 0)
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
@property
def names(self) -> list[int]:
@ -66,7 +66,7 @@ class Events:
bisect.insort(self.events, event_name)
def clear(self) -> None:
self.events_prev = {k: (v + 1 if k in self.events else 0) for k, v in self.events_prev.items()}
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
self.events = self.static_events.copy()
def contains(self, event_type: str) -> bool:
@ -85,7 +85,7 @@ class Events:
if not isinstance(alert, Alert):
alert = alert(*callback_args)
if DT_CTRL * (self.events_prev[e] + 1) >= alert.creation_delay:
if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
alert.alert_type = f"{EVENT_NAME[e]}/{et}"
alert.event_type = et
ret.append(alert)

View File

@ -1,4 +1,4 @@
Import('env', 'envCython', 'arch', 'messaging_python', 'common_python', 'opendbc_python')
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python')
gen = "c_generated_code"
@ -60,7 +60,7 @@ lenv.Clean(generated_files, Dir(gen))
generated_lat = lenv.Command(generated_files,
source_list,
f"cd {Dir('.').abspath} && python3 lat_mpc.py")
lenv.Depends(generated_lat, [messaging_python, common_python, opendbc_python])
lenv.Depends(generated_lat, [msgq_python, common_python, opendbc_python])
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")

View File

@ -14,7 +14,7 @@ from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
import cereal.messaging as messaging
from cereal import log
LaneChangeState = log.LateralPlan.LaneChangeState
LaneChangeState = log.LaneChangeState
PATH_COST = 1.0

View File

@ -5,6 +5,8 @@ from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_dead
from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.modeld.constants import ModelConstants
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
LongCtrlState = car.CarControl.Actuators.LongControlState
@ -70,19 +72,19 @@ class LongControl:
# Interp control trajectory
speeds = long_plan.speeds
if len(speeds) == CONTROL_N:
v_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds)
a_target_now = interp(t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], long_plan.accels)
v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_now = interp(t_since_plan, CONTROL_N_T_IDX, long_plan.accels)
v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds)
v_target_lower = interp(self.CP.longitudinalActuatorDelayLowerBound + t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_lower = 2 * (v_target_lower - v_target_now) / self.CP.longitudinalActuatorDelayLowerBound - a_target_now
v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, ModelConstants.T_IDXS[:CONTROL_N], speeds)
v_target_upper = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan, CONTROL_N_T_IDX, speeds)
a_target_upper = 2 * (v_target_upper - v_target_now) / self.CP.longitudinalActuatorDelayUpperBound - a_target_now
v_target = min(v_target_lower, v_target_upper)
a_target = min(a_target_lower, a_target_upper)
v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, ModelConstants.T_IDXS[:CONTROL_N], speeds)
v_target_1sec = interp(self.CP.longitudinalActuatorDelayUpperBound + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds)
else:
v_target = 0.0
v_target_now = 0.0

View File

@ -1,4 +1,4 @@
Import('env', 'envCython', 'arch', 'messaging_python', 'common_python', 'opendbc_python')
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python')
gen = "c_generated_code"
@ -66,7 +66,7 @@ lenv.Clean(generated_files, Dir(gen))
generated_long = lenv.Command(generated_files,
source_list,
f"cd {Dir('.').abspath} && python3 long_mpc.py")
lenv.Depends(generated_long, [messaging_python, common_python, opendbc_python])
lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python])
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")

View File

@ -89,9 +89,9 @@ class LongitudinalPlanner:
@staticmethod
def parse_model(model_msg, model_error):
if (len(model_msg.position.x) == 33 and
len(model_msg.velocity.x) == 33 and
len(model_msg.acceleration.x) == 33):
if (len(model_msg.position.x) == ModelConstants.IDX_N and
len(model_msg.velocity.x) == ModelConstants.IDX_N and
len(model_msg.acceleration.x) == ModelConstants.IDX_N):
x = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.position.x) - model_error * T_IDXS_MPC
v = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.velocity.x) - model_error
a = np.interp(T_IDXS_MPC, ModelConstants.T_IDXS, model_msg.acceleration.x)

1
selfdrive/controls/lib/tests/test_alertmanager.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import random
from openpilot.selfdrive.controls.lib.events import Alert, EVENTS

1
selfdrive/controls/lib/tests/test_latcontrol.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
from parameterized import parameterized
from cereal import car, log

1
selfdrive/controls/lib/tests/test_vehicle_model.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest
import math

1
selfdrive/controls/tests/test_alerts.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import copy
import json
import os

1
selfdrive/controls/tests/test_cruise_speed.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest
import itertools
import numpy as np

1
selfdrive/controls/tests/test_following_distance.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import pytest
import itertools
from parameterized import parameterized_class

1
selfdrive/controls/tests/test_leads.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
import cereal.messaging as messaging
from openpilot.selfdrive.test.process_replay import replay_process_with_name

View File

@ -4,7 +4,7 @@ from parameterized import parameterized
from cereal import log, car
import cereal.messaging as messaging
from openpilot.common.params import Params
from openpilot.selfdrive.boardd.boardd_api_impl import can_list_to_can_capnp
from openpilot.selfdrive.pandad.pandad_api_impl import can_list_to_can_capnp
from openpilot.selfdrive.car.fingerprints import _FINGERPRINTS
from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA
from openpilot.selfdrive.car.mazda.values import CAR as MAZDA
@ -105,7 +105,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand):
msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()]
for _ in range(1000):
# card waits for boardd to echo back that it has changed the multiplexing mode
# card waits for pandad to echo back that it has changed the multiplexing mode
if not params.get_bool("ObdMultiplexingChanged"):
params.put_bool("ObdMultiplexingChanged", True)

Some files were not shown because too many files have changed in this diff Show More