Merge remote-tracking branch 'upstream/master' into no-capnp-cars-simple

pull/33208/head
Shane Smiskol 1 year ago
commit e0b9e45027
  1. 34
      .github/workflows/repo-maintenance.yaml
  2. 2
      .github/workflows/selfdrive_tests.yaml
  3. 2
      .importlinter
  4. 4
      common/mock/__init__.py
  5. 26
      common/mock/generators.py
  6. 2
      launch_chffrplus.sh
  7. 2
      launch_env.sh
  8. 2
      launch_openpilot.sh
  9. 2
      panda
  10. 2
      pyproject.toml
  11. 2
      release/build_devel.sh
  12. 2
      release/build_release.sh
  13. 2
      release/check-dirty.sh
  14. 2
      release/check-submodules.sh
  15. 2
      scripts/apply-pr.sh
  16. 2
      scripts/build_small.sh
  17. 2
      scripts/cell.sh
  18. 2
      scripts/checkout-pr.sh
  19. 2
      scripts/launch_corolla.sh
  20. 15
      scripts/lint/check_shebang_format.sh
  21. 5
      scripts/lint/lint.sh
  22. 2
      scripts/retry.sh
  23. 2
      selfdrive/assets/compress-images.sh
  24. 2
      selfdrive/assets/strip-svg-metadata.sh
  25. 1
      selfdrive/car/__init__.py
  26. 3
      selfdrive/car/body/carstate.py
  27. 6
      selfdrive/car/body/interface.py
  28. 254
      selfdrive/car/car_specific.py
  29. 13
      selfdrive/car/card.py
  30. 11
      selfdrive/car/chrysler/carstate.py
  31. 24
      selfdrive/car/chrysler/interface.py
  32. 4
      selfdrive/car/disable_ecu.py
  33. 5
      selfdrive/car/ecu_addrs.py
  34. 10
      selfdrive/car/ford/carstate.py
  35. 16
      selfdrive/car/ford/interface.py
  36. 7
      selfdrive/car/fw_versions.py
  37. 25
      selfdrive/car/gm/carstate.py
  38. 47
      selfdrive/car/gm/interface.py
  39. 22
      selfdrive/car/honda/carstate.py
  40. 44
      selfdrive/car/honda/interface.py
  41. 19
      selfdrive/car/hyundai/carstate.py
  42. 1
      selfdrive/car/hyundai/fingerprints.py
  43. 33
      selfdrive/car/hyundai/interface.py
  44. 105
      selfdrive/car/interfaces.py
  45. 13
      selfdrive/car/mazda/carstate.py
  46. 25
      selfdrive/car/mazda/interface.py
  47. 4
      selfdrive/car/mock/carstate.py
  48. 17
      selfdrive/car/mock/interface.py
  49. 12
      selfdrive/car/nissan/carstate.py
  50. 20
      selfdrive/car/nissan/interface.py
  51. 3
      selfdrive/car/subaru/carstate.py
  52. 9
      selfdrive/car/subaru/interface.py
  53. 3
      selfdrive/car/tesla/carstate.py
  54. 7
      selfdrive/car/tesla/interface.py
  55. 2
      selfdrive/car/tests/big_cars_test.sh
  56. 9
      selfdrive/car/tests/test_car_interfaces.py
  57. 14
      selfdrive/car/tests/test_models.py
  58. 11
      selfdrive/car/toyota/carstate.py
  59. 32
      selfdrive/car/toyota/interface.py
  60. 4
      selfdrive/car/vin.py
  61. 20
      selfdrive/car/volkswagen/carstate.py
  62. 1
      selfdrive/car/volkswagen/fingerprints.py
  63. 46
      selfdrive/car/volkswagen/interface.py
  64. 45
      selfdrive/controls/controlsd.py
  65. 2
      selfdrive/controls/lib/latcontrol.py
  66. 2
      selfdrive/controls/lib/latcontrol_angle.py
  67. 2
      selfdrive/controls/lib/latcontrol_pid.py
  68. 7
      selfdrive/controls/lib/latcontrol_torque.py
  69. 9
      selfdrive/controls/lib/tests/test_latcontrol.py
  70. 2
      selfdrive/debug/adb.sh
  71. 2
      selfdrive/debug/cycle_alerts.py
  72. 67
      selfdrive/locationd/helpers.py
  73. 25
      selfdrive/locationd/paramsd.py
  74. 17
      selfdrive/locationd/torqued.py
  75. 2
      selfdrive/modeld/tests/tf_test/build.sh
  76. 10
      selfdrive/test/process_replay/process_replay.py
  77. 2
      selfdrive/test/process_replay/ref_commit
  78. 2
      selfdrive/test/scons_build_test.sh
  79. 4
      selfdrive/test/setup_device_ci.sh
  80. 2
      selfdrive/test/setup_vsound.sh
  81. 2
      selfdrive/ui/installer/continue_openpilot.sh
  82. 2
      selfdrive/ui/tests/create_test_translations.sh
  83. 2
      system/hardware/tici/restart_modem.sh
  84. 2
      system/hardware/tici/tests/test_power_draw.py
  85. 2
      tools/joystick/joystickd.py
  86. 2
      tools/lib/kbhit.py
  87. 34
      tools/op.sh
  88. 2
      tools/profiling/clpeak/build.sh
  89. 2
      tools/profiling/ftrace.sh
  90. 2
      tools/profiling/palanteer/setup.sh
  91. 2
      tools/profiling/perfetto/build.sh
  92. 2
      tools/profiling/perfetto/copy.sh
  93. 2
      tools/profiling/perfetto/record.sh
  94. 2
      tools/profiling/perfetto/server.sh
  95. 2
      tools/profiling/perfetto/traces.sh
  96. 2
      tools/profiling/snapdragon/setup-agnos.sh
  97. 2
      tools/profiling/snapdragon/setup-profiler.sh
  98. 2
      tools/profiling/watch-irqs.sh
  99. 2
      tools/rerun/run.sh
  100. 2
      tools/scripts/save_ubloxraw_stream.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -6,33 +6,6 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
bump_submodules:
name: bump_submodules
runs-on: ubuntu-latest
container:
image: ghcr.io/commaai/openpilot-base:latest
if: github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: bump submodules
run: |
git config --global --add safe.directory '*'
git -c submodule."tinygrad".update=none submodule update --remote
git add .
- name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
with:
author: Vehicle Researcher <user@comma.ai>
token: ${{ secrets.ACTIONS_CREATE_PR_PAT }}
commit-message: bump submodules
title: '[bot] Bump submodules'
branch: auto-bump-submodules
base: master
delete-branch: true
body: 'Automatic PR from repo-maintenance -> bump_submodules'
labels: bot
package_updates: package_updates:
name: package_updates name: package_updates
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -41,11 +14,18 @@ jobs:
if: github.repository == 'commaai/openpilot' if: github.repository == 'commaai/openpilot'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
submodules: true
- name: uv lock - name: uv lock
run: | run: |
python3 -m ensurepip --upgrade python3 -m ensurepip --upgrade
pip3 install uv pip3 install uv
uv lock --upgrade uv lock --upgrade
- name: bump submodules
run: |
git config --global --add safe.directory '*'
git -c submodule."tinygrad".update=none submodule update --remote
git add .
- name: Create Pull Request - name: Create Pull Request
uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83 uses: peter-evans/create-pull-request@9153d834b60caba6d51c9b9510b087acf9f33f83
with: with:

@ -67,7 +67,7 @@ jobs:
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE
cp pyproject.toml $STRIPPED_DIR cp pyproject.toml $STRIPPED_DIR
cd $STRIPPED_DIR cd $STRIPPED_DIR
${{ env.RUN }} "scripts/lint.sh --skip check_added_large_files" ${{ env.RUN }} "scripts/lint/lint.sh --skip check_added_large_files"
build: build:
strategy: strategy:

@ -29,7 +29,6 @@ forbidden_modules =
openpilot.tinygrad openpilot.tinygrad
ignore_imports = ignore_imports =
# remove these # remove these
openpilot.selfdrive.car.interfaces -> openpilot.selfdrive.controls.lib.events
openpilot.selfdrive.car.body.carcontroller -> openpilot.selfdrive.controls.lib.pid openpilot.selfdrive.car.body.carcontroller -> openpilot.selfdrive.controls.lib.pid
openpilot.selfdrive.car.tests.test_docs -> openpilot.common.basedir openpilot.selfdrive.car.tests.test_docs -> openpilot.common.basedir
openpilot.selfdrive.car.docs -> openpilot.common.basedir openpilot.selfdrive.car.docs -> openpilot.common.basedir
@ -75,4 +74,5 @@ ignore_imports =
openpilot.selfdrive.car.card -> cereal openpilot.selfdrive.car.card -> cereal
openpilot.selfdrive.car.card -> cereal.messaging openpilot.selfdrive.car.card -> cereal.messaging
openpilot.selfdrive.car.vin -> cereal.messaging openpilot.selfdrive.car.vin -> cereal.messaging
openpilot.selfdrive.car.car_specific -> openpilot.selfdrive.controls.lib.events
unmatched_ignore_imports_alerting = warn unmatched_ignore_imports_alerting = warn

@ -8,12 +8,12 @@ import functools
import threading import threading
from cereal.messaging import PubMaster from cereal.messaging import PubMaster
from cereal.services import SERVICE_LIST from cereal.services import SERVICE_LIST
from openpilot.common.mock.generators import generate_liveLocationKalman from openpilot.common.mock.generators import generate_livePose
from openpilot.common.realtime import Ratekeeper from openpilot.common.realtime import Ratekeeper
MOCK_GENERATOR = { MOCK_GENERATOR = {
"liveLocationKalman": generate_liveLocationKalman "livePose": generate_livePose
} }

@ -1,20 +1,14 @@
from cereal import messaging from cereal import messaging
LOCATION1 = (32.7174, -117.16277) def generate_livePose():
LOCATION2 = (32.7558, -117.2037) msg = messaging.new_message('livePose')
meas = {'x': 0.0, 'y': 0.0, 'z': 0.0, 'xStd': 0.0, 'yStd': 0.0, 'zStd': 0.0, 'valid': True}
LLK_DECIMATION = 10 msg.livePose.orientationNED = meas
RENDER_FRAMES = 15 msg.livePose.velocityDevice = meas
DEFAULT_ITERATIONS = RENDER_FRAMES * LLK_DECIMATION msg.livePose.angularVelocityDevice = meas
msg.livePose.accelerationDevice = meas
msg.livePose.inputsOK = True
def generate_liveLocationKalman(location=LOCATION1): msg.livePose.posenetOK = True
msg = messaging.new_message('liveLocationKalman') msg.livePose.sensorsOK = True
msg.liveLocationKalman.positionGeodetic = {'value': [*location, 0], 'std': [0., 0., 0.], 'valid': True}
msg.liveLocationKalman.positionECEF = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
msg.liveLocationKalman.calibratedOrientationNED = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
msg.liveLocationKalman.velocityCalibrated = {'value': [0., 0., 0.], 'std': [0., 0., 0.], 'valid': True}
msg.liveLocationKalman.status = 'valid'
msg.liveLocationKalman.gpsOK = True
return msg return msg

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
if [ -z "$BASEDIR" ]; then if [ -z "$BASEDIR" ]; then
BASEDIR="/data/openpilot" BASEDIR="/data/openpilot"

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
export OMP_NUM_THREADS=1 export OMP_NUM_THREADS=1
export MKL_NUM_THREADS=1 export MKL_NUM_THREADS=1

@ -1,3 +1,3 @@
#!/usr/bin/bash #!/usr/bin/env bash
exec ./launch_chffrplus.sh exec ./launch_chffrplus.sh

@ -1 +1 @@
Subproject commit 3c1def1cc57f3fb37399a25d0e8088c70985c5ec Subproject commit 1cbcc13c35429b06e9d36c55b9ab46df73a8b51a

@ -100,7 +100,7 @@ dev = [
"inputs", "inputs",
"lru-dict", "lru-dict",
"matplotlib", "matplotlib",
"metadrive-simulator@git+https://github.com/commaai/metadrive@opencv_headless ; platform_machine != 'aarch64'", "metadrive-simulator@git+https://github.com/commaai/metadrive@main ; platform_machine != 'aarch64'",
"parameterized >=0.8, <0.9", "parameterized >=0.8, <0.9",
#"pprofile", #"pprofile",
"pyautogui", "pyautogui",

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -ex set -ex
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
set -x set -x

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
while read hash submodule ref; do while read hash submodule ref; do
git -C $submodule fetch --depth 3000 origin master git -C $submodule fetch --depth 3000 origin master

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
if [ $# -eq 0 ]; then if [ $# -eq 0 ]; then
echo "usage: $0 <pull-request-number>" echo "usage: $0 <pull-request-number>"

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -ex set -ex
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"

@ -1,3 +1,3 @@
#!/usr/bin/bash #!/usr/bin/env bash
nmcli connection modify --temporary esim ipv4.route-metric 1 ipv6.route-metric 1 nmcli connection modify --temporary esim ipv4.route-metric 1 ipv6.route-metric 1
nmcli con up esim nmcli con up esim

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
if [ $# -eq 0 ]; then if [ $# -eq 0 ]; then

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"

@ -0,0 +1,15 @@
#!/usr/bin/env bash
FAIL=0
if grep '^#!.*python$' $@ | grep -v '#!/usr/bin/env python3$'; then
echo -e "Invalid shebang! Must use '#!/usr/bin/env python3'\n"
FAIL=1
fi
if grep '^#!.*bash$' $@ | grep -v '#!/usr/bin/env bash$'; then
echo -e "Invalid shebang! Must use '#!/usr/bin/env bash'"
FAIL=1
fi
exit $FAIL

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
RED='\033[0;31m' RED='\033[0;31m'
@ -8,7 +8,7 @@ BOLD='\033[1m'
NC='\033[0m' NC='\033[0m'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
cd $DIR/../ cd $DIR/../../
FAILED=0 FAILED=0
@ -51,6 +51,7 @@ function run_tests() {
run "lint-imports" lint-imports run "lint-imports" lint-imports
run "check_added_large_files" python3 -m pre_commit_hooks.check_added_large_files --enforce-all $ALL_FILES --maxkb=120 run "check_added_large_files" python3 -m pre_commit_hooks.check_added_large_files --enforce-all $ALL_FILES --maxkb=120
run "check_shebang_scripts_are_executable" python3 -m pre_commit_hooks.check_shebang_scripts_are_executable $ALL_FILES run "check_shebang_scripts_are_executable" python3 -m pre_commit_hooks.check_shebang_scripts_are_executable $ALL_FILES
run "check_shebang_format" $DIR/check_shebang_format.sh $ALL_FILES
if [[ -z "$FAST" ]]; then if [[ -z "$FAST" ]]; then
run "mypy" mypy $PYTHON_FILES run "mypy" mypy $PYTHON_FILES

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
function fail { function fail {
echo $1 >&2 echo $1 >&2

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
echo "compressing training guide images" echo "compressing training guide images"
optipng -o7 -strip all training/* optipng -o7 -strip all training/*

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# sudo apt install scour # sudo apt install scour

@ -25,7 +25,6 @@ DT_CTRL = 0.01 # car state and control loop timestep (s)
STD_CARGO_KG = 136. STD_CARGO_KG = 136.
ButtonType = structs.CarState.ButtonEvent.Type ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v']) AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v'])

@ -3,10 +3,9 @@ from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.body.values import DBC from openpilot.selfdrive.car.body.values import DBC
STARTUP_TICKS = 100
class CarState(CarStateBase): class CarState(CarStateBase):
def update(self, cp) -> structs.CarState: def update(self, cp, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
ret.wheelSpeeds.fl = cp.vl['MOTORS_DATA']['SPEED_L'] ret.wheelSpeeds.fl = cp.vl['MOTORS_DATA']['SPEED_L']

@ -4,6 +4,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.body.carstate import CarState from openpilot.selfdrive.car.body.carstate import CarState
from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CS: CarState CS: CarState
@ -25,8 +26,3 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = structs.CarParams.SteerControlType.angle ret.steerControlType = structs.CarParams.SteerControlType.angle
return ret return ret
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp)
return ret

@ -0,0 +1,254 @@
from cereal import car
import cereal.messaging as messaging
from openpilot.selfdrive.car import DT_CTRL
from openpilot.selfdrive.car.interfaces import MAX_CTRL_SPEED
from openpilot.selfdrive.car.volkswagen.values import CarControllerParams as VWCarControllerParams
from openpilot.selfdrive.car.hyundai.interface import ENABLE_BUTTONS as HYUNDAI_ENABLE_BUTTONS
from openpilot.selfdrive.controls.lib.events import Events
ButtonType = car.CarState.ButtonEvent.Type
GearShifter = car.CarState.GearShifter
EventName = car.CarEvent.EventName
NetworkLocation = car.CarParams.NetworkLocation
# TODO: the goal is to abstract this file into the CarState struct and make events generic
class MockCarState:
def __init__(self):
self.sm = messaging.SubMaster(['gpsLocation', 'gpsLocationExternal'])
def update(self, CS: car.CarState):
self.sm.update(0)
gps_sock = 'gpsLocationExternal' if self.sm.recv_frame['gpsLocationExternal'] > 1 else 'gpsLocation'
CS.vEgo = self.sm[gps_sock].speed
CS.vEgoRaw = self.sm[gps_sock].speed
return CS
class CarSpecificEvents:
def __init__(self, CP: car.CarParams):
self.CP = CP
self.steering_unpressed = 0
self.low_speed_alert = False
self.no_steer_warning = False
self.silent_steer_warning = True
def update(self, CS, CS_prev, CC, CC_prev):
if self.CP.carName in ('body', 'mock'):
events = Events()
elif self.CP.carName in ('tesla', 'subaru'):
events = self.create_common_events(CS.out, CS_prev)
elif self.CP.carName == 'ford':
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.manumatic])
elif self.CP.carName == 'nissan':
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.brake])
if CS.lkas_enabled:
events.add(EventName.invalidLkasSetting)
elif self.CP.carName == 'mazda':
events = self.create_common_events(CS.out, CS_prev)
if CS.lkas_disabled:
events.add(EventName.lkasDisabled)
elif CS.low_speed_alert:
events.add(EventName.belowSteerSpeed)
elif self.CP.carName == 'chrysler':
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.low])
# Low speed steer alert hysteresis logic
if self.CP.minSteerSpeed > 0. and CS.out.vEgo < (self.CP.minSteerSpeed + 0.5):
self.low_speed_alert = True
elif CS.out.vEgo > (self.CP.minSteerSpeed + 1.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(EventName.belowSteerSpeed)
elif self.CP.carName == 'honda':
events = self.create_common_events(CS.out, CS_prev, pcm_enable=False)
if self.CP.pcmCruise and CS.out.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
if self.CP.pcmCruise:
# we engage when pcm is active (rising edge)
if CS.out.cruiseState.enabled and not CS_prev.cruiseState.enabled:
events.add(EventName.pcmEnable)
elif not CS.out.cruiseState.enabled and (CC_prev.actuators.accel >= 0. or not self.CP.openpilotLongitudinalControl):
# it can happen that car cruise disables while comma system is enabled: need to
# keep braking if needed or if the speed is very low
if CS.out.vEgo < self.CP.minEnableSpeed + 2.:
# non loud alert if cruise disables below 25mph as expected (+ a little margin)
events.add(EventName.speedTooLow)
else:
events.add(EventName.cruiseDisabled)
if self.CP.minEnableSpeed > 0 and CS.out.vEgo < 0.001:
events.add(EventName.manualRestart)
elif self.CP.carName == 'toyota':
events = self.create_common_events(CS.out, CS_prev)
if self.CP.openpilotLongitudinalControl:
if CS.out.cruiseState.standstill and not CS.out.brakePressed:
events.add(EventName.resumeRequired)
if CS.low_speed_lockout:
events.add(EventName.lowSpeedLockout)
if CS.out.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
if CC_prev.actuators.accel > 0.3:
# some margin on the actuator to not false trigger cancellation while stopping
events.add(EventName.speedTooLow)
if CS.out.vEgo < 0.001:
# while in standstill, send a user alert
events.add(EventName.manualRestart)
elif self.CP.carName == 'gm':
# The ECM allows enabling on falling edge of set, but only rising edge of resume
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.sport, GearShifter.low,
GearShifter.eco, GearShifter.manumatic],
pcm_enable=self.CP.pcmCruise, enable_buttons=(ButtonType.decelCruise,))
if not self.CP.pcmCruise:
if any(b.type == ButtonType.accelCruise and b.pressed for b in CS.out.buttonEvents):
events.add(EventName.buttonEnable)
# Enabling at a standstill with brake is allowed
# TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs
below_min_enable_speed = CS.out.vEgo < self.CP.minEnableSpeed or CS.moving_backward
if below_min_enable_speed and not (CS.out.standstill and CS.out.brake >= 20 and
self.CP.networkLocation == NetworkLocation.fwdCamera):
events.add(EventName.belowEngageSpeed)
if CS.out.cruiseState.standstill:
events.add(EventName.resumeRequired)
if CS.out.vEgo < self.CP.minSteerSpeed:
events.add(EventName.belowSteerSpeed)
elif self.CP.carName == 'volkswagen':
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic],
pcm_enable=not self.CP.openpilotLongitudinalControl,
enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise))
# Low speed steer alert hysteresis logic
if (self.CP.minSteerSpeed - 1e-3) > VWCarControllerParams.DEFAULT_MIN_STEER_SPEED and CS.out.vEgo < (self.CP.minSteerSpeed + 1.):
self.low_speed_alert = True
elif CS.out.vEgo > (self.CP.minSteerSpeed + 2.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(EventName.belowSteerSpeed)
if self.CP.openpilotLongitudinalControl:
if CS.out.vEgo < self.CP.minEnableSpeed + 0.5:
events.add(EventName.belowEngageSpeed)
if CC_prev.enabled and CS.out.vEgo < self.CP.minEnableSpeed:
events.add(EventName.speedTooLow)
if CC.eps_timer_soft_disable_alert:
events.add(EventName.steerTimeLimit)
elif self.CP.carName == 'hyundai':
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
# Main button also can trigger an engagement on these cars
allow_enable = any(btn in HYUNDAI_ENABLE_BUTTONS for btn in CS.cruise_buttons) or any(CS.main_buttons)
events = self.create_common_events(CS.out, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=allow_enable)
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
if CS.out.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
self.low_speed_alert = True
if CS.out.vEgo > (self.CP.minSteerSpeed + 4.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(EventName.belowSteerSpeed)
else:
raise ValueError(f"Unsupported car: {self.CP.carName}")
return events
def create_common_events(self, CS, CS_prev, extra_gears=None, pcm_enable=True, allow_enable=True,
enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
events = Events()
if CS.doorOpen:
events.add(EventName.doorOpen)
if CS.seatbeltUnlatched:
events.add(EventName.seatbeltNotLatched)
if CS.gearShifter != GearShifter.drive and (extra_gears is None or
CS.gearShifter not in extra_gears):
events.add(EventName.wrongGear)
if CS.gearShifter == GearShifter.reverse:
events.add(EventName.reverseGear)
if not CS.cruiseState.available:
events.add(EventName.wrongCarMode)
if CS.espDisabled:
events.add(EventName.espDisabled)
if CS.espActive:
events.add(EventName.espActive)
if CS.stockFcw:
events.add(EventName.stockFcw)
if CS.stockAeb:
events.add(EventName.stockAeb)
if CS.vEgo > MAX_CTRL_SPEED:
events.add(EventName.speedTooHigh)
if CS.cruiseState.nonAdaptive:
events.add(EventName.wrongCruiseMode)
if CS.brakeHoldActive and self.CP.openpilotLongitudinalControl:
events.add(EventName.brakeHold)
if CS.parkingBrake:
events.add(EventName.parkBrake)
if CS.accFaulted:
events.add(EventName.accFaulted)
if CS.steeringPressed:
events.add(EventName.steerOverride)
if CS.brakePressed and CS.standstill:
events.add(EventName.preEnableStandstill)
if CS.gasPressed:
events.add(EventName.gasPressedOverride)
if CS.vehicleSensorsInvalid:
events.add(EventName.vehicleSensorsInvalid)
# Handle button presses
for b in CS.buttonEvents:
# Enable OP long on falling edge of enable buttons (defaults to accelCruise and decelCruise, overridable per-port)
if not self.CP.pcmCruise and (b.type in enable_buttons and not b.pressed):
events.add(EventName.buttonEnable)
# Disable on rising and falling edge of cancel for both stock and OP long
if b.type == ButtonType.cancel:
events.add(EventName.buttonCancel)
# Handle permanent and temporary steering faults
self.steering_unpressed = 0 if CS.steeringPressed else self.steering_unpressed + 1
if CS.steerFaultTemporary:
if CS.steeringPressed and (not CS_prev.steerFaultTemporary or self.no_steer_warning):
self.no_steer_warning = True
else:
self.no_steer_warning = False
# if the user overrode recently, show a less harsh alert
if self.silent_steer_warning or CS.standstill or self.steering_unpressed < int(1.5 / DT_CTRL):
self.silent_steer_warning = True
events.add(EventName.steerTempUnavailableSilent)
else:
events.add(EventName.steerTempUnavailable)
else:
self.no_steer_warning = False
self.silent_steer_warning = False
if CS.steerFaultPermanent:
events.add(EventName.steerUnavailable)
# we engage when pcm is active (rising edge)
# enabling can optionally be blocked by the car interface
if pcm_enable:
if CS.cruiseState.enabled and not CS_prev.cruiseState.enabled and allow_enable:
events.add(EventName.pcmEnable)
elif not CS.cruiseState.enabled:
events.add(EventName.pcmDisable)
return events

@ -17,6 +17,7 @@ from openpilot.common.swaglog import cloudlog, ForwardingHandler
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
from openpilot.selfdrive.car import DT_CTRL, carlog, structs from openpilot.selfdrive.car import DT_CTRL, carlog, structs
from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.car_specific import CarSpecificEvents, MockCarState
from openpilot.selfdrive.car.fw_versions import ObdCallback from openpilot.selfdrive.car.fw_versions import ObdCallback
from openpilot.selfdrive.car.car_helpers import get_car from openpilot.selfdrive.car.car_helpers import get_car
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
@ -172,6 +173,9 @@ class Car:
self.events = Events() self.events = Events()
self.car_events = CarSpecificEvents(self.CP)
self.mock_carstate = MockCarState()
# card is driven by can recv, expected at 100Hz # card is driven by can recv, expected at 100Hz
self.rk = Ratekeeper(100, print_delay_threshold=None) self.rk = Ratekeeper(100, print_delay_threshold=None)
@ -180,7 +184,10 @@ class Car:
# Update carState from CAN # Update carState from CAN
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True) can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
CS = convert_to_capnp(self.CI.update(self.CC_prev, can_capnp_to_list(can_strs))) CS = convert_to_capnp(self.CI.update(can_capnp_to_list(can_strs)))
if self.CP.carName == 'mock':
CS = self.mock_carstate.update(CS)
self.sm.update(0) self.sm.update(0)
@ -198,7 +205,9 @@ class Car:
def update_events(self, CS: car.CarState) -> car.CarState: # TODO: this is wrong def update_events(self, CS: car.CarState) -> car.CarState: # TODO: this is wrong
self.events.clear() self.events.clear()
# self.events.add_from_msg(CS.events) CS.events = self.car_events.update(self.CI.CS, self.CS_prev, self.CI.CC, self.CC_prev).to_msg()
self.events.add_from_msg(CS.events)
if self.CP.notCar: if self.CP.notCar:
# wait for everything to init first # wait for everything to init first

@ -1,10 +1,12 @@
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = structs.CarState.ButtonEvent.Type
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
@ -21,14 +23,13 @@ class CarState(CarStateBase):
else: else:
self.shifter_values = can_define.dv["GEAR"]["PRNDL"] self.shifter_values = can_define.dv["GEAR"]["PRNDL"]
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRUISE_BUTTONS"]["ACC_Distance_Dec"] self.distance_button = cp.vl["CRUISE_BUTTONS"]["ACC_Distance_Dec"]
# lock info # lock info
@ -101,6 +102,8 @@ class CarState(CarStateBase):
self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"] self.lkas_car_model = cp_cam.vl["DAS_6"]["CAR_MODEL"]
self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"] self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"]
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
return ret return ret
@staticmethod @staticmethod

@ -1,13 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from cereal import car from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.chrysler.carstate import CarState from openpilot.selfdrive.car.chrysler.carstate import CarState
from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = structs.CarState.ButtonEvent.Type
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CS: CarState CS: CarState
@ -78,23 +76,3 @@ class CarInterface(CarInterfaceBase):
ret.enableBsm = 720 in fingerprint[0] ret.enableBsm = 720 in fingerprint[0]
return ret return ret
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
# events
events = self.create_common_events(ret, extra_gears=[structs.CarState.GearShifter.low])
# Low speed steer alert hysteresis logic
if self.CP.minSteerSpeed > 0. and ret.vEgo < (self.CP.minSteerSpeed + 0.5):
self.low_speed_alert = True
elif ret.vEgo > (self.CP.minSteerSpeed + 1.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(car.CarEvent.EventName.belowSteerSpeed)
# ret.events = events.to_msg()
return ret

@ -40,10 +40,12 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
if __name__ == "__main__": if __name__ == "__main__":
import time import time
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.selfdrive.car.card import can_comm_callbacks
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
can_callbacks = can_comm_callbacks(logcan, sendcan)
time.sleep(1) time.sleep(1)
# honda bosch radar disable # honda bosch radar disable
disabled = disable_ecu(logcan, sendcan, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03', timeout=0.5, debug=False) disabled = disable_ecu(*can_callbacks, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03', timeout=0.5, debug=False)
print(f"disabled: {disabled}") print(f"disabled: {disabled}")

@ -61,7 +61,7 @@ if __name__ == "__main__":
import argparse import argparse
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.selfdrive.car.card import obd_callback from openpilot.selfdrive.car.card import can_comm_callbacks, obd_callback
parser = argparse.ArgumentParser(description='Get addresses of all ECUs') parser = argparse.ArgumentParser(description='Get addresses of all ECUs')
parser.add_argument('--debug', action='store_true') parser.add_argument('--debug', action='store_true')
@ -72,6 +72,7 @@ if __name__ == "__main__":
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
can_callbacks = can_comm_callbacks(logcan, sendcan)
# Set up params for pandad # Set up params for pandad
params = Params() params = Params()
@ -83,7 +84,7 @@ if __name__ == "__main__":
obd_callback(params)(not args.no_obd) obd_callback(params)(not args.no_obd)
print("Getting ECU addresses ...") print("Getting ECU addresses ...")
ecu_addrs = _get_all_ecu_addrs(logcan, sendcan, args.bus, args.timeout, debug=args.debug) ecu_addrs = _get_all_ecu_addrs(*can_callbacks, args.bus, args.timeout, debug=args.debug)
print() print()
print("Found ECUs on rx addresses:") print("Found ECUs on rx addresses:")

@ -1,11 +1,12 @@
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.ford.fordcan import CanBus from openpilot.selfdrive.car.ford.fordcan import CanBus
from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
@ -17,10 +18,9 @@ class CarState(CarStateBase):
if CP.transmissionType == TransmissionType.automatic: if CP.transmissionType == TransmissionType.automatic:
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"] self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement # Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
@ -85,7 +85,7 @@ class CarState(CarStateBase):
ret.rightBlinker = cp.vl["Steering_Data_FD1"]["TurnLghtSwtch_D_Stat"] == 2 ret.rightBlinker = cp.vl["Steering_Data_FD1"]["TurnLghtSwtch_D_Stat"] == 2
# TODO: block this going to the camera otherwise it will enable stock TJA # TODO: block this going to the camera otherwise it will enable stock TJA
ret.genericToggle = bool(cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"]) ret.genericToggle = bool(cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"])
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
self.distance_button = cp.vl["Steering_Data_FD1"]["AccButtnGapTogglePress"] self.distance_button = cp.vl["Steering_Data_FD1"]["AccButtnGapTogglePress"]
# lock info # lock info
@ -105,6 +105,8 @@ class CarState(CarStateBase):
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"] self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"] self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
return ret return ret
@staticmethod @staticmethod

@ -1,15 +1,12 @@
from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.ford.carstate import CarState from openpilot.selfdrive.car.ford.carstate import CarState
from openpilot.selfdrive.car.ford.fordcan import CanBus from openpilot.selfdrive.car.ford.fordcan import CanBus
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags from openpilot.selfdrive.car.ford.values import Ecu, FordFlags
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = structs.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
GearShifter = structs.CarState.GearShifter
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
@ -69,14 +66,3 @@ class CarInterface(CarInterfaceBase):
ret.autoResumeSng = ret.minEnableSpeed == -1. ret.autoResumeSng = ret.minEnableSpeed == -1.
ret.centerToFront = ret.wheelbase * 0.44 ret.centerToFront = ret.wheelbase * 0.44
return ret return ret
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
events = self.create_common_events(ret, extra_gears=[GearShifter.manumatic])
# ret.events = events.to_msg()
return ret

@ -334,7 +334,7 @@ if __name__ == "__main__":
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.selfdrive.car.vin import get_vin from openpilot.selfdrive.car.vin import get_vin
from openpilot.selfdrive.car.card import obd_callback from openpilot.selfdrive.car.card import can_comm_callbacks, obd_callback
parser = argparse.ArgumentParser(description='Get firmware version of ECUs') parser = argparse.ArgumentParser(description='Get firmware version of ECUs')
parser.add_argument('--scan', action='store_true') parser.add_argument('--scan', action='store_true')
@ -345,6 +345,7 @@ if __name__ == "__main__":
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
pandaStates_sock = messaging.sub_sock('pandaStates') pandaStates_sock = messaging.sub_sock('pandaStates')
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
can_callbacks = can_comm_callbacks(logcan, sendcan)
# Set up params for pandad # Set up params for pandad
params = Params() params = Params()
@ -369,13 +370,13 @@ if __name__ == "__main__":
t = time.time() t = time.time()
print("Getting vin...") print("Getting vin...")
set_obd_multiplexing(True) set_obd_multiplexing(True)
vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (0, 1), debug=args.debug) vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1), debug=args.debug)
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}') print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')
print(f"Getting VIN took {time.time() - t:.3f} s") print(f"Getting VIN took {time.time() - t:.3f} s")
print() print()
t = time.time() t = time.time()
fw_vers = get_fw_versions(logcan, sendcan, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, debug=args.debug, progress=True) fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, debug=args.debug, progress=True)
_, candidates = match_fw_to_car(fw_vers, vin) _, candidates = match_fw_to_car(fw_vers, vin)
print() print()

@ -1,16 +1,21 @@
import copy import copy
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.helpers import mean from openpilot.selfdrive.car.helpers import mean
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CruiseButtons, STEER_THRESHOLD
ButtonType = structs.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation NetworkLocation = structs.CarParams.NetworkLocation
STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
@ -26,14 +31,13 @@ class CarState(CarStateBase):
self.cam_lka_steering_cmd_counter = 0 self.cam_lka_steering_cmd_counter = 0
self.buttons_counter = 0 self.buttons_counter = 0
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
def update(self, pt_cp, cam_cp, loopback_cp) -> structs.CarState: def update(self, pt_cp, cam_cp, _, __, loopback_cp) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
self.prev_cruise_buttons = self.cruise_buttons prev_cruise_buttons = self.cruise_buttons
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"] self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
@ -124,6 +128,15 @@ class CarState(CarStateBase):
ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1 ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1
ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1 ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1
# Don't add event if transitioning from INIT, unless it's to an actual button
if self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT:
ret.buttonEvents = [
*create_button_events(self.cruise_buttons, prev_cruise_buttons, BUTTONS_DICT,
unpressed_btn=CruiseButtons.UNPRESS),
*create_button_events(self.distance_button, prev_distance_button,
{1: ButtonType.gapAdjustCruise})
]
return ret return ret
@staticmethod @staticmethod

@ -1,26 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
from typing import cast from typing import cast
from cereal import car
from math import fabs, exp from math import fabs, exp
from panda import Panda from panda import Panda
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
from openpilot.selfdrive.car import create_button_events, get_safety_config, get_friction, structs from openpilot.selfdrive.car import get_safety_config, get_friction, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.gm.carstate import CarState from openpilot.selfdrive.car.gm.carstate import CarState
from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG
from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus from openpilot.selfdrive.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus
from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation NetworkLocation = structs.CarParams.NetworkLocation
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
NON_LINEAR_TORQUE_PARAMS = { NON_LINEAR_TORQUE_PARAMS = {
CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178], CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
@ -203,39 +196,3 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
return ret return ret
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam, self.cp_loopback)
# Don't add event if transitioning from INIT, unless it's to an actual button
if self.CS.cruise_buttons != CruiseButtons.UNPRESS or self.CS.prev_cruise_buttons != CruiseButtons.INIT:
ret.buttonEvents = [
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT,
unpressed_btn=CruiseButtons.UNPRESS),
*create_button_events(self.CS.distance_button, self.CS.prev_distance_button,
{1: ButtonType.gapAdjustCruise})
]
# The ECM allows enabling on falling edge of set, but only rising edge of resume
events = self.create_common_events(ret, extra_gears=[GearShifter.sport, GearShifter.low,
GearShifter.eco, GearShifter.manumatic],
pcm_enable=self.CP.pcmCruise, enable_buttons=(ButtonType.decelCruise,))
if not self.CP.pcmCruise:
if any(b.type == ButtonType.accelCruise and b.pressed for b in ret.buttonEvents):
events.add(EventName.buttonEnable)
# Enabling at a standstill with brake is allowed
# TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs
below_min_enable_speed = ret.vEgo < self.CP.minEnableSpeed or self.CS.moving_backward
if below_min_enable_speed and not (ret.standstill and ret.brake >= 20 and
self.CP.networkLocation == NetworkLocation.fwdCamera):
events.add(EventName.belowEngageSpeed)
if ret.cruiseState.standstill:
events.add(EventName.resumeRequired)
if ret.vEgo < self.CP.minSteerSpeed:
events.add(EventName.belowSteerSpeed)
# ret.events = events.to_msg()
return ret

@ -3,16 +3,21 @@ from typing import cast
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.helpers import interp from openpilot.selfdrive.car.helpers import interp
from openpilot.selfdrive.car.honda.hondacan import CanBus, get_cruise_speed_conversion from openpilot.selfdrive.car.honda.hondacan import CanBus, get_cruise_speed_conversion
from openpilot.selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, \ from openpilot.selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, \ HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, \
HondaFlags HondaFlags, CruiseButtons, CruiseSettings
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
ButtonType = structs.CarState.ButtonEvent.Type
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.altButton1}
def get_can_messages(CP, gearbox_msg): def get_can_messages(CP, gearbox_msg):
@ -105,16 +110,16 @@ class CarState(CarStateBase):
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX) # However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
self.dash_speed_seen = False self.dash_speed_seen = False
def update(self, cp, cp_cam, cp_body) -> structs.CarState: def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState.new_message()
# car params # car params
v_weight_v = [0., 1.] # don't trust smooth speed at low values to avoid premature zero snapping v_weight_v = [0., 1.] # don't trust smooth speed at low values to avoid premature zero snapping
v_weight_bp = [1., 6.] # smooth blending, below ~0.6m/s the smooth speed snaps to zero v_weight_bp = [1., 6.] # smooth blending, below ~0.6m/s the smooth speed snaps to zero
# update prevs, update must run once per loop # update prevs, update must run once per loop
self.prev_cruise_buttons = self.cruise_buttons prev_cruise_buttons = self.cruise_buttons
self.prev_cruise_setting = self.cruise_setting prev_cruise_setting = self.cruise_setting
self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"] self.cruise_setting = cp.vl["SCM_BUTTONS"]["CRUISE_SETTING"]
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"] self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
@ -259,6 +264,11 @@ class CarState(CarStateBase):
ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]["BSM_ALERT"] == 1 ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]["BSM_ALERT"] == 1
ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]["BSM_ALERT"] == 1 ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]["BSM_ALERT"] == 1
ret.buttonEvents = [
*create_button_events(self.cruise_buttons, prev_cruise_buttons, BUTTONS_DICT),
*create_button_events(self.cruise_setting, prev_cruise_setting, SETTINGS_BUTTONS_DICT),
]
return ret return ret
def get_can_parser(self, CP): def get_can_parser(self, CP):

@ -1,23 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.helpers import interp from openpilot.selfdrive.car.helpers import interp
from openpilot.selfdrive.car.honda.carstate import CarState from openpilot.selfdrive.car.honda.carstate import CarState
from openpilot.selfdrive.car.honda.hondacan import CanBus from openpilot.selfdrive.car.honda.hondacan import CanBus
from openpilot.selfdrive.car.honda.values import CarControllerParams, CruiseButtons, CruiseSettings, HondaFlags, CAR, HONDA_BOSCH, \ from openpilot.selfdrive.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.disable_ecu import disable_ecu
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
TransmissionType = structs.CarParams.TransmissionType TransmissionType = structs.CarParams.TransmissionType
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.altButton1}
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
@ -223,36 +216,3 @@ class CarInterface(CarInterfaceBase):
def init(CP, can_recv, can_send): def init(CP, can_recv, can_send):
if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl: if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl:
disable_ecu(can_recv, can_send, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03') disable_ecu(can_recv, can_send, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03')
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
ret.buttonEvents = [
*create_button_events(self.CS.cruise_buttons, self.CS.prev_cruise_buttons, BUTTONS_DICT),
*create_button_events(self.CS.cruise_setting, self.CS.prev_cruise_setting, SETTINGS_BUTTONS_DICT),
]
# events
events = self.create_common_events(ret, pcm_enable=False)
if self.CP.pcmCruise and ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
if self.CP.pcmCruise:
# we engage when pcm is active (rising edge)
if ret.cruiseState.enabled and not self.CS.out.cruiseState.enabled:
events.add(EventName.pcmEnable)
elif not ret.cruiseState.enabled and (c.actuators.accel >= 0. or not self.CP.openpilotLongitudinalControl):
# it can happen that car cruise disables while comma system is enabled: need to
# keep braking if needed or if the speed is very low
if ret.vEgo < self.CP.minEnableSpeed + 2.:
# non loud alert if cruise disables below 25mph as expected (+ a little margin)
events.add(EventName.speedTooLow)
else:
events.add(EventName.cruiseDisabled)
if self.CS.CP.minEnableSpeed > 0 and ret.vEgo < 0.001:
events.add(EventName.manualRestart)
# ret.events = events.to_msg()
return ret

@ -4,17 +4,22 @@ import math
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
CANFD_CAR, Buttons, CarControllerParams CANFD_CAR, Buttons, CarControllerParams
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = car.CarState.ButtonEvent.Type
PREV_BUTTON_SAMPLES = 8 PREV_BUTTON_SAMPLES = 8
CLUSTER_SAMPLE_RATE = 20 # frames CLUSTER_SAMPLE_RATE = 20 # frames
STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
@ -52,7 +57,7 @@ class CarState(CarStateBase):
self.params = CarControllerParams(CP) self.params = CarControllerParams(CP)
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
if self.CP.carFingerprint in CANFD_CAR: if self.CP.carFingerprint in CANFD_CAR:
return self.update_canfd(cp, cp_cam) return self.update_canfd(cp, cp_cam)
@ -162,10 +167,13 @@ class CarState(CarStateBase):
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"]) self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.clu11 = copy.copy(cp.vl["CLU11"]) self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
self.prev_cruise_buttons = self.cruise_buttons[-1] prev_cruise_buttons = self.cruise_buttons[-1]
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]) self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"]) self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
if self.CP.openpilotLongitudinalControl:
ret.buttonEvents = create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT)
return ret return ret
def update_canfd(self, cp, cp_cam) -> structs.CarState: def update_canfd(self, cp, cp_cam) -> structs.CarState:
@ -238,7 +246,7 @@ class CarState(CarStateBase):
if self.CP.flags & HyundaiFlags.EV: if self.CP.flags & HyundaiFlags.EV:
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1 ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
self.prev_cruise_buttons = self.cruise_buttons[-1] prev_cruise_buttons = self.cruise_buttons[-1]
self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]) self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"]) self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"] self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
@ -248,6 +256,9 @@ class CarState(CarStateBase):
self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING self.hda2_lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING
else cp_cam.vl["CAM_0x2a4"]) else cp_cam.vl["CAM_0x2a4"])
if self.CP.openpilotLongitudinalControl:
ret.buttonEvents = create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT)
return ret return ret
def get_can_parser(self, CP): def get_can_parser(self, CP):

@ -944,6 +944,7 @@ FW_VERSIONS = {
b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.05 99210-CV000 211027',
b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT EUR LHD 1.00 1.06 99210-CV000 220328',
b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630', b'\xf1\x00CV1 MFC AT EUR RHD 1.00 1.00 99210-CV100 220630',
b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.00 99210-CV100 220630',
b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.04 99210-CV000 210823',
b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.05 99210-CV000 211027', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.05 99210-CV000 211027',
b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328', b'\xf1\x00CV1 MFC AT KOR LHD 1.00 1.06 99210-CV000 220328',

@ -1,6 +1,6 @@
from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.hyundai.carstate import CarState from openpilot.selfdrive.car.hyundai.carstate import CarState
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \ from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \
@ -11,11 +11,8 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.disable_ecu import disable_ecu
Ecu = structs.CarParams.Ecu Ecu = structs.CarParams.Ecu
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL) ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
@ -152,27 +149,3 @@ class CarInterface(CarInterfaceBase):
# for blinkers # for blinkers
if CP.flags & HyundaiFlags.ENABLE_BLINKERS: if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01') disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01')
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
if self.CS.CP.openpilotLongitudinalControl:
ret.buttonEvents = create_button_events(self.CS.cruise_buttons[-1], self.CS.prev_cruise_buttons, BUTTONS_DICT)
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
# Main button also can trigger an engagement on these cars
allow_enable = any(btn in ENABLE_BUTTONS for btn in self.CS.cruise_buttons) or any(self.CS.main_buttons)
events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise, allow_enable=allow_enable)
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
self.low_speed_alert = True
if ret.vEgo > (self.CP.minSteerSpeed + 4.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(car.CarEvent.EventName.belowSteerSpeed)
# ret.events = events.to_msg()
return ret

@ -18,11 +18,8 @@ from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, Ca
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.helpers import clip from openpilot.selfdrive.car.helpers import clip
from openpilot.selfdrive.car.values import PLATFORMS from openpilot.selfdrive.car.values import PLATFORMS
from openpilot.selfdrive.controls.lib.events import Events
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter GearShifter = structs.CarState.GearShifter
EventName = car.CarEvent.EventName
V_CRUISE_MAX = 145 V_CRUISE_MAX = 145
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
@ -93,10 +90,6 @@ class CarInterfaceBase(ABC):
self.CP = CP self.CP = CP
self.frame = 0 self.frame = 0
self.steering_unpressed = 0
self.low_speed_alert = False
self.no_steer_warning = False
self.silent_steer_warning = True
self.v_ego_cluster_seen = False self.v_ego_cluster_seen = False
self.CS: CarStateBase = CarState(CP) self.CS: CarStateBase = CarState(CP)
@ -105,7 +98,7 @@ class CarInterfaceBase(ABC):
self.cp_adas = self.CS.get_adas_can_parser(CP) self.cp_adas = self.CS.get_adas_can_parser(CP)
self.cp_body = self.CS.get_body_can_parser(CP) self.cp_body = self.CS.get_body_can_parser(CP)
self.cp_loopback = self.CS.get_loopback_can_parser(CP) self.cp_loopback = self.CS.get_loopback_can_parser(CP)
self.can_parsers = [self.cp, self.cp_cam, self.cp_adas, self.cp_body, self.cp_loopback] self.can_parsers = (self.cp, self.cp_cam, self.cp_adas, self.cp_body, self.cp_loopback)
dbc_name = "" if self.cp is None else self.cp.dbc_name dbc_name = "" if self.cp is None else self.cp.dbc_name
self.CC: CarControllerBase = CarController(dbc_name, CP) self.CC: CarControllerBase = CarController(dbc_name, CP)
@ -227,18 +220,17 @@ class CarInterfaceBase(ABC):
tune.torque.latAccelOffset = 0.0 tune.torque.latAccelOffset = 0.0
tune.torque.steeringAngleDeadzoneDeg = steering_angle_deadzone_deg tune.torque.steeringAngleDeadzoneDeg = steering_angle_deadzone_deg
@abstractmethod def _update(self) -> structs.CarState:
def _update(self, c: structs.CarControl) -> structs.CarState: return self.CS.update(*self.can_parsers)
pass
def update(self, c: structs.CarControl, can_packets: list[tuple[int, list[CanData]]]) -> structs.CarState: def update(self, can_packets: list[tuple[int, list[CanData]]]) -> car.CarState:
# parse can # parse can
for cp in self.can_parsers: for cp in self.can_parsers:
if cp is not None: if cp is not None:
cp.update_strings(can_packets) cp.update_strings(can_packets)
# get CarState # get CarState
ret = self._update(c) ret = self._update()
ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None) ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None)
ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None) ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None)
@ -249,7 +241,6 @@ class CarInterfaceBase(ABC):
self.v_ego_cluster_seen = True self.v_ego_cluster_seen = True
# Many cars apply hysteresis to the ego dash speed # Many cars apply hysteresis to the ego dash speed
if self.CS is not None:
ret.vEgoCluster = apply_hysteresis(ret.vEgoCluster, self.CS.out.vEgoCluster, self.CS.cluster_speed_hyst_gap) ret.vEgoCluster = apply_hysteresis(ret.vEgoCluster, self.CS.out.vEgoCluster, self.CS.cluster_speed_hyst_gap)
if abs(ret.vEgo) < self.CS.cluster_min_speed: if abs(ret.vEgo) < self.CS.cluster_min_speed:
ret.vEgoCluster = 0.0 ret.vEgoCluster = 0.0
@ -258,94 +249,12 @@ class CarInterfaceBase(ABC):
ret.cruiseState.speedCluster = ret.cruiseState.speed ret.cruiseState.speedCluster = ret.cruiseState.speed
# copy back for next iteration # copy back for next iteration
if self.CS is not None: # TODO: do we need to deepcopy?
self.CS.out = copy.deepcopy(ret) self.CS.out = copy.deepcopy(ret)
return ret return ret
def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True, allow_enable=True,
enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
events = Events()
if cs_out.doorOpen:
events.add(EventName.doorOpen)
if cs_out.seatbeltUnlatched:
events.add(EventName.seatbeltNotLatched)
if cs_out.gearShifter != GearShifter.drive and (extra_gears is None or
cs_out.gearShifter not in extra_gears):
events.add(EventName.wrongGear)
if cs_out.gearShifter == GearShifter.reverse:
events.add(EventName.reverseGear)
if not cs_out.cruiseState.available:
events.add(EventName.wrongCarMode)
if cs_out.espDisabled:
events.add(EventName.espDisabled)
if cs_out.espActive:
events.add(EventName.espActive)
if cs_out.stockFcw:
events.add(EventName.stockFcw)
if cs_out.stockAeb:
events.add(EventName.stockAeb)
if cs_out.vEgo > MAX_CTRL_SPEED:
events.add(EventName.speedTooHigh)
if cs_out.cruiseState.nonAdaptive:
events.add(EventName.wrongCruiseMode)
if cs_out.brakeHoldActive and self.CP.openpilotLongitudinalControl:
events.add(EventName.brakeHold)
if cs_out.parkingBrake:
events.add(EventName.parkBrake)
if cs_out.accFaulted:
events.add(EventName.accFaulted)
if cs_out.steeringPressed:
events.add(EventName.steerOverride)
if cs_out.brakePressed and cs_out.standstill:
events.add(EventName.preEnableStandstill)
if cs_out.gasPressed:
events.add(EventName.gasPressedOverride)
if cs_out.vehicleSensorsInvalid:
events.add(EventName.vehicleSensorsInvalid)
# Handle button presses
for b in cs_out.buttonEvents:
# Enable OP long on falling edge of enable buttons (defaults to accelCruise and decelCruise, overridable per-port)
if not self.CP.pcmCruise and (b.type in enable_buttons and not b.pressed):
events.add(EventName.buttonEnable)
# Disable on rising and falling edge of cancel for both stock and OP long
if b.type == ButtonType.cancel:
events.add(EventName.buttonCancel)
# Handle permanent and temporary steering faults
self.steering_unpressed = 0 if cs_out.steeringPressed else self.steering_unpressed + 1
if cs_out.steerFaultTemporary:
if cs_out.steeringPressed and (not self.CS.out.steerFaultTemporary or self.no_steer_warning):
self.no_steer_warning = True
else:
self.no_steer_warning = False
# if the user overrode recently, show a less harsh alert
if self.silent_steer_warning or cs_out.standstill or self.steering_unpressed < int(1.5 / DT_CTRL):
self.silent_steer_warning = True
events.add(EventName.steerTempUnavailableSilent)
else:
events.add(EventName.steerTempUnavailable)
else:
self.no_steer_warning = False
self.silent_steer_warning = False
if cs_out.steerFaultPermanent:
events.add(EventName.steerUnavailable)
# we engage when pcm is active (rising edge)
# enabling can optionally be blocked by the car interface
if pcm_enable:
if cs_out.cruiseState.enabled and not self.CS.out.cruiseState.enabled and allow_enable:
events.add(EventName.pcmEnable)
elif not cs_out.cruiseState.enabled:
events.add(EventName.pcmDisable)
return events
class RadarInterfaceBase(ABC): class RadarInterfaceBase(ABC):
def __init__(self, CP: structs.CarParams): def __init__(self, CP: structs.CarParams):
self.CP = CP self.CP = CP
@ -386,7 +295,7 @@ class CarStateBase(ABC):
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K) self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
@abstractmethod @abstractmethod
def update(self, *args) -> structs.CarState: def update(self, cp, cp_cam, cp_adas, cp_body, cp_loopback) -> structs.CarState:
pass pass
def update_speed_kf(self, v_ego_raw): def update_speed_kf(self, v_ego_raw):

@ -1,10 +1,13 @@
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags
ButtonType = car.CarState.ButtonEvent.Type
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
@ -18,14 +21,13 @@ class CarState(CarStateBase):
self.lkas_allowed_speed = False self.lkas_allowed_speed = False
self.lkas_disabled = False self.lkas_disabled = False
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"] self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"]
ret.wheelSpeeds = self.get_wheel_speeds( ret.wheelSpeeds = self.get_wheel_speeds(
@ -110,6 +112,9 @@ class CarState(CarStateBase):
self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"] self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"]
ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1 ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1
# TODO: add button types for inc and dec
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
return ret return ret
@staticmethod @staticmethod

@ -1,13 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from cereal import car from cereal import car
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.mazda.carstate import CarState from openpilot.selfdrive.car.mazda.carstate import CarState
from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CS: CarState CS: CarState
@ -25,28 +23,9 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if candidate not in (CAR.MAZDA_CX5_2022, ): if candidate not in (CAR.MAZDA_CX5_2022,):
ret.minSteerSpeed = LKAS_LIMITS.DISABLE_SPEED * CV.KPH_TO_MS ret.minSteerSpeed = LKAS_LIMITS.DISABLE_SPEED * CV.KPH_TO_MS
ret.centerToFront = ret.wheelbase * 0.41 ret.centerToFront = ret.wheelbase * 0.41
return ret return ret
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
# TODO: add button types for inc and dec
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
# events
events = self.create_common_events(ret)
if self.CS.lkas_disabled:
events.add(EventName.lkasDisabled)
elif self.CS.low_speed_alert:
events.add(EventName.belowSteerSpeed)
# ret.events = events.to_msg()
return ret

@ -3,5 +3,5 @@ from openpilot.selfdrive.car.interfaces import CarStateBase
class CarState(CarStateBase): class CarState(CarStateBase):
def update(self, *args) -> car.CarState: def update(self, *_) -> car.CarState:
pass return car.CarState.new_message()

@ -1,15 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import cereal.messaging as messaging
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
# mocked car interface for dashcam mode # mocked car interface for dashcam mode
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
def __init__(self, CP, CarController, CarState):
super().__init__(CP, CarController, CarState)
self.speed = 0.
self.sm = messaging.SubMaster(['gpsLocation', 'gpsLocationExternal'])
@staticmethod @staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs): def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs):
@ -20,13 +15,3 @@ class CarInterface(CarInterfaceBase):
ret.steerRatio = 13. ret.steerRatio = 13.
ret.dashcamOnly = True ret.dashcamOnly = True
return ret return ret
def _update(self, c) -> structs.CarState:
self.sm.update(0)
gps_sock = 'gpsLocationExternal' if self.sm.recv_frame['gpsLocationExternal'] > 1 else 'gpsLocation'
ret = structs.CarState()
ret.vEgo = self.sm[gps_sock].speed
ret.vEgoRaw = self.sm[gps_sock].speed
return ret

@ -2,13 +2,16 @@ import copy
from collections import deque from collections import deque
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.nissan.values import CAR, DBC, CarControllerParams from openpilot.selfdrive.car.nissan.values import CAR, DBC, CarControllerParams
ButtonType = car.CarState.ButtonEvent.Type
TORQUE_SAMPLES = 12 TORQUE_SAMPLES = 12
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
@ -20,13 +23,12 @@ class CarState(CarStateBase):
self.steeringTorqueSamples = deque(TORQUE_SAMPLES*[0], TORQUE_SAMPLES) self.steeringTorqueSamples = deque(TORQUE_SAMPLES*[0], TORQUE_SAMPLES)
self.shifter_values = can_define.dv["GEARBOX"]["GEAR_SHIFTER"] self.shifter_values = can_define.dv["GEARBOX"]["GEAR_SHIFTER"]
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
def update(self, cp, cp_adas, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, cp_adas, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRUISE_THROTTLE"]["FOLLOW_DISTANCE_BUTTON"] self.distance_button = cp.vl["CRUISE_THROTTLE"]["FOLLOW_DISTANCE_BUTTON"]
if self.CP.carFingerprint in (CAR.NISSAN_ROGUE, CAR.NISSAN_XTRAIL, CAR.NISSAN_ALTIMA): if self.CP.carFingerprint in (CAR.NISSAN_ROGUE, CAR.NISSAN_XTRAIL, CAR.NISSAN_ALTIMA):
@ -121,6 +123,8 @@ class CarState(CarStateBase):
self.lkas_hud_msg = copy.copy(cp_adas.vl["PROPILOT_HUD"]) self.lkas_hud_msg = copy.copy(cp_adas.vl["PROPILOT_HUD"])
self.lkas_hud_info_msg = copy.copy(cp_adas.vl["PROPILOT_HUD_INFO_MSG"]) self.lkas_hud_info_msg = copy.copy(cp_adas.vl["PROPILOT_HUD_INFO_MSG"])
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
return ret return ret
@staticmethod @staticmethod

@ -1,12 +1,9 @@
from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.nissan.carstate import CarState from openpilot.selfdrive.car.nissan.carstate import CarState
from openpilot.selfdrive.car.nissan.values import CAR from openpilot.selfdrive.car.nissan.values import CAR
ButtonType = structs.CarState.ButtonEvent.Type
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CS: CarState CS: CarState
@ -29,18 +26,3 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_NISSAN_ALT_EPS_BUS ret.safetyConfigs[0].safetyParam |= Panda.FLAG_NISSAN_ALT_EPS_BUS
return ret return ret
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam)
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
events = self.create_common_events(ret, extra_gears=[structs.CarState.GearShifter.brake])
if self.CS.lkas_enabled:
events.add(car.CarEvent.EventName.invalidLkasSetting)
# ret.events = events.to_msg()
return ret

@ -16,7 +16,7 @@ class CarState(CarStateBase):
self.angle_rate_calulator = CanSignalRateCalculator(50) self.angle_rate_calulator = CanSignalRateCalculator(50)
def update(self, cp, cp_cam, cp_body) -> structs.CarState: def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_body.vl["Throttle_Hybrid"] throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_body.vl["Throttle_Hybrid"]
@ -226,4 +226,3 @@ class CarState(CarStateBase):
] ]
return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus.alt) return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus.alt)

@ -97,15 +97,6 @@ class CarInterface(CarInterfaceBase):
return ret return ret
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam, self.cp_body)
# ret.events = self.create_common_events(ret).to_msg()
return ret
@staticmethod @staticmethod
def init(CP, can_recv, can_send): def init(CP, can_recv, can_send):
if CP.flags & SubaruFlags.DISABLE_EYESIGHT: if CP.flags & SubaruFlags.DISABLE_EYESIGHT:

@ -8,6 +8,7 @@ from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.tesla.values import CAR, DBC, CANBUS, GEAR_MAP, DOORS, BUTTONS from openpilot.selfdrive.car.tesla.values import CAR, DBC, CANBUS, GEAR_MAP, DOORS, BUTTONS
from openpilot.selfdrive.car.interfaces import CarStateBase from openpilot.selfdrive.car.interfaces import CarStateBase
class CarState(CarStateBase): class CarState(CarStateBase):
def __init__(self, CP): def __init__(self, CP):
super().__init__(CP) super().__init__(CP)
@ -21,7 +22,7 @@ class CarState(CarStateBase):
self.acc_state = 0 self.acc_state = 0
self.das_control_counters = deque(maxlen=32) self.das_control_counters = deque(maxlen=32)
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
# Vehicle speed # Vehicle speed

@ -40,10 +40,3 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 1.0 ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0.25 ret.steerActuatorDelay = 0.25
return ret return ret
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
# ret.events = self.create_common_events(ret).to_msg()
return ret

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
SCRIPT_DIR=$(dirname "$0") SCRIPT_DIR=$(dirname "$0")
BASEDIR=$(realpath "$SCRIPT_DIR/../../../") BASEDIR=$(realpath "$SCRIPT_DIR/../../../")

@ -12,6 +12,7 @@ from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fingerprints import all_known_cars from openpilot.selfdrive.car.fingerprints import all_known_cars
from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
from openpilot.selfdrive.car.interfaces import get_interface_attr from openpilot.selfdrive.car.interfaces import get_interface_attr
from openpilot.selfdrive.car.mock.values import CAR as MOCK
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
@ -52,7 +53,7 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict:
class TestCarInterfaces: class TestCarInterfaces:
# FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause # FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause
# many generated examples to overrun when max_examples > ~20, don't use it # many generated examples to overrun when max_examples > ~20, don't use it
@parameterized.expand([(car,) for car in sorted(all_known_cars())]) @parameterized.expand([(car,) for car in sorted(all_known_cars())] + [MOCK.MOCK])
@settings(max_examples=MAX_EXAMPLES, deadline=None, @settings(max_examples=MAX_EXAMPLES, deadline=None,
phases=(Phase.reuse, Phase.generate, Phase.shrink)) phases=(Phase.reuse, Phase.generate, Phase.shrink))
@given(data=st.data()) @given(data=st.data())
@ -81,7 +82,9 @@ class TestCarInterfaces:
# Lateral sanity checks # Lateral sanity checks
if car_params.steerControlType != CarParams.SteerControlType.angle: if car_params.steerControlType != CarParams.SteerControlType.angle:
tune = car_params.lateralTuning tune = car_params.lateralTuning
# TODO: we use which again, this is wrong
if isinstance(tune, CarParams.LateralPIDTuning): if isinstance(tune, CarParams.LateralPIDTuning):
if car_name != MOCK.MOCK:
assert not math.isnan(tune.kf) and tune.kf > 0 assert not math.isnan(tune.kf) and tune.kf > 0
assert len(tune.kpV) > 0 and len(tune.kpV) == len(tune.kpBP) assert len(tune.kpV) > 0 and len(tune.kpV) == len(tune.kpBP)
assert len(tune.kiV) > 0 and len(tune.kiV) == len(tune.kiBP) assert len(tune.kiV) > 0 and len(tune.kiV) == len(tune.kiBP)
@ -95,14 +98,14 @@ class TestCarInterfaces:
now_nanos = 0 now_nanos = 0
CC = car.CarControl.new_message(**cc_msg) CC = car.CarControl.new_message(**cc_msg)
for _ in range(10): for _ in range(10):
car_interface.update(CC, []) car_interface.update([])
car_interface.apply(CC.as_reader(), now_nanos) car_interface.apply(CC.as_reader(), now_nanos)
now_nanos += DT_CTRL * 1e9 # 10 ms now_nanos += DT_CTRL * 1e9 # 10 ms
CC = car.CarControl.new_message(**cc_msg) CC = car.CarControl.new_message(**cc_msg)
CC.enabled = True CC.enabled = True
for _ in range(10): for _ in range(10):
car_interface.update(CC, []) car_interface.update([])
car_interface.apply(CC.as_reader(), now_nanos) car_interface.apply(CC.as_reader(), now_nanos)
now_nanos += DT_CTRL * 1e9 # 10ms now_nanos += DT_CTRL * 1e9 # 10ms

@ -220,7 +220,7 @@ class TestCarModelBase(unittest.TestCase):
CC = car.CarControl.new_message().as_reader() CC = car.CarControl.new_message().as_reader()
for i, msg in enumerate(self.can_msgs): for i, msg in enumerate(self.can_msgs):
CS = self.CI.update(CC, can_capnp_to_list((msg.as_builder().to_bytes(),))) CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
self.CI.apply(CC, msg.logMonoTime) self.CI.apply(CC, msg.logMonoTime)
if CS.canValid: if CS.canValid:
@ -296,7 +296,7 @@ class TestCarModelBase(unittest.TestCase):
msgs_sent = 0 msgs_sent = 0
CI = self.CarInterface(self.CP, self.CarController, self.CarState) CI = self.CarInterface(self.CP, self.CarController, self.CarState)
for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages
CI.update(car_control, []) CI.update([])
_, sendcan = CI.apply(car_control, now_nanos) _, sendcan = CI.apply(car_control, now_nanos)
now_nanos += DT_CTRL * 1e9 now_nanos += DT_CTRL * 1e9
@ -342,8 +342,6 @@ class TestCarModelBase(unittest.TestCase):
msg_strategy = st.binary(min_size=size, max_size=size) msg_strategy = st.binary(min_size=size, max_size=size)
msgs = data.draw(st.lists(msg_strategy, min_size=20)) msgs = data.draw(st.lists(msg_strategy, min_size=20))
CC = car.CarControl.new_message()
for dat in msgs: for dat in msgs:
# due to panda updating state selectively, only edges are expected to match # due to panda updating state selectively, only edges are expected to match
# TODO: warm up CarState with real CAN messages to check edge of both sources # TODO: warm up CarState with real CAN messages to check edge of both sources
@ -361,7 +359,7 @@ class TestCarModelBase(unittest.TestCase):
can = messaging.new_message('can', 1) can = messaging.new_message('can', 1)
can.can = [log.CanData(address=address, dat=dat, src=bus)] can.can = [log.CanData(address=address, dat=dat, src=bus)]
CS = self.CI.update(CC, can_capnp_to_list((can.to_bytes(),))) CS = self.CI.update(can_capnp_to_list((can.to_bytes(),)))
if self.safety.get_gas_pressed_prev() != prev_panda_gas: if self.safety.get_gas_pressed_prev() != prev_panda_gas:
self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev()) self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev())
@ -396,11 +394,9 @@ class TestCarModelBase(unittest.TestCase):
if self.CP.dashcamOnly: if self.CP.dashcamOnly:
self.skipTest("no need to check panda safety for dashcamOnly") self.skipTest("no need to check panda safety for dashcamOnly")
CC = car.CarControl.new_message()
# warm up pass, as initial states may be different # warm up pass, as initial states may be different
for can in self.can_msgs[:300]: for can in self.can_msgs[:300]:
self.CI.update(CC, can_capnp_to_list((can.as_builder().to_bytes(), ))) self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), )))
for msg in filter(lambda m: m.src in range(64), can.can): for msg in filter(lambda m: m.src in range(64), can.can):
to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat)
self.safety.safety_rx_hook(to_send) self.safety.safety_rx_hook(to_send)
@ -410,7 +406,7 @@ class TestCarModelBase(unittest.TestCase):
checks = defaultdict(int) checks = defaultdict(int)
card = Car(CI=self.CI) card = Car(CI=self.CI)
for idx, can in enumerate(self.can_msgs): for idx, can in enumerate(self.can_msgs):
CS = self.CI.update(CC, can_capnp_to_list((can.as_builder().to_bytes(), ))) CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), )))
for msg in filter(lambda m: m.src in range(64), can.can): for msg in filter(lambda m: m.src in range(64), can.can):
to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat) to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat)
ret = self.safety.safety_rx_hook(to_send) ret = self.safety.safety_rx_hook(to_send)

@ -2,7 +2,7 @@ import copy
from opendbc.can.can_define import CANDefine from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import DT_CTRL, structs from openpilot.selfdrive.car import DT_CTRL, create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.filter_simple import FirstOrderFilter from openpilot.selfdrive.car.filter_simple import FirstOrderFilter
from openpilot.selfdrive.car.helpers import mean from openpilot.selfdrive.car.helpers import mean
@ -10,6 +10,7 @@ from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \ from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \
TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR
ButtonType = structs.CarState.ButtonEvent.Type
SteerControlType = structs.CarParams.SteerControlType SteerControlType = structs.CarParams.SteerControlType
# These steering fault definitions seem to be common across LKA (torque) and LTA (angle): # These steering fault definitions seem to be common across LKA (torque) and LTA (angle):
@ -39,7 +40,6 @@ class CarState(CarStateBase):
self.accurate_steer_angle_seen = False self.accurate_steer_angle_seen = False
self.angle_offset = FirstOrderFilter(None, 60.0, DT_CTRL, initialized=False) self.angle_offset = FirstOrderFilter(None, 60.0, DT_CTRL, initialized=False)
self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
self.pcm_follow_distance = 0 self.pcm_follow_distance = 0
@ -48,7 +48,7 @@ class CarState(CarStateBase):
self.acc_type = 1 self.acc_type = 1
self.lkas_hud = {} self.lkas_hud = {}
def update(self, cp, cp_cam) -> structs.CarState: def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"], ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"],
@ -171,10 +171,11 @@ class CarState(CarStateBase):
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR): if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR):
# distance button is wired to the ACC module (camera or radar) # distance button is wired to the ACC module (camera or radar)
self.prev_distance_button = self.distance_button prev_distance_button = self.distance_button
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR):
self.distance_button = cp_acc.vl["ACC_CONTROL"]["DISTANCE"] self.distance_button = cp_acc.vl["ACC_CONTROL"]["DISTANCE"]
ret.buttonEvents = create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise})
return ret return ret
@staticmethod @staticmethod

@ -1,15 +1,12 @@
from cereal import car
from panda import Panda from panda import Panda
from panda.python import uds from panda.python import uds
from openpilot.selfdrive.car import structs, get_safety_config
from openpilot.selfdrive.car.toyota.carstate import CarState from openpilot.selfdrive.car.toyota.carstate import CarState
from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \ from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \
MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR
from openpilot.selfdrive.car import create_button_events, get_safety_config, structs
from openpilot.selfdrive.car.disable_ecu import disable_ecu from openpilot.selfdrive.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
SteerControlType = structs.CarParams.SteerControlType SteerControlType = structs.CarParams.SteerControlType
@ -146,30 +143,3 @@ class CarInterface(CarInterfaceBase):
if CP.flags & ToyotaFlags.DISABLE_RADAR.value: if CP.flags & ToyotaFlags.DISABLE_RADAR.value:
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, uds.CONTROL_TYPE.ENABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL]) communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, uds.CONTROL_TYPE.ENABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
disable_ecu(can_recv, can_send, bus=0, addr=0x750, sub_addr=0xf, com_cont_req=communication_control) disable_ecu(can_recv, can_send, bus=0, addr=0x750, sub_addr=0xf, com_cont_req=communication_control)
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam)
if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR):
ret.buttonEvents = create_button_events(self.CS.distance_button, self.CS.prev_distance_button, {1: ButtonType.gapAdjustCruise})
# events
events = self.create_common_events(ret)
if self.CP.openpilotLongitudinalControl:
if ret.cruiseState.standstill and not ret.brakePressed:
events.add(EventName.resumeRequired)
if self.CS.low_speed_lockout:
events.add(EventName.lowSpeedLockout)
if ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
if c.actuators.accel > 0.3:
# some margin on the actuator to not false trigger cancellation while stopping
events.add(EventName.speedTooLow)
if ret.vEgo < 0.001:
# while in standstill, send a user alert
events.add(EventName.manualRestart)
# ret.events = events.to_msg()
return ret

@ -63,6 +63,7 @@ if __name__ == "__main__":
import argparse import argparse
import time import time
import cereal.messaging as messaging import cereal.messaging as messaging
from openpilot.selfdrive.car.card import can_comm_callbacks
parser = argparse.ArgumentParser(description='Get VIN of the car') parser = argparse.ArgumentParser(description='Get VIN of the car')
parser.add_argument('--debug', action='store_true') parser.add_argument('--debug', action='store_true')
@ -73,7 +74,8 @@ if __name__ == "__main__":
sendcan = messaging.pub_sock('sendcan') sendcan = messaging.pub_sock('sendcan')
logcan = messaging.sub_sock('can') logcan = messaging.sub_sock('can')
can_callbacks = can_comm_callbacks(logcan, sendcan)
time.sleep(1) time.sleep(1)
vin_rx_addr, vin_rx_bus, vin = get_vin(logcan, sendcan, (args.bus,), args.timeout, args.retry, debug=args.debug) vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (args.bus,), args.timeout, args.retry, debug=args.debug)
print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}') print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}')

@ -33,9 +33,12 @@ class CarState(CarStateBase):
return button_events return button_events
def update(self, pt_cp, cam_cp, ext_cp, trans_type) -> structs.CarState: def update(self, pt_cp, cam_cp, *_) -> structs.CarState:
ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp
if self.CP.flags & VolkswagenFlags.PQ: if self.CP.flags & VolkswagenFlags.PQ:
return self.update_pq(pt_cp, cam_cp, ext_cp, trans_type) return self.update_pq(pt_cp, cam_cp, ext_cp)
ret = structs.CarState() ret = structs.CarState()
# Update vehicle speed and acceleration from ABS wheel speeds. # Update vehicle speed and acceleration from ABS wheel speeds.
@ -74,11 +77,11 @@ class CarState(CarStateBase):
ret.parkingBrake = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"]) # FIXME: need to include an EPB check as well ret.parkingBrake = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"]) # FIXME: need to include an EPB check as well
# Update gear and/or clutch position data. # Update gear and/or clutch position data.
if trans_type == TransmissionType.automatic: if self.CP.transmissionType == TransmissionType.automatic:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_11"]["GE_Fahrstufe"], None)) ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_11"]["GE_Fahrstufe"], None))
elif trans_type == TransmissionType.direct: elif self.CP.transmissionType == TransmissionType.direct:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["EV_Gearshift"]["GearPosition"], None)) ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["EV_Gearshift"]["GearPosition"], None))
elif trans_type == TransmissionType.manual: elif self.CP.transmissionType == TransmissionType.manual:
ret.clutchPressed = not pt_cp.vl["Motor_14"]["MO_Kuppl_schalter"] ret.clutchPressed = not pt_cp.vl["Motor_14"]["MO_Kuppl_schalter"]
if bool(pt_cp.vl["Gateway_72"]["BCM1_Rueckfahrlicht_Schalter"]): if bool(pt_cp.vl["Gateway_72"]["BCM1_Rueckfahrlicht_Schalter"]):
ret.gearShifter = GearShifter.reverse ret.gearShifter = GearShifter.reverse
@ -156,7 +159,7 @@ class CarState(CarStateBase):
self.frame += 1 self.frame += 1
return ret return ret
def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type) -> structs.CarState: def update_pq(self, pt_cp, cam_cp, ext_cp) -> structs.CarState:
ret = structs.CarState() ret = structs.CarState()
# Update vehicle speed and acceleration from ABS wheel speeds. # Update vehicle speed and acceleration from ABS wheel speeds.
ret.wheelSpeeds = self.get_wheel_speeds( ret.wheelSpeeds = self.get_wheel_speeds(
@ -188,9 +191,9 @@ class CarState(CarStateBase):
ret.parkingBrake = bool(pt_cp.vl["Kombi_1"]["Bremsinfo"]) ret.parkingBrake = bool(pt_cp.vl["Kombi_1"]["Bremsinfo"])
# Update gear and/or clutch position data. # Update gear and/or clutch position data.
if trans_type == TransmissionType.automatic: if self.CP.transmissionType == TransmissionType.automatic:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_1"]["Waehlhebelposition__Getriebe_1_"], None)) ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_1"]["Waehlhebelposition__Getriebe_1_"], None))
elif trans_type == TransmissionType.manual: elif self.CP.transmissionType == TransmissionType.manual:
ret.clutchPressed = not pt_cp.vl["Motor_1"]["Kupplungsschalter"] ret.clutchPressed = not pt_cp.vl["Motor_1"]["Kupplungsschalter"]
reverse_light = bool(pt_cp.vl["Gate_Komf_1"]["GK1_Rueckfahr"]) reverse_light = bool(pt_cp.vl["Gate_Komf_1"]["GK1_Rueckfahr"])
if reverse_light: if reverse_light:
@ -388,6 +391,7 @@ class MqbExtraSignals:
("SWA_01", 20), # From J1086 Lane Change Assist ("SWA_01", 20), # From J1086 Lane Change Assist
] ]
class PqExtraSignals: class PqExtraSignals:
# Additional signal and message lists for optional or bus-portable controllers # Additional signal and message lists for optional or bus-portable controllers
fwd_radar_messages = [ fwd_radar_messages = [

@ -883,6 +883,7 @@ FW_VERSIONS = {
b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571G60533A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571G60533A1',
b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571G60733A1', b'\xf1\x875QF909144B \xf1\x895582\xf1\x82\x0571G60733A1',
b'\xf1\x875TA907145D \xf1\x891051\xf1\x82\x001PG60A1P7N', b'\xf1\x875TA907145D \xf1\x891051\xf1\x82\x001PG60A1P7N',
b'\xf1\x875TA907145F \xf1\x891063\xf1\x82\x002VG60A2VOM',
], ],
(Ecu.fwdRadar, 0x757, None): [ (Ecu.fwdRadar, 0x757, None): [
b'\xf1\x872Q0907572AA\xf1\x890396', b'\xf1\x872Q0907572AA\xf1\x890396',

@ -1,29 +1,15 @@
from cereal import car
from panda import Panda from panda import Panda
from openpilot.selfdrive.car import get_safety_config, structs from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.volkswagen.carcontroller import CarController from openpilot.selfdrive.car.volkswagen.carcontroller import CarController
from openpilot.selfdrive.car.volkswagen.carstate import CarState from openpilot.selfdrive.car.volkswagen.carstate import CarState
from openpilot.selfdrive.car.volkswagen.values import CAR, CANBUS, CarControllerParams, NetworkLocation, TransmissionType, GearShifter, VolkswagenFlags from openpilot.selfdrive.car.volkswagen.values import CAR, NetworkLocation, TransmissionType, VolkswagenFlags
ButtonType = structs.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
CS: CarState CS: CarState
CC: CarController CC: CarController
def __init__(self, CP, CarController, CarState):
super().__init__(CP, CarController, CarState)
if CP.networkLocation == NetworkLocation.fwdCamera:
self.ext_bus = CANBUS.pt
self.cp_ext = self.cp
else:
self.ext_bus = CANBUS.cam
self.cp_ext = self.cp_cam
@staticmethod @staticmethod
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs): def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
ret.carName = "volkswagen" ret.carName = "volkswagen"
@ -104,33 +90,3 @@ class CarInterface(CarInterfaceBase):
ret.autoResumeSng = ret.minEnableSpeed == -1 ret.autoResumeSng = ret.minEnableSpeed == -1
return ret return ret
# returns a car.CarState
def _update(self, c) -> structs.CarState:
ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType)
events = self.create_common_events(ret, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic],
pcm_enable=not self.CS.CP.openpilotLongitudinalControl,
enable_buttons=(ButtonType.setCruise, ButtonType.resumeCruise))
# Low speed steer alert hysteresis logic
if (self.CP.minSteerSpeed - 1e-3) > CarControllerParams.DEFAULT_MIN_STEER_SPEED and ret.vEgo < (self.CP.minSteerSpeed + 1.):
self.low_speed_alert = True
elif ret.vEgo > (self.CP.minSteerSpeed + 2.):
self.low_speed_alert = False
if self.low_speed_alert:
events.add(EventName.belowSteerSpeed)
if self.CS.CP.openpilotLongitudinalControl:
if ret.vEgo < self.CP.minEnableSpeed + 0.5:
events.add(EventName.belowEngageSpeed)
if c.enabled and ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.speedTooLow)
if self.CC.eps_timer_soft_disable_alert:
events.add(EventName.steerTimeLimit)
# ret.events = events.to_msg()
return ret

@ -28,6 +28,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, S
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.selfdrive.controls.lib.longcontrol import LongControl from openpilot.selfdrive.controls.lib.longcontrol import LongControl
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
from openpilot.system.hardware import HARDWARE from openpilot.system.hardware import HARDWARE
@ -78,6 +79,11 @@ class Controls:
# Setup sockets # Setup sockets
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents']) self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents'])
if self.params.get_bool("UbloxAvailable"):
self.gps_location_service = "gpsLocationExternal"
else:
self.gps_location_service = "gpsLocation"
self.gps_packets = [self.gps_location_service]
self.sensor_packets = ["accelerometer", "gyroscope"] self.sensor_packets = ["accelerometer", "gyroscope"]
self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"] self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"]
@ -86,16 +92,16 @@ class Controls:
# TODO: de-couple controlsd with card/conflate on carState without introducing controls mismatches # TODO: de-couple controlsd with card/conflate on carState without introducing controls mismatches
self.car_state_sock = messaging.sub_sock('carState', timeout=20) self.car_state_sock = messaging.sub_sock('carState', timeout=20)
ignore = self.sensor_packets + ['testJoystick'] ignore = self.sensor_packets + self.gps_packets + ['testJoystick']
if SIMULATION: if SIMULATION:
ignore += ['driverCameraState', 'managerState'] ignore += ['driverCameraState', 'managerState']
if REPLAY: if REPLAY:
# no vipc in replay will make them ignored anyways # no vipc in replay will make them ignored anyways
ignore += ['roadCameraState', 'wideRoadCameraState'] ignore += ['roadCameraState', 'wideRoadCameraState']
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration', self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman', 'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'testJoystick'] + self.camera_packets + self.sensor_packets, 'testJoystick'] + self.camera_packets + self.sensor_packets + self.gps_packets,
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ], ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
frequency=int(1/DT_CTRL)) frequency=int(1/DT_CTRL))
@ -120,6 +126,9 @@ class Controls:
self.AM = AlertManager() self.AM = AlertManager()
self.events = Events() self.events = Events()
self.pose_calibrator = PoseCalibrator()
self.calibrated_pose: Pose|None = None
self.LoC = LongControl(self.CP) self.LoC = LongControl(self.CP)
self.VM = VehicleModel(self.CP) self.VM = VehicleModel(self.CP)
@ -335,11 +344,9 @@ class Controls:
self.logged_comm_issue = None self.logged_comm_issue = None
if not (self.CP.notCar and self.joystick_mode): if not (self.CP.notCar and self.joystick_mode):
if not self.sm['liveLocationKalman'].posenetOK: if not self.sm['livePose'].posenetOK:
self.events.add(EventName.posenetInvalid) self.events.add(EventName.posenetInvalid)
if not self.sm['liveLocationKalman'].deviceStable: if not self.sm['livePose'].inputsOK:
self.events.add(EventName.deviceFalling)
if not self.sm['liveLocationKalman'].inputsOK:
self.events.add(EventName.locationdTemporaryError) self.events.add(EventName.locationdTemporaryError)
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY): if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
self.events.add(EventName.paramsdTemporaryError) self.events.add(EventName.paramsdTemporaryError)
@ -375,10 +382,10 @@ class Controls:
# TODO: fix simulator # TODO: fix simulator
if not SIMULATION or REPLAY: if not SIMULATION or REPLAY:
# Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes gps_ok = self.sm.recv_frame[self.gps_location_service] > 0 and (self.sm.frame - self.sm.recv_frame[self.gps_location_service]) * DT_CTRL < 2.0
if not self.sm['liveLocationKalman'].gpsOK and self.sm['liveLocationKalman'].inputsOK and (self.distance_traveled > 1500): if not gps_ok and self.sm['livePose'].inputsOK and (self.distance_traveled > 1500):
self.events.add(EventName.noGps) self.events.add(EventName.noGps)
if self.sm['liveLocationKalman'].gpsOK: if gps_ok:
self.distance_traveled = 0 self.distance_traveled = 0
self.distance_traveled += CS.vEgo * DT_CTRL self.distance_traveled += CS.vEgo * DT_CTRL
@ -429,6 +436,13 @@ class Controls:
if ps.safetyModel not in IGNORED_SAFETY_MODES): if ps.safetyModel not in IGNORED_SAFETY_MODES):
self.mismatch_counter += 1 self.mismatch_counter += 1
# calibrate the live pose and save it for later use
if self.sm.updated["liveCalibration"]:
self.pose_calibrator.feed_live_calib(self.sm['liveCalibration'])
if self.sm.updated["livePose"]:
device_pose = Pose.from_live_pose(self.sm['livePose'])
self.calibrated_pose = self.pose_calibrator.build_calibrated_pose(device_pose)
return CS return CS
def state_transition(self, CS): def state_transition(self, CS):
@ -573,7 +587,7 @@ class Controls:
actuators.curvature = self.desired_curvature actuators.curvature = self.desired_curvature
actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp, actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
self.steer_limited, self.desired_curvature, self.steer_limited, self.desired_curvature,
self.sm['liveLocationKalman']) self.calibrated_pose) # TODO what if not available
else: else:
lac_log = log.ControlsState.LateralDebugState.new_message() lac_log = log.ControlsState.LateralDebugState.new_message()
if self.sm.recv_frame['testJoystick'] > 0: if self.sm.recv_frame['testJoystick'] > 0:
@ -650,12 +664,9 @@ class Controls:
# Orientation and angle rates can be useful for carcontroller # Orientation and angle rates can be useful for carcontroller
# Only calibrated (car) frame is relevant for the carcontroller # Only calibrated (car) frame is relevant for the carcontroller
orientation_value = list(self.sm['liveLocationKalman'].calibratedOrientationNED.value) if self.calibrated_pose is not None:
if len(orientation_value) > 2: CC.orientationNED = self.calibrated_pose.orientation.xyz.tolist()
CC.orientationNED = orientation_value CC.angularVelocity = self.calibrated_pose.angular_velocity.xyz.tolist()
angular_rate_value = list(self.sm['liveLocationKalman'].angularVelocityCalibrated.value)
if len(angular_rate_value) > 2:
CC.angularVelocity = angular_rate_value
CC.cruiseControl.override = self.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl CC.cruiseControl.override = self.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl
CC.cruiseControl.cancel = CS.cruiseState.enabled and (not self.enabled or not self.CP.pcmCruise) CC.cruiseControl.cancel = CS.cruiseState.enabled and (not self.enabled or not self.CP.pcmCruise)

@ -17,7 +17,7 @@ class LatControl(ABC):
self.steer_max = 1.0 self.steer_max = 1.0
@abstractmethod @abstractmethod
def update(self, active, CS, VM, params, steer_limited, desired_curvature, llk): def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
pass pass
def reset(self): def reset(self):

@ -11,7 +11,7 @@ class LatControlAngle(LatControl):
super().__init__(CP, CI) super().__init__(CP, CI)
self.sat_check_min_speed = 5. self.sat_check_min_speed = 5.
def update(self, active, CS, VM, params, steer_limited, desired_curvature, llk): def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
angle_log = log.ControlsState.LateralAngleState.new_message() angle_log = log.ControlsState.LateralAngleState.new_message()
if not active: if not active:

@ -17,7 +17,7 @@ class LatControlPID(LatControl):
super().reset() super().reset()
self.pid.reset() self.pid.reset()
def update(self, active, CS, VM, params, steer_limited, desired_curvature, llk): def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
pid_log = log.ControlsState.LateralPIDState.new_message() pid_log = log.ControlsState.LateralPIDState.new_message()
pid_log.steeringAngleDeg = float(CS.steeringAngleDeg) pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
pid_log.steeringRateDeg = float(CS.steeringRateDeg) pid_log.steeringRateDeg = float(CS.steeringRateDeg)

@ -37,7 +37,7 @@ class LatControlTorque(LatControl):
self.torque_params.latAccelOffset = latAccelOffset self.torque_params.latAccelOffset = latAccelOffset
self.torque_params.friction = friction self.torque_params.friction = friction
def update(self, active, CS, VM, params, steer_limited, desired_curvature, llk): def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
pid_log = log.ControlsState.LateralTorqueState.new_message() pid_log = log.ControlsState.LateralTorqueState.new_message()
if not active: if not active:
output_torque = 0.0 output_torque = 0.0
@ -49,8 +49,9 @@ class LatControlTorque(LatControl):
actual_curvature = actual_curvature_vm actual_curvature = actual_curvature_vm
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0)) curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
else: else:
actual_curvature_llk = llk.angularVelocityCalibrated.value[2] / CS.vEgo assert calibrated_pose is not None
actual_curvature = interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_llk]) actual_curvature_pose = calibrated_pose.angular_velocity.yaw / CS.vEgo
actual_curvature = interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_pose])
curvature_deadzone = 0.0 curvature_deadzone = 0.0
desired_lateral_accel = desired_curvature * CS.vEgo ** 2 desired_lateral_accel = desired_curvature * CS.vEgo ** 2

@ -10,7 +10,8 @@ from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
from openpilot.common.mock.generators import generate_liveLocationKalman from openpilot.selfdrive.locationd.helpers import Pose
from openpilot.common.mock.generators import generate_livePose
class TestLatControl: class TestLatControl:
@ -31,8 +32,10 @@ class TestLatControl:
params = log.LiveParametersData.new_message() params = log.LiveParametersData.new_message()
llk = generate_liveLocationKalman() lp = generate_livePose()
pose = Pose.from_live_pose(lp.livePose)
for _ in range(1000): for _ in range(1000):
_, _, lac_log = controller.update(True, CS, VM, params, False, 1, llk) _, _, lac_log = controller.update(True, CS, VM, params, False, 1, pose)
assert lac_log.saturated assert lac_log.saturated

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
PORT=5555 PORT=5555

@ -54,7 +54,7 @@ def cycle_alerts(duration=200, is_metric=False):
CS = car.CarState.new_message() CS = car.CarState.new_message()
CP = CarInterface.get_non_essential_params("HONDA_CIVIC") CP = CarInterface.get_non_essential_params("HONDA_CIVIC")
sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration', sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration',
'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman', 'driverMonitoringState', 'longitudinalPlan', 'livePose',
'managerState'] + cameras) 'managerState'] + cameras)
pm = messaging.PubMaster(['controlsState', 'pandaStates', 'deviceState']) pm = messaging.PubMaster(['controlsState', 'pandaStates', 'deviceState'])

@ -2,6 +2,7 @@ import numpy as np
from typing import Any from typing import Any
from cereal import log from cereal import log
from openpilot.common.transformations.orientation import rot_from_euler, euler_from_rot
def rotate_cov(rot_matrix, cov_in): def rotate_cov(rot_matrix, cov_in):
@ -70,3 +71,69 @@ class ParameterEstimator:
def get_msg(self, valid: bool, with_points: bool) -> log.Event: def get_msg(self, valid: bool, with_points: bool) -> log.Event:
raise NotImplementedError raise NotImplementedError
class Measurement:
x, y, z = (property(lambda self: self.xyz[0]), property(lambda self: self.xyz[1]), property(lambda self: self.xyz[2]))
x_std, y_std, z_std = (property(lambda self: self.xyz_std[0]), property(lambda self: self.xyz_std[1]), property(lambda self: self.xyz_std[2]))
roll, pitch, yaw = x, y, z
roll_std, pitch_std, yaw_std = x_std, y_std, z_std
def __init__(self, xyz: np.ndarray, xyz_std: np.ndarray):
self.xyz: np.ndarray = xyz
self.xyz_std: np.ndarray = xyz_std
@classmethod
def from_measurement_xyz(cls, measurement: log.LivePose.XYZMeasurement) -> 'Measurement':
return cls(
xyz=np.array([measurement.x, measurement.y, measurement.z]),
xyz_std=np.array([measurement.xStd, measurement.yStd, measurement.zStd])
)
class Pose:
def __init__(self, orientation: Measurement, velocity: Measurement, acceleration: Measurement, angular_velocity: Measurement):
self.orientation = orientation
self.velocity = velocity
self.acceleration = acceleration
self.angular_velocity = angular_velocity
@classmethod
def from_live_pose(cls, live_pose: log.LivePose) -> 'Pose':
return Pose(
orientation=Measurement.from_measurement_xyz(live_pose.orientationNED),
velocity=Measurement.from_measurement_xyz(live_pose.velocityDevice),
acceleration=Measurement.from_measurement_xyz(live_pose.accelerationDevice),
angular_velocity=Measurement.from_measurement_xyz(live_pose.angularVelocityDevice)
)
class PoseCalibrator:
def __init__(self):
self.calib_valid = False
self.calib_from_device = np.eye(3)
def _transform_calib_from_device(self, meas: Measurement):
new_xyz = self.calib_from_device @ meas.xyz
new_xyz_std = rotate_std(self.calib_from_device, meas.xyz_std)
return Measurement(new_xyz, new_xyz_std)
def _ned_from_calib(self, orientation: Measurement):
ned_from_device = rot_from_euler(orientation.xyz)
ned_from_calib = ned_from_device @ self.calib_from_device.T
ned_from_calib_euler_meas = Measurement(euler_from_rot(ned_from_calib), np.full(3, np.nan))
return ned_from_calib_euler_meas
def build_calibrated_pose(self, pose: Pose) -> Pose:
ned_from_calib_euler = self._ned_from_calib(pose.orientation)
angular_velocity_calib = self._transform_calib_from_device(pose.angular_velocity)
acceleration_calib = self._transform_calib_from_device(pose.acceleration)
velocity_calib = self._transform_calib_from_device(pose.angular_velocity)
return Pose(ned_from_calib_euler, velocity_calib, acceleration_calib, angular_velocity_calib)
def feed_live_calib(self, live_calib: log.LiveCalibrationData):
calib_rpy = np.array(live_calib.rpyCalib)
device_from_calib = rot_from_euler(calib_rpy)
self.calib_from_device = device_from_calib.T
self.calib_valid = live_calib.calStatus == log.LiveCalibrationData.Status.calibrated

@ -9,10 +9,9 @@ from cereal import car, log
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, DT_MDL from openpilot.common.realtime import config_realtime_process, DT_MDL
from openpilot.common.numpy_fast import clip from openpilot.common.numpy_fast import clip
from openpilot.common.transformations.orientation import rot_from_euler
from openpilot.selfdrive.locationd.models.car_kf import CarKalman, ObservationKind, States from openpilot.selfdrive.locationd.models.car_kf import CarKalman, ObservationKind, States
from openpilot.selfdrive.locationd.models.constants import GENERATED_DIR from openpilot.selfdrive.locationd.models.constants import GENERATED_DIR
from openpilot.selfdrive.locationd.helpers import rotate_std from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
@ -40,9 +39,8 @@ class ParamsLearner:
self.kf.filter.set_global("stiffness_rear", CP.tireStiffnessRear) self.kf.filter.set_global("stiffness_rear", CP.tireStiffnessRear)
self.active = False self.active = False
self.calibrated = False
self.calib_from_device = np.eye(3) self.calibrator = PoseCalibrator()
self.speed = 0.0 self.speed = 0.0
self.yaw_rate = 0.0 self.yaw_rate = 0.0
@ -53,15 +51,12 @@ class ParamsLearner:
def handle_log(self, t, which, msg): def handle_log(self, t, which, msg):
if which == 'livePose': if which == 'livePose':
angular_velocity_device = np.array([msg.angularVelocityDevice.x, msg.angularVelocityDevice.y, msg.angularVelocityDevice.z]) device_pose = Pose.from_live_pose(msg)
angular_velocity_device_std = np.array([msg.angularVelocityDevice.xStd, msg.angularVelocityDevice.yStd, msg.angularVelocityDevice.zStd]) calibrated_pose = self.calibrator.build_calibrated_pose(device_pose)
angular_velocity_calibrated = np.matmul(self.calib_from_device, angular_velocity_device) self.yaw_rate, self.yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
angular_velocity_calibrated_std = rotate_std(self.calib_from_device, angular_velocity_device_std)
self.yaw_rate, self.yaw_rate_std = angular_velocity_calibrated[2], angular_velocity_calibrated_std[2] localizer_roll, localizer_roll_std = device_pose.orientation.x, device_pose.orientation.x_std
localizer_roll_std = np.radians(1) if np.isnan(localizer_roll_std) else localizer_roll_std
localizer_roll = msg.orientationNED.x
localizer_roll_std = np.radians(1) if np.isnan(msg.orientationNED.xStd) else msg.orientationNED.xStd
self.roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK self.roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK
if self.roll_valid: if self.roll_valid:
roll = localizer_roll roll = localizer_roll
@ -73,7 +68,7 @@ class ParamsLearner:
roll_std = np.radians(10.0) roll_std = np.radians(10.0)
self.roll = clip(roll, self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA) self.roll = clip(roll, self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA)
yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrated yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrator.calib_valid
yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s
yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s
@ -101,9 +96,7 @@ class ParamsLearner:
self.kf.predict_and_observe(t, ObservationKind.STEER_RATIO, np.array([[steer_ratio]])) self.kf.predict_and_observe(t, ObservationKind.STEER_RATIO, np.array([[steer_ratio]]))
elif which == 'liveCalibration': elif which == 'liveCalibration':
self.calibrated = msg.calStatus == log.LiveCalibrationData.Status.calibrated self.calibrator.feed_live_calib(msg)
device_from_calib = rot_from_euler(np.array(msg.rpyCalib))
self.calib_from_device = device_from_calib.T
elif which == 'carState': elif which == 'carState':
self.steering_angle = msg.steeringAngleDeg self.steering_angle = msg.steeringAngleDeg

@ -8,9 +8,8 @@ from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, DT_MDL from openpilot.common.realtime import config_realtime_process, DT_MDL
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.common.transformations.orientation import rot_from_euler
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator from openpilot.selfdrive.locationd.helpers import PointBuckets, ParameterEstimator, PoseCalibrator, Pose
HISTORY = 5 # secs HISTORY = 5 # secs
POINTS_PER_BUCKET = 1500 POINTS_PER_BUCKET = 1500
@ -78,7 +77,7 @@ class TorqueEstimator(ParameterEstimator):
self.offline_friction = CP.lateralTuning.torque.friction self.offline_friction = CP.lateralTuning.torque.friction
self.offline_latAccelFactor = CP.lateralTuning.torque.latAccelFactor self.offline_latAccelFactor = CP.lateralTuning.torque.latAccelFactor
self.calib_from_device = np.eye(3) self.calibrator = PoseCalibrator()
self.reset() self.reset()
@ -175,17 +174,17 @@ class TorqueEstimator(ParameterEstimator):
self.raw_points["vego"].append(msg.vEgo) self.raw_points["vego"].append(msg.vEgo)
self.raw_points["steer_override"].append(msg.steeringPressed) self.raw_points["steer_override"].append(msg.steeringPressed)
elif which == "liveCalibration": elif which == "liveCalibration":
device_from_calib = rot_from_euler(np.array(msg.rpyCalib)) self.calibrator.feed_live_calib(msg)
self.calib_from_device = device_from_calib.T
# calculate lateral accel from past steering torque # calculate lateral accel from past steering torque
elif which == "livePose": elif which == "livePose":
if len(self.raw_points['steer_torque']) == self.hist_len: if len(self.raw_points['steer_torque']) == self.hist_len:
angular_velocity_device = np.array([msg.angularVelocityDevice.x, msg.angularVelocityDevice.y, msg.angularVelocityDevice.z]) device_pose = Pose.from_live_pose(msg)
angular_velocity_calibrated = np.matmul(self.calib_from_device, angular_velocity_device) calibrated_pose = self.calibrator.build_calibrated_pose(device_pose)
angular_velocity_calibrated = calibrated_pose.angular_velocity
yaw_rate = angular_velocity_calibrated[2] yaw_rate = angular_velocity_calibrated.yaw
roll = msg.orientationNED.x roll = device_pose.orientation.roll
# check lat active up to now (without lag compensation) # check lat active up to now (without lag compensation)
lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t + self.lag, DT_MDL), lat_active = np.interp(np.arange(t - MIN_ENGAGE_BUFFER, t + self.lag, DT_MDL),
self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool) self.raw_points['carControl_t'], self.raw_points['lat_active']).astype(bool)

@ -1,2 +1,2 @@
#!/bin/bash #!/usr/bin/env bash
clang++ -I /home/batman/one/external/tensorflow/include/ -L /home/batman/one/external/tensorflow/lib -Wl,-rpath=/home/batman/one/external/tensorflow/lib main.cc -ltensorflow clang++ -I /home/batman/one/external/tensorflow/include/ -L /home/batman/one/external/tensorflow/lib -Wl,-rpath=/home/batman/one/external/tensorflow/lib main.cc -ltensorflow

@ -466,6 +466,11 @@ def controlsd_config_callback(params, cfg, lr):
assert controlsState is not None and initialized, "controlsState never initialized" assert controlsState is not None and initialized, "controlsState never initialized"
params.put("ReplayControlsState", controlsState.as_builder().to_bytes()) params.put("ReplayControlsState", controlsState.as_builder().to_bytes())
ublox = params.get_bool("UbloxAvailable")
sub_keys = ({"gpsLocation", } if ublox else {"gpsLocationExternal", })
cfg.pubs = set(cfg.pubs) - sub_keys
def locationd_config_pubsub_callback(params, cfg, lr): def locationd_config_pubsub_callback(params, cfg, lr):
ublox = params.get_bool("UbloxAvailable") ublox = params.get_bool("UbloxAvailable")
@ -479,9 +484,10 @@ CONFIGS = [
proc_name="controlsd", proc_name="controlsd",
pubs=[ pubs=[
"carState", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState", "carState", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState",
"longitudinalPlan", "liveLocationKalman", "liveParameters", "radarState", "longitudinalPlan", "livePose", "liveParameters", "radarState",
"modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState", "modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState",
"testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope", "carOutput" "testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope", "carOutput",
"gpsLocationExternal", "gpsLocation",
], ],
subs=["controlsState", "carControl", "onroadEvents"], subs=["controlsState", "carControl", "onroadEvents"],
ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"], ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"],

@ -1 +1 @@
6ca7313b9c1337fad1334d9e087cb4984fdce74d d768496a1a85bfe5b74c99a79203affdf9a0a065

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
SCRIPT_DIR=$(dirname "$0") SCRIPT_DIR=$(dirname "$0")
BASEDIR=$(realpath "$SCRIPT_DIR/../../") BASEDIR=$(realpath "$SCRIPT_DIR/../../")

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
@ -23,7 +23,7 @@ rm -rf /data/safe_staging/* || true
CONTINUE_PATH="/data/continue.sh" CONTINUE_PATH="/data/continue.sh"
tee $CONTINUE_PATH << EOF tee $CONTINUE_PATH << EOF
#!/usr/bin/bash #!/usr/bin/env bash
sudo abctl --set_success sudo abctl --set_success

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
{ {
#start pulseaudio daemon #start pulseaudio daemon

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
cd /data/openpilot cd /data/openpilot
exec ./launch_openpilot.sh exec ./launch_openpilot.sh

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
#nmcli connection modify --temporary lte gsm.home-only yes #nmcli connection modify --temporary lte gsm.home-only yes
#nmcli connection modify --temporary lte gsm.auto-config yes #nmcli connection modify --temporary lte gsm.auto-config yes

@ -96,7 +96,7 @@ class TestPowerDraw:
return now, msg_counts, time.monotonic() - start_time - SAMPLE_TIME return now, msg_counts, time.monotonic() - start_time - SAMPLE_TIME
@mock_messages(['liveLocationKalman']) @mock_messages(['livePose'])
def test_camera_procs(self, subtests): def test_camera_procs(self, subtests):
baseline = get_power() baseline = get_power()

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import os import os
import argparse import argparse
import threading import threading

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import sys import sys
import termios import termios
import atexit import atexit

@ -23,7 +23,7 @@ function op_install() {
echo "Installing op system-wide..." echo "Installing op system-wide..."
CMD="\nalias op='"$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n" CMD="\nalias op='"$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )/op.sh" \"\$@\"'\n"
grep "alias op=" "$RC_FILE" &> /dev/null || printf "$CMD" >> $RC_FILE grep "alias op=" "$RC_FILE" &> /dev/null || printf "$CMD" >> $RC_FILE
echo -e " ↳ [${GREEN}${NC}] op installed successfully. Open a new shell to use it.\n" echo -e " ↳ [${GREEN}${NC}] op installed successfully. Open a new shell to use it."
} }
function loge() { function loge() {
@ -37,7 +37,13 @@ function loge() {
function op_run_command() { function op_run_command() {
CMD="$@" CMD="$@"
echo -e "${BOLD}Running:${NC} $CMD"
echo -e "${BOLD}Running command →${NC} $CMD"
for ((i=0; i<$((19 + ${#CMD})); i++)); do
echo -n "─"
done
echo -e "┘\n"
if [[ -z "$DRY" ]]; then if [[ -z "$DRY" ]]; then
eval "$CMD" eval "$CMD"
fi fi
@ -58,7 +64,7 @@ function op_get_openpilot_dir() {
function op_check_openpilot_dir() { function op_check_openpilot_dir() {
echo "Checking for openpilot directory..." echo "Checking for openpilot directory..."
if [[ -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]]; then if [[ -f "$OPENPILOT_ROOT/launch_openpilot.sh" ]]; then
echo -e " ↳ [${GREEN}${NC}] openpilot found.\n" echo -e " ↳ [${GREEN}${NC}] openpilot found."
return 0 return 0
fi fi
@ -118,7 +124,7 @@ function op_check_os() {
fi fi
elif [[ "$OSTYPE" == "darwin"* ]]; then elif [[ "$OSTYPE" == "darwin"* ]]; then
echo -e " ↳ [${GREEN}${NC}] macOS detected.\n" echo -e " ↳ [${GREEN}${NC}] macOS detected."
else else
echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!" echo -e " ↳ [${RED}${NC}] OS type $OSTYPE not supported!"
loge "ERROR_UNKNOWN_OS" "$OSTYPE" loge "ERROR_UNKNOWN_OS" "$OSTYPE"
@ -171,7 +177,7 @@ function op_before_cmd() {
result="${result}\n$(( op_check_python ) 2>&1)" || (echo -e "$result" && return 1) result="${result}\n$(( op_check_python ) 2>&1)" || (echo -e "$result" && return 1)
if [[ -z $VERBOSE ]]; then if [[ -z $VERBOSE ]]; then
echo -e "Checking system → [${GREEN}${NC}] system is good." echo -e "${BOLD}Checking system →${NC} [${GREEN}${NC}]"
else else
echo -e "$result" echo -e "$result"
fi fi
@ -183,7 +189,6 @@ function op_setup() {
op_check_openpilot_dir op_check_openpilot_dir
op_check_os op_check_os
op_check_python
echo "Installing dependencies..." echo "Installing dependencies..."
st="$(date +%s)" st="$(date +%s)"
@ -192,33 +197,33 @@ function op_setup() {
elif [[ "$OSTYPE" == "darwin"* ]]; then elif [[ "$OSTYPE" == "darwin"* ]]; then
SETUP_SCRIPT="tools/mac_setup.sh" SETUP_SCRIPT="tools/mac_setup.sh"
fi fi
if ! op_run_command "$OPENPILOT_ROOT/$SETUP_SCRIPT"; then if ! $OPENPILOT_ROOT/$SETUP_SCRIPT; then
echo -e " ↳ [${RED}${NC}] Dependencies installation failed!" echo -e " ↳ [${RED}${NC}] Dependencies installation failed!"
loge "ERROR_DEPENDENCIES_INSTALLATION" loge "ERROR_DEPENDENCIES_INSTALLATION"
return 1 return 1
fi fi
et="$(date +%s)" et="$(date +%s)"
echo -e " ↳ [${GREEN}${NC}] Dependencies installed successfully in $((et - st)) seconds.\n" echo -e " ↳ [${GREEN}${NC}] Dependencies installed successfully in $((et - st)) seconds."
echo "Getting git submodules..." echo "Getting git submodules..."
st="$(date +%s)" st="$(date +%s)"
if ! op_run_command git submodule update --filter=blob:none --jobs 4 --init --recursive; then if ! git submodule update --filter=blob:none --jobs 4 --init --recursive; then
echo -e " ↳ [${RED}${NC}] Getting git submodules failed!" echo -e " ↳ [${RED}${NC}] Getting git submodules failed!"
loge "ERROR_GIT_SUBMODULES" loge "ERROR_GIT_SUBMODULES"
return 1 return 1
fi fi
et="$(date +%s)" et="$(date +%s)"
echo -e " ↳ [${GREEN}${NC}] Submodules installed successfully in $((et - st)) seconds.\n" echo -e " ↳ [${GREEN}${NC}] Submodules installed successfully in $((et - st)) seconds."
echo "Pulling git lfs files..." echo "Pulling git lfs files..."
st="$(date +%s)" st="$(date +%s)"
if ! op_run_command git lfs pull; then if ! git lfs pull; then
echo -e " ↳ [${RED}${NC}] Pulling git lfs files failed!" echo -e " ↳ [${RED}${NC}] Pulling git lfs files failed!"
loge "ERROR_GIT_LFS" loge "ERROR_GIT_LFS"
return 1 return 1
fi fi
et="$(date +%s)" et="$(date +%s)"
echo -e " ↳ [${GREEN}${NC}] Files pulled successfully in $((et - st)) seconds.\n" echo -e " ↳ [${GREEN}${NC}] Files pulled successfully in $((et - st)) seconds."
op_check op_check
} }
@ -268,7 +273,7 @@ function op_juggle() {
function op_lint() { function op_lint() {
op_before_cmd op_before_cmd
op_run_command scripts/lint.sh $@ op_run_command scripts/lint/lint.sh $@
} }
function op_test() { function op_test() {
@ -328,8 +333,6 @@ function op_default() {
echo " Don't actually run anything, just print what would be run" echo " Don't actually run anything, just print what would be run"
echo -e " ${BOLD}-n, --no-verify${NC}" echo -e " ${BOLD}-n, --no-verify${NC}"
echo " Skip environment check before running commands" echo " Skip environment check before running commands"
echo -e " ${BOLD}-v, --verbose${NC}"
echo " Show the result of all checks before running a command"
echo "" echo ""
echo -e "${BOLD}${UNDERLINE}Examples:${NC}" echo -e "${BOLD}${UNDERLINE}Examples:${NC}"
echo " op setup" echo " op setup"
@ -350,7 +353,6 @@ function _op() {
-d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;; -d | --dir ) shift 1; OPENPILOT_ROOT="$1"; shift 1 ;;
--dry ) shift 1; DRY="1" ;; --dry ) shift 1; DRY="1" ;;
-n | --no-verify ) shift 1; NO_VERIFY="1" ;; -n | --no-verify ) shift 1; NO_VERIFY="1" ;;
-v | --verbose ) shift 1; VERBOSE="1" ;;
-l | --log ) shift 1; LOG_FILE="$1" ; shift 1 ;; -l | --log ) shift 1; LOG_FILE="$1" ; shift 1 ;;
esac esac

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd $DIR cd $DIR

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
cd /sys/kernel/tracing cd /sys/kernel/tracing

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
if [ ! -d perfetto ]; then if [ ! -d perfetto ]; then
git clone https://android.googlesource.com/platform/external/perfetto/ git clone https://android.googlesource.com/platform/external/perfetto/

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
DEST=tici:/data/openpilot/selfdrive/debug/profiling/perfetto DEST=tici:/data/openpilot/selfdrive/debug/profiling/perfetto

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd $DIR cd $DIR

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
curl -LO https://get.perfetto.dev/trace_processor curl -LO https://get.perfetto.dev/trace_processor
chmod +x ./trace_processor chmod +x ./trace_processor

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
DEST=tici:/data/openpilot/selfdrive/debug/profiling/perfetto DEST=tici:/data/openpilot/selfdrive/debug/profiling/perfetto

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# TODO: there's probably a better way to do this # TODO: there's probably a better way to do this

@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# install depends # install depends
sudo apt update sudo apt update

@ -1,4 +1,4 @@
#!/usr/bin/bash #!/usr/bin/env bash
set -e set -e
RUBYOPT="-W0" irqtop -d1 -R RUBYOPT="-W0" irqtop -d1 -R

@ -1,4 +1,4 @@
#! /bin/bash #!/usr/bin/env bash
# TODO: remove this file once Rerun has interface to set log message level # TODO: remove this file once Rerun has interface to set log message level
set -e set -e

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import argparse import argparse
import os import os
import sys import sys

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

Loading…
Cancel
Save