diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index af67bdbe5..1115c375d 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,11 +1,11 @@
FROM ghcr.io/commaai/openpilot-base:latest
-RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa libegl1-mesa gdb bash-completion
+RUN apt update && apt install -y vim net-tools usbutils htop ripgrep tmux wget mesa-utils xvfb libxtst6 libxv1 libglu1-mesa gdb bash-completion
RUN pip install ipython jupyter jupyterlab
RUN cd /tmp && \
ARCH=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && \
- curl -L -o virtualgl.deb "https://downloads.sourceforge.net/project/virtualgl/3.1/virtualgl_3.1_$ARCH.deb" && \
+ curl -L -o virtualgl.deb "https://github.com/VirtualGL/virtualgl/releases/download/3.1.1/virtualgl_3.1.1_$ARCH.deb" && \
dpkg -i virtualgl.deb
RUN usermod -aG video batman
diff --git a/.github/workflows/setup/action.yaml b/.github/workflows/setup/action.yaml
index 970d62030..701675942 100644
--- a/.github/workflows/setup/action.yaml
+++ b/.github/workflows/setup/action.yaml
@@ -60,4 +60,4 @@ runs:
find . -type f -not -executable -not -perm 644 -exec chmod 644 {} \;
# build our docker image
- shell: bash
- run: eval ${{ env.BUILD }}
\ No newline at end of file
+ run: eval ${{ env.BUILD }}
diff --git a/.github/workflows/tools_tests.yaml b/.github/workflows/tools_tests.yaml
index c2f7d86e6..9a26ca9a2 100644
--- a/.github/workflows/tools_tests.yaml
+++ b/.github/workflows/tools_tests.yaml
@@ -39,12 +39,13 @@ jobs:
source selfdrive/test/setup_vsound.sh && \
CI=1 pytest tools/sim/tests/test_metadrive_bridge.py"
- test_python311:
- name: test python3.11 support
- runs-on: ubuntu-latest
- timeout-minutes: 5
+ test_compatibility:
+ name: test 20.04 + 3.11
+ runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
+ with:
+ submodules: true
- name: Installing ubuntu dependencies
run: INSTALL_EXTRA_PACKAGES=no tools/install_ubuntu_dependencies.sh
- name: Installing python
@@ -57,6 +58,25 @@ jobs:
run: pip install poetry==1.7.0
- name: Installing python dependencies
run: poetry install --no-cache --no-root
+ - name: git LFS
+ run: git lfs pull
+ - run: echo "CACHE_COMMIT_DATE=$(git log -1 --pretty='format:%cd' --date=format:'%Y-%m-%d-%H:%M')" >> $GITHUB_ENV
+ - name: Getting scons cache
+ uses: 'actions/cache@v4'
+ with:
+ path: /tmp/scons_cache
+ key: scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
+ restore-keys: |
+ scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}
+ scons-${{ runner.arch }}-ubuntu2004
+ - name: Building openpilot
+ run: poetry run scons -u -j$(nproc)
+ - name: Saving scons cache
+ uses: actions/cache/save@v4
+ if: github.ref == 'refs/heads/master'
+ with:
+ path: /tmp/scons_cache
+ key: scons-${{ runner.arch }}-ubuntu2004-${{ env.CACHE_COMMIT_DATE }}-${{ github.sha }}
devcontainer:
name: devcontainer
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 61b782364..ecde9fe77 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -33,7 +33,7 @@ repos:
- -L bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn
- --builtins clear,rare,informal,usage,code,names,en-GB_to_en-US
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.4.8
+ rev: v0.4.9
hooks:
- id: ruff
exclude: '^(third_party/)|(msgq/)|(panda/)|(rednose/)|(rednose_repo/)|(tinygrad/)|(tinygrad_repo/)|(teleoprtc/)|(teleoprtc_repo/)'
@@ -62,6 +62,8 @@ repos:
- --quiet
- --force
- -j8
+ - --library=qt
+ - --include=third_party/kaitai/kaitaistream.h
- repo: https://github.com/cpplint/cpplint
rev: 1.6.1
hooks:
@@ -98,6 +100,6 @@ repos:
args:
- --lock
- repo: https://github.com/python-jsonschema/check-jsonschema
- rev: 0.28.4
+ rev: 0.28.5
hooks:
- id: check-github-workflows
diff --git a/Dockerfile.openpilot_base b/Dockerfile.openpilot_base
index 45b29bdcb..7228d16ef 100644
--- a/Dockerfile.openpilot_base
+++ b/Dockerfile.openpilot_base
@@ -1,4 +1,4 @@
-FROM ubuntu:20.04
+FROM ubuntu:24.04
ENV PYTHONUNBUFFERED 1
@@ -15,7 +15,7 @@ ENV LC_ALL en_US.UTF-8
COPY tools/install_ubuntu_dependencies.sh /tmp/tools/
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 && \
+ cd /usr/lib/gcc/arm-none-eabi/* && \
rm -rf arm/ thumb/nofp thumb/v6* thumb/v8* thumb/v7+fp thumb/v7-r+fp.sp
# Add OpenCL
@@ -30,23 +30,28 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
gcc-arm-none-eabi \
tmux \
vim \
- lsb-core \
libx11-6 \
+ wget \
&& rm -rf /var/lib/apt/lists/*
-ARG INTEL_DRIVER=l_opencl_p_18.1.0.015.tgz
-ARG INTEL_DRIVER_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/vcp/15532
-RUN mkdir -p /tmp/opencl-driver-intel
-
-RUN cd /tmp/opencl-driver-intel && \
- echo INTEL_DRIVER is $INTEL_DRIVER && \
- curl -O $INTEL_DRIVER_URL/$INTEL_DRIVER && \
- tar -xzf $INTEL_DRIVER && \
- for i in $(basename $INTEL_DRIVER .tgz)/rpm/*.rpm; do alien --to-deb $i; done && \
- dpkg -i *.deb && \
- rm -rf $INTEL_DRIVER $(basename $INTEL_DRIVER .tgz) *.deb && \
+RUN mkdir -p /tmp/opencl-driver-intel && \
+ cd /tmp/opencl-driver-intel && \
+ wget https://github.com/intel/llvm/releases/download/2024-WW14/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
+ wget https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/oneapi-tbb-2021.12.0-lin.tgz && \
+ mkdir -p /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
+ cd /opt/intel/oclcpuexp_2024.17.3.0.09_rel && \
+ tar -zxvf /tmp/opencl-driver-intel/oclcpuexp-2024.17.3.0.09_rel.tar.gz && \
mkdir -p /etc/OpenCL/vendors && \
- echo /opt/intel/opencl_compilers_and_libraries_18.1.0.015/linux/compiler/lib/intel64_lin/libintelocl.so > /etc/OpenCL/vendors/intel.icd && \
+ echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64/libintelocl.so > /etc/OpenCL/vendors/intel_expcpu.icd && \
+ cd /opt/intel && \
+ tar -zxvf /tmp/opencl-driver-intel/oneapi-tbb-2021.12.0-lin.tgz && \
+ ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
+ ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
+ ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbb.so.12 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
+ ln -s /opt/intel/oneapi-tbb-2021.12.0/lib/intel64/gcc4.8/libtbbmalloc.so.2 /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 && \
+ mkdir -p /etc/ld.so.conf.d && \
+ echo /opt/intel/oclcpuexp_2024.17.3.0.09_rel/x64 > /etc/ld.so.conf.d/libintelopenclexp.conf && \
+ ldconfig -f /etc/ld.so.conf.d/libintelopenclexp.conf && \
cd / && \
rm -rf /tmp/opencl-driver-intel
@@ -57,7 +62,7 @@ ENV QTWEBENGINE_DISABLE_SANDBOX 1
RUN dbus-uuidgen > /etc/machine-id
ARG USER=batman
-ARG USER_UID=1000
+ARG USER_UID=1001
RUN useradd -m -s /bin/bash -u $USER_UID $USER
RUN usermod -aG sudo $USER
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
diff --git a/SConstruct b/SConstruct
index 4a51c59a6..09df57696 100644
--- a/SConstruct
+++ b/SConstruct
@@ -14,6 +14,8 @@ SCons.Warnings.warningAsException(True)
TICI = os.path.isfile('/TICI')
AGNOS = TICI
+UBUNTU_FOCAL = int(subprocess.check_output('[ -f /etc/os-release ] && . /etc/os-release && [ "$ID" = "ubuntu" ] && [ "$VERSION_ID" = "20.04" ] && echo 1 || echo 0', shell=True, encoding='utf-8').rstrip())
+Export('UBUNTU_FOCAL')
Decider('MD5-timestamp')
diff --git a/cereal/car.capnp b/cereal/car.capnp
index 7f3f64c91..c17e1c063 100644
--- a/cereal/car.capnp
+++ b/cereal/car.capnp
@@ -541,8 +541,8 @@ struct CarParams {
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @6 :Float32;
- deadzoneBP @4 :List(Float32);
- deadzoneV @5 :List(Float32);
+ deadzoneBPDEPRECATED @4 :List(Float32);
+ deadzoneVDEPRECATED @5 :List(Float32);
}
struct LateralINDITuning {
diff --git a/cereal/log.capnp b/cereal/log.capnp
index 958c5c910..7d95ceff0 100644
--- a/cereal/log.capnp
+++ b/cereal/log.capnp
@@ -698,7 +698,6 @@ struct ControlsState @0x97ff69c53601abf1 {
personality @66 :LongitudinalPersonality;
longControlState @30 :Car.CarControl.Actuators.LongControlState;
- vPid @2 :Float32;
vTargetLead @3 :Float32;
vCruise @22 :Float32; # actual set speed
vCruiseCluster @63 :Float32; # set speed to display in the UI
@@ -866,6 +865,7 @@ struct ControlsState @0x97ff69c53601abf1 {
canMonoTimesDEPRECATED @21 :List(UInt64);
desiredCurvatureRateDEPRECATED @62 :Float32;
canErrorCounterDEPRECATED @57 :UInt32;
+ vPidDEPRECATED @2 :Float32;
}
# All SI units and in device frame
@@ -1060,6 +1060,11 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
accels @32 :List(Float32);
speeds @33 :List(Float32);
jerks @34 :List(Float32);
+ aTarget @18 :Float32;
+ shouldStop @37: Bool;
+ allowThrottle @38: Bool;
+ allowBrake @39: Bool;
+
solverExecutionTime @35 :Float32;
@@ -1076,7 +1081,6 @@ struct LongitudinalPlan @0xe00b5b3eba12876c {
aCruiseDEPRECATED @17 :Float32;
vTargetDEPRECATED @3 :Float32;
vTargetFutureDEPRECATED @14 :Float32;
- aTargetDEPRECATED @18 :Float32;
vStartDEPRECATED @26 :Float32;
aStartDEPRECATED @27 :Float32;
vMaxDEPRECATED @20 :Float32;
diff --git a/docs/CARS.md b/docs/CARS.md
index 3b163dcee..43bd8a8b3 100644
--- a/docs/CARS.md
+++ b/docs/CARS.md
@@ -90,9 +90,9 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here |
|
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|Parts
- 1 Hyundai J connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|Parts
- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Hyundai|Ioniq 5 (with HDA II) 2022-23[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Hyundai|Ioniq 5 (without HDA II) 2022-23[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Hyundai|Ioniq 5 (Non-US only) 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Hyundai|Ioniq 5 (with HDA II) 2022-24[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai Q connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Hyundai|Ioniq 5 (without HDA II) 2022-24[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|Ioniq 6 (with HDA II) 2023-24[5](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|Parts
- 1 Hyundai C connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|Ioniq Electric 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai H connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
@@ -127,7 +127,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Carnival 2022-24[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai A connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Kia|Carnival (China only) 2023[5](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Kia|EV6 (Southeast Asia only) 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Kia|EV6 (Non-US only) 2022-24[5](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Kia|EV6 (with HDA II) 2022-24[5](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai P connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Kia|EV6 (without HDA II) 2022-24[5](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai L connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[](##)|[](##)|Parts
- 1 Hyundai G connector
- 1 RJ45 cable (7 ft)
- 1 comma 3X
- 1 comma power v2
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
diff --git a/poetry.lock b/poetry.lock
index 7e772276e..58fa7dee6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
[[package]]
name = "aiohttp"
@@ -1074,18 +1074,18 @@ files = [
[[package]]
name = "filelock"
-version = "3.14.0"
+version = "3.15.1"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.8"
files = [
- {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"},
- {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"},
+ {file = "filelock-3.15.1-py3-none-any.whl", hash = "sha256:71b3102950e91dfc1bb4209b64be4dc8854f40e5f534428d8684f953ac847fac"},
+ {file = "filelock-3.15.1.tar.gz", hash = "sha256:58a2549afdf9e02e10720eaa4d4470f56386d7a6f72edd7d0596337af8ed7ad8"},
]
[package.extras]
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
typing = ["typing-extensions (>=4.8)"]
[[package]]
@@ -2270,8 +2270,8 @@ ros = ["zmq"]
[package.source]
type = "git"
url = "https://github.com/commaai/metadrive.git"
-reference = "python3.12"
-resolved_reference = "0823c7491a1ab870bcd53d10a41e985a3ad1b968"
+reference = "anisotropic_off"
+resolved_reference = "1606c844345f98aa79f76177856e328edc6ec428"
[[package]]
name = "mouseinfo"
@@ -2730,6 +2730,7 @@ optional = false
python-versions = ">=3.6"
files = [
{file = "opencv-python-4.10.0.82.tar.gz", hash = "sha256:dbc021eaa310c4145c47cd648cb973db69bb5780d6e635386cd53d3ea76bd2d5"},
+ {file = "opencv_python-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:5f78652339957ec24b80a782becfb32f822d2008a865512121fad8c3ce233e9a"},
{file = "opencv_python-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:e6be19a0615aa8c4e0d34e0c7b133e26e386f4b7e9b557b69479104ab2c133ec"},
{file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b49e530f7fd86f671514b39ffacdf5d14ceb073bc79d0de46bbb6b0cad78eaf"},
{file = "opencv_python-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955c5ce8ac90c9e4636ad7f5c0d9c75b80abbe347182cfd09b0e3eec6e50472c"},
@@ -2739,8 +2740,8 @@ files = [
[package.dependencies]
numpy = [
- {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
{version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
+ {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
]
[[package]]
@@ -2751,6 +2752,7 @@ optional = false
python-versions = ">=3.6"
files = [
{file = "opencv-python-headless-4.10.0.82.tar.gz", hash = "sha256:de9e742c1b9540816fbd115b0b03841d41ed0c65566b0d7a5371f98b131b7e6d"},
+ {file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a09ed50ba21cc5bf5d436cb0e784ad09c692d6b1d1454252772f6c8f2c7b4088"},
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:977a5fd21e1fe0d3d2134887db4441f8725abeae95150126302f31fcd9f548fa"},
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4ec6755838b0be12510bfc9ffb014779c612418f11f4f7e6f505c36124a3aa"},
{file = "opencv_python_headless-4.10.0.82-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a37fa5276967ecf6eb297295b16b28b7a2eb3b568ca0ee469fb1a5954de298"},
@@ -2760,8 +2762,8 @@ files = [
[package.dependencies]
numpy = [
- {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
{version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
+ {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
]
[[package]]
@@ -2925,8 +2927,8 @@ files = [
[package.dependencies]
numpy = [
- {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
+ {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
]
python-dateutil = ">=2.8.2"
pytz = ">=2020.1"
@@ -7217,28 +7219,28 @@ docs = ["furo (==2024.4.27)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx
[[package]]
name = "ruff"
-version = "0.4.8"
+version = "0.4.9"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
- {file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
- {file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
- {file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
- {file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
- {file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
- {file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
- {file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
- {file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
- {file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
- {file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
+ {file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"},
+ {file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"},
+ {file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"},
+ {file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"},
+ {file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"},
+ {file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"},
+ {file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"},
+ {file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"},
+ {file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"},
+ {file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"},
+ {file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"},
]
[[package]]
@@ -7725,19 +7727,23 @@ widechars = ["wcwidth"]
[[package]]
name = "timezonefinder"
-version = "6.5.0"
+version = "6.5.2"
description = "python package for finding the timezone of any point on earth (coordinates) offline"
optional = false
-python-versions = ">=3.8,<4"
+python-versions = "<4,>=3.8"
files = [
- {file = "timezonefinder-6.5.0-cp38-cp38-manylinux_2_35_x86_64.whl", hash = "sha256:3c70e1ea468ecac11272aa0a727450fd7cf43039ae2a2c62f7900a0a42efb6d6"},
- {file = "timezonefinder-6.5.0.tar.gz", hash = "sha256:7afdb1516927e7766deb6da80c8bd66734a44ba3d898038fe73aef1e9cd39bb0"},
+ {file = "timezonefinder-6.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7ca91f25d988d69efeae020ed828534ed01f6687646a50e464d82da4704b30"},
+ {file = "timezonefinder-6.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4a3bca9933ea165380d54b336227def58e62682968437cd44223a065ecff7e9"},
+ {file = "timezonefinder-6.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ac4ef31d379c7ba54710462857bea36a9630ea23550ffb15550322e6988efbd"},
+ {file = "timezonefinder-6.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524ab145a2f4ce5101e52308868ecd9da0cdcc2cb3024c13356616b41a685fd6"},
+ {file = "timezonefinder-6.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93927a4996a5c01f0628eb6858c61b2a7f9f49e02c07bed2a95e96a8dc1b65e"},
+ {file = "timezonefinder-6.5.2.tar.gz", hash = "sha256:3279e67d5b1b9a54d1a16f3bd4234169f14e2b90c0f58ed37bcfa7303645d610"},
]
[package.dependencies]
cffi = ">=1.15.1,<2"
h3 = ">=3.7.6,<4"
-numpy = {version = ">=1.23,<2", markers = "python_version >= \"3.9\""}
+numpy = {version = ">=1.23,<3", markers = "python_version >= \"3.9\""}
setuptools = ">=65.5"
[package.extras]
@@ -7824,13 +7830,13 @@ files = [
[[package]]
name = "urllib3"
-version = "2.2.1"
+version = "2.2.2"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
files = [
- {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
- {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
+ {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
+ {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
]
[package.extras]
@@ -8009,7 +8015,103 @@ files = [
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
+[[package]]
+name = "zstd"
+version = "1.5.5.1"
+description = "ZSTD Bindings for Python"
+optional = false
+python-versions = "*"
+files = [
+ {file = "zstd-1.5.5.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:555779789bc75cd05089c3ba857f45a0a8c4b87d45e5ced02fec77fa8719237a"},
+ {file = "zstd-1.5.5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:86496bd4830cdb7b4b05a9ce6ce2baee87d327ff90845da4ee308452bfbbed4e"},
+ {file = "zstd-1.5.5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:b487c2e67ed42a4e0d47997d209f4456b01b334023083ef61873f79577c84c62"},
+ {file = "zstd-1.5.5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:45ccd45a5b681088fca1a863ca9236ded5112b8011f1d5bf69e908f5eb32023a"},
+ {file = "zstd-1.5.5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8403fe84207d8b0c7b17bca6c4caad431ac765b1b9b626ad9fae4bb93a64a9d8"},
+ {file = "zstd-1.5.5.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:0ab979c6357b8927f0c025ea2f72f25e15d03ce17a8a6c1789e2d5b108bf39ae"},
+ {file = "zstd-1.5.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:98cbee6c1b2fe85f02fd475d885f98363c63bc64eebc249d7eb7469a0ff70283"},
+ {file = "zstd-1.5.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9962714b89641301029f3832bdf07c20f60b9e64e39e8d7b6253451a82b54f5c"},
+ {file = "zstd-1.5.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f59cc92d71537f8082306f75aa403ddb4a4a1069a39f104525673110e4d23f7"},
+ {file = "zstd-1.5.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:569f13d0c926ddafceebce8ac73baddfc2bd9cbbbbc922b6b3073338cc43dae6"},
+ {file = "zstd-1.5.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba530c44f252016acc6ef906d7d2070c1ad0cfe835c498fdcd37493e4772ac6e"},
+ {file = "zstd-1.5.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ee3496ed8fff3add6c6e658b207f18d96474c3db0c28ab7a69623380b1a0a8c"},
+ {file = "zstd-1.5.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:530d69bea2791cde8afa7fe988f3a37c3ba37015f6a1d5593c0500f089f3090e"},
+ {file = "zstd-1.5.5.1-cp310-cp310-win32.whl", hash = "sha256:cf179e51f447b6a7ff47e449fcb98fb5fe15aedcc90401697cf7c93dd6e4434e"},
+ {file = "zstd-1.5.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f5e6e0805d710d7509c8d175a467eb89c631a4142b1a630ceeb8e3e3138d152"},
+ {file = "zstd-1.5.5.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:022f935a8666e08f0fff6204938a84d9fe4fcd8235a205787275933a07a164fb"},
+ {file = "zstd-1.5.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3d15a2d18dac8bcafdde52fdf5d40ecae1f73b7de19b171f42339d2e51346d0"},
+ {file = "zstd-1.5.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45b9c67989f50ba63ffa0c50c9eaa037c2d14abacb0813e838ad705135245b4b"},
+ {file = "zstd-1.5.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97da6a842ba7e4acf8bba7c596057143ee39b3c4a467196c2096d460e44accd6"},
+ {file = "zstd-1.5.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dafd492fb8ee4ae04c81ab00f5f137860e7071f611335dd4cdb1c38bd8f11bc"},
+ {file = "zstd-1.5.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9ee83e0bcbfd776200b026b3b9e86c6c86b8f414749f58d87c85dcf456b27066"},
+ {file = "zstd-1.5.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ae2fd4bc8ea772a7b5f1acd1cac9e34bb9cd8fcde191f170092fdeea779a3a12"},
+ {file = "zstd-1.5.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:edea52a0109f48fd46f4763689d3d356dcafd20ddf6789c559a1bd2e62b40a32"},
+ {file = "zstd-1.5.5.1-cp311-cp311-win32.whl", hash = "sha256:88410481209520298ec4430e0d1d57e004c45e0b27c3035674fb182ccd2d8b7b"},
+ {file = "zstd-1.5.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:dce18aaefbacf8b133367be86beec670baf68c0420bfcca49be08dbdbf933db6"},
+ {file = "zstd-1.5.5.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:634dc632f7cf87e95dabf74dcf682e3507bd5cb9dd1bcdb81f92a6521aab0bd2"},
+ {file = "zstd-1.5.5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:608414eb75ead573891d97a1e529848b8f31749d21a440e80838548a19d8c0e6"},
+ {file = "zstd-1.5.5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:384128f7a731e3f45da49976591cec03fc4079e70653df10d9ea43a1d3b49d50"},
+ {file = "zstd-1.5.5.1-cp35-cp35m-win32.whl", hash = "sha256:4bce254174ef05cea01021d67e18489d5d08db1168e758b62ecee121572a52a9"},
+ {file = "zstd-1.5.5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:3f0ff81232b49d7eb4f4d9e6f92443c9d242c139ad98ffedac0e889568f900ce"},
+ {file = "zstd-1.5.5.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a871df41b801a260cc849c2c76f300ebb9d286c4b7a1fd6ce45fe0c91340b767"},
+ {file = "zstd-1.5.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5a53860dbfbea281eb690ce09cae28967cf1df8e6d7560e4a8bf5b9fcb258147"},
+ {file = "zstd-1.5.5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a37cbc0580fdfd66c8b3ec65f9af00a4a34e9781b54dfb89f04d301dc375c90a"},
+ {file = "zstd-1.5.5.1-cp36-cp36m-win32.whl", hash = "sha256:5531b683539ae1f7b2ad23dacee8a73e5d7eaa6702ea8df5a24bd3318647dee1"},
+ {file = "zstd-1.5.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eeaff418269b41eee8c7971fbba9d32d07d3f6aa26f962a72aff725071096a1b"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:8bd6a9050de8bbe844447348372ca17d01bc05207619f6a5d448567d111b5cd9"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2ece3d20ef357370584f304407fbd1e4ff9c231209320e08a889b8e3725d56e"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687f9e03dc9f9b8803840425bb23bf6bc700888b4860afcf43c4f238102752d2"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a649daac9c8f1b37d29f2b3d0a43f134061659b54877fe4b0da6df2965dc91f"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bddc7e3c3ce31c01fe1edaa7c03c0b9e71eadf4ce1609746d32f86d95a0449e6"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:12bf8e04add8bb84f9fe9117f3de6d9394eade6a5a82fe4d6bd95914fc6ef423"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e6a15fa4d2e65c5902ab2a4e41279ac126cb371ce6c3c75ad5789bb20dd1f54"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-win32.whl", hash = "sha256:a1c269243a4321beb948635b544ccbe6390846358ace620fd000ab7099011d9c"},
+ {file = "zstd-1.5.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:91366e36773241cb4b049a32f4495d33dd274df1eea5b55396f5f3984a3de22e"},
+ {file = "zstd-1.5.5.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:d3ce2cb310690994274d133ea7f269dd4b81799fdbce158690556209723d7d4e"},
+ {file = "zstd-1.5.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e0c87bfbfa9d852f79c90bcd7426c3ba46cf3285e6984013636d4fc854ba9230"},
+ {file = "zstd-1.5.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce6d829d515f272fddb3a87e1a5f32cc0f1a7b0cba24d360c89f4a165b74b"},
+ {file = "zstd-1.5.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e05f81f346213b23ed1b12d84fc1f72e65eacd8978e1e88facf185c82bd3d053"},
+ {file = "zstd-1.5.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43ec66c4c3a76351c672c6ef9f0ff3412fca9ede0a56d18dddaf6418a93faef8"},
+ {file = "zstd-1.5.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:58e554e91e0d49f4f2b2df390cdd0f64aa9b6fd5f4dcb208c094bfd079b30f3a"},
+ {file = "zstd-1.5.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:883c6d3b6f5574e1765ca97f4b6a41b69094a41be56175552faebc0e0e43b65e"},
+ {file = "zstd-1.5.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d52b6932cab5419c434bccfea3e5640e755369fc9eeb51e3d17e15bf8e8cb103"},
+ {file = "zstd-1.5.5.1-cp38-cp38-win32.whl", hash = "sha256:dcaf44270ec88552e969be4dd3359b34aa3065663ccd8168a257c78f150a356c"},
+ {file = "zstd-1.5.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:627f12cb7035723c8f3d8d4cefcad6d950ed9cba33fd3eb46bae04ccab479234"},
+ {file = "zstd-1.5.5.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:c0dab132c1a5a7cc838a7c3e4e380ad153b9d7bd1fadafabf6cfeb780b916201"},
+ {file = "zstd-1.5.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4ab0a5dd9a41d3b083304beee7ada40ee36431acbeb75132032f4fe5cf0490a"},
+ {file = "zstd-1.5.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f6e38f496d287020658c6b4cdb5e815ecc6998889bd0f1f9ab0825f2e3d74ef"},
+ {file = "zstd-1.5.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0096c8ee0ed4bfe406bc961019f55552109e19771bfd3eb32d2af56ea27085c"},
+ {file = "zstd-1.5.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a0f1527728c50b6aa8f04b47a07580f0ae13cfc6c6d9c96bb0bdf5259487559"},
+ {file = "zstd-1.5.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6a64e420c904063c5c3de53c00ec0993ebc0a48cebbef97dc6c768562c5abab5"},
+ {file = "zstd-1.5.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:03444e357b7632c64480a81ce7095242dab9d7f8aed317326563ef6c663263eb"},
+ {file = "zstd-1.5.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:88b9a10f80d2b87bf8cc1a1fc20a815ed92b5eefdc15cbe8062021f0b5a26a10"},
+ {file = "zstd-1.5.5.1-cp39-cp39-win32.whl", hash = "sha256:c91cc1606eb8b3a6fed11faaef4c6e55f1133d70cf0db0c829a2cf9c2ac1dfd9"},
+ {file = "zstd-1.5.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:f462e2ebf26dcbfc2c8dddd6b5c56859683f0b77edb8f268e637f7d390a58f74"},
+ {file = "zstd-1.5.5.1-pp27-pypy_73-macosx_10_14_x86_64.whl", hash = "sha256:c63f916732e3e309e49ec95e7a0af5d37ff1321f3df2aac10e507bd2b56fceda"},
+ {file = "zstd-1.5.5.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:50d4850d758bb033df50722cc13ed913b2afcd5385250be4f3ffb79a26b319c3"},
+ {file = "zstd-1.5.5.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:0412d666515e78a91ada7e2d78e9dd6b25ddda1b41623b145b99653275c7f3ce"},
+ {file = "zstd-1.5.5.1-pp36-pypy36_pp73-macosx_10_14_x86_64.whl", hash = "sha256:0ea91f74869a3cdcb2dde08f8f30ee3da72782c5d1737afed9c703232815864e"},
+ {file = "zstd-1.5.5.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:477548897dc2b8b595af7bec5f0f55dcba8e9a282335f687cc663b52b171357b"},
+ {file = "zstd-1.5.5.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c518938b57a56001ee04dcf79a432152f5bd431416f3b22819ba959bc6054d89"},
+ {file = "zstd-1.5.5.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:894a8fe0228d5e24dc286a8d98eb0ce2883f8e2e57f3b7e7619ebdb67967120a"},
+ {file = "zstd-1.5.5.1-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:42ec0a4ae9bedd9909fa4f580f3c800469da1b631faeaa94f204e1b66c767fa2"},
+ {file = "zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d56dedaa04ab8ecc23492972b12e0bf8529f64c9bceb28c11f43c2369c9768b3"},
+ {file = "zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5b060770d796e4c01f5848b345c3cea8a177ab4e7cd95a1963a355042d429e1"},
+ {file = "zstd-1.5.5.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fea04805ef6e1cb93d6e5d6bbc7a03bc75a5c733fd352d5aaa81109986fdf1ef"},
+ {file = "zstd-1.5.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:405c28a35756e57a434bbd7ed29dc5e6490cd2fc2118cbf78b60eaebd134f5e9"},
+ {file = "zstd-1.5.5.1-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:c42e630443b01a891277426365a51a2aa630b059ce675992c70c1928d30eccb4"},
+ {file = "zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1520d23f24f26cdfbcdb4dc86947446b8f694838bfce728d7fc4b3492397357c"},
+ {file = "zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4730737f63cf802321743ded6acc85e747e7f5587c5ba2e51a760bf009f7de"},
+ {file = "zstd-1.5.5.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9f8c014395e89ad7f67ffe873c0fa1d8e9b4dea8b1801d24e8d9ccd8259858d"},
+ {file = "zstd-1.5.5.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5d9ba4f6af0945809bfa3387c6a1208a22937a876521b9ec347e7183d623311b"},
+ {file = "zstd-1.5.5.1-pp39-pypy39_pp73-macosx_10_14_x86_64.whl", hash = "sha256:04dfd9f46b0b0b1bc413884fe028b726febcb726d4f66e3cf8afc00c2d9026bf"},
+ {file = "zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af52436a2eb5caa925d95461973984cb34d472a963b6be1c0a9f2dfbafad096f"},
+ {file = "zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610928b888a2e7ae9d2018ffa814859d47ec4ba75f89a1188ab4eb9232636ee5"},
+ {file = "zstd-1.5.5.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee3c9feea99c7f4ff43129a885da056b5aa0cde3f7876bf6397bfb9433f44352"},
+ {file = "zstd-1.5.5.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ac9768eeb3c6b530db93de2fec9b363776075dc8a00ee4049612ba5397ca8e"},
+ {file = "zstd-1.5.5.1.tar.gz", hash = "sha256:1ef980abf0e1e072b028d2d76ef95b476632651c96225cf30b619c6eef625672"},
+]
+
[metadata]
lock-version = "2.0"
python-versions = ">=3.11, <3.13"
-content-hash = "b5c62b81368f0e972fbcf0dbb88746f3ae930ebdc171ad004c926f3588d1f244"
+content-hash = "32df734a6ad6ad6a665c94c41cd0e3643a48174904faaf6f21c5c84f350f3cec"
diff --git a/pyproject.toml b/pyproject.toml
index 7b780c87f..374b0f46c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -139,35 +139,20 @@ psutil = "*"
timezonefinder = "*" # just used for nav ETA
pycryptodome = "*" # used in updated/casync, panda, body, and a test
-[tool.poetry.group.dev.dependencies]
-av = "*"
-azure-identity = "*"
-azure-storage-blob = "*"
-breathe = "*"
-control = "*"
-coverage = "*"
-dictdiffer = "*"
-flaky = "*"
-hypothesis = "~6.47"
-inputs = "*"
+#logreader
+zstd = "*"
+
+[tool.poetry.group.docs.dependencies]
Jinja2 = "*"
-lru-dict = "*"
-matplotlib = "*"
-metadrive-simulator = { git = "https://github.com/commaai/metadrive.git", branch = "python3.12", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
-mpld3 = "*"
+sphinx = "*"
+sphinx-rtd-theme = "*"
+sphinx-sitemap = "*"
+
+[tool.poetry.group.testing.dependencies]
+coverage = "*"
+hypothesis = "~6.47"
mypy = "*"
-myst-parser = "*"
-natsort = "*"
-opencv-python-headless = "*"
-parameterized = "^0.8"
-#pprofile = "*"
-polyline = "*"
pre-commit = "*"
-pyautogui = "*"
-pyopencl = { version = "*", markers = "platform_machine != 'aarch64'" } # broken on arm64
-pygame = "*"
-pywinctl = "*"
-pyprof2calltree = "*"
pytest = "*"
pytest-cov = "*"
pytest-cpp = "*"
@@ -178,11 +163,33 @@ pytest-randomly = "*"
pytest-asyncio = "*"
pytest-mock = "*"
pytest-repeat = "*"
-rerun-sdk = "*"
ruff = "*"
-sphinx = "*"
-sphinx-rtd-theme = "*"
-sphinx-sitemap = "*"
+
+[tool.poetry.group.dev.dependencies]
+av = "*"
+azure-identity = "*"
+azure-storage-blob = "*"
+breathe = "*"
+control = "*"
+dictdiffer = "*"
+flaky = "*"
+inputs = "*"
+lru-dict = "*"
+matplotlib = "*"
+metadrive-simulator = { git = "https://github.com/commaai/metadrive.git", branch = "anisotropic_off", markers = "platform_machine != 'aarch64'" } # no linux/aarch64 wheels for certain dependencies
+mpld3 = "*"
+myst-parser = "*"
+natsort = "*"
+opencv-python-headless = "*"
+parameterized = "^0.8"
+#pprofile = "*"
+polyline = "*"
+pyautogui = "*"
+pygame = "*"
+pyopencl = { version = "*", markers = "platform_machine != 'aarch64'" } # broken on arm64
+pywinctl = "*"
+pyprof2calltree = "*"
+rerun-sdk = "*"
tabulate = "*"
types-requests = "*"
types-tabulate = "*"
diff --git a/release/check-submodules.sh b/release/check-submodules.sh
index bff8d7a28..5305cecd3 100755
--- a/release/check-submodules.sh
+++ b/release/check-submodules.sh
@@ -1,7 +1,7 @@
#!/bin/bash
while read hash submodule ref; do
- git -C $submodule fetch --depth 2000 origin master
+ git -C $submodule fetch --depth 3000 origin master
git -C $submodule branch -r --contains $hash | grep "origin/master"
if [ "$?" -eq 0 ]; then
echo "$submodule ok"
diff --git a/selfdrive/car/ecu_addrs.py b/selfdrive/car/ecu_addrs.py
index e7a9fbcf2..756cd7f96 100755
--- a/selfdrive/car/ecu_addrs.py
+++ b/selfdrive/car/ecu_addrs.py
@@ -71,25 +71,35 @@ def get_ecu_addrs(logcan: messaging.SubSocket, sendcan: messaging.PubSocket, que
if __name__ == "__main__":
import argparse
+ from openpilot.common.params import Params
+ from openpilot.selfdrive.car.fw_versions import set_obd_multiplexing
parser = argparse.ArgumentParser(description='Get addresses of all ECUs')
parser.add_argument('--debug', action='store_true')
parser.add_argument('--bus', type=int, default=1)
+ parser.add_argument('--no-obd', action='store_true')
parser.add_argument('--timeout', type=float, default=1.0)
args = parser.parse_args()
logcan = messaging.sub_sock('can')
sendcan = messaging.pub_sock('sendcan')
- time.sleep(1.0)
+ # Set up params for pandad
+ params = Params()
+ params.remove("FirmwareQueryDone")
+ params.put_bool("IsOnroad", False)
+ time.sleep(0.2) # thread is 10 Hz
+ params.put_bool("IsOnroad", True)
+
+ set_obd_multiplexing(params, not args.no_obd)
print("Getting ECU addresses ...")
ecu_addrs = get_all_ecu_addrs(logcan, sendcan, args.bus, args.timeout, debug=args.debug)
print()
- print("Found ECUs on addresses:")
+ print("Found ECUs on rx addresses:")
for addr, subaddr, _ in ecu_addrs:
- msg = f" 0x{hex(addr)}"
+ msg = f" {hex(addr)}"
if subaddr is not None:
msg += f" (sub-address: {hex(subaddr)})"
print(msg)
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index 2ef5d427e..54cf86510 100644
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -22,10 +22,6 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.2
ret.steerLimitTimer = 1.0
- ret.longitudinalTuning.kpBP = [0.]
- ret.longitudinalTuning.kpV = [0.5]
- ret.longitudinalTuning.kiV = [0.]
-
CAN = CanBus(fingerprint=fingerprint)
cfgs = [get_safety_config(car.CarParams.SafetyModel.ford)]
if CAN.main >= 4:
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index 2e194b12f..5ea2b1989 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -94,11 +94,7 @@ class CarInterface(CarInterfaceBase):
else:
ret.transmissionType = TransmissionType.automatic
- ret.longitudinalTuning.deadzoneBP = [0.]
- ret.longitudinalTuning.deadzoneV = [0.15]
-
- ret.longitudinalTuning.kpBP = [5., 35.]
- ret.longitudinalTuning.kiBP = [0.]
+ ret.longitudinalTuning.kiBP = [5., 35.]
if candidate in CAMERA_ACC_CAR:
ret.experimentalLongitudinalAvailable = True
@@ -110,8 +106,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 10 * CV.KPH_TO_MS
# Tuning for experimental long
- ret.longitudinalTuning.kpV = [2.0, 1.5]
- ret.longitudinalTuning.kiV = [0.72]
+ ret.longitudinalTuning.kiV = [2.0, 1.5]
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25
@@ -131,8 +126,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
# Tuning
- ret.longitudinalTuning.kpV = [2.4, 1.5]
- ret.longitudinalTuning.kiV = [0.36]
+ ret.longitudinalTuning.kiV = [2.4, 1.5]
# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 43a4454b9..fdcba8bb8 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -72,17 +72,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward
if candidate in HONDA_BOSCH:
- ret.longitudinalTuning.kpV = [0.25]
- ret.longitudinalTuning.kiV = [0.05]
ret.longitudinalActuatorDelay = 0.5 # s
if candidate in HONDA_BOSCH_RADARLESS:
ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model
else:
# default longitudinal tuning for all hondas
- ret.longitudinalTuning.kpBP = [0., 5., 35.]
- ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5]
- ret.longitudinalTuning.kiBP = [0., 35.]
- ret.longitudinalTuning.kiV = [0.18, 0.12]
+ ret.longitudinalTuning.kiBP = [0., 5., 35.]
+ ret.longitudinalTuning.kiV = [1.2, 0.8, 0.5]
eps_modified = False
for fw in car_fw:
diff --git a/selfdrive/car/hyundai/fingerprints.py b/selfdrive/car/hyundai/fingerprints.py
index d115283dd..e489a3cf6 100644
--- a/selfdrive/car/hyundai/fingerprints.py
+++ b/selfdrive/car/hyundai/fingerprints.py
@@ -2,6 +2,9 @@
from cereal import car
from openpilot.selfdrive.car.hyundai.values import CAR
+# The existence of SCC or RDR in the fwdRadar FW usually determines the radar's function,
+# i.e. if it sends the SCC messages or if another ECU like the camera or ADAS Driving ECU does
+
Ecu = car.CarParams.Ecu
FINGERPRINTS = {
@@ -995,6 +998,8 @@ FW_VERSIONS = {
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
+ b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI100 230915',
+ b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.00 99211-GI100 230915',
],
},
CAR.HYUNDAI_IONIQ_6: {
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index 0ba4dcb5e..ecedf3fd7 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -80,12 +80,8 @@ class CarInterface(CarInterfaceBase):
# *** longitudinal control ***
if candidate in CANFD_CAR:
- ret.longitudinalTuning.kpV = [0.1]
- ret.longitudinalTuning.kiV = [0.0]
ret.experimentalLongitudinalAvailable = candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
else:
- ret.longitudinalTuning.kpV = [0.5]
- ret.longitudinalTuning.kiV = [0.0]
ret.experimentalLongitudinalAvailable = candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
ret.openpilotLongitudinalControl = experimental_long and ret.experimentalLongitudinalAvailable
ret.pcmCruise = not ret.openpilotLongitudinalControl
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index c489ea004..8cb29c803 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -306,9 +306,9 @@ class CAR(Platforms):
)
HYUNDAI_IONIQ_5 = HyundaiCanFDPlatformConfig(
[
- HyundaiCarDocs("Hyundai Ioniq 5 (Southeast Asia only) 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
- HyundaiCarDocs("Hyundai Ioniq 5 (without HDA II) 2022-23", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_k])),
- HyundaiCarDocs("Hyundai Ioniq 5 (with HDA II) 2022-23", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ HyundaiCarDocs("Hyundai Ioniq 5 (Non-US only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ HyundaiCarDocs("Hyundai Ioniq 5 (without HDA II) 2022-24", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ HyundaiCarDocs("Hyundai Ioniq 5 (with HDA II) 2022-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
],
CarSpecs(mass=1948, wheelbase=2.97, steerRatio=14.26, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
@@ -478,7 +478,7 @@ class CAR(Platforms):
)
KIA_EV6 = HyundaiCanFDPlatformConfig(
[
- HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
+ HyundaiCarDocs("Kia EV6 (Non-US only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
HyundaiCarDocs("Kia EV6 (without HDA II) 2022-24", "Highway Driving Assist", car_parts=CarParts.common([CarHarness.hyundai_l])),
HyundaiCarDocs("Kia EV6 (with HDA II) 2022-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
],
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index 5eac6062a..e5762ed52 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -202,13 +202,11 @@ class CarInterfaceBase(ABC):
ret.vEgoStopping = 0.5
ret.vEgoStarting = 0.5
ret.stoppingControl = True
- ret.longitudinalTuning.deadzoneBP = [0.]
- ret.longitudinalTuning.deadzoneV = [0.]
ret.longitudinalTuning.kf = 1.
ret.longitudinalTuning.kpBP = [0.]
- ret.longitudinalTuning.kpV = [1.]
+ ret.longitudinalTuning.kpV = [0.]
ret.longitudinalTuning.kiBP = [0.]
- ret.longitudinalTuning.kiV = [1.]
+ ret.longitudinalTuning.kiV = [0.]
# TODO estimate car specific lag, use .15s for now
ret.longitudinalActuatorDelay = 0.15
ret.steerLimitTimer = 1.0
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index 1aa4bd95e..cb0093437 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -91,11 +91,6 @@ class CarInterface(CarInterfaceBase):
ret.flags |= SubaruFlags.DISABLE_EYESIGHT.value
if ret.openpilotLongitudinalControl:
- ret.longitudinalTuning.kpBP = [0., 5., 35.]
- ret.longitudinalTuning.kpV = [0.8, 1.0, 1.5]
- ret.longitudinalTuning.kiBP = [0., 35.]
- ret.longitudinalTuning.kiV = [0.54, 0.36]
-
ret.stoppingControl = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_LONG
diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py
index 09de10b54..deb0e0023 100755
--- a/selfdrive/car/tesla/interface.py
+++ b/selfdrive/car/tesla/interface.py
@@ -18,11 +18,6 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = car.CarParams.SteerControlType.angle
- # Set kP and kI to 0 over the whole speed range to have the planner accel as actuator command
- ret.longitudinalTuning.kpBP = [0]
- ret.longitudinalTuning.kpV = [0]
- ret.longitudinalTuning.kiBP = [0]
- ret.longitudinalTuning.kiV = [0]
ret.longitudinalActuatorDelay = 0.5 # s
ret.radarTimeStep = (1.0 / 8) # 8Hz
diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py
index dd3a8f633..b1156f0e8 100755
--- a/selfdrive/car/tests/routes.py
+++ b/selfdrive/car/tests/routes.py
@@ -225,7 +225,6 @@ routes = [
CarTestRoute("cd9cff4b0b26c435|2021-05-13--15-12-39", TOYOTA.TOYOTA_CHR),
CarTestRoute("57858ede0369a261|2021-05-18--20-34-20", TOYOTA.TOYOTA_CHR), # hybrid
CarTestRoute("ea8fbe72b96a185c|2023-02-08--15-11-46", TOYOTA.TOYOTA_CHR_TSS2),
- CarTestRoute("ea8fbe72b96a185c|2023-02-22--09-20-34", TOYOTA.TOYOTA_CHR_TSS2), # openpilot longitudinal, with smartDSU
CarTestRoute("6719965b0e1d1737|2023-02-09--22-44-05", TOYOTA.TOYOTA_CHR_TSS2), # hybrid
CarTestRoute("6719965b0e1d1737|2023-08-29--06-40-05", TOYOTA.TOYOTA_CHR_TSS2), # hybrid, openpilot longitudinal, radar disabled
CarTestRoute("14623aae37e549f3|2021-10-24--01-20-49", TOYOTA.TOYOTA_PRIUS_V),
diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py
index 19096c23e..a6f74d685 100644
--- a/selfdrive/car/tests/test_car_interfaces.py
+++ b/selfdrive/car/tests/test_car_interfaces.py
@@ -75,7 +75,6 @@ class TestCarInterfaces:
# Longitudinal sanity checks
assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
- assert len(car_params.longitudinalTuning.deadzoneV) == len(car_params.longitudinalTuning.deadzoneBP)
# Lateral sanity checks
if car_params.steerControlType != car.CarParams.SteerControlType.angle:
diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py
index 8315f24ae..a596881c3 100644
--- a/selfdrive/car/toyota/carstate.py
+++ b/selfdrive/car/toyota/carstate.py
@@ -132,8 +132,7 @@ class CarState(CarStateBase):
cp_acc = cp_cam if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) else cp
if self.CP.carFingerprint in TSS2_CAR and not self.CP.flags & ToyotaFlags.DISABLE_RADAR.value:
- if not (self.CP.flags & ToyotaFlags.SMART_DSU.value):
- self.acc_type = cp_acc.vl["ACC_CONTROL"]["ACC_TYPE"]
+ self.acc_type = cp_acc.vl["ACC_CONTROL"]["ACC_TYPE"]
ret.stockFcw = bool(cp_acc.vl["PCS_HUD"]["FCW"])
# some TSS2 cars have low speed lockout permanently set, so ignore on those cars
@@ -167,13 +166,11 @@ class CarState(CarStateBase):
if self.CP.carFingerprint not in UNSUPPORTED_DSU_CAR:
self.pcm_follow_distance = cp.vl["PCM_CRUISE_2"]["PCM_FOLLOW_DISTANCE"]
- if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER):
+ if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR):
# distance button is wired to the ACC module (camera or radar)
self.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"]
- else:
- self.distance_button = cp.vl["SDSU"]["FD_BUTTON"]
return ret
@@ -208,12 +205,9 @@ class CarState(CarStateBase):
messages.append(("BSM", 1))
if CP.carFingerprint in RADAR_ACC_CAR and not CP.flags & ToyotaFlags.DISABLE_RADAR.value:
- if not CP.flags & ToyotaFlags.SMART_DSU.value:
- messages += [
- ("ACC_CONTROL", 33),
- ]
messages += [
("PCS_HUD", 1),
+ ("ACC_CONTROL", 33),
]
if CP.carFingerprint not in (TSS2_CAR - RADAR_ACC_CAR) and not CP.enableDsu and not CP.flags & ToyotaFlags.DISABLE_RADAR.value:
@@ -221,11 +215,6 @@ class CarState(CarStateBase):
("PRE_COLLISION", 33),
]
- if CP.flags & ToyotaFlags.SMART_DSU and not CP.flags & ToyotaFlags.RADAR_CAN_FILTER:
- messages += [
- ("SDSU", 100),
- ]
-
return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0)
@staticmethod
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index 3ea05f9fe..6487257bb 100644
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -44,18 +44,9 @@ class CarInterface(CarInterfaceBase):
stop_and_go = candidate in TSS2_CAR
- # Detect smartDSU, which intercepts ACC_CMD from the DSU (or radar) allowing openpilot to send it
- # 0x2AA is sent by a similar device which intercepts the radar instead of DSU on NO_DSU_CARs
- if 0x2FF in fingerprint[0] or (0x2AA in fingerprint[0] and candidate in NO_DSU_CAR):
- ret.flags |= ToyotaFlags.SMART_DSU.value
-
- if 0x2AA in fingerprint[0] and candidate in NO_DSU_CAR:
- ret.flags |= ToyotaFlags.RADAR_CAN_FILTER.value
-
# In TSS2 cars, the camera does long control
found_ecus = [fw.ecu for fw in car_fw]
- ret.enableDsu = len(found_ecus) > 0 and Ecu.dsu not in found_ecus and candidate not in (NO_DSU_CAR | UNSUPPORTED_DSU_CAR) \
- and not (ret.flags & ToyotaFlags.SMART_DSU)
+ ret.enableDsu = len(found_ecus) > 0 and Ecu.dsu not in found_ecus and candidate not in (NO_DSU_CAR | UNSUPPORTED_DSU_CAR)
if candidate == CAR.TOYOTA_PRIUS:
stop_and_go = True
@@ -98,7 +89,7 @@ class CarInterface(CarInterfaceBase):
# TODO: these models can do stop and go, but unclear if it requires sDSU or unplugging DSU.
# For now, don't list stop and go functionality in the docs
if ret.flags & ToyotaFlags.SNG_WITHOUT_DSU:
- stop_and_go = stop_and_go or bool(ret.flags & ToyotaFlags.SMART_DSU.value) or (ret.enableDsu and not docs)
+ stop_and_go = stop_and_go or (ret.enableDsu and not docs)
ret.centerToFront = ret.wheelbase * 0.44
@@ -110,28 +101,20 @@ class CarInterface(CarInterfaceBase):
# TODO: make an adas dbc file for dsu-less models
ret.radarUnavailable = DBC[candidate]['radar'] is None or candidate in (NO_DSU_CAR - TSS2_CAR)
- # if the smartDSU is detected, openpilot can send ACC_CONTROL and the smartDSU will block it from the DSU or radar.
# since we don't yet parse radar on TSS2/TSS-P radar-based ACC cars, gate longitudinal behind experimental toggle
- use_sdsu = bool(ret.flags & ToyotaFlags.SMART_DSU)
if candidate in (RADAR_ACC_CAR | NO_DSU_CAR):
- ret.experimentalLongitudinalAvailable = use_sdsu or candidate in RADAR_ACC_CAR
+ ret.experimentalLongitudinalAvailable = candidate in RADAR_ACC_CAR
- if not use_sdsu:
- # Disabling radar is only supported on TSS2 radar-ACC cars
- if experimental_long and candidate in RADAR_ACC_CAR:
- ret.flags |= ToyotaFlags.DISABLE_RADAR.value
- else:
- use_sdsu = use_sdsu and experimental_long
+ # Disabling radar is only supported on TSS2 radar-ACC cars
+ if experimental_long and candidate in RADAR_ACC_CAR:
+ ret.flags |= ToyotaFlags.DISABLE_RADAR.value
# openpilot longitudinal enabled by default:
- # - non-(TSS2 radar ACC cars) w/ smartDSU installed
# - cars w/ DSU disconnected
# - TSS2 cars with camera sending ACC_CONTROL where we can block it
# openpilot longitudinal behind experimental long toggle:
- # - TSS2 radar ACC cars w/ smartDSU installed
- # - TSS2 radar ACC cars w/o smartDSU installed (disables radar)
- # - TSS-P DSU-less cars w/ CAN filter installed (no radar parser yet)
- ret.openpilotLongitudinalControl = use_sdsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)
+ # - TSS2 radar ACC cars (disables radar)
+ ret.openpilotLongitudinalControl = ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value)
ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR
if not ret.openpilotLongitudinalControl:
@@ -142,28 +125,21 @@ class CarInterface(CarInterfaceBase):
ret.minEnableSpeed = -1. if stop_and_go else MIN_ACC_SPEED
tune = ret.longitudinalTuning
- tune.deadzoneBP = [0., 9.]
- tune.deadzoneV = [.0, .15]
if candidate in TSS2_CAR:
- tune.kpBP = [0., 5., 20.]
- tune.kpV = [1.3, 1.0, 0.7]
- tune.kiBP = [0., 5., 12., 20., 27.]
- tune.kiV = [.35, .23, .20, .17, .1]
- if candidate in TSS2_CAR:
- ret.vEgoStopping = 0.25
- ret.vEgoStarting = 0.25
- ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
+ tune.kpV = [0.0]
+ tune.kiV = [0.5]
+ ret.vEgoStopping = 0.25
+ ret.vEgoStarting = 0.25
+ ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
else:
- tune.kpBP = [0., 5., 35.]
- tune.kiBP = [0., 35.]
- tune.kpV = [3.6, 2.4, 1.5]
- tune.kiV = [0.54, 0.36]
+ tune.kiBP = [0., 5., 35.]
+ tune.kiV = [3.6, 2.4, 1.5]
return ret
@staticmethod
def init(CP, logcan, sendcan):
- # disable radar if alpha longitudinal toggled on radar-ACC car without CAN filter/smartDSU
+ # disable radar if alpha longitudinal toggled on radar-ACC car
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])
disable_ecu(logcan, sendcan, bus=0, addr=0x750, sub_addr=0xf, com_cont_req=communication_control)
@@ -172,7 +148,7 @@ class CarInterface(CarInterfaceBase):
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_cam)
- if self.CP.carFingerprint in (TSS2_CAR - RADAR_ACC_CAR) or (self.CP.flags & ToyotaFlags.SMART_DSU and not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER):
+ 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
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index 2e781ad0a..8022e8b3a 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -44,9 +44,7 @@ class CarControllerParams:
class ToyotaFlags(IntFlag):
# Detected flags
HYBRID = 1
- SMART_DSU = 2
DISABLE_RADAR = 4
- RADAR_CAN_FILTER = 1024
# Static flags
TSS2 = 8
@@ -56,7 +54,7 @@ class ToyotaFlags(IntFlag):
# these cars use the Lane Tracing Assist (LTA) message for lateral control
ANGLE_CONTROL = 128
NO_STOP_TIMER = 256
- # these cars are speculated to allow stop and go when the DSU is unplugged or disabled with sDSU
+ # these cars are speculated to allow stop and go when the DSU is unplugged
SNG_WITHOUT_DSU = 512
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index 91cd300e9..77e56875b 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -96,8 +96,6 @@ class CarInterface(CarInterfaceBase):
ret.stopAccel = -0.55
ret.vEgoStarting = 0.1
ret.vEgoStopping = 0.5
- ret.longitudinalTuning.kpV = [0.1]
- ret.longitudinalTuning.kiV = [0.0]
ret.autoResumeSng = ret.minEnableSpeed == -1
return ret
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index 5746777f1..393824741 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -580,13 +580,12 @@ class Controls:
if not CC.latActive:
self.LaC.reset()
if not CC.longActive:
- self.LoC.reset(v_pid=CS.vEgo)
+ self.LoC.reset()
if not self.joystick_mode:
# accel PID loop
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_helper.v_cruise_kph * CV.KPH_TO_MS)
- t_since_plan = (self.sm.frame - self.sm.recv_frame['longitudinalPlan']) * DT_CTRL
- actuators.accel = self.LoC.update(CC.longActive, CS, long_plan, pid_accel_limits, t_since_plan)
+ actuators.accel = self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits)
# Steering PID loop and lateral MPC
self.desired_curvature = clip_curvature(CS.vEgo, self.desired_curvature, model_v2.action.desiredCurvature)
@@ -769,7 +768,6 @@ class Controls:
controlsState.state = self.state
controlsState.engageable = not self.events.contains(ET.NO_ENTRY)
controlsState.longControlState = self.LoC.long_control_state
- controlsState.vPid = float(self.LoC.v_pid)
controlsState.vCruise = float(self.v_cruise_helper.v_cruise_kph)
controlsState.vCruiseCluster = float(self.v_cruise_helper.v_cruise_cluster_kph)
controlsState.upAccelCmd = float(self.LoC.pid.p)
@@ -860,7 +858,7 @@ class Controls:
while True:
self.step()
self.rk.monitor_time()
- except SystemExit:
+ finally:
e.set()
t.join()
diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py
index 6a5b22f68..cfc6374a1 100644
--- a/selfdrive/controls/lib/drive_helpers.py
+++ b/selfdrive/controls/lib/drive_helpers.py
@@ -141,16 +141,6 @@ class VCruiseHelper:
self.v_cruise_cluster_kph = self.v_cruise_kph
-def apply_deadzone(error, deadzone):
- if error > deadzone:
- error -= deadzone
- elif error < - deadzone:
- error += deadzone
- else:
- error = 0.
- return error
-
-
def apply_center_deadzone(error, deadzone):
if (error > - deadzone) and (error < deadzone):
error = 0.
diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py
index a619c4763..e4841c705 100644
--- a/selfdrive/controls/lib/longcontrol.py
+++ b/selfdrive/controls/lib/longcontrol.py
@@ -1,7 +1,7 @@
from cereal import car
-from openpilot.common.numpy_fast import clip, interp
+from openpilot.common.numpy_fast import clip
from openpilot.common.realtime import DT_CTRL
-from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
+from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.modeld.constants import ModelConstants
@@ -10,18 +10,10 @@ CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
LongCtrlState = car.CarControl.Actuators.LongControlState
-def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
- v_target_1sec, brake_pressed, cruise_standstill):
- accelerating = v_target_1sec > v_target
- planned_stop = (v_target < CP.vEgoStopping and
- v_target_1sec < CP.vEgoStopping and
- not accelerating)
- stay_stopped = (v_ego < CP.vEgoStopping and
- (brake_pressed or cruise_standstill))
- stopping_condition = planned_stop or stay_stopped
-
- starting_condition = (v_target_1sec > CP.vEgoStarting and
- accelerating and
+def long_control_state_trans(CP, active, long_control_state, v_ego,
+ should_stop, brake_pressed, cruise_standstill):
+ stopping_condition = should_stop
+ starting_condition = (not should_stop and
not cruise_standstill and
not brake_pressed)
started_condition = v_ego > CP.vEgoStarting
@@ -34,7 +26,6 @@ def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
long_control_state = LongCtrlState.pid
if stopping_condition:
long_control_state = LongCtrlState.stopping
-
elif long_control_state == LongCtrlState.stopping:
if starting_condition and CP.startingState:
long_control_state = LongCtrlState.starting
@@ -49,78 +40,45 @@ def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
return long_control_state
-
class LongControl:
def __init__(self, CP):
self.CP = CP
- self.long_control_state = LongCtrlState.off # initialized to off
+ self.long_control_state = LongCtrlState.off
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL)
- self.v_pid = 0.0
self.last_output_accel = 0.0
- def reset(self, v_pid):
- """Reset PID controller and change setpoint"""
+ def reset(self):
self.pid.reset()
- self.v_pid = v_pid
- def update(self, active, CS, long_plan, accel_limits, t_since_plan):
+ def update(self, active, CS, a_target, should_stop, accel_limits):
"""Update longitudinal control. This updates the state machine and runs a PID loop"""
- # Interp control trajectory
- speeds = long_plan.speeds
- if len(speeds) == CONTROL_N:
- v_target_now = interp(t_since_plan, CONTROL_N_T_IDX, speeds)
- a_target_now = interp(t_since_plan, CONTROL_N_T_IDX, long_plan.accels)
-
- v_target = interp(self.CP.longitudinalActuatorDelay + t_since_plan, CONTROL_N_T_IDX, speeds)
- a_target = 2 * (v_target - v_target_now) / self.CP.longitudinalActuatorDelay - a_target_now
-
- v_target_1sec = interp(self.CP.longitudinalActuatorDelay + t_since_plan + 1.0, CONTROL_N_T_IDX, speeds)
- else:
- v_target = 0.0
- v_target_now = 0.0
- v_target_1sec = 0.0
- a_target = 0.0
-
self.pid.neg_limit = accel_limits[0]
self.pid.pos_limit = accel_limits[1]
- output_accel = self.last_output_accel
self.long_control_state = long_control_state_trans(self.CP, active, self.long_control_state, CS.vEgo,
- v_target, v_target_1sec, CS.brakePressed,
+ should_stop, CS.brakePressed,
CS.cruiseState.standstill)
-
if self.long_control_state == LongCtrlState.off:
- self.reset(CS.vEgo)
+ self.reset()
output_accel = 0.
elif self.long_control_state == LongCtrlState.stopping:
+ output_accel = self.last_output_accel
if output_accel > self.CP.stopAccel:
output_accel = min(output_accel, 0.0)
output_accel -= self.CP.stoppingDecelRate * DT_CTRL
- self.reset(CS.vEgo)
+ self.reset()
elif self.long_control_state == LongCtrlState.starting:
output_accel = self.CP.startAccel
- self.reset(CS.vEgo)
+ self.reset()
- elif self.long_control_state == LongCtrlState.pid:
- self.v_pid = v_target_now
-
- # Toyota starts braking more when it thinks you want to stop
- # Freeze the integrator so we don't accelerate to compensate, and don't allow positive acceleration
- # TODO too complex, needs to be simplified and tested on toyotas
- prevent_overshoot = not self.CP.stoppingControl and CS.vEgo < 1.5 and v_target_1sec < 0.7 and v_target_1sec < self.v_pid
- deadzone = interp(CS.vEgo, self.CP.longitudinalTuning.deadzoneBP, self.CP.longitudinalTuning.deadzoneV)
- freeze_integrator = prevent_overshoot
-
- error = self.v_pid - CS.vEgo
- error_deadzone = apply_deadzone(error, deadzone)
- output_accel = self.pid.update(error_deadzone, speed=CS.vEgo,
- feedforward=a_target,
- freeze_integrator=freeze_integrator)
+ else: # LongCtrlState.pid
+ error = a_target - CS.aEgo
+ output_accel = self.pid.update(error, speed=CS.vEgo,
+ feedforward=a_target)
self.last_output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
-
return self.last_output_accel
diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py
index 5126f0dab..2157a584f 100755
--- a/selfdrive/controls/lib/longitudinal_planner.py
+++ b/selfdrive/controls/lib/longitudinal_planner.py
@@ -23,6 +23,7 @@ LON_MPC_STEP = 0.2 # first step is 0.2s
A_CRUISE_MIN = -1.2
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
+CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
# Lookup table for turns
_A_TOTAL_MAX_V = [1.7, 3.2]
@@ -38,7 +39,6 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP):
This function returns a limited long acceleration allowed, depending on the existing lateral acceleration
this should avoid accelerating when losing the target in turns
"""
-
# FIXME: This function to calculate lateral accel is incorrect and should use the VehicleModel
# The lookup table for turns should also be updated if we do this
a_total_max = interp(v_ego, _A_TOTAL_MAX_BP, _A_TOTAL_MAX_V)
@@ -48,6 +48,26 @@ def limit_accel_in_turns(v_ego, angle_steers, a_target, CP):
return [a_target[0], min(a_target[1], a_x_allowed)]
+def get_accel_from_plan(CP, long_plan):
+ speeds = long_plan.speeds
+ if len(speeds) == CONTROL_N:
+ v_target_now = interp(DT_MDL, CONTROL_N_T_IDX, speeds)
+ a_target_now = interp(DT_MDL, CONTROL_N_T_IDX, long_plan.accels)
+
+ v_target = interp(CP.longitudinalActuatorDelay + DT_MDL, CONTROL_N_T_IDX, speeds)
+ a_target = 2 * (v_target - v_target_now) / CP.longitudinalActuatorDelay - a_target_now
+
+ v_target_1sec = interp(CP.longitudinalActuatorDelay + DT_MDL + 1.0, CONTROL_N_T_IDX, speeds)
+ else:
+ v_target = 0.0
+ v_target_now = 0.0
+ v_target_1sec = 0.0
+ a_target = 0.0
+ should_stop = (v_target < CP.vEgoStopping and
+ v_target_1sec < CP.vEgoStopping)
+ return a_target, should_stop
+
+
class LongitudinalPlanner:
def __init__(self, CP, init_v=0.0, init_a=0.0, dt=DT_MDL):
self.CP = CP
@@ -165,9 +185,14 @@ class LongitudinalPlanner:
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
+
longitudinalPlan = plan_send.longitudinalPlan
longitudinalPlan.modelMonoTime = sm.logMonoTime['modelV2']
longitudinalPlan.processingDelay = (plan_send.logMonoTime / 1e9) - sm.logMonoTime['modelV2']
+ longitudinalPlan.solverExecutionTime = self.mpc.solve_time
+
+ longitudinalPlan.allowBrake = True
+ longitudinalPlan.allowThrottle = True
longitudinalPlan.speeds = self.v_desired_trajectory.tolist()
longitudinalPlan.accels = self.a_desired_trajectory.tolist()
@@ -177,7 +202,11 @@ class LongitudinalPlanner:
longitudinalPlan.longitudinalPlanSource = self.mpc.source
longitudinalPlan.fcw = self.fcw
- longitudinalPlan.solverExecutionTime = self.mpc.solve_time
+ a_target, should_stop = get_accel_from_plan(self.CP, longitudinalPlan)
+ longitudinalPlan.aTarget = a_target
+ longitudinalPlan.shouldStop = should_stop
+ longitudinalPlan.allowBrake = True
+ longitudinalPlan.allowThrottle = True
pm.send('longitudinalPlan', plan_send)
diff --git a/selfdrive/debug/internal/qlog_size.py b/selfdrive/debug/internal/qlog_size.py
index 0b816604a..2d17a1ee2 100755
--- a/selfdrive/debug/internal/qlog_size.py
+++ b/selfdrive/debug/internal/qlog_size.py
@@ -6,6 +6,7 @@ from collections import defaultdict
import matplotlib.pyplot as plt
from openpilot.tools.lib.logreader import LogReader
+from tqdm import tqdm
MIN_SIZE = 0.5 # Percent size of total to show as separate entry
@@ -15,19 +16,23 @@ def make_pie(msgs, typ):
for m in msgs:
msgs_by_type[m.which()].append(m.as_builder().to_bytes())
- length_by_type = {k: len(b"".join(v)) for k, v in msgs_by_type.items()}
- compressed_length_by_type = {k: len(bz2.compress(b"".join(v))) for k, v in msgs_by_type.items()}
-
- total = sum(compressed_length_by_type.values())
+ total = len(bz2.compress(b"".join([m.as_builder().to_bytes() for m in msgs])))
uncompressed_total = len(b"".join([m.as_builder().to_bytes() for m in msgs]))
+ length_by_type = {k: len(b"".join(v)) for k, v in msgs_by_type.items()}
+ # calculate compressed size by calculating diff when removed from the segment
+ compressed_length_by_type = {}
+ for k in tqdm(msgs_by_type.keys(), desc="Compressing"):
+ compressed_length_by_type[k] = total - len(bz2.compress(b"".join([m.as_builder().to_bytes() for m in msgs if m.which() != k])))
+
sizes = sorted(compressed_length_by_type.items(), key=lambda kv: kv[1])
print("name - comp. size (uncomp. size)")
for (name, sz) in sizes:
print(f"{name:<22} - {sz / 1024:.2f} kB ({length_by_type[name] / 1024:.2f} kB)")
print()
- print(f"{typ} - Total {total / 1024:.2f} kB")
+ print(f"{typ} - Real total {total / 1024:.2f} kB")
+ print(f"{typ} - Breakdown total {sum(compressed_length_by_type.values()) / 1024:.2f} kB")
print(f"{typ} - Uncompressed total {uncompressed_total / 1024 / 1024:.2f} MB")
sizes_large = [(k, sz) for (k, sz) in sizes if sz >= total * MIN_SIZE / 100]
diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript
index 295e8127d..378e76249 100644
--- a/selfdrive/navd/SConscript
+++ b/selfdrive/navd/SConscript
@@ -1,4 +1,4 @@
-Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations')
+Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations', 'UBUNTU_FOCAL')
map_env = qt_env.Clone()
libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, visionipc, transformations,
@@ -6,7 +6,7 @@ libs = ['qt_widgets', 'qt_util', 'QMapLibre', common, messaging, visionipc, tran
if arch == 'larch64':
libs.append(':libEGL_mesa.so.0')
-if arch in ['larch64', 'aarch64', 'x86_64']:
+if arch in ['larch64', 'aarch64', 'x86_64'] and not UBUNTU_FOCAL:
if arch == 'x86_64':
rpath = Dir(f"#third_party/maplibre-native-qt/{arch}/lib").srcnode().abspath
map_env["RPATH"] += [rpath, ]
diff --git a/selfdrive/pandad/panda_comms.cc b/selfdrive/pandad/panda_comms.cc
index 4e8a0a27b..59908f0cd 100644
--- a/selfdrive/pandad/panda_comms.cc
+++ b/selfdrive/pandad/panda_comms.cc
@@ -120,7 +120,7 @@ std::vector PandaUsbHandle::list() {
libusb_close(handle);
if (ret < 0) { goto finish; }
- serials.push_back(std::string((char *)desc_serial, ret).c_str());
+ serials.push_back(std::string((char *)desc_serial, ret));
}
}
diff --git a/selfdrive/pandad/tests/test_pandad_spi.py b/selfdrive/pandad/tests/test_pandad_spi.py
index 11e20e72c..9c5990cd3 100644
--- a/selfdrive/pandad/tests/test_pandad_spi.py
+++ b/selfdrive/pandad/tests/test_pandad_spi.py
@@ -84,8 +84,8 @@ class TestBoarddSpi:
ps = m.peripheralState
assert ps.pandaType == "tres"
assert 4000 < ps.voltage < 14000
- assert 100 < ps.current < 1000
- assert ps.fanSpeedRpm < 8000
+ assert 50 < ps.current < 1000
+ assert ps.fanSpeedRpm < 10000
time.sleep(0.5)
et = time.monotonic() - st
diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit
index 227202839..96161a42d 100644
--- a/selfdrive/test/process_replay/ref_commit
+++ b/selfdrive/test/process_replay/ref_commit
@@ -1 +1 @@
-6438bd5edad674c2de3c7e2d126271cb2576383d
+8737e368e17f859291164286feb4246e00c0b4a5
diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript
index 30fce52c5..14ff57ec7 100644
--- a/selfdrive/ui/SConscript
+++ b/selfdrive/ui/SConscript
@@ -1,6 +1,6 @@
import os
import json
-Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations')
+Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'transformations', 'UBUNTU_FOCAL')
base_libs = [common, messaging, visionipc, transformations,
'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + qt_env["LIBS"]
@@ -13,7 +13,7 @@ dp_priv = len(os.listdir(Dir(f"#dp_priv/").abspath)) > 2
if arch == 'larch64':
base_libs.append('EGL')
-maps = arch in ['larch64', 'aarch64', 'x86_64']
+maps = arch in ['larch64', 'aarch64', 'x86_64'] and not UBUNTU_FOCAL
if arch == "Darwin":
del base_libs[base_libs.index('OpenCL')]
diff --git a/selfdrive/ui/qt/maps/map_helpers.cc b/selfdrive/ui/qt/maps/map_helpers.cc
index 16923f7a4..50e140116 100644
--- a/selfdrive/ui/qt/maps/map_helpers.cc
+++ b/selfdrive/ui/qt/maps/map_helpers.cc
@@ -143,11 +143,11 @@ std::pair map_format_distance(float d, bool is_metric) {
d = std::max(d, 0.0f);
if (is_metric) {
- return (d > 500) ? std::pair{round_distance(d / 1000), QObject::tr("km")}
- : std::pair{QString::number(50 * std::nearbyint(d / 50)), QObject::tr("m")};
+ return (d > 500) ? std::pair(round_distance(d / 1000), QObject::tr("km"))
+ : std::pair(QString::number(50 * std::nearbyint(d / 50)), QObject::tr("m"));
} else {
float feet = d * METER_TO_FOOT;
- return (feet > 500) ? std::pair{round_distance(d * METER_TO_MILE), QObject::tr("mi")}
- : std::pair{QString::number(50 * std::nearbyint(d / 50)), QObject::tr("ft")};
+ return (feet > 500) ? std::pair(round_distance(d * METER_TO_MILE), QObject::tr("mi"))
+ : std::pair(QString::number(50 * std::nearbyint(d / 50)), QObject::tr("ft"));
}
}
diff --git a/third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so.3.0.0 b/third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so.3.0.0
index f2fcf107b..e49d321c7 100755
--- a/third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so.3.0.0
+++ b/third_party/maplibre-native-qt/x86_64/lib/libQMapLibre.so.3.0.0
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b718e4ea770105893dc41f64be36f806586a9471e2bb9d18d5ad97e906434548
-size 11000296
+oid sha256:d62e192aa7806302ed79866d9e3c51efc4bc315a6fdfe0e58e448dac5b279098
+size 11549728
diff --git a/tools/README.md b/tools/README.md
index 361a27ded..f465ea123 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -2,11 +2,11 @@
## System Requirements
-openpilot is developed and tested on **Ubuntu 20.04**, which is the primary development target aside from the [supported embedded hardware](https://github.com/commaai/openpilot#running-on-a-dedicated-device-in-a-car).
+openpilot is developed and tested on **Ubuntu 24.04**, which is the primary development target aside from the [supported embedded hardware](https://github.com/commaai/openpilot#running-on-a-dedicated-device-in-a-car).
Running natively on any other system is not recommended and will require modifications. On Windows you can use WSL, and on macOS or incompatible Linux systems, it is recommended to use the dev containers.
-## Native setup on Ubuntu 20.04
+## Native setup on Ubuntu 24.04
**1. Clone openpilot**
@@ -55,7 +55,7 @@ GUI apps like `ui` or `cabana` can also run inside the container by leveraging X
[Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/about) should provide a similar experience to native Ubuntu. [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/compare-versions) specifically has been reported by several users to be a seamless experience.
-Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-20.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment. See [these instructions](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) for running GUI apps.
+Follow [these instructions](https://docs.microsoft.com/en-us/windows/wsl/install) to setup the WSL and install the `Ubuntu-24.04` distribution. Once your Ubuntu WSL environment is setup, follow the Linux setup instructions to finish setting up your environment. See [these instructions](https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps) for running GUI apps.
**NOTE**: If you are running WSL and any GUIs are failing (segfaulting or other strange issues) even after following the steps above, you may need to enable software rendering with `LIBGL_ALWAYS_SOFTWARE=1`, e.g. `LIBGL_ALWAYS_SOFTWARE=1 selfdrive/ui/ui`.
diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc
index fcf171a85..7a056c767 100644
--- a/tools/cabana/chart/chart.cc
+++ b/tools/cabana/chart/chart.cc
@@ -277,7 +277,7 @@ void ChartView::updateSeriesPoints() {
}
((QScatterSeries *)s.series)->setMarkerSize(size);
} else {
- s.series->setPointsVisible(pixels_per_point > 20);
+ s.series->setPointsVisible(num_points == 1 || pixels_per_point > 20);
}
}
}
@@ -513,7 +513,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) {
// no rubber dragged, seek to mouse position
can->seekTo(min);
} else if (rubber->width() > 10 && (max - min) > MIN_ZOOM_SECONDS) {
- charts_widget->zoom_undo_stack->push(new ZoomCommand(charts_widget, {min, max}));
+ charts_widget->zoom_undo_stack->push(new ZoomCommand({min, max}));
} else {
viewport()->update();
}
diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc
index a7bdd7464..59c188afb 100644
--- a/tools/cabana/chart/chartswidget.cc
+++ b/tools/cabana/chart/chartswidget.cc
@@ -103,6 +103,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QFrame(parent) {
QObject::connect(dbc(), &DBCManager::DBCFileChanged, this, &ChartsWidget::removeAll);
QObject::connect(can, &AbstractStream::eventsMerged, this, &ChartsWidget::eventsMerged);
QObject::connect(can, &AbstractStream::msgsReceived, this, &ChartsWidget::updateState);
+ QObject::connect(can, &AbstractStream::seeking, this, &ChartsWidget::updateState);
+ QObject::connect(can, &AbstractStream::timeRangeChanged, this, &ChartsWidget::timeRangeChanged);
QObject::connect(range_slider, &QSlider::valueChanged, this, &ChartsWidget::setMaxChartRange);
QObject::connect(new_plot_btn, &QToolButton::clicked, this, &ChartsWidget::newChart);
QObject::connect(remove_all_btn, &QToolButton::clicked, this, &ChartsWidget::removeAll);
@@ -159,16 +161,13 @@ void ChartsWidget::eventsMerged(const MessageEventsMap &new_events) {
}
}
-void ChartsWidget::setZoom(double min, double max) {
- zoomed_range = {min, max};
- is_zoomed = zoomed_range != display_range;
+void ChartsWidget::timeRangeChanged(const std::optional> &time_range) {
updateToolBar();
updateState();
- emit rangeChanged(min, max, is_zoomed);
}
void ChartsWidget::zoomReset() {
- setZoom(display_range.first, display_range.second);
+ can->setTimeRange(std::nullopt);
zoom_undo_stack->clear();
}
@@ -186,8 +185,9 @@ void ChartsWidget::showValueTip(double sec) {
void ChartsWidget::updateState() {
if (charts.isEmpty()) return;
+ const auto &time_range = can->timeRange();
const double cur_sec = can->currentSec();
- if (!is_zoomed) {
+ if (!time_range.has_value()) {
double pos = (cur_sec - display_range.first) / std::max(1.0, max_chart_range);
if (pos < 0 || pos > 0.8) {
display_range.first = std::max(0.0, cur_sec - max_chart_range * 0.1);
@@ -195,13 +195,9 @@ void ChartsWidget::updateState() {
double max_sec = std::min(display_range.first + max_chart_range, can->totalSeconds());
display_range.first = std::max(0.0, max_sec - max_chart_range);
display_range.second = display_range.first + max_chart_range;
- } else if (cur_sec < (zoomed_range.first - 0.1) || cur_sec >= zoomed_range.second) {
- // loop in zoomed range
- QTimer::singleShot(0, [ts = zoomed_range.first]() { can->seekTo(ts);});
- return;
}
- const auto &range = is_zoomed ? zoomed_range : display_range;
+ const auto &range = time_range ? *time_range : display_range;
for (auto c : charts) {
c->updatePlot(cur_sec, range.first, range.second);
}
@@ -217,12 +213,14 @@ void ChartsWidget::updateToolBar() {
title_label->setText(tr("Charts: %1").arg(charts.size()));
columns_action->setText(tr("Column: %1").arg(column_count));
range_lb->setText(utils::formatSeconds(max_chart_range));
+
+ bool is_zoomed = can->timeRange().has_value();
range_lb_action->setVisible(!is_zoomed);
range_slider_action->setVisible(!is_zoomed);
undo_zoom_action->setVisible(is_zoomed);
redo_zoom_action->setVisible(is_zoomed);
reset_zoom_action->setVisible(is_zoomed);
- reset_zoom_btn->setText(is_zoomed ? tr("%1-%2").arg(zoomed_range.first, 0, 'f', 2).arg(zoomed_range.second, 0, 'f', 2) : "");
+ reset_zoom_btn->setText(is_zoomed ? tr("%1-%2").arg(can->timeRange()->first, 0, 'f', 2).arg(can->timeRange()->second, 0, 'f', 2) : "");
remove_all_btn->setEnabled(!charts.isEmpty());
dock_btn->setIcon(docking ? "arrow-up-right-square" : "arrow-down-left-square");
dock_btn->setToolTip(docking ? tr("Undock charts") : tr("Dock charts"));
@@ -252,7 +250,7 @@ ChartView *ChartsWidget::findChart(const MessageId &id, const cabana::Signal *si
}
ChartView *ChartsWidget::createChart() {
- auto chart = new ChartView(is_zoomed ? zoomed_range : display_range, this);
+ auto chart = new ChartView(can->timeRange().value_or(display_range), this);
chart->setFixedHeight(settings.chart_height);
chart->setMinimumWidth(CHART_MIN_WIDTH);
chart->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
diff --git a/tools/cabana/chart/chartswidget.h b/tools/cabana/chart/chartswidget.h
index a39b4d73a..a9ac05db2 100644
--- a/tools/cabana/chart/chartswidget.h
+++ b/tools/cabana/chart/chartswidget.h
@@ -46,11 +46,10 @@ public:
public slots:
void setColumnCount(int n);
void removeAll();
- void setZoom(double min, double max);
+ void timeRangeChanged(const std::optional> &time_range);
signals:
void dock(bool floating);
- void rangeChanged(double min, double max, bool is_zommed);
void seriesChanged();
private:
@@ -102,9 +101,7 @@ private:
ChartsContainer *charts_container;
QScrollArea *charts_scroll;
uint32_t max_chart_range = 0;
- bool is_zoomed = false;
std::pair display_range;
- std::pair zoomed_range;
QAction *columns_action;
int column_count = 1;
int current_column_count = 0;
@@ -119,12 +116,11 @@ private:
class ZoomCommand : public QUndoCommand {
public:
- ZoomCommand(ChartsWidget *charts, std::pair range) : charts(charts), range(range), QUndoCommand() {
- prev_range = charts->is_zoomed ? charts->zoomed_range : charts->display_range;
+ ZoomCommand(std::pair range) : range(range), QUndoCommand() {
+ prev_range = can->timeRange();
setText(QObject::tr("Zoom to %1-%2").arg(range.first, 0, 'f', 2).arg(range.second, 0, 'f', 2));
}
- void undo() override { charts->setZoom(prev_range.first, prev_range.second); }
- void redo() override { charts->setZoom(range.first, range.second); }
- ChartsWidget *charts;
- std::pair prev_range, range;
+ void undo() override { can->setTimeRange(prev_range); }
+ void redo() override { can->setTimeRange(range); }
+ std::optional> prev_range, range;
};
diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc
index e6c9b49ca..d099fcec9 100644
--- a/tools/cabana/mainwin.cc
+++ b/tools/cabana/mainwin.cc
@@ -192,7 +192,6 @@ void MainWindow::createDockWidgets() {
video_splitter = new QSplitter(Qt::Vertical, this);
video_widget = new VideoWidget(this);
video_splitter->addWidget(video_widget);
- QObject::connect(charts_widget, &ChartsWidget::rangeChanged, video_widget, &VideoWidget::updateTimeRange);
video_splitter->addWidget(charts_container);
video_splitter->setStretchFactor(1, 1);
diff --git a/tools/cabana/streams/abstractstream.cc b/tools/cabana/streams/abstractstream.cc
index 2e6ca9662..2584106ce 100644
--- a/tools/cabana/streams/abstractstream.cc
+++ b/tools/cabana/streams/abstractstream.cc
@@ -92,13 +92,23 @@ void AbstractStream::updateLastMessages() {
std::set msgs;
{
std::lock_guard lk(mutex_);
+ double max_sec = 0;
for (const auto &id : new_msgs_) {
const auto &can_data = messages_[id];
- current_sec_ = std::max(current_sec_, can_data.ts);
+ max_sec = std::max(max_sec, can_data.ts);
last_msgs[id] = can_data;
sources.insert(id.source);
}
- msgs = std::move(new_msgs_);
+
+ if (!new_msgs_.empty()) {
+ msgs = std::move(new_msgs_);
+ current_sec_ = max_sec;
+ }
+ }
+
+ if (time_range_ && (current_sec_ < time_range_->first || current_sec_ >= time_range_->second)) {
+ seekTo(time_range_->first);
+ return;
}
if (sources.size() != prev_src_size) {
@@ -108,6 +118,14 @@ void AbstractStream::updateLastMessages() {
emit msgsReceived(&msgs, prev_msg_size != last_msgs.size());
}
+void AbstractStream::setTimeRange(const std::optional> &range) {
+ time_range_ = range;
+ if (time_range_ && (current_sec_ < time_range_->first || current_sec_ >= time_range_->second)) {
+ seekTo(time_range_->first);
+ }
+ emit timeRangeChanged(time_range_);
+}
+
void AbstractStream::updateEvent(const MessageId &id, double sec, const uint8_t *data, uint8_t size) {
std::lock_guard lk(mutex_);
messages_[id].compute(id, data, size, sec, getSpeed(), masks_[id]);
diff --git a/tools/cabana/streams/abstractstream.h b/tools/cabana/streams/abstractstream.h
index cfd423b36..822dd03d8 100644
--- a/tools/cabana/streams/abstractstream.h
+++ b/tools/cabana/streams/abstractstream.h
@@ -3,8 +3,10 @@
#include
#include
#include
+#include
#include
#include
+#include
#include
#include
@@ -77,6 +79,8 @@ public:
virtual double getSpeed() { return 1; }
virtual bool isPaused() const { return false; }
virtual void pause(bool pause) {}
+ void setTimeRange(const std::optional> &range);
+ const std::optional> &timeRange() const { return time_range_; }
inline const std::unordered_map &lastMessages() const { return last_msgs; }
inline const MessageEventsMap &eventsMap() const { return events_; }
@@ -91,8 +95,9 @@ public:
signals:
void paused();
void resume();
- void seekingTo(double sec);
+ void seeking(double sec);
void seekedTo(double sec);
+ void timeRangeChanged(const std::optional> &range);
void streamStarted();
void eventsMerged(const MessageEventsMap &events_map);
void msgsReceived(const std::set *new_msgs, bool has_new_ids);
@@ -110,6 +115,7 @@ protected:
std::vector all_events_;
double current_sec_ = 0;
+ std::optional> time_range_;
uint64_t lastest_event_ts = 0;
private:
diff --git a/tools/cabana/streams/replaystream.cc b/tools/cabana/streams/replaystream.cc
index 5fda6b048..bdb9ebb01 100644
--- a/tools/cabana/streams/replaystream.cc
+++ b/tools/cabana/streams/replaystream.cc
@@ -53,10 +53,31 @@ bool ReplayStream::loadRoute(const QString &route, const QString &data_dir, uint
{}, nullptr, replay_flags, data_dir, this));
replay->setSegmentCacheLimit(settings.max_cached_minutes);
replay->installEventFilter(event_filter, this);
+ QObject::connect(replay.get(), &Replay::seeking, this, &AbstractStream::seeking);
QObject::connect(replay.get(), &Replay::seekedTo, this, &AbstractStream::seekedTo);
QObject::connect(replay.get(), &Replay::segmentsMerged, this, &ReplayStream::mergeSegments);
- QObject::connect(replay.get(), &Replay::qLogLoaded, this, &ReplayStream::qLogLoaded, Qt::QueuedConnection);
- return replay->load();
+ bool success = replay->load();
+ if (!success) {
+ if (replay->lastRouteError() == RouteLoadError::AccessDenied) {
+ auto auth_content = util::read_file(util::getenv("HOME") + "/.comma/auth.json");
+ QString message;
+ if (auth_content.empty()) {
+ message = "Authentication Required. Please run the following command to authenticate:\n\n"
+ "python tools/lib/auth.py\n\n"
+ "This will grant access to routes from your comma account.";
+ } else {
+ message = tr("Access Denied. You do not have permission to access route:\n\n%1\n\n"
+ "This is likely a private route.").arg(route);
+ }
+ QMessageBox::warning(nullptr, tr("Access Denied"), message);
+ } else if (replay->lastRouteError() == RouteLoadError::NetworkError) {
+ QMessageBox::warning(nullptr, tr("Network Error"),
+ tr("Unable to load the route:\n\n %1.\n\nPlease check your network connection and try again.").arg(route));
+ } else {
+ QMessageBox::warning(nullptr, tr("Route Load Failed"), tr("Failed to load route: '%1'").arg(route));
+ }
+ }
+ return success;
}
void ReplayStream::start() {
@@ -92,12 +113,7 @@ bool ReplayStream::eventFilter(const Event *event) {
}
void ReplayStream::seekTo(double ts) {
- // Update timestamp and notify receivers of the time change.
current_sec_ = ts;
- std::set new_msgs;
- msgsReceived(&new_msgs, false);
-
- // Seek to the specified timestamp
replay->seekTo(std::max(double(0), ts), false);
}
@@ -149,7 +165,7 @@ OpenReplayWidget::OpenReplayWidget(AbstractStream **stream) : AbstractOpenStream
bool OpenReplayWidget::open() {
QString route = route_edit->text();
QString data_dir;
- if (int idx = route.lastIndexOf('/'); idx != -1) {
+ if (int idx = route.lastIndexOf('/'); idx != -1 && util::file_exists(route.toStdString())) {
data_dir = route.mid(0, idx + 1);
route = route.mid(idx + 1);
}
@@ -166,8 +182,6 @@ bool OpenReplayWidget::open() {
if (replay_stream->loadRoute(route, data_dir, flags)) {
*stream = replay_stream.release();
- } else {
- QMessageBox::warning(nullptr, tr("Warning"), tr("Failed to load route: '%1'").arg(route));
}
}
return *stream != nullptr;
diff --git a/tools/cabana/streams/replaystream.h b/tools/cabana/streams/replaystream.h
index 049ccddaf..ced78680d 100644
--- a/tools/cabana/streams/replaystream.h
+++ b/tools/cabana/streams/replaystream.h
@@ -34,9 +34,6 @@ public:
void pause(bool pause) override;
static AbstractOpenStreamWidget *widget(AbstractStream **stream);
-signals:
- void qLogLoaded(int segnum, std::shared_ptr qlog);
-
private:
void mergeSegments();
std::unique_ptr replay = nullptr;
diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc
index 7fca45c39..d2f78babc 100644
--- a/tools/cabana/videowidget.cc
+++ b/tools/cabana/videowidget.cc
@@ -38,6 +38,8 @@ VideoWidget::VideoWidget(QWidget *parent) : QFrame(parent) {
QObject::connect(can, &AbstractStream::paused, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &AbstractStream::resume, this, &VideoWidget::updatePlayBtnState);
QObject::connect(can, &AbstractStream::msgsReceived, this, &VideoWidget::updateState);
+ QObject::connect(can, &AbstractStream::seeking, this, &VideoWidget::updateState);
+ QObject::connect(can, &AbstractStream::timeRangeChanged, this, &VideoWidget::timeRangeChanged);
updatePlayBtnState();
setWhatsThis(tr(R"(
@@ -150,14 +152,16 @@ QWidget *VideoWidget::createCameraWidget() {
setMaximumTime(can->totalSeconds());
QObject::connect(slider, &QSlider::sliderReleased, [this]() { can->seekTo(slider->currentSecond()); });
- QObject::connect(slider, &Slider::updateMaximumTime, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection);
QObject::connect(can, &AbstractStream::eventsMerged, this, [this]() { slider->update(); });
- QObject::connect(static_cast(can), &ReplayStream::qLogLoaded, slider, &Slider::parseQLog);
QObject::connect(cam_widget, &CameraWidget::clicked, []() { can->pause(!can->isPaused()); });
QObject::connect(cam_widget, &CameraWidget::vipcAvailableStreamsUpdated, this, &VideoWidget::vipcAvailableStreamsUpdated);
QObject::connect(camera_tab, &QTabBar::currentChanged, [this](int index) {
if (index != -1) cam_widget->setStreamType((VisionStreamType)camera_tab->tabData(index).toInt());
});
+
+ auto replay = static_cast(can)->getReplay();
+ QObject::connect(replay, &Replay::qLogLoaded, slider, &Slider::parseQLog, Qt::QueuedConnection);
+ QObject::connect(replay, &Replay::totalSecondsUpdated, this, &VideoWidget::setMaximumTime, Qt::QueuedConnection);
return w;
}
@@ -198,13 +202,13 @@ void VideoWidget::setMaximumTime(double sec) {
slider->setTimeRange(0, sec);
}
-void VideoWidget::updateTimeRange(double min, double max, bool is_zoomed) {
+void VideoWidget::timeRangeChanged(const std::optional> &time_range) {
if (can->liveStreaming()) {
- skip_to_end_btn->setEnabled(!is_zoomed);
+ skip_to_end_btn->setEnabled(!time_range.has_value());
return;
}
- is_zoomed ? slider->setTimeRange(min, max)
- : slider->setTimeRange(0, maximum_time);
+ time_range ? slider->setTimeRange(time_range->first, time_range->second)
+ : slider->setTimeRange(0, maximum_time);
}
QString VideoWidget::formatTime(double sec, bool include_milliseconds) {
@@ -255,12 +259,7 @@ void Slider::setTimeRange(double min, double max) {
setRange(min * factor, max * factor);
}
-void Slider::parseQLog(int segnum, std::shared_ptr qlog) {
- const auto &segments = qobject_cast(can)->route()->segments();
- if (segments.size() > 0 && segnum == segments.rbegin()->first && !qlog->events.empty()) {
- emit updateMaximumTime(qlog->events.back().mono_time / 1e9 - can->routeStartTime());
- }
-
+void Slider::parseQLog(std::shared_ptr qlog) {
std::mutex mutex;
QtConcurrent::blockingMap(qlog->events.cbegin(), qlog->events.cend(), [&mutex, this](const Event &e) {
if (e.which == cereal::Event::Which::THUMBNAIL) {
diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h
index b2039e09a..ac34c6600 100644
--- a/tools/cabana/videowidget.h
+++ b/tools/cabana/videowidget.h
@@ -2,7 +2,9 @@
#include