mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-08-07 17:25:40 +08:00
Merge remote-tracking branch 'origin/master' into master3
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
run: eval ${{ env.BUILD }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+21
-16
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+6
-2
@@ -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;
|
||||
|
||||
+4
-4
@@ -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[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Genesis 2015-16">Buy Here</a></sub></details>||
|
||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=i30 2017-19">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (Southeast Asia only) 2022-23[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-23[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-23">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (Non-US only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (Non-US only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 5 (without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq 6 (with HDA II) 2023-24">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2019">Buy Here</a></sub></details>||
|
||||
|Hyundai|Ioniq Electric 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Hyundai&model=Ioniq Electric 2020">Buy Here</a></sub></details>||
|
||||
@@ -127,7 +127,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Kia|Carnival 2022-24[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival (China only) 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Non-US only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Non-US only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Forte 2019-21">Buy Here</a></sub></details>||
|
||||
|
||||
Generated
+139
-37
@@ -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"
|
||||
|
||||
+37
-30
@@ -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 = "*"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]))
|
||||
],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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, ]
|
||||
|
||||
@@ -120,7 +120,7 @@ std::vector<std::string> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
6438bd5edad674c2de3c7e2d126271cb2576383d
|
||||
8737e368e17f859291164286feb4246e00c0b4a5
|
||||
|
||||
@@ -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')]
|
||||
|
||||
@@ -143,11 +143,11 @@ std::pair<QString, QString> 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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b718e4ea770105893dc41f64be36f806586a9471e2bb9d18d5ad97e906434548
|
||||
size 11000296
|
||||
oid sha256:d62e192aa7806302ed79866d9e3c51efc4bc315a6fdfe0e58e448dac5b279098
|
||||
size 11549728
|
||||
|
||||
+3
-3
@@ -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`.
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<std::pair<double, double>> &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<float>(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);
|
||||
|
||||
@@ -46,11 +46,10 @@ public:
|
||||
public slots:
|
||||
void setColumnCount(int n);
|
||||
void removeAll();
|
||||
void setZoom(double min, double max);
|
||||
void timeRangeChanged(const std::optional<std::pair<double, double>> &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<double, double> display_range;
|
||||
std::pair<double, double> 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<double, double> range) : charts(charts), range(range), QUndoCommand() {
|
||||
prev_range = charts->is_zoomed ? charts->zoomed_range : charts->display_range;
|
||||
ZoomCommand(std::pair<double, double> 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<double, double> prev_range, range;
|
||||
void undo() override { can->setTimeRange(prev_range); }
|
||||
void redo() override { can->setTimeRange(range); }
|
||||
std::optional<std::pair<double, double>> prev_range, range;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -92,13 +92,23 @@ void AbstractStream::updateLastMessages() {
|
||||
std::set<MessageId> 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<std::pair<double, double>> &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]);
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <QColor>
|
||||
@@ -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<std::pair<double, double>> &range);
|
||||
const std::optional<std::pair<double, double>> &timeRange() const { return time_range_; }
|
||||
|
||||
inline const std::unordered_map<MessageId, CanData> &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<std::pair<double, double>> &range);
|
||||
void streamStarted();
|
||||
void eventsMerged(const MessageEventsMap &events_map);
|
||||
void msgsReceived(const std::set<MessageId> *new_msgs, bool has_new_ids);
|
||||
@@ -110,6 +115,7 @@ protected:
|
||||
|
||||
std::vector<const CanEvent *> all_events_;
|
||||
double current_sec_ = 0;
|
||||
std::optional<std::pair<double, double>> time_range_;
|
||||
uint64_t lastest_event_ts = 0;
|
||||
|
||||
private:
|
||||
|
||||
@@ -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<MessageId> 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;
|
||||
|
||||
@@ -34,9 +34,6 @@ public:
|
||||
void pause(bool pause) override;
|
||||
static AbstractOpenStreamWidget *widget(AbstractStream **stream);
|
||||
|
||||
signals:
|
||||
void qLogLoaded(int segnum, std::shared_ptr<LogReader> qlog);
|
||||
|
||||
private:
|
||||
void mergeSegments();
|
||||
std::unique_ptr<Replay> replay = nullptr;
|
||||
|
||||
+11
-12
@@ -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<ReplayStream*>(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<ReplayStream*>(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<std::pair<double, double>> &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<LogReader> qlog) {
|
||||
const auto &segments = qobject_cast<ReplayStream *>(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<LogReader> qlog) {
|
||||
std::mutex mutex;
|
||||
QtConcurrent::blockingMap(qlog->events.cbegin(), qlog->events.cend(), [&mutex, this](const Event &e) {
|
||||
if (e.which == cereal::Event::Which::THUMBNAIL) {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QFrame>
|
||||
@@ -40,13 +42,10 @@ public:
|
||||
void setTimeRange(double min, double max);
|
||||
AlertInfo alertInfo(double sec);
|
||||
QPixmap thumbnail(double sec);
|
||||
void parseQLog(int segnum, std::shared_ptr<LogReader> qlog);
|
||||
void parseQLog(std::shared_ptr<LogReader> qlog);
|
||||
|
||||
const double factor = 1000.0;
|
||||
|
||||
signals:
|
||||
void updateMaximumTime(double);
|
||||
|
||||
private:
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
@@ -63,11 +62,11 @@ class VideoWidget : public QFrame {
|
||||
|
||||
public:
|
||||
VideoWidget(QWidget *parnet = nullptr);
|
||||
void updateTimeRange(double min, double max, bool is_zommed);
|
||||
void setMaximumTime(double sec);
|
||||
|
||||
protected:
|
||||
QString formatTime(double sec, bool include_milliseconds = false);
|
||||
void timeRangeChanged(const std::optional<std::pair<double, double>> &time_range);
|
||||
void updateState();
|
||||
void updatePlayBtnState();
|
||||
QWidget *createCameraWidget();
|
||||
|
||||
+23
-13
@@ -10,6 +10,7 @@ import sys
|
||||
import tqdm
|
||||
import urllib.parse
|
||||
import warnings
|
||||
import zstd
|
||||
|
||||
from collections.abc import Callable, Iterable, Iterator
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
@@ -34,8 +35,8 @@ class _LogFileReader:
|
||||
ext = None
|
||||
if not dat:
|
||||
_, ext = os.path.splitext(urllib.parse.urlparse(fn).path)
|
||||
if ext not in ('', '.bz2'):
|
||||
# old rlogs weren't bz2 compressed
|
||||
if ext not in ('', '.bz2', '.zst'):
|
||||
# old rlogs weren't compressed
|
||||
raise Exception(f"unknown extension {ext}")
|
||||
|
||||
with FileReader(fn) as f:
|
||||
@@ -43,18 +44,21 @@ class _LogFileReader:
|
||||
|
||||
if ext == ".bz2" or dat.startswith(b'BZh9'):
|
||||
dat = bz2.decompress(dat)
|
||||
elif ext == ".zst" or dat.startswith(b'\x28\xB5\x2F\xFD'):
|
||||
# https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#zstandard-frames
|
||||
dat = zstd.decompress(dat)
|
||||
|
||||
ents = capnp_log.Event.read_multiple_bytes(dat)
|
||||
|
||||
_ents = []
|
||||
self._ents = []
|
||||
try:
|
||||
for e in ents:
|
||||
_ents.append(e)
|
||||
self._ents.append(e)
|
||||
except capnp.KjException:
|
||||
warnings.warn("Corrupted events detected", RuntimeWarning, stacklevel=1)
|
||||
|
||||
self._ents = list(sorted(_ents, key=lambda x: x.logMonoTime) if sort_by_time else _ents)
|
||||
self._ts = [x.logMonoTime for x in self._ents]
|
||||
if sort_by_time:
|
||||
self._ents.sort(key=lambda x: x.logMonoTime)
|
||||
|
||||
def __iter__(self) -> Iterator[capnp._DynamicStructReader]:
|
||||
for ent in self._ents:
|
||||
@@ -126,12 +130,12 @@ def comma_api_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
return apply_strategy(mode, rlog_paths, qlog_paths, valid_file=valid_file)
|
||||
|
||||
|
||||
def internal_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
def internal_source(sr: SegmentRange, mode: ReadMode, file_ext: str = "bz2") -> LogPaths:
|
||||
if not internal_source_available():
|
||||
raise InternalUnavailableException
|
||||
|
||||
def get_internal_url(sr: SegmentRange, seg, file):
|
||||
return f"cd:/{sr.dongle_id}/{sr.timestamp}/{seg}/{file}.bz2"
|
||||
return f"cd:/{sr.dongle_id}/{sr.log_id}/{seg}/{file}.{file_ext}"
|
||||
|
||||
rlog_paths = [get_internal_url(sr, seg, "rlog") for seg in sr.seg_idxs]
|
||||
qlog_paths = [get_internal_url(sr, seg, "qlog") for seg in sr.seg_idxs]
|
||||
@@ -139,6 +143,10 @@ def internal_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
return apply_strategy(mode, rlog_paths, qlog_paths)
|
||||
|
||||
|
||||
def internal_source_zst(sr: SegmentRange, mode: ReadMode, file_ext: str = "zst") -> LogPaths:
|
||||
return internal_source(sr, mode, file_ext)
|
||||
|
||||
|
||||
def openpilotci_source(sr: SegmentRange, mode: ReadMode) -> LogPaths:
|
||||
rlog_paths = [get_url(sr.route_name, seg, "rlog") for seg in sr.seg_idxs]
|
||||
qlog_paths = [get_url(sr.route_name, seg, "qlog") for seg in sr.seg_idxs]
|
||||
@@ -162,7 +170,8 @@ def get_invalid_files(files):
|
||||
|
||||
def check_source(source: Source, *args) -> LogPaths:
|
||||
files = source(*args)
|
||||
assert next(get_invalid_files(files), False) is False
|
||||
assert len(files) > 0, "No files on source"
|
||||
assert next(get_invalid_files(files), False) is False, "Some files are invalid"
|
||||
return files
|
||||
|
||||
|
||||
@@ -170,8 +179,8 @@ def auto_source(sr: SegmentRange, mode=ReadMode.RLOG) -> LogPaths:
|
||||
if mode == ReadMode.SANITIZED:
|
||||
return comma_car_segments_source(sr, mode)
|
||||
|
||||
SOURCES: list[Source] = [internal_source, openpilotci_source, comma_api_source, comma_car_segments_source,]
|
||||
exceptions = []
|
||||
SOURCES: list[Source] = [internal_source, internal_source_zst, openpilotci_source, comma_api_source, comma_car_segments_source,]
|
||||
exceptions = {}
|
||||
|
||||
# for automatic fallback modes, auto_source needs to first check if rlogs exist for any source
|
||||
if mode in [ReadMode.AUTO, ReadMode.AUTO_INTERACTIVE]:
|
||||
@@ -186,9 +195,10 @@ def auto_source(sr: SegmentRange, mode=ReadMode.RLOG) -> LogPaths:
|
||||
try:
|
||||
return check_source(source, sr, mode)
|
||||
except Exception as e:
|
||||
exceptions.append(e)
|
||||
exceptions[source.__name__] = e
|
||||
|
||||
raise Exception(f"auto_source could not find any valid source, exceptions for sources: {exceptions}")
|
||||
raise Exception("auto_source could not find any valid source, exceptions for sources:\n - " +
|
||||
"\n - ".join([f"{k}: {repr(v)}" for k, v in exceptions.items()]))
|
||||
|
||||
|
||||
def parse_useradmin(identifier: str):
|
||||
|
||||
+1
-5
@@ -9,7 +9,7 @@ from openpilot.tools.lib.auth_config import get_token
|
||||
from openpilot.tools.lib.api import CommaApi
|
||||
from openpilot.tools.lib.helpers import RE
|
||||
|
||||
QLOG_FILENAMES = ['qlog', 'qlog.bz2']
|
||||
QLOG_FILENAMES = ['qlog', 'qlog.bz2', 'qlog.zst']
|
||||
QCAMERA_FILENAMES = ['qcamera.ts']
|
||||
LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2']
|
||||
CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc']
|
||||
@@ -260,10 +260,6 @@ class SegmentRange:
|
||||
def dongle_id(self) -> str:
|
||||
return self.m.group("dongle_id")
|
||||
|
||||
@property
|
||||
def timestamp(self) -> str:
|
||||
return self.m.group("timestamp")
|
||||
|
||||
@property
|
||||
def log_id(self) -> str:
|
||||
return self.m.group("log_id")
|
||||
|
||||
@@ -3,7 +3,7 @@ snapdragon profiler
|
||||
|
||||
|
||||
* download from https://developer.qualcomm.com/software/snapdragon-profiler/tools-archive (need a qc developer account)
|
||||
* choose v2021.5 (verified working with 20.04 dev environment)
|
||||
* choose v2021.5 (verified working with 24.04 dev environment)
|
||||
* unzip to selfdrive/debug/profiling/snapdragon/SnapdragonProfiler
|
||||
* run ```./setup-profiler.sh```
|
||||
* run ```./setup-agnos.sh```
|
||||
|
||||
@@ -60,7 +60,6 @@ void CameraServer::cameraThread(Camera &cam) {
|
||||
capnp::FlatArrayMessageReader reader(event->data);
|
||||
auto evt = reader.getRoot<cereal::Event>();
|
||||
auto eidx = capnp::AnyStruct::Reader(evt).getPointerSection()[0].getAs<cereal::EncodeIndex>();
|
||||
if (eidx.getType() != cereal::EncodeIndex::Type::FULL_H_E_V_C) continue;
|
||||
|
||||
int segment_id = eidx.getSegmentId();
|
||||
uint32_t frame_id = eidx.getFrameId();
|
||||
|
||||
@@ -42,10 +42,10 @@ bool LogReader::load(const char *data, size_t size, std::atomic<bool> *abort) {
|
||||
evt.which == cereal::Event::DRIVER_ENCODE_IDX ||
|
||||
evt.which == cereal::Event::WIDE_ROAD_ENCODE_IDX) {
|
||||
auto idx = capnp::AnyStruct::Reader(event).getPointerSection()[0].getAs<cereal::EncodeIndex>();
|
||||
if (uint64_t sof = idx.getTimestampSof()) {
|
||||
mono_time = sof;
|
||||
if (idx.getType() == cereal::EncodeIndex::Type::FULL_H_E_V_C) {
|
||||
uint64_t sof = idx.getTimestampSof();
|
||||
events.emplace_back(which, sof ? sof : mono_time, event_data, idx.getSegmentNum());
|
||||
}
|
||||
events.emplace_back(which, mono_time, event_data, idx.getSegmentNum());
|
||||
}
|
||||
}
|
||||
} catch (const kj::Exception &e) {
|
||||
|
||||
+51
-37
@@ -55,11 +55,11 @@ void Replay::stop() {
|
||||
rInfo("shutdown: in progress...");
|
||||
if (stream_thread_ != nullptr) {
|
||||
exit_ = true;
|
||||
paused_ = true;
|
||||
pauseStreamThread();
|
||||
stream_cv_.notify_one();
|
||||
stream_thread_->quit();
|
||||
stream_thread_->wait();
|
||||
delete stream_thread_;
|
||||
stream_thread_->deleteLater();
|
||||
stream_thread_ = nullptr;
|
||||
}
|
||||
timeline_future.waitForFinished();
|
||||
@@ -104,28 +104,40 @@ void Replay::updateEvents(const std::function<bool()> &update_events_function) {
|
||||
|
||||
void Replay::seekTo(double seconds, bool relative) {
|
||||
updateEvents([&]() {
|
||||
seeking_to_seconds_ = relative ? seconds + currentSeconds() : seconds;
|
||||
seeking_to_seconds_ = std::max(double(0.0), seeking_to_seconds_);
|
||||
int target_segment = (int)seeking_to_seconds_ / 60;
|
||||
double target_time = relative ? seconds + currentSeconds() : seconds;
|
||||
target_time = std::max(double(0.0), target_time);
|
||||
int target_segment = (int)target_time / 60;
|
||||
if (segments_.count(target_segment) == 0) {
|
||||
rWarning("can't seek to %d s segment %d is invalid", (int)seeking_to_seconds_, target_segment);
|
||||
rWarning("Can't seek to %d s segment %d is invalid", (int)target_time, target_segment);
|
||||
return true;
|
||||
}
|
||||
|
||||
rInfo("seeking to %d s, segment %d", (int)seeking_to_seconds_, target_segment);
|
||||
rInfo("Seeking to %d s, segment %d", (int)target_time, target_segment);
|
||||
current_segment_ = target_segment;
|
||||
cur_mono_time_ = route_start_ts_ + seeking_to_seconds_ * 1e9;
|
||||
bool segment_merged = isSegmentMerged(target_segment);
|
||||
if (segment_merged) {
|
||||
emit seekedTo(seeking_to_seconds_);
|
||||
// Reset seeking_to_seconds_ to indicate completion of seek
|
||||
seeking_to_seconds_ = -1;
|
||||
}
|
||||
return segment_merged;
|
||||
cur_mono_time_ = route_start_ts_ + target_time * 1e9;
|
||||
seeking_to_ = target_time;
|
||||
return false;
|
||||
});
|
||||
|
||||
checkSeekProgress();
|
||||
updateSegmentsCache();
|
||||
}
|
||||
|
||||
void Replay::checkSeekProgress() {
|
||||
if (seeking_to_) {
|
||||
auto it = segments_.find(int(*seeking_to_ / 60));
|
||||
if (it != segments_.end() && it->second && it->second->isLoaded()) {
|
||||
emit seekedTo(*seeking_to_);
|
||||
seeking_to_ = std::nullopt;
|
||||
// wake up stream thread
|
||||
updateEvents([]() { return true; });
|
||||
} else {
|
||||
// Emit signal indicating the ongoing seek operation
|
||||
emit seeking(*seeking_to_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Replay::seekToFlag(FindFlag flag) {
|
||||
if (auto next = find(flag)) {
|
||||
seekTo(*next - 2, false); // seek to 2 seconds before next
|
||||
@@ -150,8 +162,9 @@ void Replay::buildTimeline() {
|
||||
const auto &route_segments = route_->segments();
|
||||
for (auto it = route_segments.cbegin(); it != route_segments.cend() && !exit_; ++it) {
|
||||
std::shared_ptr<LogReader> log(new LogReader());
|
||||
if (!log->load(it->second.qlog.toStdString(), &exit_, !hasFlag(REPLAY_FLAG_NO_FILE_CACHE), 0, 3)) continue;
|
||||
if (!log->load(it->second.qlog.toStdString(), &exit_, !hasFlag(REPLAY_FLAG_NO_FILE_CACHE), 0, 3) || log->events.empty()) continue;
|
||||
|
||||
std::vector<std::tuple<double, double, TimelineType>> timeline;
|
||||
for (const Event &e : log->events) {
|
||||
if (e.which == cereal::Event::Which::CONTROLS_STATE) {
|
||||
capnp::FlatArrayMessageReader reader(e.data);
|
||||
@@ -160,7 +173,6 @@ void Replay::buildTimeline() {
|
||||
|
||||
if (engaged != cs.getEnabled()) {
|
||||
if (engaged) {
|
||||
std::lock_guard lk(timeline_lock);
|
||||
timeline.push_back({toSeconds(engaged_begin), toSeconds(e.mono_time), TimelineType::Engaged});
|
||||
}
|
||||
engaged_begin = e.mono_time;
|
||||
@@ -169,7 +181,6 @@ void Replay::buildTimeline() {
|
||||
|
||||
if (alert_type != cs.getAlertType().cStr() || alert_status != cs.getAlertStatus()) {
|
||||
if (!alert_type.empty() && alert_size != cereal::ControlsState::AlertSize::NONE) {
|
||||
std::lock_guard lk(timeline_lock);
|
||||
timeline.push_back({toSeconds(alert_begin), toSeconds(e.mono_time), timeline_types[(int)alert_status]});
|
||||
}
|
||||
alert_begin = e.mono_time;
|
||||
@@ -178,12 +189,20 @@ void Replay::buildTimeline() {
|
||||
alert_status = cs.getAlertStatus();
|
||||
}
|
||||
} else if (e.which == cereal::Event::Which::USER_FLAG) {
|
||||
std::lock_guard lk(timeline_lock);
|
||||
timeline.push_back({toSeconds(e.mono_time), toSeconds(e.mono_time), TimelineType::UserFlag});
|
||||
}
|
||||
}
|
||||
std::sort(timeline.begin(), timeline.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); });
|
||||
emit qLogLoaded(it->first, log);
|
||||
|
||||
{
|
||||
std::lock_guard lk(timeline_lock);
|
||||
timeline_.insert(timeline_.end(), timeline.begin(), timeline.end());
|
||||
std::sort(timeline_.begin(), timeline_.end(), [](auto &l, auto &r) { return std::get<2>(l) < std::get<2>(r); });
|
||||
}
|
||||
|
||||
if (it->first == route_segments.rbegin()->first) {
|
||||
emit totalSecondsUpdated(toSeconds(log->events.back().mono_time));
|
||||
}
|
||||
emit qLogLoaded(log);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,14 +279,13 @@ void Replay::updateSegmentsCache() {
|
||||
const auto &cur_segment = cur->second;
|
||||
if (stream_thread_ == nullptr && cur_segment->isLoaded()) {
|
||||
startStream(cur_segment.get());
|
||||
emit streamStarted();
|
||||
}
|
||||
}
|
||||
|
||||
void Replay::loadSegmentInRange(SegmentMap::iterator begin, SegmentMap::iterator cur, SegmentMap::iterator end) {
|
||||
auto loadNext = [this](auto begin, auto end) {
|
||||
auto it = std::find_if(begin, end, [](const auto &seg_it) { return !seg_it.second || !seg_it.second->isLoaded(); });
|
||||
if (it != end && !it->second) {
|
||||
auto loadNextSegment = [this](auto first, auto last) {
|
||||
auto it = std::find_if(first, last, [](const auto &seg_it) { return !seg_it.second || !seg_it.second->isLoaded(); });
|
||||
if (it != last && !it->second) {
|
||||
rDebug("loading segment %d...", it->first);
|
||||
it->second = std::make_unique<Segment>(it->first, route_->at(it->first), flags_, filters_);
|
||||
QObject::connect(it->second.get(), &Segment::loadFinished, this, &Replay::segmentLoadFinished);
|
||||
@@ -276,9 +294,9 @@ void Replay::loadSegmentInRange(SegmentMap::iterator begin, SegmentMap::iterator
|
||||
return false;
|
||||
};
|
||||
|
||||
// Load forward segments, then try reverse
|
||||
if (!loadNext(cur, end)) {
|
||||
loadNext(std::make_reverse_iterator(cur), segments_.rend());
|
||||
// Try loading forward segments, then reverse segments
|
||||
if (!loadNextSegment(cur, end)) {
|
||||
loadNextSegment(std::make_reverse_iterator(cur), std::make_reverse_iterator(begin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,15 +334,10 @@ void Replay::mergeSegments(const SegmentMap::iterator &begin, const SegmentMap::
|
||||
updateEvents([&]() {
|
||||
events_.swap(new_events);
|
||||
merged_segments_ = segments_to_merge;
|
||||
// Check if seeking is in progress
|
||||
int target_segment = int(seeking_to_seconds_ / 60);
|
||||
if (seeking_to_seconds_ >= 0 && segments_to_merge.count(target_segment) > 0) {
|
||||
emit seekedTo(seeking_to_seconds_);
|
||||
seeking_to_seconds_ = -1; // Reset seeking_to_seconds_ to indicate completion of seek
|
||||
}
|
||||
// Wake up the stream thread if the current segment is loaded or invalid.
|
||||
return isSegmentMerged(current_segment_) || (segments_.count(current_segment_) == 0);
|
||||
return !seeking_to_ && (isSegmentMerged(current_segment_) || (segments_.count(current_segment_) == 0));
|
||||
});
|
||||
checkSeekProgress();
|
||||
}
|
||||
|
||||
void Replay::startStream(const Segment *cur_segment) {
|
||||
@@ -379,6 +392,7 @@ void Replay::startStream(const Segment *cur_segment) {
|
||||
stream_thread_->start();
|
||||
|
||||
timeline_future = QtConcurrent::run(this, &Replay::buildTimeline);
|
||||
emit streamStarted();
|
||||
}
|
||||
|
||||
void Replay::publishMessage(const Event *e) {
|
||||
@@ -473,6 +487,7 @@ std::vector<Event>::const_iterator Replay::publishEvents(std::vector<Event>::con
|
||||
// Skip events if socket is not present
|
||||
if (!sockets_[evt.which]) continue;
|
||||
|
||||
cur_mono_time_ = evt.mono_time;
|
||||
const uint64_t current_nanos = nanos_since_boot();
|
||||
const int64_t time_diff = (evt.mono_time - evt_start_ts) / speed_ - (current_nanos - loop_start_ts);
|
||||
|
||||
@@ -484,12 +499,11 @@ std::vector<Event>::const_iterator Replay::publishEvents(std::vector<Event>::con
|
||||
loop_start_ts = current_nanos;
|
||||
prev_replay_speed = speed_;
|
||||
} else if (time_diff > 0) {
|
||||
precise_nano_sleep(time_diff);
|
||||
precise_nano_sleep(time_diff, paused_);
|
||||
}
|
||||
|
||||
if (paused_) break;
|
||||
|
||||
cur_mono_time_ = evt.mono_time;
|
||||
if (evt.eidx_segnum == -1) {
|
||||
publishMessage(&evt);
|
||||
} else if (camera_server_) {
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
uint32_t flags = REPLAY_FLAG_NONE, QString data_dir = "", QObject *parent = 0);
|
||||
~Replay();
|
||||
bool load();
|
||||
RouteLoadError lastRouteError() const { return route_->lastError(); }
|
||||
void start(int seconds = 0);
|
||||
void stop();
|
||||
void pause(bool pause);
|
||||
@@ -85,14 +86,16 @@ public:
|
||||
inline const std::string &carFingerprint() const { return car_fingerprint_; }
|
||||
inline const std::vector<std::tuple<double, double, TimelineType>> getTimeline() {
|
||||
std::lock_guard lk(timeline_lock);
|
||||
return timeline;
|
||||
return timeline_;
|
||||
}
|
||||
|
||||
signals:
|
||||
void streamStarted();
|
||||
void segmentsMerged();
|
||||
void seeking(double sec);
|
||||
void seekedTo(double sec);
|
||||
void qLogLoaded(int segnum, std::shared_ptr<LogReader> qlog);
|
||||
void qLogLoaded(std::shared_ptr<LogReader> qlog);
|
||||
void totalSecondsUpdated(double sec);
|
||||
|
||||
protected slots:
|
||||
void segmentLoadFinished(bool success);
|
||||
@@ -112,6 +115,7 @@ protected:
|
||||
void publishMessage(const Event *e);
|
||||
void publishFrame(const Event *e);
|
||||
void buildTimeline();
|
||||
void checkSeekProgress();
|
||||
inline bool isSegmentMerged(int n) const { return merged_segments_.count(n) > 0; }
|
||||
|
||||
pthread_t stream_thread_id = 0;
|
||||
@@ -120,7 +124,7 @@ protected:
|
||||
bool user_paused_ = false;
|
||||
std::condition_variable stream_cv_;
|
||||
std::atomic<int> current_segment_ = 0;
|
||||
double seeking_to_seconds_ = -1;
|
||||
std::optional<double> seeking_to_;
|
||||
SegmentMap segments_;
|
||||
// the following variables must be protected with stream_lock_
|
||||
std::atomic<bool> exit_ = false;
|
||||
@@ -143,7 +147,7 @@ protected:
|
||||
|
||||
std::mutex timeline_lock;
|
||||
QFuture<void> timeline_future;
|
||||
std::vector<std::tuple<double, double, TimelineType>> timeline;
|
||||
std::vector<std::tuple<double, double, TimelineType>> timeline_;
|
||||
std::string car_fingerprint_;
|
||||
std::atomic<float> speed_ = 1.0;
|
||||
replayEventFilter event_filter = nullptr;
|
||||
|
||||
@@ -74,7 +74,10 @@ bool Route::loadFromServer(int retries) {
|
||||
return loadFromJson(result);
|
||||
} else if (err == QNetworkReply::ContentAccessDenied || err == QNetworkReply::AuthenticationRequiredError) {
|
||||
rWarning(">> Unauthorized. Authenticate with tools/lib/auth.py <<");
|
||||
err_ = RouteLoadError::AccessDenied;
|
||||
return false;
|
||||
} else {
|
||||
err_ = RouteLoadError::NetworkError;
|
||||
}
|
||||
rWarning("Retrying %d/%d", i, retries);
|
||||
util::sleep_for(3000);
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
#include "tools/replay/logreader.h"
|
||||
#include "tools/replay/util.h"
|
||||
|
||||
enum class RouteLoadError {
|
||||
None,
|
||||
AccessDenied,
|
||||
NetworkError,
|
||||
FileNotFound,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
struct RouteIdentifier {
|
||||
QString dongle_id;
|
||||
QString timestamp;
|
||||
@@ -33,6 +41,7 @@ class Route {
|
||||
public:
|
||||
Route(const QString &route, const QString &data_dir = {});
|
||||
bool load();
|
||||
RouteLoadError lastError() const { return err_; }
|
||||
inline const QString &name() const { return route_.str; }
|
||||
inline const QDateTime datetime() const { return date_time_; }
|
||||
inline const QString &dir() const { return data_dir_; }
|
||||
@@ -50,6 +59,7 @@ protected:
|
||||
QString data_dir_;
|
||||
std::map<int, SegmentFile> segments_;
|
||||
QDateTime date_time_;
|
||||
RouteLoadError err_ = RouteLoadError::None;
|
||||
};
|
||||
|
||||
class Segment : public QObject {
|
||||
|
||||
@@ -158,7 +158,6 @@ def ui_thread(addr):
|
||||
# TODO brake is deprecated
|
||||
plot_arr[-1, name_to_arr_idx['computer_brake']] = clip(-sm['carControl'].actuators.accel/4.0, 0.0, 1.0)
|
||||
plot_arr[-1, name_to_arr_idx['v_ego']] = sm['carState'].vEgo
|
||||
plot_arr[-1, name_to_arr_idx['v_pid']] = sm['controlsState'].vPid
|
||||
plot_arr[-1, name_to_arr_idx['v_cruise']] = sm['carState'].cruiseState.speed
|
||||
plot_arr[-1, name_to_arr_idx['a_ego']] = sm['carState'].aEgo
|
||||
|
||||
|
||||
+13
-23
@@ -318,33 +318,23 @@ std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic<bool>
|
||||
return {};
|
||||
}
|
||||
|
||||
void precise_nano_sleep(int64_t nanoseconds) {
|
||||
#ifdef __APPLE__
|
||||
const long estimate_ns = 1 * 1e6; // 1ms
|
||||
struct timespec req = {.tv_nsec = estimate_ns};
|
||||
uint64_t start_sleep = nanos_since_boot();
|
||||
while (nanoseconds > estimate_ns) {
|
||||
nanosleep(&req, nullptr);
|
||||
uint64_t end_sleep = nanos_since_boot();
|
||||
nanoseconds -= (end_sleep - start_sleep);
|
||||
start_sleep = end_sleep;
|
||||
}
|
||||
// spin wait
|
||||
if (nanoseconds > 0) {
|
||||
while ((nanos_since_boot() - start_sleep) <= nanoseconds) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void precise_nano_sleep(int64_t nanoseconds, std::atomic<bool> &should_exit) {
|
||||
struct timespec req, rem;
|
||||
|
||||
req.tv_sec = nanoseconds / 1e9;
|
||||
req.tv_nsec = nanoseconds % (int64_t)1e9;
|
||||
while (clock_nanosleep(CLOCK_MONOTONIC, 0, &req, &rem) && errno == EINTR) {
|
||||
req.tv_sec = nanoseconds / 1000000000;
|
||||
req.tv_nsec = nanoseconds % 1000000000;
|
||||
while (!should_exit) {
|
||||
#ifdef __APPLE_
|
||||
int ret = nanosleep(&req, &rem);
|
||||
if (ret == 0 || errno != EINTR)
|
||||
break;
|
||||
#else
|
||||
int ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &req, &rem);
|
||||
if (ret == 0 || ret != EINTR)
|
||||
break;
|
||||
#endif
|
||||
// Retry sleep if interrupted by a signal
|
||||
req = rem;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string sha256(const std::string &str) {
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ private:
|
||||
};
|
||||
|
||||
std::string sha256(const std::string &str);
|
||||
void precise_nano_sleep(int64_t nanoseconds);
|
||||
void precise_nano_sleep(int64_t nanoseconds, std::atomic<bool> &should_exit);
|
||||
std::string decompressBZ2(const std::string &in, std::atomic<bool> *abort = nullptr);
|
||||
std::string decompressBZ2(const std::byte *in, size_t in_size, std::atomic<bool> *abort = nullptr);
|
||||
std::string getUrlWithoutQuery(const std::string &url);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||
cd $DIR
|
||||
|
||||
OPENPILOT_DIR="/tmp/openpilot"
|
||||
if ! [[ -z "$MOUNT_OPENPILOT" ]]; then
|
||||
OPENPILOT_DIR="$(dirname $(dirname $DIR))"
|
||||
EXTRA_ARGS="-v $OPENPILOT_DIR:$OPENPILOT_DIR -e PYTHONPATH=$OPENPILOT_DIR:$PYTHONPATH"
|
||||
fi
|
||||
|
||||
if [[ "$CI" ]]; then
|
||||
CMD="CI=1 ${OPENPILOT_DIR}/tools/sim/tests/test_metadrive_integration.py"
|
||||
else
|
||||
# expose X to the container
|
||||
xhost +local:root
|
||||
|
||||
docker pull ghcr.io/commaai/openpilot-sim:latest
|
||||
CMD="./tmux_script.sh $*"
|
||||
EXTRA_ARGS="${EXTRA_ARGS} -it"
|
||||
fi
|
||||
|
||||
docker kill openpilot_client || true
|
||||
docker run --net=host\
|
||||
--name openpilot_client \
|
||||
--rm \
|
||||
--gpus all \
|
||||
--device=/dev/dri:/dev/dri \
|
||||
--device=/dev/input:/dev/input \
|
||||
-v /tmp/.X11-unix:/tmp/.X11-unix \
|
||||
--shm-size 1G \
|
||||
-e DISPLAY=$DISPLAY \
|
||||
-e QT_X11_NO_MITSHM=1 \
|
||||
-w "$OPENPILOT_DIR/tools/sim" \
|
||||
$EXTRA_ARGS \
|
||||
ghcr.io/commaai/openpilot-sim:latest \
|
||||
/bin/bash -c "$CMD"
|
||||
@@ -1,7 +1,7 @@
|
||||
# Run openpilot with webcam on PC
|
||||
|
||||
What's needed:
|
||||
- Ubuntu 20.04
|
||||
- Ubuntu 24.04
|
||||
- GPU (recommended)
|
||||
- Two USB webcams, at least 720p and 78 degrees FOV (e.g. Logitech C920/C615)
|
||||
- [Car harness](https://comma.ai/shop/products/comma-car-harness) with black panda to connect to your car
|
||||
|
||||
Reference in New Issue
Block a user