Merge remote-tracking branch 'upstream/master' into ford-vehicle-cfg-lca

pull/31821/head
Shane Smiskol 1 year ago
commit 76495f227c
  1. 3
      .devcontainer/devcontainer.json
  2. 222
      .github/workflows/auto_pr_review.yaml
  3. 24
      .github/workflows/selfdrive_tests.yaml
  4. 2
      .github/workflows/tools_tests.yaml
  5. 4
      .gitignore
  6. 4
      .pre-commit-config.yaml
  7. 12
      Dockerfile.openpilot_base
  8. 2
      cereal
  9. 2
      common/api/__init__.py
  10. 4
      common/gpio.py
  11. 2
      common/spinner.py
  12. 4
      common/stat_live.py
  13. 1
      docs/BOUNTIES.md
  14. 24
      pyproject.toml
  15. 21
      release/files_common
  16. 2
      selfdrive/car/body/carcontroller.py
  17. 104
      selfdrive/car/card.py
  18. 2
      selfdrive/car/chrysler/carcontroller.py
  19. 10
      selfdrive/car/chrysler/fingerprints.py
  20. 2
      selfdrive/car/ford/carcontroller.py
  21. 2
      selfdrive/car/gm/carcontroller.py
  22. 2
      selfdrive/car/honda/carcontroller.py
  23. 2
      selfdrive/car/hyundai/carcontroller.py
  24. 1
      selfdrive/car/hyundai/fingerprints.py
  25. 2
      selfdrive/car/mazda/carcontroller.py
  26. 2
      selfdrive/car/mock/carcontroller.py
  27. 2
      selfdrive/car/nissan/carcontroller.py
  28. 2
      selfdrive/car/subaru/carcontroller.py
  29. 2
      selfdrive/car/tesla/carcontroller.py
  30. 4
      selfdrive/car/tests/test_car_interfaces.py
  31. 12
      selfdrive/car/tests/test_models.py
  32. 2
      selfdrive/car/toyota/carcontroller.py
  33. 1
      selfdrive/car/toyota/fingerprints.py
  34. 2
      selfdrive/car/volkswagen/carcontroller.py
  35. 42
      selfdrive/controls/controlsd.py
  36. 2
      selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py
  37. 2
      selfdrive/controls/lib/pid.py
  38. 4
      selfdrive/controls/radard.py
  39. 2
      selfdrive/controls/tests/test_following_distance.py
  40. 3
      selfdrive/controls/tests/test_startup.py
  41. 2
      selfdrive/debug/vw_mqb_config.py
  42. 2
      selfdrive/locationd/models/car_kf.py
  43. 4
      selfdrive/locationd/models/live_kf.py
  44. 2
      selfdrive/manager/build.py
  45. 4
      selfdrive/manager/manager.py
  46. 2
      selfdrive/manager/process.py
  47. 9
      selfdrive/manager/process_config.py
  48. 7
      selfdrive/modeld/modeld.py
  49. 8
      selfdrive/monitoring/driver_monitor.py
  50. 2
      selfdrive/test/docker_build.sh
  51. 2
      selfdrive/test/longitudinal_maneuvers/plant.py
  52. 22
      selfdrive/test/process_replay/migration.py
  53. 32
      selfdrive/test/process_replay/process_replay.py
  54. 2
      selfdrive/test/process_replay/ref_commit
  55. 2
      selfdrive/test/process_replay/test_fuzzy.py
  56. 4
      selfdrive/test/process_replay/test_imgproc.py
  57. 36
      selfdrive/test/process_replay/test_processes.py
  58. 4
      selfdrive/test/profiling/lib.py
  59. 9
      selfdrive/test/test_onroad.py
  60. 15
      selfdrive/ui/ui.cc
  61. 0
      system/athena/__init__.py
  62. 0
      system/athena/athenad.py
  63. 2
      system/athena/manage_athenad.py
  64. 0
      system/athena/registration.py
  65. 0
      system/athena/tests/__init__.py
  66. 6
      system/athena/tests/helpers.py
  67. 8
      system/athena/tests/test_athenad.py
  68. 4
      system/athena/tests/test_athenad_ping.py
  69. 12
      system/athena/tests/test_registration.py
  70. 6
      system/loggerd/tests/loggerd_tests_common.py
  71. 2
      system/sentry.py
  72. 4
      system/statsd.py
  73. 0
      system/thermald/__init__.py
  74. 0
      system/thermald/fan_controller.py
  75. 2
      system/thermald/power_monitoring.py
  76. 0
      system/thermald/tests/__init__.py
  77. 2
      system/thermald/tests/test_fan_controller.py
  78. 6
      system/thermald/tests/test_power_monitoring.py
  79. 6
      system/thermald/thermald.py
  80. 2
      system/tombstoned.py
  81. 2
      system/ubloxd/pigeond.py
  82. 3
      system/updated/casync/tar.py
  83. 2
      system/version.py
  84. 2
      system/webrtc/tests/test_webrtcd.py
  85. 12
      system/webrtc/webrtcd.py
  86. 60
      tools/install_ubuntu_dependencies.sh
  87. 2
      tools/lib/api.py
  88. 1
      tools/sim/tests/test_metadrive_bridge.py

@ -14,6 +14,7 @@
"force_color_prompt": "1"
},
"runArgs": [
"--volume=/dev:/dev",
"--volume=/tmp/.X11-unix:/tmp/.X11-unix",
"--volume=${localWorkspaceFolder}/.devcontainer/.host/.Xauthority:/home/batman/.Xauthority",
"--volume=${localEnv:HOME}/.comma:/home/batman/.comma",
@ -49,4 +50,4 @@
"mounts": [
"type=volume,source=scons_cache,target=/tmp/scons_cache"
]
}
}

@ -5,7 +5,7 @@ on:
jobs:
labeler:
name: apply labels
name: review
permissions:
contents: read
pull-requests: write
@ -14,17 +14,17 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: false
# Label PRs
- uses: actions/labeler@v5.0.0
with:
dot: true
configuration-path: .github/labeler.yaml
pr_branch_check:
name: check branch
runs-on: ubuntu-latest
if: github.repository == 'commaai/openpilot'
steps:
- uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
# Check PR target branch
- name: check branch
uses: Vankka/pr-target-branch-action@def32ec9d93514138d6ac0132ee62e120a72aed5
if: github.repository == 'commaai/openpilot'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -34,194 +34,20 @@ jobs:
already-exists-action: close_this
already-exists-comment: "Your PR should be made against the `master` branch"
comment:
runs-on: ubuntu-latest
steps:
- name: comment
uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
with:
message: |
<!-- _(run_id **${{ github.run_id }}**)_ -->
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following:
* Convert your PR to a draft unless it's ready to review
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md)
* Before marking as "ready for review", ensure:
* the goal is clearly stated in the description
* all the tests are passing
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
* include a route or your device' dongle ID if relevant
comment_tag: run_id
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
check-pr-template:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
actions: read
if: false && github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
steps:
- uses: actions/github-script@v7
with:
script: |
// Comment to add to the PR if no template has been used
const NO_TEMPLATE_MESSAGE =
"It looks like you didn't use one of the Pull Request templates. Please check [the contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md). \
Also make sure that you didn't modify any of the checkboxes or headings within the template.";
// body data for future requests
const body_data = {
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
};
// Utility function to extract all headings
const extractHeadings = (markdown) => {
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
const boldTextRegex = /^(?:\*\*|__)(.+?)(?:\*\*|__)\s*$/gm;
const headings = [];
let headingMatch;
while ((headingMatch = headingRegex.exec(markdown))) {
headings.push(headingMatch[2].trim());
}
let boldMatch;
while ((boldMatch = boldTextRegex.exec(markdown))) {
headings.push(boldMatch[1].trim());
}
return headings;
};
// Utility function to extract all check box descriptions
const extractCheckBoxTexts = (markdown) => {
const checkboxRegex = /^\s*-\s*\[( |x)\]\s+(.+)$/gm;
const checkboxes = [];
let match;
while ((match = checkboxRegex.exec(markdown))) {
checkboxes.push(match[2].trim());
}
return checkboxes;
};
// Utility function to check if a list is a subset of another list
isSubset = (subset, superset) => {
return subset.every((item) => superset.includes(item));
};
// Utility function to check if a list of checkboxes is a subset of another list of checkboxes
isCheckboxSubset = (templateCheckBoxTexts, prTextCheckBoxTexts) => {
// Check if each template checkbox text is a substring of at least one PR checkbox text
// (user should be allowed to add additional text)
return templateCheckBoxTexts.every((item) => prTextCheckBoxTexts.some((element) => element.includes(item)))
}
// Get filenames of all currently checked-in PR templates
const template_contents = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: ".github/PULL_REQUEST_TEMPLATE",
});
var template_filenames = [];
for (const content of template_contents.data) {
template_filenames.push(content.path);
}
console.debug("Received template filenames: " + template_filenames);
// Retrieve templates
var templates = [];
for (const template_filename of template_filenames) {
const template_response = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: template_filename,
});
// Convert Base64 content back
const decoded_template = atob(template_response.data.content);
const headings = extractHeadings(decoded_template);
const checkboxes = extractCheckBoxTexts(decoded_template);
if (!headings.length && !checkboxes.length) {
console.warn(
"Invalid template! Contains neither headings nor checkboxes, ignoring it: \n" +
decoded_template
);
} else {
templates.push({ headings: headings, checkboxes: checkboxes });
}
}
// Retrieve the PR Body
const pull_request = await github.rest.issues.get({
...body_data,
});
const pull_request_text = pull_request.data.body;
console.debug("Received Pull Request body: \n" + pull_request_text);
/* Check if the PR Body matches one of the templates
A template is defined by all headings and checkboxes it contains
We extract all Headings and Checkboxes from the PR text and check if any of the templates is a subset of that
*/
const pr_headings = extractHeadings(pull_request_text);
const pr_checkboxes = extractCheckBoxTexts(pull_request_text);
console.debug("Found Headings in PR body:\n" + pr_headings);
console.debug("Found Checkboxes in PR body:\n" + pr_checkboxes);
var template_found = false;
// Iterate over each template to check if it applies
for (const template of templates) {
console.log(
"Checking for headings: [" +
template.headings +
"] and checkboxes: [" +
template.checkboxes + "]"
);
if (
isCheckboxSubset(template.checkboxes, pr_checkboxes) &&
isSubset(template.headings, pr_headings)
) {
console.debug("Found matching template!");
template_found = true;
}
}
// List comments from previous runs
var existing_comments = [];
const comments = await github.rest.issues.listComments({
...body_data,
});
for (const comment of comments.data) {
if (comment.body === NO_TEMPLATE_MESSAGE) {
existing_comments.push(comment);
}
}
// Add a comment to the PR that it is not using a the template (but only if this comment does not exist already)
if (!template_found) {
var comment_already_sent = false;
// Add an 'in-bot-review' label since this PR doesn't have the template
github.rest.issues.addLabels({
...body_data,
labels: ["in-bot-review"],
});
if (existing_comments.length < 1) {
github.rest.issues.createComment({
...body_data,
body: NO_TEMPLATE_MESSAGE,
});
}
} else {
// If template has been found, delete any old comment about missing template
for (const existing_comment of existing_comments) {
github.rest.issues.deleteComment({
...body_data,
comment_id: existing_comment.id,
});
}
// Remove the 'in-bot-review' label after the review is done and the PR has passed
github.rest.issues.removeLabel({
...body_data,
name: "in-bot-review",
}).catch((error) => {
console.log("Label 'in-bot-review' not found, ignoring");
});
}
# Welcome comment
- name: comment
uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6
if: github.event.pull_request.head.repo.full_name != 'commaai/openpilot'
with:
message: |
<!-- _(run_id **${{ github.run_id }}**)_ -->
Thanks for contributing to openpilot! In order for us to review your PR as quickly as possible, check the following:
* Convert your PR to a draft unless it's ready to review
* Read the [contributing docs](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md)
* Before marking as "ready for review", ensure:
* the goal is clearly stated in the description
* all the tests are passing
* the change is [something we merge](https://github.com/commaai/openpilot/blob/master/docs/CONTRIBUTING.md#what-gets-merged)
* include a route or your device' dongle ID if relevant
comment_tag: run_id
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -76,24 +76,8 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/workflows/setup-with-retry
with:
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
- uses: ./.github/workflows/compile-openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
docker_push:
name: docker push
strategy:
matrix:
arch: ${{ fromJson( (github.repository == 'commaai/openpilot') && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
runs-on: ${{ (matrix.arch == 'aarch64') && 'namespace-profile-arm64-2x8' || 'ubuntu-latest' }}
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup to push to repo
- name: Setup docker push
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
run: |
echo "PUSH_IMAGE=true" >> "$GITHUB_ENV"
echo "TARGET_ARCHITECTURE=${{ matrix.arch }}" >> "$GITHUB_ENV"
@ -101,12 +85,14 @@ jobs:
- uses: ./.github/workflows/setup-with-retry
with:
docker_hub_pat: ${{ secrets.DOCKER_HUB_PAT }}
- uses: ./.github/workflows/compile-openpilot
timeout-minutes: ${{ ((steps.restore-scons-cache.outputs.cache-hit == 'true') && 15 || 30) }} # allow more time when we missed the scons cache
docker_push_multiarch:
name: docker push multiarch tag
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/openpilot'
needs: [docker_push]
needs: [build]
steps:
- uses: actions/checkout@v4
with:

@ -59,7 +59,7 @@ jobs:
${{ env.RUN }} "export MAPBOX_TOKEN='pk.eyJ1Ijoiam5ld2IiLCJhIjoiY2xxNW8zZXprMGw1ZzJwbzZneHd2NHljbSJ9.gV7VPRfbXFetD-1OVF0XZg' && \
source selfdrive/test/setup_xvfb.sh && \
source selfdrive/test/setup_vsound.sh && \
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py -W ignore::pyopencl.CompilerWarning"
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py"
devcontainer:
name: devcontainer

4
.gitignore vendored

@ -55,12 +55,8 @@ selfdrive/modeld/_modeld
selfdrive/modeld/_dmonitoringmodeld
/src/
one
notebooks
xx
yy
hyperthneed
panda_jungle
provisioning
.coverage*

@ -47,7 +47,7 @@ repos:
args:
- --local-partial-types
- --explicit-package-bases
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)|(xx/)'
exclude: '^(third_party/)|(cereal/)|(opendbc/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
- repo: local
hooks:
- id: cppcheck
@ -89,7 +89,7 @@ repos:
entry: selfdrive/ui/tests/test_translations.py
language: script
pass_filenames: false
files: 'selfdrive/ui/translations/*'
files: '^selfdrive/ui/translations/'
- repo: https://github.com/python-poetry/poetry
rev: '1.8.0'
hooks:

@ -13,14 +13,10 @@ ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
RUN cd /tmp && \
tools/install_ubuntu_dependencies.sh && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/* && \
# remove unused architectures from gcc for panda
RUN INSTALL_EXTRA_PACKAGES=no /tmp/tools/install_ubuntu_dependencies.sh && \
rm -rf /var/lib/apt/lists/* /tmp/* && \
cd /usr/lib/gcc/arm-none-eabi/9.2.1 && \
rm -rf arm/ && \
rm -rf thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
# Add OpenCL
RUN apt-get update && apt-get install -y --no-install-recommends \
@ -83,4 +79,4 @@ RUN cd /tmp && \
rm -rf /home/$USER/pyenv/versions/3.11.4/lib/python3.11/test
USER root
RUN sudo git config --global --add safe.directory /tmp/openpilot
RUN sudo git config --global --add safe.directory /tmp/openpilot

@ -1 +1 @@
Subproject commit 0a9b426e55653daea6cc9d3c40c3f7600ec0db49
Subproject commit 5812f2c075a5364cecafe4e8ed68a12b12a5631f

@ -7,7 +7,7 @@ from openpilot.system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
class Api():
class Api:
def __init__(self, dongle_id):
self.dongle_id = dongle_id
with open(Paths.persist_root()+'/comma/id_rsa') as f:

@ -1,5 +1,5 @@
import os
from functools import lru_cache
from functools import cache
def gpio_init(pin: int, output: bool) -> None:
try:
@ -35,7 +35,7 @@ def gpio_export(pin: int) -> None:
except Exception:
print(f"Failed to export gpio {pin}")
@lru_cache(maxsize=None)
@cache
def get_irq_action(irq: int) -> list[str]:
try:
with open(f"/sys/kernel/irq/{irq}/actions") as f:

@ -3,7 +3,7 @@ import subprocess
from openpilot.common.basedir import BASEDIR
class Spinner():
class Spinner:
def __init__(self):
try:
self.spinner_proc = subprocess.Popen(["./spinner"],

@ -1,6 +1,6 @@
import numpy as np
class RunningStat():
class RunningStat:
# tracks realtime mean and standard deviation without storing any data
def __init__(self, priors=None, max_trackable=-1):
self.max_trackable = max_trackable
@ -51,7 +51,7 @@ class RunningStat():
def params_to_save(self):
return [self.M, self.S, self.n]
class RunningStatFilter():
class RunningStatFilter:
def __init__(self, raw_priors=None, filtered_priors=None, max_trackable=-1):
self.raw_stat = RunningStat(raw_priors, -1)
self.filtered_stat = RunningStat(filtered_priors, max_trackable)

@ -9,6 +9,7 @@ Get paid to improve openpilot!
* once you open a PR, the bounty is locked to you until you stop working on it
* open a ticket at [comma.ai/support](https://comma.ai/support/shop-order) with links to your PRs to claim
* get an extra 20% if you redeem your bounty in [comma shop](https://comma.ai/shop) credit (including refunds on previous orders)
* for bounties >$100, the first PR gets a lock, which times out after a week of no progress
We put up each bounty with the intention that it'll get merged, but occasionally the right resolution is to close the bounty, which only becomes clear once some effort is put in.
This is still valuable work, so we'll pay out $100 for getting any bounty closed with a good explanation.

@ -20,17 +20,17 @@ markers = [
]
testpaths = [
"common",
"selfdrive/athena",
"selfdrive/boardd",
"selfdrive/car",
"selfdrive/controls",
"selfdrive/locationd",
"selfdrive/monitoring",
"selfdrive/navd/tests",
"selfdrive/thermald",
"selfdrive/test/longitudinal_maneuvers",
"selfdrive/test/process_replay/test_fuzzy.py",
"selfdrive/updated",
"system/thermald",
"system/athena",
"system/camerad",
"system/hardware/tici",
"system/loggerd",
@ -184,8 +184,24 @@ build-backend = "poetry.core.masonry.api"
# https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
[tool.ruff]
indent-width = 2
lint.select = ["E", "F", "W", "PIE", "C4", "ISC", "RUF008", "RUF100", "A", "B", "TID251"]
lint.ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"]
lint.select = [
"E", "F", "W", "PIE", "C4", "ISC", "A", "B",
"NPY", # numpy
"UP", # pyupgrade
"TRY302", "TRY400", "TRY401", # try/excepts
"RUF008", "RUF100",
"TID251"
]
lint.ignore = [
"E741",
"E402",
"C408",
"ISC003",
"B027",
"B024",
"NPY002", # new numpy random syntax is worse
"UP038", # (x, y) -> x|y for isinstance
]
line-length = 160
target-version="py311"
exclude = [

@ -53,9 +53,6 @@ tools/replay/*.cc
tools/replay/*.h
selfdrive/__init__.py
selfdrive/sentry.py
selfdrive/tombstoned.py
selfdrive/statsd.py
selfdrive/updated/**
@ -65,10 +62,10 @@ system/version.py
selfdrive/SConscript
selfdrive/athena/__init__.py
selfdrive/athena/athenad.py
selfdrive/athena/manage_athenad.py
selfdrive/athena/registration.py
system/athena/__init__.py
system/athena/athenad.py
system/athena/manage_athenad.py
system/athena/registration.py
selfdrive/boardd/.gitignore
selfdrive/boardd/SConscript
@ -162,6 +159,10 @@ selfdrive/controls/lib/longitudinal_mpc_lib/*
system/__init__.py
system/*.py
system/sentry.py
system/tombstoned.py
system/statsd.py
system/hardware/__init__.py
system/hardware/base.h
system/hardware/base.py
@ -252,9 +253,9 @@ system/webrtc/schema.py
system/webrtc/device/audio.py
system/webrtc/device/video.py
selfdrive/thermald/thermald.py
selfdrive/thermald/power_monitoring.py
selfdrive/thermald/fan_controller.py
system/thermald/thermald.py
system/thermald/power_monitoring.py
system/thermald/fan_controller.py
selfdrive/test/__init__.py
selfdrive/test/fuzzy_generation.py

@ -75,7 +75,7 @@ class CarController(CarControllerBase):
can_sends = []
can_sends.append(bodycan.create_control(self.packer, torque_l, torque_r))
new_actuators = CC.actuators.copy()
new_actuators = CC.actuators.as_builder()
new_actuators.accel = torque_l
new_actuators.steer = torque_r
new_actuators.steerOutputCan = torque_r

@ -9,7 +9,7 @@ from cereal import car
from panda import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from openpilot.common.realtime import DT_CTRL
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
from openpilot.selfdrive.car.car_helpers import get_car, get_one_can
@ -21,22 +21,24 @@ REPLAY = "REPLAY" in os.environ
EventName = car.CarEvent.EventName
class CarD:
class Car:
CI: CarInterfaceBase
def __init__(self, CI=None):
self.can_sock = messaging.sub_sock('can', timeout=20)
self.sm = messaging.SubMaster(['pandaStates'])
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'])
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput'])
self.can_rcv_timeout_counter = 0 # consecutive timeout count
self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count
self.CC_prev = car.CarControl.new_message()
self.CS_prev = car.CarState.new_message()
self.initialized_prev = False
self.last_actuators = None
self.last_actuators_output = car.CarControl.Actuators.new_message()
self.params = Params()
params = Params()
if CI is None:
# wait for one pandaState and one CAN packet
@ -44,18 +46,18 @@ class CarD:
get_one_can(self.can_sock)
num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled")
experimental_long_allowed = params.get_bool("ExperimentalLongitudinalEnabled")
self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
else:
self.CI, self.CP = CI, CI.CP
# set alternative experiences from parameters
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
self.disengage_on_accelerator = params.get_bool("DisengageOnAccelerator")
self.CP.alternativeExperience = 0
if not self.disengage_on_accelerator:
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
@ -66,22 +68,20 @@ class CarD:
self.CP.safetyConfigs = [safety_config]
# Write previous route's CarParams
prev_cp = self.params.get("CarParamsPersistent")
prev_cp = params.get("CarParamsPersistent")
if prev_cp is not None:
self.params.put("CarParamsPrevRoute", prev_cp)
params.put("CarParamsPrevRoute", prev_cp)
# Write CarParams for controls and radard
cp_bytes = self.CP.to_bytes()
self.params.put("CarParams", cp_bytes)
self.params.put_nonblocking("CarParamsCache", cp_bytes)
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
params.put("CarParams", cp_bytes)
params.put_nonblocking("CarParamsCache", cp_bytes)
params.put_nonblocking("CarParamsPersistent", cp_bytes)
self.CS_prev = car.CarState.new_message()
self.events = Events()
def initialize(self):
"""Initialize CarInterface, once controls are ready"""
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
# card is driven by can recv, expected at 100Hz
self.rk = Ratekeeper(100, print_delay_threshold=None)
def state_update(self) -> car.CarState:
"""carState update loop, driven by can"""
@ -106,11 +106,6 @@ class CarD:
if can_rcv_valid and REPLAY:
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
self.update_events(CS)
self.state_publish(CS)
CS = CS.as_reader()
self.CS_prev = CS
return CS
def update_events(self, CS: car.CarState) -> car.CarState:
@ -129,12 +124,6 @@ class CarD:
def state_publish(self, CS: car.CarState):
"""carState and carParams publish loop"""
# carState
cs_send = messaging.new_message('carState')
cs_send.valid = CS.canValid
cs_send.carState = CS
self.pm.send('carState', cs_send)
# carParams - logged every 50 seconds (> 1 per segment)
if self.sm.frame % int(50. / DT_CTRL) == 0:
cp_send = messaging.new_message('carParams')
@ -144,17 +133,60 @@ class CarD:
# publish new carOutput
co_send = messaging.new_message('carOutput')
co_send.valid = True
if self.last_actuators is not None:
co_send.carOutput.actuatorsOutput = self.last_actuators
co_send.valid = self.sm.all_checks(['carControl'])
co_send.carOutput.actuatorsOutput = self.last_actuators_output
self.pm.send('carOutput', co_send)
# kick off controlsd step while we actuate the latest carControl packet
cs_send = messaging.new_message('carState')
cs_send.valid = CS.canValid
cs_send.carState = CS
cs_send.carState.canRcvTimeout = self.can_rcv_timeout
cs_send.carState.canErrorCounter = self.can_rcv_cum_timeout_counter
cs_send.carState.cumLagMs = -self.rk.remaining * 1000.
self.pm.send('carState', cs_send)
def controls_update(self, CS: car.CarState, CC: car.CarControl):
"""control update loop, driven by carControl"""
# send car controls over can
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
self.last_actuators, can_sends = self.CI.apply(CC, now_nanos)
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
if not self.initialized_prev:
# Initialize CarInterface, once controls are ready
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
if self.sm.all_alive(['carControl']):
# send car controls over can
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos)
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
self.CC_prev = CC
def step(self):
CS = self.state_update()
self.update_events(CS)
self.state_publish(CS)
initialized = (not any(e.name == EventName.controlsInitializing for e in self.sm['onroadEvents']) and
self.sm.seen['onroadEvents'])
if not self.CP.passive and initialized:
self.controls_update(CS, self.sm['carControl'])
self.initialized_prev = initialized
self.CS_prev = CS.as_reader()
def card_thread(self):
while True:
self.step()
self.rk.monitor_time()
def main():
config_realtime_process(4, Priority.CTRL_HIGH)
car = Car()
car.card_thread()
self.CC_prev = CC
if __name__ == "__main__":
main()

@ -78,7 +78,7 @@ class CarController(CarControllerBase):
self.frame += 1
new_actuators = CC.actuators.copy()
new_actuators = CC.actuators.as_builder()
new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

@ -68,6 +68,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [
b'68267018AO ',
b'68267020AJ ',
b'68303534AG ',
b'68303534AJ ',
b'68340762AD ',
b'68340764AD ',
@ -106,6 +107,7 @@ FW_VERSIONS = {
b'68405565AB',
b'68405565AC',
b'68444299AC',
b'68480707AC',
b'68480708AC',
b'68526663AB',
],
@ -147,6 +149,7 @@ FW_VERSIONS = {
b'68443120AE ',
b'68443123AC ',
b'68443125AC ',
b'68496647AI ',
b'68496647AJ ',
b'68496650AH ',
b'68496650AI ',
@ -264,6 +267,7 @@ FW_VERSIONS = {
},
CAR.JEEP_GRAND_CHEROKEE: {
(Ecu.combinationMeter, 0x742, None): [
b'68243549AG',
b'68302211AC',
b'68302212AD',
b'68302223AC',
@ -275,18 +279,22 @@ FW_VERSIONS = {
b'68340272AD',
],
(Ecu.srs, 0x744, None): [
b'68309533AA',
b'68316742AB',
b'68355363AB',
],
(Ecu.abs, 0x747, None): [
b'68252642AG',
b'68306178AD',
b'68336276AB',
],
(Ecu.fwdRadar, 0x753, None): [
b'04672627AB',
b'68251506AF',
b'68332015AB',
],
(Ecu.eps, 0x75a, None): [
b'68276201AG',
b'68321644AB',
b'68321644AC',
b'68321646AC',
@ -294,6 +302,7 @@ FW_VERSIONS = {
],
(Ecu.engine, 0x7e0, None): [
b'05035920AE ',
b'68252272AG ',
b'68284455AI ',
b'68284456AI ',
b'68284477AF ',
@ -304,6 +313,7 @@ FW_VERSIONS = {
],
(Ecu.transmission, 0x7e1, None): [
b'05035517AH',
b'68253222AF',
b'68311218AC',
b'68311223AF',
b'68311223AG',

@ -113,7 +113,7 @@ class CarController(CarControllerBase):
self.steer_alert_last = steer_alert
self.lead_distance_bars_last = hud_control.leadDistanceBars
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.curvature = self.apply_curvature_last
self.frame += 1

@ -155,7 +155,7 @@ class CarController(CarControllerBase):
if self.frame % 10 == 0:
can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status))
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last
new_actuators.gas = self.apply_gas

@ -244,7 +244,7 @@ class CarController(CarControllerBase):
self.speed = pcm_speed
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.speed = self.speed
new_actuators.accel = self.accel
new_actuators.gas = self.gas

@ -163,7 +163,7 @@ class CarController(CarControllerBase):
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steer = apply_steer / self.params.STEER_MAX
new_actuators.steerOutputCan = apply_steer
new_actuators.accel = accel

@ -864,6 +864,7 @@ FW_VERSIONS = {
b'\xf1\x00CN7_ SCC FNCUP 1.00 1.01 99110-AA000 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA050 4CNDC106',
b'\xf1\x00CN7 MDPS C 1.00 1.06 56310/AA070 4CNDC106',
b'\xf1\x00CN7 MDPS C 1.00 1.06 56310AA050\x00 4CNDC106',
b'\xf1\x00CN7 MDPS C 1.00 1.07 56310AA050\x00 4CNDC107',

@ -58,7 +58,7 @@ class CarController(CarControllerBase):
can_sends.append(mazdacan.create_steering_control(self.packer, self.CP,
self.frame, apply_steer, CS.cam_lkas))
new_actuators = CC.actuators.copy()
new_actuators = CC.actuators.as_builder()
new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX
new_actuators.steerOutputCan = apply_steer

@ -2,4 +2,4 @@ from openpilot.selfdrive.car.interfaces import CarControllerBase
class CarController(CarControllerBase):
def update(self, CC, CS, now_nanos):
return CC.actuators.copy(), []
return CC.actuators.as_builder(), []

@ -75,7 +75,7 @@ class CarController(CarControllerBase):
self.packer, CS.lkas_hud_info_msg, steer_hud_alert
))
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steeringAngleDeg = apply_angle
self.frame += 1

@ -136,7 +136,7 @@ class CarController(CarControllerBase):
if self.frame % 2 == 0:
can_sends.append(subarucan.create_es_static_2(self.packer))
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

@ -60,7 +60,7 @@ class CarController(CarControllerBase):
# TODO: HUD control
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steeringAngleDeg = self.apply_angle_last
self.frame += 1

@ -91,14 +91,14 @@ class TestCarInterfaces:
CC = car.CarControl.new_message(**cc_msg)
for _ in range(10):
car_interface.update(CC, [])
car_interface.apply(CC, now_nanos)
car_interface.apply(CC.as_reader(), now_nanos)
now_nanos += DT_CTRL * 1e9 # 10 ms
CC = car.CarControl.new_message(**cc_msg)
CC.enabled = True
for _ in range(10):
car_interface.update(CC, [])
car_interface.apply(CC, now_nanos)
car_interface.apply(CC.as_reader(), now_nanos)
now_nanos += DT_CTRL * 1e9 # 10ms
# Test controller initialization

@ -15,7 +15,7 @@ from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.car import gen_empty_fingerprint
from openpilot.selfdrive.car.card import CarD
from openpilot.selfdrive.car.card import Car
from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION
from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces
from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags
@ -215,7 +215,7 @@ class TestCarModelBase(unittest.TestCase):
# TODO: also check for checksum violations from can parser
can_invalid_cnt = 0
can_valid = False
CC = car.CarControl.new_message()
CC = car.CarControl.new_message().as_reader()
for i, msg in enumerate(self.can_msgs):
CS = self.CI.update(CC, (msg.as_builder().to_bytes(),))
@ -308,17 +308,17 @@ class TestCarModelBase(unittest.TestCase):
# Make sure we can send all messages while inactive
CC = car.CarControl.new_message()
test_car_controller(CC)
test_car_controller(CC.as_reader())
# Test cancel + general messages (controls_allowed=False & cruise_engaged=True)
self.safety.set_cruise_engaged_prev(True)
CC = car.CarControl.new_message(cruiseControl={'cancel': True})
test_car_controller(CC)
test_car_controller(CC.as_reader())
# Test resume + general messages (controls_allowed=True & cruise_engaged=True)
self.safety.set_controls_allowed(True)
CC = car.CarControl.new_message(cruiseControl={'resume': True})
test_car_controller(CC)
test_car_controller(CC.as_reader())
# Skip stdout/stderr capture with pytest, causes elevated memory usage
@pytest.mark.nocapture
@ -406,7 +406,7 @@ class TestCarModelBase(unittest.TestCase):
controls_allowed_prev = False
CS_prev = car.CarState.new_message()
checks = defaultdict(int)
card = CarD(CI=self.CI)
card = Car(CI=self.CI)
for idx, can in enumerate(self.can_msgs):
CS = self.CI.update(CC, (can.as_builder().to_bytes(), ))
for msg in filter(lambda m: m.src in range(64), can.can):

@ -168,7 +168,7 @@ class CarController(CarControllerBase):
if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value:
can_sends.append([0x750, 0, b"\x0F\x02\x3E\x00\x00\x00\x00\x00", 0])
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steer = apply_steer / self.params.STEER_MAX
new_actuators.steerOutputCan = apply_steer
new_actuators.steeringAngleDeg = self.last_angle

@ -1476,6 +1476,7 @@ FW_VERSIONS = {
b'\x01896630E41200\x00\x00\x00\x00',
b'\x01896630E41500\x00\x00\x00\x00',
b'\x01896630EA3100\x00\x00\x00\x00',
b'\x01896630EA3300\x00\x00\x00\x00',
b'\x01896630EA3400\x00\x00\x00\x00',
b'\x01896630EA4100\x00\x00\x00\x00',
b'\x01896630EA4300\x00\x00\x00\x00',

@ -112,7 +112,7 @@ class CarController(CarControllerBase):
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.ext_bus, CS.gra_stock_values,
cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume))
new_actuators = actuators.copy()
new_actuators = actuators.as_builder()
new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

@ -18,8 +18,7 @@ from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.car.car_helpers import get_startup_event
from openpilot.selfdrive.car.card import CarD
from openpilot.selfdrive.car.car_helpers import get_car_interface, get_startup_event
from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, clip_curvature
from openpilot.selfdrive.controls.lib.events import Events, ET
@ -61,16 +60,19 @@ ENABLED_STATES = (State.preEnabled, *ACTIVE_STATES)
class Controls:
def __init__(self, CI=None):
self.card = CarD(CI)
self.params = Params()
with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg:
# TODO: this shouldn't need to be a builder
self.CP = msg.as_builder()
self.CI = self.card.CI
if CI is None:
cloudlog.info("controlsd is waiting for CarParams")
with car.CarParams.from_bytes(self.params.get("CarParams", block=True)) as msg:
# TODO: this shouldn't need to be a builder
self.CP = msg.as_builder()
cloudlog.info("controlsd got CarParams")
# Uses car interface helper functions, altering state won't be considered by card for actuation
self.CI = get_car_interface(self.CP)
else:
self.CI, self.CP = CI, CI.CP
# Ensure the current branch is cached, otherwise the first iteration of controlsd lags
self.branch = get_short_branch()
@ -83,6 +85,9 @@ class Controls:
self.log_sock = messaging.sub_sock('androidLog')
# TODO: de-couple controlsd with card/conflate on carState without introducing controls mismatches
self.car_state_sock = messaging.sub_sock('carState', timeout=20)
ignore = self.sensor_packets + ['testJoystick']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
@ -110,6 +115,7 @@ class Controls:
if not self.CP.openpilotLongitudinalControl:
self.params.remove("ExperimentalMode")
self.CS_prev = car.CarState.new_message()
self.AM = AlertManager()
self.events = Events()
@ -161,7 +167,7 @@ class Controls:
elif self.CP.passive:
self.events.add(EventName.dashcamMode, static=True)
# controlsd is driven by can recv, expected at 100Hz
# controlsd is driven by carState, expected at 100Hz
self.rk = Ratekeeper(100, print_delay_threshold=None)
def set_initial_state(self):
@ -308,7 +314,7 @@ class Controls:
# generic catch-all. ideally, a more specific event should be added above instead
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors:
if (not self.sm.all_checks() or CS.canRcvTimeout) and no_system_errors:
if not self.sm.all_alive():
self.events.add(EventName.commIssue)
elif not self.sm.all_freq_ok():
@ -320,7 +326,7 @@ class Controls:
'invalid': [s for s, valid in self.sm.valid.items() if not valid],
'not_alive': [s for s, alive in self.sm.alive.items() if not alive],
'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok],
'can_rcv_timeout': self.card.can_rcv_timeout,
'can_rcv_timeout': CS.canRcvTimeout,
}
if logs != self.logged_comm_issue:
cloudlog.event("commIssue", error=True, **logs)
@ -380,9 +386,10 @@ class Controls:
self.events.add(EventName.modeldLagging)
def data_sample(self):
"""Receive data from sockets and update carState"""
"""Receive data from sockets"""
CS = self.card.state_update()
car_state = messaging.recv_one(self.car_state_sock)
CS = car_state.carState if car_state else self.CS_prev
self.sm.update(0)
@ -396,9 +403,6 @@ class Controls:
if VisionStreamType.VISION_STREAM_WIDE_ROAD not in available_streams:
self.sm.ignore_alive.append('wideRoadCameraState')
if not self.CP.passive:
self.card.initialize()
self.initialized = True
self.set_initial_state()
self.params.put_bool_nonblocking("ControlsReady", True)
@ -709,7 +713,6 @@ class Controls:
hudControl.visualAlert = current_alert.visual_alert
if not self.CP.passive and self.initialized:
self.card.controls_update(CS, CC)
CO = self.sm['carOutput']
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
self.steer_limited = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
@ -757,7 +760,6 @@ class Controls:
controlsState.cumLagMs = -self.rk.remaining * 1000.
controlsState.startMonoTime = int(start_time * 1e9)
controlsState.forceDecel = bool(force_decel)
controlsState.canErrorCounter = self.card.can_rcv_cum_timeout_counter
controlsState.experimentalMode = self.experimental_mode
controlsState.personality = self.personality
@ -807,6 +809,8 @@ class Controls:
# Publish data
self.publish_logs(CS, start_time, CC, lac_log)
self.CS_prev = CS
def read_personality_param(self):
try:
return int(self.params.get('LongitudinalPersonality'))

@ -128,7 +128,7 @@ def gen_lat_ocp():
return ocp
class LateralMpc():
class LateralMpc:
def __init__(self, x0=None):
if x0 is None:
x0 = np.zeros(X_DIM)

@ -4,7 +4,7 @@ from numbers import Number
from openpilot.common.numpy_fast import clip, interp
class PIDController():
class PIDController:
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100):
self._k_p = k_p
self._k_i = k_i

@ -2,7 +2,7 @@
import importlib
import math
from collections import deque
from typing import Any, Optional
from typing import Any
import capnp
from cereal import messaging, log, car
@ -208,7 +208,7 @@ class RadarD:
self.ready = False
def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]):
def update(self, sm: messaging.SubMaster, rr):
self.ready = sm.seen['modelV2']
self.current_time = 1e-9*max(sm.logMonoTime.values())

@ -32,7 +32,7 @@ def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False, personalit
log.LongitudinalPersonality.standard,
log.LongitudinalPersonality.aggressive],
[0,10,35])) # speed
class TestFollowingDistance():
class TestFollowingDistance:
def test_following_distance(self):
v_lead = float(self.speed)
simulation_steady_state = run_following_distance_simulation(v_lead, e2e=self.e2e, personality=self.personality)

@ -87,6 +87,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand):
os.environ['SKIP_FW_QUERY'] = '1'
managed_processes['controlsd'].start()
managed_processes['card'].start()
assert pm.wait_for_readers_to_update('can', 5)
pm.send('can', can_list_to_can_capnp([[0, 0, b"", 0]]))
@ -104,7 +105,7 @@ def test_startup_alert(expected_event, car_model, fw_versions, brand):
msgs = [[addr, 0, b'\x00'*length, 0] for addr, length in finger.items()]
for _ in range(1000):
# controlsd waits for boardd to echo back that it has changed the multiplexing mode
# card waits for boardd to echo back that it has changed the multiplexing mode
if not params.get_bool("ObdMultiplexingChanged"):
params.put_bool("ObdMultiplexingChanged", True)

@ -139,7 +139,7 @@ if __name__ == "__main__":
# so fib a little and say that same tester did the programming
current_date = date.today()
formatted_date = current_date.strftime('%y-%m-%d')
year, month, day = [int(part) for part in formatted_date.split('-')]
year, month, day = (int(part) for part in formatted_date.split('-'))
prog_date = bytes([year, month, day])
uds_client.write_data_by_identifier(DATA_IDENTIFIER_TYPE.PROGRAMMING_DATE, prog_date)
tester_num = uds_client.read_data_by_identifier(DATA_IDENTIFIER_TYPE.CALIBRATION_REPAIR_SHOP_CODE_OR_CALIBRATION_EQUIPMENT_SERIAL_NUMBER)

@ -28,7 +28,7 @@ def _slice(n):
return s
class States():
class States:
# Vehicle model params
STIFFNESS = _slice(1) # [-]
STEER_RATIO = _slice(1) # [-]

@ -20,7 +20,7 @@ def numpy2eigenstring(arr):
return f"(Eigen::VectorXd({len(arr)}) << {arr_str}).finished()"
class States():
class States:
ECEF_POS = slice(0, 3) # x, y and z in ECEF in meters
ECEF_ORIENTATION = slice(3, 7) # quat for pose of phone in ecef
ECEF_VELOCITY = slice(7, 10) # ecef velocity in m/s
@ -39,7 +39,7 @@ class States():
ACC_BIAS_ERR = slice(18, 21)
class LiveKalman():
class LiveKalman:
name = 'live'
initial_x = np.array([3.88e6, -3.37e6, 3.76e6,

@ -14,7 +14,7 @@ from openpilot.system.version import get_build_metadata
MAX_CACHE_SIZE = 4e9 if "CI" in os.environ else 2e9
CACHE_DIR = Path("/data/scons_cache" if AGNOS else "/tmp/scons_cache")
TOTAL_SCONS_NODES = 2560
TOTAL_SCONS_NODES = 2410
MAX_BUILD_PROGRESS = 100
def build(spinner: Spinner, dirty: bool = False, minimal: bool = False) -> None:

@ -7,14 +7,14 @@ import traceback
from cereal import log
import cereal.messaging as messaging
import openpilot.selfdrive.sentry as sentry
import openpilot.system.sentry as sentry
from openpilot.common.params import Params, ParamKeyType
from openpilot.common.text_window import TextWindow
from openpilot.system.hardware import HARDWARE, PC
from openpilot.selfdrive.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog
from openpilot.selfdrive.manager.process import ensure_running
from openpilot.selfdrive.manager.process_config import managed_processes
from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID
from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID
from openpilot.common.swaglog import cloudlog, add_file_handler
from openpilot.system.version import get_build_metadata, terms_version, training_version

@ -12,7 +12,7 @@ from setproctitle import setproctitle
from cereal import car, log
import cereal.messaging as messaging
import openpilot.selfdrive.sentry as sentry
import openpilot.system.sentry as sentry
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog

@ -42,7 +42,7 @@ def only_offroad(started, params, CP: car.CarParams) -> bool:
return not started
procs = [
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"),
NativeProcess("camerad", "system/camerad", ["./camerad"], driverview),
NativeProcess("logcatd", "system/logcatd", ["./logcatd"], only_onroad),
@ -64,6 +64,7 @@ procs = [
PythonProcess("calibrationd", "selfdrive.locationd.calibrationd", only_onroad),
PythonProcess("torqued", "selfdrive.locationd.torqued", only_onroad),
PythonProcess("controlsd", "selfdrive.controls.controlsd", only_onroad),
PythonProcess("card", "selfdrive.car.card", only_onroad),
PythonProcess("deleter", "system.loggerd.deleter", always_run),
PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", driverview, enabled=(not PC or WEBCAM)),
PythonProcess("qcomgpsd", "system.qcomgpsd.qcomgpsd", qcomgps, enabled=TICI),
@ -75,11 +76,11 @@ procs = [
PythonProcess("pigeond", "system.ubloxd.pigeond", ublox, enabled=TICI),
PythonProcess("plannerd", "selfdrive.controls.plannerd", only_onroad),
PythonProcess("radard", "selfdrive.controls.radard", only_onroad),
PythonProcess("thermald", "selfdrive.thermald.thermald", always_run),
PythonProcess("tombstoned", "selfdrive.tombstoned", always_run, enabled=not PC),
PythonProcess("thermald", "system.thermald.thermald", always_run),
PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC),
PythonProcess("updated", "selfdrive.updated.updated", only_offroad, enabled=not PC),
PythonProcess("uploader", "system.loggerd.uploader", always_run),
PythonProcess("statsd", "selfdrive.statsd", always_run),
PythonProcess("statsd", "system.statsd", always_run),
# debug procs
NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar),

@ -15,7 +15,7 @@ from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import config_realtime_process
from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.transformations.model import get_warp_matrix
from openpilot.selfdrive import sentry
from openpilot.system import sentry
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime
@ -206,9 +206,8 @@ def main(demo=False):
continue
if abs(meta_main.timestamp_sof - meta_extra.timestamp_sof) > 10000000:
cloudlog.error("frames out of sync! main: {} ({:.5f}), extra: {} ({:.5f})".format(
meta_main.frame_id, meta_main.timestamp_sof / 1e9,
meta_extra.frame_id, meta_extra.timestamp_sof / 1e9))
cloudlog.error(f"frames out of sync! main: {meta_main.frame_id} ({meta_main.timestamp_sof / 1e9:.5f}),\
extra: {meta_extra.frame_id} ({meta_extra.timestamp_sof / 1e9:.5f})")
else:
# Use single camera

@ -15,7 +15,7 @@ EventName = car.CarEvent.EventName
# We recommend that you do not change these numbers from the defaults.
# ******************************************************************************************
class DRIVER_MONITOR_SETTINGS():
class DRIVER_MONITOR_SETTINGS:
def __init__(self):
self._DT_DMON = DT_DMON
# ref (page15-16): https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:42018X1947&rid=2
@ -102,7 +102,7 @@ def face_orientation_from_net(angles_desc, pos_desc, rpy_calib):
yaw -= rpy_calib[2]
return roll_net, pitch, yaw
class DriverPose():
class DriverPose:
def __init__(self, max_trackable):
self.yaw = 0.
self.pitch = 0.
@ -116,12 +116,12 @@ class DriverPose():
self.cfactor_pitch = 1.
self.cfactor_yaw = 1.
class DriverBlink():
class DriverBlink:
def __init__(self):
self.left_blink = 0.
self.right_blink = 0.
class DriverStatus():
class DriverStatus:
def __init__(self, rhd_saved=False, settings=None, always_on=False):
if settings is None:
settings = DRIVER_MONITOR_SETTINGS()

@ -17,7 +17,7 @@ fi
source $SCRIPT_DIR/docker_common.sh $1 "$TAG_SUFFIX"
DOCKER_BUILDKIT=1 docker buildx build --provenance false --pull --platform $PLATFORM --load --cache-to type=inline --cache-from type=registry,ref=$REMOTE_TAG -t $REMOTE_TAG -t $LOCAL_TAG -f $OPENPILOT_DIR/$DOCKER_FILE $OPENPILOT_DIR
DOCKER_BUILDKIT=1 docker buildx build --provenance false --pull --platform $PLATFORM --load --cache-to type=inline --cache-from type=registry,ref=$REMOTE_TAG -t $DOCKER_IMAGE:latest -t $REMOTE_TAG -t $LOCAL_TAG -f $OPENPILOT_DIR/$DOCKER_FILE $OPENPILOT_DIR
if [ -n "$PUSH_IMAGE" ]; then
docker push $REMOTE_TAG

@ -83,7 +83,7 @@ class Plant:
lead = log.RadarState.LeadData.new_message()
lead.dRel = float(d_rel)
lead.yRel = float(0.0)
lead.yRel = 0.0
lead.vRel = float(v_rel)
lead.aRel = float(a_lead - self.acceleration)
lead.vLead = float(v_lead)

@ -14,6 +14,7 @@ def migrate_all(lr, old_logtime=False, manager_states=False, panda_states=False,
msgs = migrate_carParams(msgs, old_logtime)
msgs = migrate_gpsLocation(msgs)
msgs = migrate_deviceState(msgs)
msgs = migrate_carOutput(msgs)
if manager_states:
msgs = migrate_managerState(msgs)
if panda_states:
@ -69,6 +70,23 @@ def migrate_deviceState(lr):
return all_msgs
def migrate_carOutput(lr):
# migration needed only for routes before carOutput
if any(msg.which() == 'carOutput' for msg in lr):
return lr
all_msgs = []
for msg in lr:
if msg.which() == 'carControl':
co = messaging.new_message('carOutput')
co.valid = msg.valid
co.logMonoTime = msg.logMonoTime
co.carOutput.actuatorsOutput = msg.carControl.actuatorsOutputDEPRECATED
all_msgs.append(co.as_reader())
all_msgs.append(msg)
return all_msgs
def migrate_pandaStates(lr):
all_msgs = []
# TODO: safety param migration should be handled automatically
@ -183,9 +201,7 @@ def migrate_carParams(lr, old_logtime=False):
all_msgs = []
for msg in lr:
if msg.which() == 'carParams':
CP = messaging.new_message('carParams')
CP.valid = True
CP.carParams = msg.carParams.as_builder()
CP = msg.as_builder()
CP.carParams.carFingerprint = MIGRATION.get(CP.carParams.carFingerprint, CP.carParams.carFingerprint)
for car_fw in CP.carParams.carFw:
car_fw.brand = CP.carParams.carName

@ -317,12 +317,12 @@ class ProcessContainer:
return output_msgs
def controlsd_fingerprint_callback(rc, pm, msgs, fingerprint):
def card_fingerprint_callback(rc, pm, msgs, fingerprint):
print("start fingerprinting")
params = Params()
canmsgs = [msg for msg in msgs if msg.which() == "can"][:300]
# controlsd expects one arbitrary can and pandaState
# card expects one arbitrary can and pandaState
rc.send_sync(pm, "can", messaging.new_message("can", 1))
pm.send("pandaStates", messaging.new_message("pandaStates", 1))
rc.send_sync(pm, "can", messaging.new_message("can", 1))
@ -356,12 +356,20 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
for m in canmsgs[:300]:
can.send(m.as_builder().to_bytes())
_, CP = get_car(can, sendcan, Params().get_bool("ExperimentalLongitudinalEnabled"))
if not params.get_bool("DisengageOnAccelerator"):
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
params.put("CarParams", CP.to_bytes())
return CP
def controlsd_rcv_callback(msg, cfg, frame):
# no sendcan until controlsd is initialized
return (frame - 1) == 0 or msg.which() == 'carState'
def card_rcv_callback(msg, cfg, frame):
# no sendcan until card is initialized
if msg.which() != "can":
return False
@ -461,18 +469,28 @@ CONFIGS = [
ProcessConfig(
proc_name="controlsd",
pubs=[
"can", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState",
"carState", "deviceState", "pandaStates", "peripheralState", "liveCalibration", "driverMonitoringState",
"longitudinalPlan", "liveLocationKalman", "liveParameters", "radarState",
"modelV2", "driverCameraState", "roadCameraState", "wideRoadCameraState", "managerState",
"testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope"
"testJoystick", "liveTorqueParameters", "accelerometer", "gyroscope", "carOutput"
],
subs=["controlsState", "carState", "carControl", "carOutput", "sendcan", "onroadEvents", "carParams"],
subs=["controlsState", "carControl", "onroadEvents"],
ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"],
config_callback=controlsd_config_callback,
init_callback=controlsd_fingerprint_callback,
init_callback=get_car_params_callback,
should_recv_callback=controlsd_rcv_callback,
tolerance=NUMPY_TOLERANCE,
processing_time=0.004,
),
ProcessConfig(
proc_name="card",
pubs=["pandaStates", "carControl", "onroadEvents", "can"],
subs=["sendcan", "carState", "carParams", "carOutput"],
ignore=["logMonoTime", "carState.cumLagMs"],
init_callback=card_fingerprint_callback,
should_recv_callback=card_rcv_callback,
tolerance=NUMPY_TOLERANCE,
processing_time=0.004,
main_pub="can",
),
ProcessConfig(

@ -1 +1 @@
cc4e23ca0fceb300a3048c187ae9bc793794c095
c84b55c256ccb0ee042643a8a7f7f4dc429ff157

@ -12,7 +12,7 @@ import openpilot.selfdrive.test.process_replay.process_replay as pr
# These processes currently fail because of unrealistic data breaking assumptions
# that openpilot makes causing error with NaN, inf, int size, array indexing ...
# TODO: Make each one testable
NOT_TESTED = ['controlsd', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld']
NOT_TESTED = ['controlsd', 'card', 'plannerd', 'calibrationd', 'dmonitoringd', 'paramsd', 'dmonitoringmodeld', 'modeld']
TEST_CASES = [(cfg.proc_name, copy.deepcopy(cfg)) for cfg in pr.CONFIGS if cfg.proc_name not in NOT_TESTED]

@ -93,7 +93,7 @@ if __name__ == "__main__":
if pix_hash != ref_hash:
print("result changed! please check kernel")
print("ref: %s" % ref_hash)
print("new: %s" % pix_hash)
print(f"ref: {ref_hash}")
print(f"new: {pix_hash}")
else:
print("test passed")

@ -41,23 +41,23 @@ source_segments = [
]
segments = [
("BODY", "regen02ECB79BACC|2024-05-18--04-29-29--0"),
("HYUNDAI", "regen845DC1916E6|2024-05-18--04-30-52--0"),
("HYUNDAI2", "regenBAE0915FE22|2024-05-18--04-33-11--0"),
("TOYOTA", "regen1108D19FC2E|2024-05-18--04-34-34--0"),
("TOYOTA2", "regen846521F39C7|2024-05-18--04-35-58--0"),
("TOYOTA3", "regen788C3623D11|2024-05-18--04-38-21--0"),
("HONDA", "regenDE43F170E99|2024-05-18--04-39-47--0"),
("HONDA2", "regen1EE0FA383C3|2024-05-18--04-41-12--0"),
("CHRYSLER", "regen9C5A30F471C|2024-05-18--04-42-36--0"),
("RAM", "regenCCA313D117D|2024-05-18--04-44-53--0"),
("SUBARU", "regenA41511F882A|2024-05-18--04-47-14--0"),
("GM", "regen9D7B9CE4A66|2024-05-18--04-48-36--0"),
("GM2", "regen07CECA52D41|2024-05-18--04-50-55--0"),
("NISSAN", "regen2D6B856D0AE|2024-05-18--04-52-17--0"),
("VOLKSWAGEN", "regen2D3AC6A6F05|2024-05-18--04-53-41--0"),
("MAZDA", "regen0D5A777DD16|2024-05-18--04-56-02--0"),
("FORD", "regen235D0937965|2024-05-18--04-58-16--0"),
("BODY", "regen29FD9FF7760|2024-05-21--06-58-51--0"),
("HYUNDAI", "regen0B1B76A1C27|2024-05-21--06-57-53--0"),
("HYUNDAI2", "regen3BB55FA5E20|2024-05-21--06-59-03--0"),
("TOYOTA", "regenF6FB954C1E2|2024-05-21--06-57-53--0"),
("TOYOTA2", "regen0AC637CE7BA|2024-05-21--06-57-54--0"),
("TOYOTA3", "regenC7BE3FAE496|2024-05-21--06-59-01--0"),
("HONDA", "regen58E9F8B695A|2024-05-21--06-57-55--0"),
("HONDA2", "regen8695608EB15|2024-05-21--06-57-55--0"),
("CHRYSLER", "regenB0F8C25C902|2024-05-21--06-59-47--0"),
("RAM", "regenB3B2C7A105B|2024-05-21--07-00-47--0"),
("SUBARU", "regen860FD736DCC|2024-05-21--07-00-50--0"),
("GM", "regen8CB3048DEB9|2024-05-21--06-59-49--0"),
("GM2", "regen379D446541D|2024-05-21--07-00-51--0"),
("NISSAN", "regen24871108F80|2024-05-21--07-00-38--0"),
("VOLKSWAGEN", "regenF390392F275|2024-05-21--07-00-52--0"),
("MAZDA", "regenE5A36020581|2024-05-21--07-01-51--0"),
("FORD", "regenDC288ED0D78|2024-05-21--07-02-18--0"),
]
# dashcamOnly makes don't need to be tested until a full port is done
@ -109,7 +109,7 @@ def test_process(cfg, lr, segment, ref_log_path, new_log_path, ignore_fields=Non
if not check_openpilot_enabled(log_msgs):
return f"Route did not enable at all or for long enough: {new_log_path}", log_msgs
if cfg.proc_name != 'ubloxd' or segment != 'regenBAE0915FE22|2024-05-18--04-33-11--0':
if cfg.proc_name != 'ubloxd' or segment != 'regen3BB55FA5E20|2024-05-21--06-59-03--0':
seen_msgs = {m.which() for m in log_msgs}
expected_msgs = set(cfg.subs)
if seen_msgs != expected_msgs:

@ -8,7 +8,7 @@ class ReplayDone(Exception):
pass
class SubSocket():
class SubSocket:
def __init__(self, msgs, trigger):
self.i = 0
self.trigger = trigger
@ -28,7 +28,7 @@ class SubSocket():
return msg
class PubSocket():
class PubSocket:
def send(self, data):
pass

@ -35,7 +35,8 @@ CPU usage budget
MAX_TOTAL_CPU = 250. # total for all 8 cores
PROCS = {
# Baseline CPU usage by process
"selfdrive.controls.controlsd": 46.0,
"selfdrive.controls.controlsd": 32.0,
"selfdrive.car.card": 22.0,
"./loggerd": 14.0,
"./encoderd": 17.0,
"./camerad": 14.5,
@ -47,19 +48,19 @@ PROCS = {
"selfdrive.controls.radard": 7.0,
"selfdrive.modeld.modeld": 13.0,
"selfdrive.modeld.dmonitoringmodeld": 8.0,
"selfdrive.thermald.thermald": 3.87,
"system.thermald.thermald": 3.87,
"selfdrive.locationd.calibrationd": 2.0,
"selfdrive.locationd.torqued": 5.0,
"selfdrive.ui.soundd": 3.5,
"selfdrive.monitoring.dmonitoringd": 4.0,
"./proclogd": 1.54,
"system.logmessaged": 0.2,
"selfdrive.tombstoned": 0,
"system.tombstoned": 0,
"./logcatd": 0,
"system.micd": 6.0,
"system.timed": 0,
"selfdrive.boardd.pandad": 0,
"selfdrive.statsd": 0.4,
"system.statsd": 0.4,
"selfdrive.navd.navd": 0.4,
"system.loggerd.uploader": (0.5, 15.0),
"system.loggerd.deleter": 0.1,

@ -57,26 +57,23 @@ void update_leads(UIState *s, const cereal::RadarState::Reader &radar_state, con
void update_line_data(const UIState *s, const cereal::XYZTData::Reader &line,
float y_off, float z_off, QPolygonF *pvd, int max_idx, bool allow_invert=true) {
const auto line_x = line.getX(), line_y = line.getY(), line_z = line.getZ();
QPolygonF left_points, right_points;
left_points.reserve(max_idx + 1);
right_points.reserve(max_idx + 1);
QPointF left, right;
pvd->clear();
for (int i = 0; i <= max_idx; i++) {
// highly negative x positions are drawn above the frame and cause flickering, clip to zy plane of camera
if (line_x[i] < 0) continue;
QPointF left, right;
bool l = calib_frame_to_full_frame(s, line_x[i], line_y[i] - y_off, line_z[i] + z_off, &left);
bool r = calib_frame_to_full_frame(s, line_x[i], line_y[i] + y_off, line_z[i] + z_off, &right);
if (l && r) {
// For wider lines the drawn polygon will "invert" when going over a hill and cause artifacts
if (!allow_invert && left_points.size() && left.y() > left_points.back().y()) {
if (!allow_invert && pvd->size() && left.y() > pvd->back().y()) {
continue;
}
left_points.push_back(left);
right_points.push_front(right);
pvd->push_back(left);
pvd->push_front(right);
}
}
*pvd = left_points + right_points;
}
void update_model(UIState *s,

@ -28,7 +28,7 @@ def main():
try:
while 1:
cloudlog.info("starting athena daemon")
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad'))
proc = Process(name='athenad', target=launcher, args=('system.athena.athenad', 'athenad'))
proc.start()
proc.join()
cloudlog.event("athenad exited", exitcode=proc.exitcode)

@ -9,7 +9,7 @@ class MockResponse:
self.status_code = status_code
class EchoSocket():
class EchoSocket:
def __init__(self, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind(('127.0.0.1', port))
@ -34,7 +34,7 @@ class EchoSocket():
self.socket.close()
class MockApi():
class MockApi:
def __init__(self, dongle_id):
pass
@ -42,7 +42,7 @@ class MockApi():
return "fake-token"
class MockWebsocket():
class MockWebsocket:
sock = socket.socket()
def __init__(self, recv_queue, send_queue):

@ -19,9 +19,9 @@ from cereal import messaging
from openpilot.common.params import Params
from openpilot.common.timeout import Timeout
from openpilot.selfdrive.athena import athenad
from openpilot.selfdrive.athena.athenad import MAX_RETRY_COUNT, dispatcher
from openpilot.selfdrive.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket
from openpilot.system.athena import athenad
from openpilot.system.athena.athenad import MAX_RETRY_COUNT, dispatcher
from openpilot.system.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket
from openpilot.selfdrive.test.helpers import http_server_context
from openpilot.system.hardware.hw import Paths
@ -50,7 +50,7 @@ def with_upload_handler(func):
@pytest.fixture
def mock_create_connection(mocker):
return mocker.patch('openpilot.selfdrive.athena.athenad.create_connection')
return mocker.patch('openpilot.system.athena.athenad.create_connection')
@pytest.fixture
def host():

@ -7,7 +7,7 @@ from typing import cast
from openpilot.common.params import Params
from openpilot.common.timeout import Timeout
from openpilot.selfdrive.athena import athenad
from openpilot.system.athena import athenad
from openpilot.selfdrive.manager.helpers import write_onroad_params
from openpilot.system.hardware import TICI
@ -59,7 +59,7 @@ class TestAthenadPing:
def assertTimeout(self, reconnect_time: float, subtests, mocker) -> None:
self.athenad.start()
mock_create_connection = mocker.patch('openpilot.selfdrive.athena.athenad.create_connection',
mock_create_connection = mocker.patch('openpilot.system.athena.athenad.create_connection',
new_callable=lambda: mocker.MagicMock(wraps=athenad.create_connection))
time.sleep(1)

@ -4,8 +4,8 @@ from Crypto.PublicKey import RSA
from pathlib import Path
from openpilot.common.params import Params
from openpilot.selfdrive.athena.registration import register, UNREGISTERED_DONGLE_ID
from openpilot.selfdrive.athena.tests.helpers import MockResponse
from openpilot.system.athena.registration import register, UNREGISTERED_DONGLE_ID
from openpilot.system.athena.tests.helpers import MockResponse
from openpilot.system.hardware.hw import Paths
@ -36,7 +36,7 @@ class TestRegistration:
self.params.put("HardwareSerial", "serial")
self._generate_keys()
m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True)
m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True)
dongle = "DONGLE_ID_123"
self.params.put("DongleId", dongle)
assert register() == dongle
@ -44,7 +44,7 @@ class TestRegistration:
def test_no_keys(self, mocker):
# missing pubkey
m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True)
m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True)
dongle = register()
assert m.call_count == 0
assert dongle == UNREGISTERED_DONGLE_ID
@ -53,7 +53,7 @@ class TestRegistration:
def test_missing_cache(self, mocker):
# keys exist but no dongle id
self._generate_keys()
m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True)
m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True)
dongle = "DONGLE_ID_123"
m.return_value = MockResponse(json.dumps({'dongle_id': dongle}), 200)
assert register() == dongle
@ -67,7 +67,7 @@ class TestRegistration:
def test_unregistered(self, mocker):
# keys exist, but unregistered
self._generate_keys()
m = mocker.patch("openpilot.selfdrive.athena.registration.api_get", autospec=True)
m = mocker.patch("openpilot.system.athena.registration.api_get", autospec=True)
m.return_value = MockResponse(None, 402)
dongle = register()
assert m.call_count == 1

@ -28,12 +28,12 @@ def create_random_file(file_path: Path, size_mb: float, lock: bool = False, uplo
if upload_xattr is not None:
setxattr(str(file_path), uploader.UPLOAD_ATTR_NAME, upload_xattr)
class MockResponse():
class MockResponse:
def __init__(self, text, status_code):
self.text = text
self.status_code = status_code
class MockApi():
class MockApi:
def __init__(self, dongle_id):
pass
@ -43,7 +43,7 @@ class MockApi():
def get_token(self):
return "fake-token"
class MockApiIgnore():
class MockApiIgnore:
def __init__(self, dongle_id):
pass

@ -4,7 +4,7 @@ from enum import Enum
from sentry_sdk.integrations.threading import ThreadingIntegration
from openpilot.common.params import Params
from openpilot.selfdrive.athena.registration import is_registered_device
from openpilot.system.athena.registration import is_registered_device
from openpilot.system.hardware import HARDWARE, PC
from openpilot.common.swaglog import cloudlog
from openpilot.system.version import get_build_metadata, get_version

@ -4,7 +4,7 @@ import zmq
import time
from pathlib import Path
from collections import defaultdict
from datetime import datetime, timezone
from datetime import datetime, UTC
from typing import NoReturn
from openpilot.common.params import Params
@ -133,7 +133,7 @@ def main() -> NoReturn:
# flush when started state changes or after FLUSH_TIME_S
if (time.monotonic() > last_flush_time + STATS_FLUSH_TIME_S) or (sm['deviceState'].started != started_prev):
result = ""
current_time = datetime.utcnow().replace(tzinfo=timezone.utc)
current_time = datetime.utcnow().replace(tzinfo=UTC)
tags['started'] = sm['deviceState'].started
for key, value in gauges.items():

@ -4,7 +4,7 @@ import threading
from openpilot.common.params import Params
from openpilot.system.hardware import HARDWARE
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.statsd import statlog
from openpilot.system.statsd import statlog
CAR_VOLTAGE_LOW_PASS_K = 0.011 # LPF gain for 45s tau (dt/tau / (dt/tau + 1))

@ -1,7 +1,7 @@
#!/usr/bin/env python3
import pytest
from openpilot.selfdrive.thermald.fan_controller import TiciFanController
from openpilot.system.thermald.fan_controller import TiciFanController
ALL_CONTROLLERS = [TiciFanController]

@ -2,7 +2,7 @@
import pytest
from openpilot.common.params import Params
from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \
from openpilot.system.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \
CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING, DELAY_SHUTDOWN_TIME_S
# Create fake time
@ -18,9 +18,9 @@ VOLTAGE_BELOW_PAUSE_CHARGING = (VBATT_PAUSE_CHARGING - 1) * 1e3
def pm_patch(mocker, name, value, constant=False):
if constant:
mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", value)
mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", value)
else:
mocker.patch(f"openpilot.selfdrive.thermald.power_monitoring.{name}", return_value=value)
mocker.patch(f"openpilot.system.thermald.power_monitoring.{name}", return_value=value)
@pytest.fixture(autouse=True)

@ -19,10 +19,10 @@ from openpilot.common.realtime import DT_TRML
from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert
from openpilot.system.hardware import HARDWARE, TICI, AGNOS
from openpilot.system.loggerd.config import get_available_percent
from openpilot.selfdrive.statsd import statlog
from openpilot.system.statsd import statlog
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring
from openpilot.selfdrive.thermald.fan_controller import TiciFanController
from openpilot.system.thermald.power_monitoring import PowerMonitoring
from openpilot.system.thermald.fan_controller import TiciFanController
from openpilot.system.version import terms_version, training_version
ThermalStatus = log.DeviceState.ThermalStatus

@ -9,7 +9,7 @@ import time
import glob
from typing import NoReturn
import openpilot.selfdrive.sentry as sentry
import openpilot.system.sentry as sentry
from openpilot.system.hardware.hw import Paths
from openpilot.common.swaglog import cloudlog
from openpilot.system.version import get_build_metadata

@ -61,7 +61,7 @@ def get_assistnow_messages(token: bytes) -> list[bytes]:
return msgs
class TTYPigeon():
class TTYPigeon:
def __init__(self):
self.tty = serial.VTIMESerial(UBLOX_TTY, baudrate=9600, timeout=0)

@ -1,6 +1,7 @@
import pathlib
import tarfile
from typing import IO, Callable
from typing import IO
from collections.abc import Callable
def include_default(_) -> bool:

@ -27,7 +27,7 @@ def get_version(path: str = BASEDIR) -> str:
def get_release_notes(path: str = BASEDIR) -> str:
with open(os.path.join(path, "RELEASES.md"), "r") as f:
with open(os.path.join(path, "RELEASES.md")) as f:
return f.read().split('\n\n', 1)[0]

@ -20,7 +20,7 @@ from parameterized import parameterized_class
([], []),
])
@pytest.mark.asyncio
class TestWebrtcdProc():
class TestWebrtcdProc:
async def assertCompletesWithTimeout(self, awaitable, timeout=1):
try:
async with asyncio.timeout(timeout):

@ -97,8 +97,8 @@ class CerealProxyRunner:
except InvalidStateError:
self.logger.warning("Cereal outgoing proxy invalid state (connection closed)")
break
except Exception as ex:
self.logger.error("Cereal outgoing proxy failure: %s", ex)
except Exception:
self.logger.exception("Cereal outgoing proxy failure")
await asyncio.sleep(0.01)
@ -175,8 +175,8 @@ class StreamSession:
assert self.incoming_bridge is not None
try:
self.incoming_bridge.send(message)
except Exception as ex:
self.logger.error("Cereal incoming proxy failure: %s", ex)
except Exception:
self.logger.exception("Cereal incoming proxy failure")
async def run(self):
try:
@ -200,8 +200,8 @@ class StreamSession:
await self.post_run_cleanup()
self.logger.info("Stream session (%s) ended", self.identifier)
except Exception as ex:
self.logger.error("Stream session failure: %s", ex)
except Exception:
self.logger.exception("Stream session failure")
async def post_run_cleanup(self):
await self.stream.stop()

@ -12,24 +12,16 @@ if [[ ! $(id -u) -eq 0 ]]; then
SUDO="sudo"
fi
# Install packages present in all supported versions of Ubuntu
# Install common packages
function install_ubuntu_common_requirements() {
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
autoconf \
build-essential \
ca-certificates \
casync \
clang \
cmake \
make \
cppcheck \
libtool \
build-essential \
gcc-arm-none-eabi \
bzip2 \
liblzma-dev \
libarchive-dev \
libbz2-dev \
capnproto \
libcapnp-dev \
curl \
@ -42,41 +34,53 @@ function install_ubuntu_common_requirements() {
libavdevice-dev \
libavutil-dev \
libavfilter-dev \
libbz2-dev \
libeigen3-dev \
libffi-dev \
libglew-dev \
libgles2-mesa-dev \
libglfw3-dev \
libglib2.0-0 \
libqt5charts5-dev \
libncurses5-dev \
libncursesw5-dev \
libomp-dev \
libpng16-16 \
libportaudio2 \
libssl-dev \
libsqlite3-dev \
libusb-1.0-0-dev \
libzmq3-dev \
libsqlite3-dev \
libsystemd-dev \
locales \
opencl-headers \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
clinfo \
portaudio19-dev \
qml-module-qtquick2 \
qtmultimedia5-dev \
qtlocation5-dev \
qtpositioning5-dev \
qttools5-dev-tools \
libqt5sql5-sqlite \
libqt5svg5-dev \
libqt5charts5-dev \
libqt5serialbus5-dev \
libqt5x11extras5-dev \
libqt5opengl5-dev \
libqt5opengl5-dev
}
# Install extra packages
function install_extra_packages() {
echo "Installing extra packages..."
$SUDO apt-get install -y --no-install-recommends \
casync \
cmake \
make \
clinfo \
libqt5sql5-sqlite \
libreadline-dev \
libdw1
libdw1 \
autoconf \
libtool \
bzip2 \
libarchive-dev \
libncursesw5-dev \
libportaudio2 \
locales
}
# Install Ubuntu 24.04 LTS packages
@ -125,7 +129,19 @@ if [ -f "/etc/os-release" ]; then
install_ubuntu_lts_latest_requirements
fi
esac
# Install extra packages
if [[ -z "$INSTALL_EXTRA_PACKAGES" ]]; then
read -p "Base setup done. Do you want to install extra development packages? [Y/n]: " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
INSTALL_EXTRA_PACKAGES="yes"
fi
fi
if [[ "$INSTALL_EXTRA_PACKAGES" == "yes" ]]; then
install_extra_packages
fi
else
echo "No /etc/os-release in the system"
echo "No /etc/os-release in the system. Make sure you're running on Ubuntu, or similar."
exit 1
fi

@ -2,7 +2,7 @@ import os
import requests
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
class CommaApi():
class CommaApi:
def __init__(self, token=None):
self.session = requests.Session()
self.session.headers['User-agent'] = 'OpenpilotTools'

@ -8,6 +8,7 @@ from openpilot.tools.sim.bridge.metadrive.metadrive_bridge import MetaDriveBridg
from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase
@pytest.mark.slow
@pytest.mark.filterwarnings("ignore::pyopencl.CompilerWarning") # Unimportant warning of non-empty compile log
class TestMetaDriveBridge(TestSimBridgeBase):
def create_bridge(self):
return MetaDriveBridge(False, False)

Loading…
Cancel
Save