31 Commits

Author SHA1 Message Date
mawei 38fe76e2df 编辑launch_openpilot.sh 2026-06-06 22:37:02 +08:00
Comma Device c430381736 VERSION 2026-06-04 13:13:02 +00:00
mawei 24ce7c586b feat(home): increase welcome text font size to 100 2026-06-04 20:19:19 +08:00
mawei 6332384304 feat(sidebar): use Chinese for remote connection status 2026-06-04 20:18:10 +08:00
mawei c6416a899b feat(sidebar): change CONNECT label to REMOTE when connected 2026-06-04 20:17:42 +08:00
mawei e578a8ef87 feat(sidebar): show max CPU temperature instead of static GOOD/OK/HIGH 2026-06-04 20:16:18 +08:00
mawei 30239bfbd2 fix(updated): fall back to current branch when target_branch not found on remote
Prevents false 'update available' notifications when the stored
target_branch doesn't match any branch on the remote. Instead, compare
against the currently running branch for accurate update detection.
2026-06-04 20:16:18 +08:00
mawei 0cc5666b64 编辑manager.py 2026-06-04 08:47:58 +08:00
mawei 59d951ea32 设置面板主菜单字号加大到85px 2026-06-03 20:40:02 +08:00
mawei 10bf80af09 unifont 字体渲染尺寸改为 64px 2026-06-03 20:30:42 +08:00
mawei 1bff880a88 隐藏 Sunnylink 和 Models 菜单 2026-06-03 17:25:34 +08:00
mawei 74f0ba7b7a 首页免责声明去掉末尾感叹号 2026-06-03 17:23:36 +08:00
mawei cdf424d261 manager_init 中默认设置语言为中文简体 (zh-CHS) 2026-06-03 17:21:55 +08:00
mawei 92ebfb42ca 默认语言改为中文简体 (zh-CHS) 2026-06-03 17:17:33 +08:00
mawei 6fe513fd66 Revert "移植 IQ.Pilot panda 子系统"
This reverts commit 237816d8f9.

Reason: IQ.Pilot panda 子系统依赖 cereal::IQCarParams 和 iqState
service,在 openpilot 标准 cereal 中不存在,设备上编译失败。
回退到上一个正常编译版本。panda 固件层(F4/H7)已确认编译通过,
保留固件编译修复的成果。
2026-06-03 16:20:36 +08:00
mawei 237816d8f9 移植 IQ.Pilot panda 子系统
- 用 IQ.Pilot 的 panda/ 完整替换原版(含 board 固件、python 库、certs、构建脚本)
- 同步 selfdrive/pandad/ 为 IQ.Pilot 版(多 panda 管理,新增 panda_comms.cc)
- 修复 IQ.Pilot board 固件编译问题:
  - health.h 补充 CAN_PACKET_VERSION 宏定义
  - IQ.Pilot 特有变量/函数名改回 sunnypilot 原版
    (current_safety_param_iq→current_safety_param_sp 等)
- 固件编译通过:panda(F4)/panda_h7/panda_jungle_h7/body_h7
2026-06-03 16:10:12 +08:00
mawei c75bf1ad61 mazda: steerFaultTemporary 恒为 False 2026-06-03 15:09:26 +08:00
mawei 7dc8596bbd chore: 统一首页字体大小,免责声明改为红色 2026-06-03 11:44:18 +08:00
mawei 5eca39c629 chore: 首页增加免责声明 2026-06-03 11:40:00 +08:00
mawei 2997cb455b chore: 首页显示欢迎选用 MR.ONE 2026-06-03 11:33:32 +08:00
mawei a0844b6aa3 Revert "feat: 首页内容区替换为 HelloKitty 图片"
This reverts commit e53e809fce.
2026-06-03 11:31:58 +08:00
mawei e53e809fce feat: 首页内容区替换为 HelloKitty 图片 2026-06-03 11:25:21 +08:00
mawei e810b1c1e7 chore: 移除主界面 sunnylink 连接状态显示 2026-06-03 11:15:24 +08:00
mawei 9967a69abe chore: 隐藏 OSM、行程、数据洪流菜单 2026-06-03 10:47:37 +08:00
mawei 858a9d6fb9 chore: 隐藏数据洪流(Firehose)菜单 2026-06-03 10:47:16 +08:00
mawei 026d0a5e48 fix(i18n): 将菜单文字翻译延迟到渲染时执行,修复语言切换后仍是英文的问题
PanelInfo 构造时调用 tr() 只会在模块加载时(默认 en)执行一次,
后续语言切换后 panel_info.name 不会自动更新。
将 NavButton._render() 中对 self.panel_info.name 的引用改为
tr(self.panel_info.name),在每次渲染时实时翻译。
2026-06-03 09:57:03 +08:00
mawei b2f5adc98f fix(i18n): replace tr_noop with tr for sidebar menu names in sunnypilot settings
Root cause: all sidebar menu buttons used tr_noop() which returns the
original string without translation. Replaced with tr() for all 16 menu
items (Device, Network, sunnylink, Toggles, Software, Models, Steering,
Cruise, Visuals, Display, OSM, Trips, Vehicle, Firehose, Developer).

Also fixes:
- PairBigButton: pair/paired/subscribed/upgrade to prime hardcoded text
- UpdateOpenpilotBigButton: 'update sunnypilot' hardcoded text
- SunnylinkHeader title: '🚀 sunnylink 🚀' hardcoded text
- OSM: DELETING..., Loading... hardcoded text
- PO: added 25 new translation entries for all above items
2026-06-02 21:10:16 +08:00
mawei cae81899fb fix(i18n): 修复汉化问题 - 补充 tr() 包裹和 PO 翻译
1. 源码 8 个文件:40 处硬编码英文改为 tr() 调用
   - settings.py: 主菜单按钮(toggles/network/device/developer/firehose)
   - network_layout.py: 网络设置全部按钮
   - toggles.py: 开关页全部选项
   - developer.py: 开发者页全部按钮
   - device.py: 设备页按钮
   - onboarding.py: 引导页全部按钮文字
   - sunnylink.py: Backup/Restore 确认对话框
   - sunnypilot/onboarding.py: sunnylink 引导页

2. PO 文件 app_zh-CHS.po: 新增 40 条翻译条目
   - 覆盖所有新增 tr() 调用的中文翻译
   - 翻译风格与原有中文 PO 保持一致

改动: 9 files, +215/-38 lines
2026-06-02 20:55:17 +08:00
mawei 4015dbd04c feat(i18n): 完整汉化 + 替换中文字体(NotoSansSC 子集)
汉化:
- app_zh-CHS.po 从 182 条翻译扩展至 519 条(+1241/-38)
- 覆盖所有功能名称、设置项描述、系统提示等

字体:
- 替换 unifont.otf(5.1MB 像素字体)→ unifont.ttf(426KB NotoSansSC 子集)
- 矢量字体渲染更清晰圆润,体积仅原来的 1/12
- 在设备运行 process.py 后生效
2026-06-02 20:18:52 +08:00
1okko 3c388b5648 2026-5-31 2026-06-02 19:07:47 +08:00
github-actions[bot] 7c44d10fed sunnypilot v2026.002.000 release
date: 2026-06-02T19:04:03
master commit: dfc3c98b226da57a653daf57131a8a3d66166fcb
2026-06-02 19:04:12 +08:00
125 changed files with 9581 additions and 4592 deletions
+11
View File
@@ -0,0 +1,11 @@
* @sunnypilot/dev-internal
/.github/ @devtekve @sunnyhaibin
/release/ci/ @devtekve @sunnyhaibin
/tinygrad_repo @devtekve @Discountchubbs
/tinygrad/ @devtekve @Discountchubbs
/selfdrive/controls/lib/longitudinal_planner.py @devtekve @Discountchubbs
/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @devtekve @Discountchubbs
/selfdrive/modeld/ @devtekve @Discountchubbs
/sunnypilot/model* @devtekve @Discountchubbs
/sunnypilot/sunnylink/ @devtekve
/system/athena/ @devtekve
+47
View File
@@ -0,0 +1,47 @@
name: Bug report
description: For issues with running openpilot on your comma device
labels: ["bug"]
body:
- type: markdown
attributes:
value: >
Before creating a **bug report**, please check the following:
* If the issue likely only affects your car model or make, go back and open a **car bug report** instead.
* If the issue is related to the driving or driver monitoring models, you should open a [discussion](https://github.com/commaai/openpilot/discussions/categories/model-feedback) instead.
* Ensure you're running the latest openpilot release.
* Ensure you're using officially supported hardware. Issues running on PCs have a different issue template.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
- type: textarea
attributes:
label: Describe the bug
description: Also include a description of how to reproduce the bug
validations:
required: true
- type: input
id: route
attributes:
label: Provide a route where the issue occurs
description: Ensure the route is fully uploaded at https://useradmin.comma.ai. We cannot look into issues without routes, or at least a Dongle ID.
placeholder: 77611a1fac303767|2020-05-11--16-37-07
validations:
required: true
- type: input
id: version
attributes:
label: openpilot version
description: If you're not on release, provide the commit hash
placeholder: 0.8.10
validations:
required: true
- type: textarea
attributes:
label: Additional info
+14
View File
@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Car bug report
url: https://github.com/commaai/opendbc/issues/new
about: For issues with a particular car make or model
- name: Join the Discord
url: https://discord.comma.ai
about: The community Discord is for both openpilot development and experience discussion
- name: Report driving behavior feedback
url: https://discord.com/channels/469524606043160576/1254834193066623017
about: Feedback for the driving and driver monitoring models goes in the #driving-feedback in Discord
- name: Community Wiki
url: https://github.com/commaai/openpilot/wiki
about: Check out our community wiki
+8
View File
@@ -0,0 +1,8 @@
---
name: Enhancement
about: For openpilot enhancement suggestions
title: ''
labels: 'enhancement'
assignees: ''
---
+42
View File
@@ -0,0 +1,42 @@
name: PC bug report
description: For issues with running openpilot on PC
labels: ["PC"]
body:
- type: markdown
attributes:
value: >
Before creating a **bug report**, please check the following:
* Ensure you're running the latest openpilot release.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
- type: textarea
attributes:
label: Describe the bug
description: Also include a description of how to reproduce the bug
validations:
required: true
- type: input
id: os-version
attributes:
label: OS Version
placeholder: Ubuntu 24.04
validations:
required: true
- type: input
id: version
attributes:
label: openpilot version or commit
placeholder: bd36f2ec8d3559909678eff2690c10a520938367
validations:
required: false
- type: textarea
attributes:
label: Additional info
+31
View File
@@ -0,0 +1,31 @@
ci:
- changed-files:
- any-glob-to-all-files: "{.github/**,**/test_*,**/test/**,Jenkinsfile}"
chore:
- changed-files:
- any-glob-to-all-files: "{.github/**}"
car:
- changed-files:
- any-glob-to-all-files: '{selfdrive/car/**,opendbc_repo}'
simulation:
- changed-files:
- any-glob-to-all-files: 'tools/sim/**'
ui:
- changed-files:
- any-glob-to-all-files: '{selfdrive/assets/**,selfdrive/ui/**,system/ui/**}'
tools:
- changed-files:
- any-glob-to-all-files: 'tools/**'
multilanguage:
- changed-files:
- any-glob-to-all-files: 'selfdrive/ui/translations/**'
autonomy:
- changed-files:
- any-glob-to-all-files: "{selfdrive/modeld/models/**,selfdrive/test/process_replay/model_replay_ref_commit,sunnypilot/modeld*/models/**}"
+68
View File
@@ -0,0 +1,68 @@
<!-- Please copy and paste the relevant template -->
<!--- ***** Template: Fingerprint *****
**Car**
Which car (make, model, year) this fingerprint is for
**Route**
A route with the fingerprint
-->
<!--- ***** Template: Car Bugfix *****
**Description**
A description of the bug and the fix. Also link the issue if it exists.
**Verification**
Explain how you tested this bug fix.
**Route**
Route: [a route with the bug fix]
-->
<!--- ***** Template: Bugfix *****
**Description**
A description of the bug and the fix. Also link the issue if it exists.
**Verification**
Explain how you tested this bug fix.
-->
<!--- ***** Template: Car Port *****
**Checklist**
- [ ] added entry to CAR in selfdrive/car/*/values.py and ran `selfdrive/car/docs.py` to generate new docs
- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot:
- [ ] route with stock system:
- [ ] car harness used (if comma doesn't sell it, put N/A):
-->
<!--- ***** Template: Refactor *****
**Description**
A description of the refactor, including the goals it accomplishes.
**Verification**
Explain how you tested the refactor for regressions.
-->
+43
View File
@@ -0,0 +1,43 @@
exclude-labels:
- 'no-changelog'
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
collapse-after: 5
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
collapse-after: 5
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&'
replacers:
- search: '/[Ss][Uu][Nn][Nn][Yy][Pp][Ii][Ll][Oo][Tt]/g'
replace: 'sunnypilot'
- search: '/\b[Ss][Pp]\b/g'
replace: 'SP'
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
name-template: 'v$RESOLVED_VERSION 🚀'
tag-template: 'v$RESOLVED_VERSION'
version-template: "0.$MAJOR.$MINOR.$PATCH" # The day OP becomes v1, we need to bump this
tag-prefix: "v0." # The day OP becomes v1, we need to bump this
prerelease-identifier: "staging"
template: |
## Changes
$CHANGES
-83
View File
@@ -1,83 +0,0 @@
#!/bin/env sh
persist_dir=/persist
target_dir=${persist_dir}/comma
# Change target dir from sunnylink to comma to make this no longer a test
# Function to remount /persist as read-only
cleanup() {
echo "Remounting ${persist_dir} as read-only..."
sudo mount -o remount,ro ${persist_dir}
}
# Function to check and backup existing keys
backup_keys() {
if [ -f "id_rsa" ] || [ -f "id_rsa.pub" ]; then
timestamp=$(date +%s)
backup_base="id_rsa_backup_$timestamp"
backup_private="$backup_base"
backup_public="${backup_base}.pub"
# Ensure we're not overwriting an existing backup
counter=0
while [ -f "$backup_private" ] || [ -f "$backup_public" ]; do
counter=$((counter + 1))
backup_private="${backup_base}_$counter"
backup_public="${backup_base}_$counter.pub"
done
# Backup the keys
cp id_rsa "$backup_private"
cp id_rsa.pub "$backup_public"
# Verify the backup
original_private_hash=$(sha256sum id_rsa | cut -d ' ' -f 1)
backup_private_hash=$(sha256sum "$backup_private" | cut -d ' ' -f 1)
original_public_hash=$(sha256sum id_rsa.pub | cut -d ' ' -f 1)
backup_public_hash=$(sha256sum "$backup_public" | cut -d ' ' -f 1)
if [ "$original_private_hash" = "$backup_private_hash" ] && [ "$original_public_hash" = "$backup_public_hash" ]; then
echo "Backup verified successfully."
# Safe to delete original keys after successful backup verification
else
echo "Backup verification failed. Aborting operation."
exit 1
fi
echo "Existing keys backed up as $backup_private and $backup_public"
fi
}
# Trap any signal that exits the script to run cleanup function
trap cleanup EXIT
# Remount /persist as read-write
sudo mount -o remount,rw ${persist_dir}
# Ensure the directory exists
mkdir -p ${target_dir}
cd ${target_dir}
# Check for and backup existing keys
#backup_keys
# Generate new keys
if ! ssh-keygen -t rsa -b 4096 -m PEM -f id_rsa -N ''; then
echo "Failed to generate new RSA keys. Exiting..."
exit 1
fi
# Convert the generated SSH public key to PEM format and store it temporarily
if ! openssl rsa -pubout -in id_rsa -out id_rsa.pub -outform PEM; then
echo "Failed to convert the public key to PEM format. Exiting..."
exit 1
fi
# Display the public key
echo "Displaying the public key:"
cat id_rsa.pub
# Cleanup will be called automatically due to trap on EXIT
#echo "Operation completed successfully. System will reboot now."
#sudo reboot
+269
View File
@@ -0,0 +1,269 @@
import os
import subprocess
import sys
import sysconfig
import platform
import shlex
import importlib
import numpy as np
import SCons.Errors
from SCons.Defaults import _stripixes
SCons.Warnings.warningAsException(True)
Decider('MD5-timestamp')
SetOption('num_jobs', max(1, int(os.cpu_count()/2)))
AddOption('--ccflags', action='store', type='string', default='', help='pass arbitrary flags over the command line')
AddOption('--verbose', action='store_true', default=False, help='show full build commands')
AddOption('--minimal',
action='store_false',
dest='extras',
default=os.path.exists(File('#.gitattributes').abspath), # minimal by default on release branch (where there's no LFS)
help='the minimum build to run openpilot. no tests, tools, etc.')
# Detect platform
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin":
arch = "Darwin"
elif arch == "aarch64" and os.path.isfile('/TICI'):
arch = "larch64"
assert arch in [
"larch64", # linux tici arm64
"aarch64", # linux pc arm64
"x86_64", # linux pc x64
"Darwin", # macOS arm64 (x86 not supported)
]
pkg_names = ['bzip2', 'capnproto', 'eigen', 'ffmpeg', 'libjpeg', 'libyuv', 'ncurses', 'zeromq', 'zstd']
pkgs = [importlib.import_module(name) for name in pkg_names]
# ***** enforce a whitelist of system libraries *****
# this prevents silently relying on a 3rd party package,
# e.g. apt-installed libusb. all libraries should either
# be distributed with all Linux distros and macOS, or
# vendored in commaai/dependencies.
allowed_system_libs = {
"EGL", "GLESv2", "GL",
"Qt5Charts", "Qt5Core", "Qt5Gui", "Qt5Widgets",
"dl", "drm", "gbm", "m", "pthread",
}
def _resolve_lib(env, name):
for d in env.Flatten(env.get('LIBPATH', [])):
p = Dir(str(d)).abspath
for ext in ('.a', '.so', '.dylib'):
f = File(os.path.join(p, f'lib{name}{ext}'))
if f.exists() or f.has_builder():
return name
if name in allowed_system_libs:
return name
raise SCons.Errors.UserError(f"Unexpected non-vendored library '{name}'")
def _libflags(target, source, env, for_signature):
libs = []
lp = env.subst('$LIBLITERALPREFIX')
for lib in env.Flatten(env.get('LIBS', [])):
if isinstance(lib, str):
if os.sep in lib or lib.startswith('#'):
libs.append(File(lib))
elif lib.startswith('-') or (lp and lib.startswith(lp)):
libs.append(lib)
else:
libs.append(_resolve_lib(env, lib))
else:
libs.append(lib)
return _stripixes(env['LIBLINKPREFIX'], libs, env['LIBLINKSUFFIX'],
env['LIBPREFIXES'], env['LIBSUFFIXES'], env, env['LIBLITERALPREFIX'])
env = Environment(
ENV={
"PATH": os.environ['PATH'],
"PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath,
"ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath,
"ACADOS_PYTHON_INTERFACE_PATH": Dir("#third_party/acados/acados_template").abspath,
"TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer"
},
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Wunused",
"-Werror",
"-Wshadow" if arch in ("Darwin", "larch64") else "-Wshadow=local",
"-Wno-unknown-warning-option",
"-Wno-inconsistent-missing-override",
"-Wno-c99-designator",
"-Wno-reorder-init-list",
"-Wno-vla-cxx-extension",
],
CFLAGS=["-std=gnu11"],
CXXFLAGS=["-std=c++1z"],
CPPPATH=[
"#",
"#msgq",
"#third_party",
"#third_party/json11",
"#third_party/linux/include",
"#third_party/acados/include",
"#third_party/acados/include/blasfeo/include",
"#third_party/acados/include/hpipm/include",
"#third_party/catch2/include",
[x.INCLUDE_DIR for x in pkgs],
],
LIBPATH=[
"#common",
"#msgq_repo",
"#third_party",
"#selfdrive/pandad",
"#rednose/helpers",
f"#third_party/acados/{arch}/lib",
[x.LIB_DIR for x in pkgs],
],
RPATH=[],
CYTHONCFILESUFFIX=".cpp",
COMPILATIONDB_USE_ABSPATH=True,
REDNOSE_ROOT="#",
tools=["default", "cython", "compilation_db", "rednose_filter"],
toolpath=["#site_scons/site_tools", "#rednose_repo/site_scons/site_tools"],
)
if arch != "larch64":
env['_LIBFLAGS'] = _libflags
# Arch-specific flags and paths
if arch == "larch64":
env["CC"] = "clang"
env["CXX"] = "clang++"
env.Append(LIBPATH=[
"/usr/lib/aarch64-linux-gnu",
])
arch_flags = ["-D__TICI__", "-mcpu=cortex-a57", "-DQCOM2"]
env.Append(CCFLAGS=arch_flags)
env.Append(CXXFLAGS=arch_flags)
elif arch == "Darwin":
env.Append(LIBPATH=[
"/System/Library/Frameworks/OpenGL.framework/Libraries",
])
env.Append(CCFLAGS=["-DGL_SILENCE_DEPRECATION"])
env.Append(CXXFLAGS=["-DGL_SILENCE_DEPRECATION"])
_extra_cc = shlex.split(GetOption('ccflags') or '')
if _extra_cc:
env.Append(CCFLAGS=_extra_cc)
# no --as-needed on mac linker
if arch != "Darwin":
env.Append(LINKFLAGS=["-Wl,--as-needed", "-Wl,--no-undefined"])
# Shorter build output: show brief descriptions instead of full commands.
# Full command lines are still printed on failure by scons.
if not GetOption('verbose'):
for action, short in (
("CC", "CC"),
("CXX", "CXX"),
("LINK", "LINK"),
("SHCC", "CC"),
("SHCXX", "CXX"),
("SHLINK", "LINK"),
("AR", "AR"),
("RANLIB", "RANLIB"),
("AS", "AS"),
):
env[f"{action}COMSTR"] = f" [{short}] $TARGET"
# progress output
node_interval = 5
node_count = 0
def progress_function(node):
global node_count
node_count += node_interval
sys.stderr.write("progress: %d\n" % node_count)
if os.environ.get('SCONS_PROGRESS'):
Progress(progress_function, interval=node_interval)
# ********** Cython build environment **********
envCython = env.Clone()
envCython["CPPPATH"] += [sysconfig.get_paths()['include'], np.get_include()]
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-cpp", "-Wno-shadow", "-Wno-deprecated-declarations"]
envCython["CCFLAGS"].remove("-Werror")
envCython["LIBS"] = []
if arch == "Darwin":
envCython["LINKFLAGS"] = env["LINKFLAGS"] + ["-bundle", "-undefined", "dynamic_lookup"]
else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
np_version = SCons.Script.Value(np.__version__)
Export('envCython', 'np_version')
Export('env', 'arch')
# Setup cache dir
default_cache_dir = '/data/scons_cache' if arch == "larch64" else '/tmp/scons_cache'
cache_dir = ARGUMENTS.get('cache_dir', default_cache_dir)
CacheDir(cache_dir)
Clean(["."], cache_dir)
# ********** start building stuff **********
# Build common module
SConscript(['common/SConscript'])
Import('_common')
common = [_common, 'json11', 'zmq']
Export('common')
# Build messaging (cereal + msgq + socketmaster + their dependencies)
# Enable swaglog include in submodules
env_swaglog = env.Clone()
env_swaglog['CXXFLAGS'].append('-DSWAGLOG="\\"common/swaglog.h\\""')
SConscript(['msgq_repo/SConscript'], exports={'env': env_swaglog})
SConscript(['cereal/SConscript'])
Import('socketmaster', 'msgq')
messaging = [socketmaster, msgq, 'capnp', 'kj',]
Export('messaging')
# Build other submodules
SConscript(['panda/SConscript'])
# Build rednose library
SConscript(['rednose/SConscript'])
# Build system services
SConscript([
'system/loggerd/SConscript',
])
if arch == "larch64":
SConscript(['system/camerad/SConscript'])
# Build openpilot
SConscript(['third_party/SConscript'])
# Build selfdrive
SConscript([
'selfdrive/pandad/SConscript',
'selfdrive/controls/lib/lateral_mpc_lib/SConscript',
'selfdrive/controls/lib/longitudinal_mpc_lib/SConscript',
'selfdrive/locationd/SConscript',
'selfdrive/modeld/SConscript',
'selfdrive/ui/SConscript',
])
SConscript(['sunnypilot/SConscript'])
# Build tools
if arch != "larch64":
SConscript([
'tools/replay/SConscript',
'tools/cabana/SConscript',
'tools/jotpluggler/SConscript',
])
env.CompilationDatabase('compile_commands.json')
+20
View File
@@ -0,0 +1,20 @@
Import('env', 'common', 'msgq')
cereal_dir = Dir('.')
gen_dir = Dir('gen')
# Build cereal
schema_files = ['log.capnp', 'car.capnp', 'deprecated.capnp', 'custom.capnp']
env.Command([f'gen/cpp/{s}.c++' for s in schema_files] + [f'gen/cpp/{s}.h' for s in schema_files],
schema_files,
f"capnpc --src-prefix={cereal_dir.path} $SOURCES -o c++:{gen_dir.path}/cpp/")
cereal = env.Library('cereal', [f'gen/cpp/{s}.c++' for s in schema_files])
# Build messaging
services_h = env.Command(['services.h'], ['services.py'], 'python3 ' + cereal_dir.path + '/services.py > $TARGET')
env.Program('messaging/bridge', ['messaging/bridge.cc', 'messaging/msgq_to_zmq.cc', 'messaging/bridge_zmq.cc'], LIBS=[msgq, common, 'pthread'])
socketmaster = env.Library('socketmaster', ['messaging/socketmaster.cc'])
Export('cereal', 'socketmaster')
+23
View File
@@ -0,0 +1,23 @@
Import('env', 'envCython')
common_libs = [
'params.cc',
'swaglog.cc',
'util.cc',
'ratekeeper.cc',
]
_common = env.Library('common', common_libs, LIBS="json11")
Export('_common')
if GetOption('extras'):
env.Program('tests/test_common',
['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'],
LIBS=[_common, 'json11', 'zmq', 'pthread'])
# Cython bindings
params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11'])
common_python = [params_python]
Export('common_python')
+1
View File
@@ -0,0 +1 @@
dfc3c98b226da57a653daf57131a8a3d66166fcb
+1
View File
@@ -0,0 +1 @@
1779852714 2026-05-26 23:31:54 -0400
+2 -1
View File
@@ -5,7 +5,8 @@ export API_HOST='http://res.mr-one.cn'
echo -n "2" > /data/params/d/HasAcceptedTerms
echo -n "1.0" > /data/params/d/HasAcceptedTermsSP
echo -n "0.2.0" > /data/params/d/CompletedTrainingVersion
echo -n "1.0" > /data/params/d/CompletedSunnylinkConsentVersion # Sunnylink 同意
echo -n "1" > /data/params/d/IsMetric
exec ./launch_chffrplus.sh
+39
View File
@@ -0,0 +1,39 @@
Import('env', 'envCython', 'arch', 'common')
visionipc_dir = Dir('msgq/visionipc')
# Build msgq
msgq_objects = env.SharedObject([
'msgq/ipc.cc',
'msgq/event.cc',
'msgq/impl_msgq.cc',
'msgq/impl_fake.cc',
'msgq/msgq.cc',
])
msgq = env.Library('msgq', msgq_objects)
msgq_python = envCython.Program('msgq/ipc_pyx.so', 'msgq/ipc_pyx.pyx', LIBS=envCython["LIBS"]+[msgq, common])
# Build Vision IPC
vipc_files = ['visionipc.cc', 'visionipc_server.cc', 'visionipc_client.cc']
if arch == "larch64":
vipc_files += ['visionbuf_ion.cc']
else:
vipc_files += ['visionbuf.cc']
vipc_sources = [f'{visionipc_dir.abspath}/{f}' for f in vipc_files]
vipc_objects = env.SharedObject(vipc_sources)
visionipc = env.Library('visionipc', vipc_objects)
vipc_libs = envCython["LIBS"] + [visionipc, msgq, common]
envCython.Program(f'{visionipc_dir.abspath}/visionipc_pyx.so', f'{visionipc_dir.abspath}/visionipc_pyx.pyx',
LIBS=vipc_libs)
if GetOption('extras'):
env.Program('msgq/test_runner', ['msgq/test_runner.cc', 'msgq/msgq_tests.cc'], LIBS=[msgq, common])
env.Program(f'{visionipc_dir.abspath}/test_runner',
[f'{visionipc_dir.abspath}/test_runner.cc', f'{visionipc_dir.abspath}/visionipc_tests.cc'],
LIBS=['pthread'] + vipc_libs)
Export('visionipc', 'msgq', 'msgq_python')
+83
View File
@@ -0,0 +1,83 @@
import os
import platform
import subprocess
import sysconfig
import numpy as np
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin":
arch = "Darwin"
common = ''
cpppath = [
f"#/",
'#msgq/',
'/usr/lib/include',
sysconfig.get_paths()['include'],
]
AddOption('--minimal',
action='store_false',
dest='extras',
default=True,
help='the minimum build. no tests, tools, etc.')
AddOption('--asan',
action='store_true',
help='turn on ASAN')
AddOption('--ubsan',
action='store_true',
help='turn on UBSan')
ccflags = []
ldflags = []
if GetOption('ubsan'):
flags = [
"-fsanitize=undefined",
"-fno-sanitize-recover=undefined",
]
ccflags += flags
ldflags += flags
elif GetOption('asan'):
ccflags += ["-fsanitize=address", "-fno-omit-frame-pointer"]
ldflags += ["-fsanitize=address"]
env = Environment(
ENV=os.environ,
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Wunused",
"-Werror",
"-Wshadow" if arch == "Darwin" else "-Wshadow=local",
"-Wno-vla-cxx-extension",
"-Wno-unknown-warning-option",
] + ccflags,
LDFLAGS=ldflags,
LINKFLAGS=ldflags,
CFLAGS="-std=gnu11",
CXXFLAGS="-std=c++1z",
CPPPATH=cpppath,
CYTHONCFILESUFFIX=".cpp",
tools=["default", "cython"]
)
Export('env', 'arch', 'common')
envCython = env.Clone(LIBS=[])
envCython["CPPPATH"] += [np.get_include()]
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-cpp", "-Wno-shadow", "-Wno-deprecated-declarations"]
envCython["CCFLAGS"].remove('-Werror')
if arch == "Darwin":
envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"]
else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
Export('envCython')
SConscript(['SConscript'])
+49
View File
@@ -0,0 +1,49 @@
name: Car bug report
description: For issues with a particular car make or model
labels: ["car", "bug"]
body:
- type: markdown
attributes:
value: >
Before creating a **car bug report**, please check the following:
* If the issue likely isn't specific to your car model or make, go back and open an **openpilot bug report** instead.
* If the issue is related to the driving or driver monitoring models, you should open a [discussion](https://github.com/commaai/openpilot/discussions/categories/model-feedback) instead.
* If you are fingerprinting your car, refer to the [fingerprinting guide](https://github.com/commaai/openpilot/wiki/Fingerprinting) or visit the [community Discord server](https://discord.comma.ai) to request help.
* If you are inquiring about future car support, check the [community Discord server](https://discord.comma.ai) for progress on your vehicle and help contribute. Issues simply requesting support for new vehicles will be closed.
* Ensure you're running the latest openpilot release.
* Ensure you're using officially supported hardware.
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
* Ensure you're running stock openpilot. We cannot look into bug reports from forks.
If you're unsure whether you've hit a bug, check out the #installation-help channel in the [community Discord server](https://discord.comma.ai).
- type: textarea
attributes:
label: Describe the car bug
description: Also include a description of how to reproduce the bug
validations:
required: true
- type: input
id: route
attributes:
label: Provide a route where the issue occurs
description: Ensure the route is fully uploaded at https://useradmin.comma.ai. We cannot look into issues without routes, or at least a Dongle ID.
placeholder: 77611a1fac303767|2020-05-11--16-37-07
validations:
required: true
- type: input
id: version
attributes:
label: openpilot version
description: If you're not on release, provide the commit hash
placeholder: 0.8.10
validations:
required: true
- type: textarea
attributes:
label: Additional info
+14
View File
@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: openpilot bug report
url: https://github.com/commaai/openpilot/issues/new
about: For issues not limited to a particular car make or model, e.g. driving model performance or issues with your comma device.
- name: Join the Discord
url: https://discord.comma.ai
about: The community Discord is for both car port development and experience discussion
- name: Report driving behavior feedback
url: https://discord.com/channels/469524606043160576/1254834193066623017
about: Feedback for the driving and driver monitoring models goes in the #driving-feedback in Discord
- name: Community Wiki
url: https://github.com/commaai/openpilot/wiki
about: Check out our community wiki
+36
View File
@@ -0,0 +1,36 @@
name: Miscellaneous
description: For tools or test bugs, or enhancements
labels: ["bug"]
body:
- type: markdown
attributes:
value: >
* If the issue likely only affects your car model or make, go back and open a **car bug report** instead.
Before creating a **miscellaneous bug report**, please check the following:
* Ensure there isn't an existing issue for your bug. If there is, leave a comment on the existing issue.
- type: textarea
attributes:
label: Describe the bug or enhancement
description: Also include a description of how to reproduce the bug or how the enhancement would work
validations:
required: true
- type: input
id: route
attributes:
label: Provide a route where the issue occurs if applicable
description: Ensure the route is fully uploaded at https://useradmin.comma.ai
placeholder: 77611a1fac303767|2020-05-11--16-37-07
- type: input
id: version
attributes:
label: openpilot version if applicable
description: If you're not on release, provide the commit hash
placeholder: 0.8.10
- type: textarea
attributes:
label: Additional info
+76
View File
@@ -0,0 +1,76 @@
CI / testing:
- changed-files:
- any-glob-to-any-file: '.github/**'
car:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/**'
car safety:
- changed-files:
- any-glob-to-any-file: 'opendbc/safety/**'
can:
- changed-files:
- any-glob-to-any-file: 'opendbc/can/**'
DBC signals:
- changed-files:
- any-glob-to-any-file: 'opendbc/dbc/**'
body:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/body/**'
chrysler:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/chrysler/**'
ford:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/ford/**'
gm:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/gm/**'
honda:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/honda/**'
hyundai:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/hyundai/**'
mazda:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/mazda/**'
nissan:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/nissan/**'
rivian:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/rivian/**'
subaru:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/subaru/**'
tesla:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/tesla/**'
toyota:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/toyota/**'
volkswagen:
- changed-files:
- any-glob-to-any-file: 'opendbc/car/volkswagen/**'
fingerprint:
- changed-files:
- any-glob-to-all-files: 'opendbc/car/*/fingerprints.py'
+11
View File
@@ -0,0 +1,11 @@
<!--
We need these details to verify your pull request.
Find your device's dongle ID and a route at https://connect.comma.ai.
Ideally, the route is recorded with the exact branch of your pull request.
If you are porting a car with a new harness variant, please add it to https://github.com/commaai/opendbc/blob/master/opendbc/car/docs_definitions.py. Let us know and we can add it to the shop at the time of merge.
-->
Validation
* Dongle ID:
* Route:
+1 -1
View File
@@ -101,7 +101,7 @@ class CarState(CarStateBase):
# Check if LKAS is disabled due to lack of driver torque when all other states indicate
# it should be enabled (steer lockout). Don't warn until we actually get lkas active
# and lose it again, i.e, after initial lkas activation
ret.steerFaultTemporary = self.lkas_allowed_speed and lkas_blocked
ret.steerFaultTemporary = False
self.acc_active_last = ret.cruiseState.enabled
+139
View File
@@ -0,0 +1,139 @@
def docker_run(String step_label, int timeout_mins, String cmd) {
timeout(time: timeout_mins, unit: 'MINUTES') {
sh script: "docker run --rm --privileged \
--env PYTHONWARNINGS=error \
--volume /dev/bus/usb:/dev/bus/usb \
--volume /var/run/dbus:/var/run/dbus \
--net host \
${env.DOCKER_IMAGE_TAG} \
bash -c 'scons && ${cmd}'", \
label: step_label
}
}
def phone(String ip, String step_label, String cmd) {
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
def ssh_cmd = """
ssh -tt -o StrictHostKeyChecking=no -o ConnectTimeout=30 -o ConnectionAttempts=3 -o ServerAliveInterval=10 -o ServerAliveCountMax=3 -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
set -e
source ~/.bash_profile
if [ -f /etc/profile ]; then
source /etc/profile
fi
export CI=1
export TEST_DIR=${env.TEST_DIR}
export SOURCE_DIR=${env.SOURCE_DIR}
export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT}
export PYTHONPATH=${env.TEST_DIR}/../
export PYTHONWARNINGS=error
export LOGLEVEL=debug
ln -sf /data/openpilot/opendbc_repo/opendbc /data/opendbc
# TODO: this is an agnos issue
export PYTEST_ADDOPTS="-p no:asyncio"
cd ${env.TEST_DIR} || true
${cmd}
exit 0
END"""
sh script: ssh_cmd, label: step_label
}
}
def phone_steps(String device_type, steps) {
lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
timeout(time: 20, unit: 'MINUTES') {
retry (3) {
def date = sh(script: 'date', returnStdout: true).trim()
phone(device_ip, "set time", "date -s '${date}'")
phone(device_ip, "git checkout", readFile("tests/setup_device_ci.sh"))
}
steps.each { item ->
phone(device_ip, item[0], item[1])
}
}
}
}
pipeline {
agent any
environment {
CI = "1"
PYTHONWARNINGS= "error"
DOCKER_IMAGE_TAG = "panda:build-${env.GIT_COMMIT}"
TEST_DIR = "/data/panda"
SOURCE_DIR = "/data/panda_source/"
}
options {
timeout(time: 3, unit: 'HOURS')
disableConcurrentBuilds(abortPrevious: env.BRANCH_NAME != 'master')
}
stages {
stage ('Acquire resource locks') {
options {
lock(resource: "pandas")
}
stages {
stage('Build Docker Image') {
steps {
timeout(time: 20, unit: 'MINUTES') {
script {
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}", "--build-arg CACHEBUST=${env.GIT_COMMIT} .")
}
}
}
}
stage('jungle tests') {
steps {
script {
retry (3) {
docker_run("reset hardware", 3, "python3 ./tests/hitl/reset_jungles.py")
}
}
}
}
stage('parallel tests') {
parallel {
stage('test cuatro') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("panda-cuatro", [
["build", "scons"],
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py --all"],
["test", "cd tests/hitl && pytest -o 'addopts=' --durations=0 2*.py [5-9]*.py"],
])
}
}
stage('test tres') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("panda-tres", [
["build", "scons"],
["flash", "cd scripts/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py --all"],
["test", "cd tests/hitl && pytest -o 'addopts=' --durations=0 2*.py [5-9]*.py"],
])
}
}
}
}
}
}
}
}
+176
View File
@@ -0,0 +1,176 @@
import os
import hashlib
import opendbc
import subprocess
PREFIX = "arm-none-eabi-"
BUILDER = "DEV"
common_flags = []
if os.getenv("RELEASE"):
BUILD_TYPE = "RELEASE"
cert_fn = os.getenv("CERT")
assert cert_fn is not None, 'No certificate file specified. Please set CERT env variable'
assert os.path.exists(cert_fn), 'Certificate file not found. Please specify absolute path'
else:
BUILD_TYPE = "DEBUG"
cert_fn = File("./board/certs/debug").srcnode().relpath
common_flags += ["-DALLOW_DEBUG"]
if os.getenv("DEBUG"):
common_flags += ["-DDEBUG"]
def objcopy(source, target, env, for_signature):
return '$OBJCOPY -O binary %s %s' % (source[0], target[0])
def get_version(builder, build_type):
try:
git = subprocess.check_output(["git", "rev-parse", "--short=8", "HEAD"], encoding='utf8').strip()
except subprocess.CalledProcessError:
git = "unknown"
return f"{builder}-{git}-{build_type}"
def get_key_header(name):
from Crypto.PublicKey import RSA
public_fn = File(f'./board/certs/{name}.pub').srcnode().get_path()
with open(public_fn) as f:
rsa = RSA.importKey(f.read())
assert(rsa.size_in_bits() == 1024)
rr = pow(2**1024, 2, rsa.n)
n0inv = 2**32 - pow(rsa.n, -1, 2**32)
r = [
f"RSAPublicKey {name}_rsa_key = {{",
f" .len = 0x20,",
f" .n0inv = {n0inv}U,",
f" .n = {to_c_uint32(rsa.n)},",
f" .rr = {to_c_uint32(rr)},",
f" .exponent = {rsa.e},",
f"}};",
]
return r
def to_c_uint32(x):
nums = []
for _ in range(0x20):
nums.append(x % (2**32))
x //= (2**32)
return "{" + 'U,'.join(map(str, nums)) + "U}"
def build_project(project_name, project, main, extra_flags):
project_dir = Dir(f'./board/obj/{project_name}/')
flags = project["FLAGS"] + extra_flags + common_flags + [
"-Wall",
"-Wextra",
"-Wstrict-prototypes",
"-Werror",
"-mlittle-endian",
"-mthumb",
"-nostdlib",
"-fno-builtin",
"-std=gnu11",
"-fmax-errors=1",
f"-T{File(project['LINKER_SCRIPT']).srcnode().relpath}",
"-fsingle-precision-constant",
"-Os",
"-g",
]
env = Environment(
ENV=os.environ,
CC=PREFIX + 'gcc',
AS=PREFIX + 'gcc',
OBJCOPY=PREFIX + 'objcopy',
OBJDUMP=PREFIX + 'objdump',
OBJPREFIX=project_dir,
CFLAGS=flags,
ASFLAGS=flags,
LINKFLAGS=flags,
CPPPATH=[Dir("./"), "./board/stm32h7/inc", opendbc.INCLUDE_PATH],
ASCOM="$AS $ASFLAGS -o $TARGET -c $SOURCES",
BUILDERS={
'Objcopy': Builder(generator=objcopy, suffix='.bin', src_suffix='.elf')
},
tools=["default", "compilation_db"],
)
startup = env.Object(project["STARTUP_FILE"])
# Build bootstub
bs_env = env.Clone()
bs_env.Append(CFLAGS="-DBOOTSTUB", ASFLAGS="-DBOOTSTUB", LINKFLAGS="-DBOOTSTUB")
bs_elf = bs_env.Program(f"{project_dir}/bootstub.elf", [
startup,
"./board/crypto/rsa.c",
"./board/crypto/sha.c",
"./board/bootstub.c",
])
bs_env.Objcopy(f"./board/obj/bootstub.{project_name}.bin", bs_elf)
# Build + sign main (aka app)
main_elf = env.Program(f"{project_dir}/main.elf", [
startup,
main
], LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags)
main_bin = env.Objcopy(f"{project_dir}/main.bin", main_elf)
sign_py = File(f"./board/crypto/sign.py").srcnode().relpath
env.Command(f"./board/obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}")
base_project_h7 = {
"STARTUP_FILE": "./board/stm32h7/startup_stm32h7x5xx.s",
"LINKER_SCRIPT": "./board/stm32h7/stm32h7x5_flash.ld",
"APP_START_ADDRESS": "0x8020000",
"FLAGS": [
"-mcpu=cortex-m7",
"-mhard-float",
"-DSTM32H7",
"-DSTM32H725xx",
"-Iboard/stm32h7/inc",
"-mfpu=fpv5-d16",
],
}
# Common autogenerated includes
with open("board/obj/gitversion.h", "w") as f:
version = get_version(BUILDER, BUILD_TYPE)
f.write(f'extern const uint8_t gitversion[{len(version)+1}];\n')
f.write(f'const uint8_t gitversion[{len(version)+1}] = "{version}";\n')
with open("board/obj/version", "w") as f:
f.write(f'{get_version(BUILDER, BUILD_TYPE)}')
certs = [get_key_header(n) for n in ["debug", "release"]]
with open("board/obj/cert.h", "w") as f:
for cert in certs:
f.write("\n".join(cert) + "\n")
# Packet version defines: SHA hash of the struct header files
def version_hash(path):
with open(path, "rb") as f:
# Normalize line endings on Windows
return int.from_bytes(hashlib.sha256(f.read().replace(b'\r', b'')).digest()[:4], 'little')
hh, ch, jh = version_hash("board/health.h"), version_hash(os.path.join(opendbc.INCLUDE_PATH, "opendbc/safety/can.h")), version_hash("board/jungle/jungle_health.h")
common_flags += [f"-DHEALTH_PACKET_VERSION=0x{hh:08X}U", f"-DCAN_PACKET_VERSION_HASH=0x{ch:08X}U",
f"-DJUNGLE_HEALTH_PACKET_VERSION=0x{jh:08X}U"]
# panda fw
build_project("panda_h7", base_project_h7, "./board/main.c", [])
# panda jungle fw
flags = [
"-DPANDA_JUNGLE",
]
build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags)
# body fw
build_project("body_h7", base_project_h7, "./board/body/main.c", ["-DPANDA_BODY"])
# test files
SConscript('tests/libpanda/SConscript')
+13
View File
@@ -0,0 +1,13 @@
import os
env = Environment(
COMPILATIONDB_USE_ABSPATH=True,
tools=["default", "compilation_db"],
)
SetOption('num_jobs', max(1, int((os.cpu_count() or 1)-1)))
env.CompilationDatabase("compile_commands.json")
# panda fw & test files
SConscript('SConscript')
+1 -1
View File
@@ -7,7 +7,7 @@ from .python import (Panda, PandaDFU, # noqa: F401
DLC_TO_LEN, LEN_TO_DLC, CANPACKET_HEAD_SIZE)
# panda jungle
#from .board.jungle import PandaJungle, PandaJungleDFU # noqa: F401
from .board.jungle import PandaJungle, PandaJungleDFU # noqa: F401
# panda body
from .board.body import PandaBody # noqa: F401
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[18];
const uint8_t gitversion[18] = "DEV-unknown-DEBUG";
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-24ce7c58-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-unknown-DEBUG
DEV-24ce7c58-DEBUG
+15
View File
@@ -0,0 +1,15 @@
import opendbc
env = Environment(
CFLAGS=[
'-nostdlib',
'-fno-builtin',
'-std=gnu11',
'-Wfatal-errors',
'-Wno-pointer-to-int-cast',
],
CPPPATH=[".", "../../", "../../board/", opendbc.INCLUDE_PATH],
)
panda = env.SharedObject("panda.os", "panda.c")
libpanda = env.SharedLibrary("libpanda.so", [panda])
+57
View File
@@ -0,0 +1,57 @@
import os
import subprocess
import sysconfig
import numpy as np
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
common = ''
python_path = sysconfig.get_paths()['include']
cpppath = [
'#',
'#rednose',
'#rednose/examples/generated',
'/usr/lib/include',
python_path,
np.get_include(),
]
env = Environment(
ENV=os.environ,
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Werror=implicit-function-declaration",
"-Werror=incompatible-pointer-types",
"-Werror=int-conversion",
"-Werror=return-type",
"-Werror=format-extra-args",
"-Wshadow",
],
LIBPATH=["#rednose/examples/generated"],
CFLAGS="-std=gnu11",
CXXFLAGS="-std=c++1z",
CPPPATH=cpppath,
REDNOSE_ROOT=Dir("#").abspath,
tools=["default", "cython", "rednose_filter"],
)
# Cython build enviroment
envCython = env.Clone()
envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-cpp", "-Wno-shadow", "-Wno-deprecated-declarations"]
envCython["LIBS"] = []
if arch == "Darwin":
envCython["LINKFLAGS"] = ["-bundle", "-undefined", "dynamic_lookup"]
elif arch == "aarch64":
envCython["LINKFLAGS"] = ["-shared"]
envCython["LIBS"] = [os.path.basename(python_path)]
else:
envCython["LINKFLAGS"] = ["-pthread", "-shared"]
Export('env', 'envCython', 'common')
SConscript(['#rednose/SConscript'])
SConscript(['#examples/SConscript'])
+19
View File
@@ -0,0 +1,19 @@
Import('env')
gen_dir = Dir('generated/').abspath
env.RednoseCompileFilter(
target="live",
filter_gen_script="live_kf.py",
output_dir=gen_dir,
)
env.RednoseCompileFilter(
target="kinematic",
filter_gen_script="kinematic_kf.py",
output_dir=gen_dir,
)
env.RednoseCompileFilter(
target="compare",
filter_gen_script="test_compare.py",
output_dir=gen_dir,
)
+17
View File
@@ -0,0 +1,17 @@
Import('env', 'envCython', 'common')
cc_sources = [
"helpers/ekf_load.cc",
"helpers/ekf_sym.cc",
]
libs = ["dl"]
if common != "":
# for SWAGLOG support
libs += [common, 'zmq']
ekf_objects = env.SharedObject(cc_sources)
rednose = env.Library("helpers/ekf_sym", ekf_objects, LIBS=libs)
rednose_python = envCython.Program("helpers/ekf_sym_pyx.so", ["helpers/ekf_sym_pyx.pyx", ekf_objects],
LIBS=libs + envCython["LIBS"])
Export('rednose', 'rednose_python')
+3 -3
View File
@@ -26351,7 +26351,7 @@ __Pyx_RefNannySetupContext("PyInit_ekf_sym_pyx", 0);
(void)__Pyx_modinit_variable_import_code(__pyx_mstate);
(void)__Pyx_modinit_function_import_code(__pyx_mstate);
/*--- Execution code ---*/
__Pyx_TraceStartFunc("PyInit_ekf_sym_pyx", __pyx_f[0], 1, 0, 0, 0, __PYX_ERR(0, 1, __pyx_L1_error));
__Pyx_TraceStartFunc("PyInit_ekf_sym_pyx", __pyx_f[0], 1, 1, 0, 0, __PYX_ERR(0, 1, __pyx_L1_error));
/* "View.MemoryView":100
*
@@ -27145,7 +27145,7 @@ __Pyx_RefNannySetupContext("PyInit_ekf_sym_pyx", 0);
__Pyx_GOTREF(__pyx_t_5);
if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_5) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
__Pyx_TraceReturnValue(Py_None, 0, 0, __PYX_ERR(0, 1, __pyx_L1_error));
__Pyx_TraceReturnValue(Py_None, 1, 0, __PYX_ERR(0, 1, __pyx_L1_error));
__Pyx_PyMonitoring_ExitScope(0);
/*--- Wrapped vars code ---*/
@@ -27156,7 +27156,7 @@ __Pyx_RefNannySetupContext("PyInit_ekf_sym_pyx", 0);
__Pyx_XDECREF(__pyx_t_5);
__Pyx_XDECREF(__pyx_t_6);
__Pyx_TraceException(__pyx_lineno, 0, 0);
__Pyx_TraceExceptionUnwind(0, 0);
__Pyx_TraceExceptionUnwind(1, 0);
if (__pyx_m) {
if (__pyx_mstate->__pyx_d && stringtab_initialized) {
__Pyx_AddTraceback("init rednose.helpers.ekf_sym_pyx", __pyx_clineno, __pyx_lineno, __pyx_filename);
+1 -1
View File
@@ -90,7 +90,7 @@ def _process_font(font_path: Path, codepoints: tuple[int, ...]):
print(f"Processing {font_path.name}...")
font_size = {
"unifont.otf": 16, # unifont is only 16x8 or 16x16 pixels per glyph
"unifont.otf": 64, # unifont is only 16x8 or 16x16 pixels per glyph
}.get(font_path.name, 200)
data = font_path.read_bytes()
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.
@@ -0,0 +1,97 @@
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'np_version')
gen = "c_generated_code"
casadi_model = [
f'{gen}/lat_model/lat_expl_ode_fun.c',
f'{gen}/lat_model/lat_expl_vde_forw.c',
]
casadi_cost_y = [
f'{gen}/lat_cost/lat_cost_y_fun.c',
f'{gen}/lat_cost/lat_cost_y_fun_jac_ut_xt.c',
f'{gen}/lat_cost/lat_cost_y_hess.c',
]
casadi_cost_e = [
f'{gen}/lat_cost/lat_cost_y_e_fun.c',
f'{gen}/lat_cost/lat_cost_y_e_fun_jac_ut_xt.c',
f'{gen}/lat_cost/lat_cost_y_e_hess.c',
]
casadi_cost_0 = [
f'{gen}/lat_cost/lat_cost_y_0_fun.c',
f'{gen}/lat_cost/lat_cost_y_0_fun_jac_ut_xt.c',
f'{gen}/lat_cost/lat_cost_y_0_hess.c',
]
build_files = [f'{gen}/acados_solver_lat.c'] + casadi_model + casadi_cost_y + casadi_cost_e + casadi_cost_0
# extra generated files used to trigger a rebuild
generated_files = [
f'{gen}/Makefile',
f'{gen}/main_lat.c',
f'{gen}/main_sim_lat.c',
f'{gen}/acados_solver_lat.h',
f'{gen}/acados_sim_solver_lat.h',
f'{gen}/acados_sim_solver_lat.c',
f'{gen}/acados_solver.pxd',
f'{gen}/lat_model/lat_expl_vde_adj.c',
f'{gen}/lat_model/lat_model.h',
f'{gen}/lat_constraints/lat_constraints.h',
f'{gen}/lat_cost/lat_cost.h',
] + build_files
acados_dir = '#third_party/acados'
acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera'
source_list = ['lat_mpc.py',
'#selfdrive/modeld/constants.py',
f'{acados_dir}/include/acados_c/ocp_nlp_interface.h',
f'{acados_templates_dir}/acados_solver.in.c',
]
lenv = env.Clone()
acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib"))
lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')]
lenv.Clean(generated_files, Dir(gen))
generated_lat = lenv.Command(generated_files,
source_list,
f"cd {Dir('.').abspath} && python3 lat_mpc.py")
lenv.Depends(generated_lat, [msgq_python, common_python])
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CCFLAGS"].append("-Wno-unused")
if arch != "Darwin":
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
else:
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_lat.dylib")
lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}")
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_lat",
build_files,
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
# generate cython stuff
acados_ocp_solver_pyx = File("#third_party/acados/acados_template/acados_ocp_solver_pyx.pyx")
acados_ocp_solver_common = File("#third_party/acados/acados_template/acados_solver_common.pxd")
libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd')
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
lenv2 = envCython.Clone()
lenv2["LIBPATH"] += [lib_solver[0].dir.abspath]
lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')]
lenv2.Command(libacados_ocp_solver_c,
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
f'cython' + \
f' -o {libacados_ocp_solver_c.get_labspath()}' + \
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
f' {acados_ocp_solver_pyx.get_labspath()}')
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_lat'])
lenv2.Depends(lib_cython, lib_solver)
lenv2.Depends(libacados_ocp_solver_c, np_version)
@@ -0,0 +1,102 @@
Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'np_version')
gen = "c_generated_code"
casadi_model = [
f'{gen}/long_model/long_expl_ode_fun.c',
f'{gen}/long_model/long_expl_vde_forw.c',
]
casadi_cost_y = [
f'{gen}/long_cost/long_cost_y_fun.c',
f'{gen}/long_cost/long_cost_y_fun_jac_ut_xt.c',
f'{gen}/long_cost/long_cost_y_hess.c',
]
casadi_cost_e = [
f'{gen}/long_cost/long_cost_y_e_fun.c',
f'{gen}/long_cost/long_cost_y_e_fun_jac_ut_xt.c',
f'{gen}/long_cost/long_cost_y_e_hess.c',
]
casadi_cost_0 = [
f'{gen}/long_cost/long_cost_y_0_fun.c',
f'{gen}/long_cost/long_cost_y_0_fun_jac_ut_xt.c',
f'{gen}/long_cost/long_cost_y_0_hess.c',
]
casadi_constraints = [
f'{gen}/long_constraints/long_constr_h_fun.c',
f'{gen}/long_constraints/long_constr_h_fun_jac_uxt_zt.c',
]
build_files = [f'{gen}/acados_solver_long.c'] + casadi_model + casadi_cost_y + casadi_cost_e + \
casadi_cost_0 + casadi_constraints
# extra generated files used to trigger a rebuild
generated_files = [
f'{gen}/Makefile',
f'{gen}/main_long.c',
f'{gen}/main_sim_long.c',
f'{gen}/acados_solver_long.h',
f'{gen}/acados_sim_solver_long.h',
f'{gen}/acados_sim_solver_long.c',
f'{gen}/acados_solver.pxd',
f'{gen}/long_model/long_expl_vde_adj.c',
f'{gen}/long_model/long_model.h',
f'{gen}/long_constraints/long_constraints.h',
f'{gen}/long_cost/long_cost.h',
] + build_files
acados_dir = '#third_party/acados'
acados_templates_dir = '#third_party/acados/acados_template/c_templates_tera'
source_list = ['long_mpc.py',
'#selfdrive/modeld/constants.py',
f'{acados_dir}/include/acados_c/ocp_nlp_interface.h',
f'{acados_templates_dir}/acados_solver.in.c',
]
lenv = env.Clone()
acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib"))
lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')]
lenv.Clean(generated_files, Dir(gen))
generated_long = lenv.Command(generated_files,
source_list,
f"cd {Dir('.').abspath} && python3 long_mpc.py")
lenv.Depends(generated_long, [msgq_python, common_python])
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES")
lenv["CCFLAGS"].append("-Wno-unused")
if arch != "Darwin":
lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags")
else:
lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_long.dylib")
lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}")
lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long",
build_files,
LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e'])
# generate cython stuff
acados_ocp_solver_pyx = File("#third_party/acados/acados_template/acados_ocp_solver_pyx.pyx")
acados_ocp_solver_common = File("#third_party/acados/acados_template/acados_solver_common.pxd")
libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd')
libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c')
lenv2 = envCython.Clone()
lenv2["LIBPATH"] += [lib_solver[0].dir.abspath]
lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')]
lenv2.Command(libacados_ocp_solver_c,
[acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd],
f'cython' + \
f' -o {libacados_ocp_solver_c.get_labspath()}' + \
f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \
f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \
f' {acados_ocp_solver_pyx.get_labspath()}')
lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_long'])
lenv2.Depends(lib_cython, lib_solver)
lenv2.Depends(libacados_ocp_solver_c, np_version)
+21
View File
@@ -0,0 +1,21 @@
Import('env', 'rednose')
# build ekf models
rednose_gen_dir = 'models/generated'
rednose_gen_deps = [
"models/constants.py",
]
pose_ekf = env.RednoseCompileFilter(
target='pose',
filter_gen_script='models/pose_kf.py',
output_dir=rednose_gen_dir,
extra_gen_artifacts=[],
gen_script_deps=rednose_gen_deps,
)
car_ekf = env.RednoseCompileFilter(
target='car',
filter_gen_script='models/car_kf.py',
output_dir=rednose_gen_dir,
extra_gen_artifacts=[],
gen_script_deps=rednose_gen_deps,
)
+342 -342
View File
@@ -45,326 +45,326 @@ const static double MAHA_THRESH_31 = 3.8414588206941227;
* *
* This file is part of 'ekf' *
******************************************************************************/
void err_fun(double *nom_x, double *delta_x, double *out_2367152293466283987) {
out_2367152293466283987[0] = delta_x[0] + nom_x[0];
out_2367152293466283987[1] = delta_x[1] + nom_x[1];
out_2367152293466283987[2] = delta_x[2] + nom_x[2];
out_2367152293466283987[3] = delta_x[3] + nom_x[3];
out_2367152293466283987[4] = delta_x[4] + nom_x[4];
out_2367152293466283987[5] = delta_x[5] + nom_x[5];
out_2367152293466283987[6] = delta_x[6] + nom_x[6];
out_2367152293466283987[7] = delta_x[7] + nom_x[7];
out_2367152293466283987[8] = delta_x[8] + nom_x[8];
void err_fun(double *nom_x, double *delta_x, double *out_5479217515808027394) {
out_5479217515808027394[0] = delta_x[0] + nom_x[0];
out_5479217515808027394[1] = delta_x[1] + nom_x[1];
out_5479217515808027394[2] = delta_x[2] + nom_x[2];
out_5479217515808027394[3] = delta_x[3] + nom_x[3];
out_5479217515808027394[4] = delta_x[4] + nom_x[4];
out_5479217515808027394[5] = delta_x[5] + nom_x[5];
out_5479217515808027394[6] = delta_x[6] + nom_x[6];
out_5479217515808027394[7] = delta_x[7] + nom_x[7];
out_5479217515808027394[8] = delta_x[8] + nom_x[8];
}
void inv_err_fun(double *nom_x, double *true_x, double *out_5829526074669369656) {
out_5829526074669369656[0] = -nom_x[0] + true_x[0];
out_5829526074669369656[1] = -nom_x[1] + true_x[1];
out_5829526074669369656[2] = -nom_x[2] + true_x[2];
out_5829526074669369656[3] = -nom_x[3] + true_x[3];
out_5829526074669369656[4] = -nom_x[4] + true_x[4];
out_5829526074669369656[5] = -nom_x[5] + true_x[5];
out_5829526074669369656[6] = -nom_x[6] + true_x[6];
out_5829526074669369656[7] = -nom_x[7] + true_x[7];
out_5829526074669369656[8] = -nom_x[8] + true_x[8];
void inv_err_fun(double *nom_x, double *true_x, double *out_8100295571519039240) {
out_8100295571519039240[0] = -nom_x[0] + true_x[0];
out_8100295571519039240[1] = -nom_x[1] + true_x[1];
out_8100295571519039240[2] = -nom_x[2] + true_x[2];
out_8100295571519039240[3] = -nom_x[3] + true_x[3];
out_8100295571519039240[4] = -nom_x[4] + true_x[4];
out_8100295571519039240[5] = -nom_x[5] + true_x[5];
out_8100295571519039240[6] = -nom_x[6] + true_x[6];
out_8100295571519039240[7] = -nom_x[7] + true_x[7];
out_8100295571519039240[8] = -nom_x[8] + true_x[8];
}
void H_mod_fun(double *state, double *out_1755007343641557895) {
out_1755007343641557895[0] = 1.0;
out_1755007343641557895[1] = 0.0;
out_1755007343641557895[2] = 0.0;
out_1755007343641557895[3] = 0.0;
out_1755007343641557895[4] = 0.0;
out_1755007343641557895[5] = 0.0;
out_1755007343641557895[6] = 0.0;
out_1755007343641557895[7] = 0.0;
out_1755007343641557895[8] = 0.0;
out_1755007343641557895[9] = 0.0;
out_1755007343641557895[10] = 1.0;
out_1755007343641557895[11] = 0.0;
out_1755007343641557895[12] = 0.0;
out_1755007343641557895[13] = 0.0;
out_1755007343641557895[14] = 0.0;
out_1755007343641557895[15] = 0.0;
out_1755007343641557895[16] = 0.0;
out_1755007343641557895[17] = 0.0;
out_1755007343641557895[18] = 0.0;
out_1755007343641557895[19] = 0.0;
out_1755007343641557895[20] = 1.0;
out_1755007343641557895[21] = 0.0;
out_1755007343641557895[22] = 0.0;
out_1755007343641557895[23] = 0.0;
out_1755007343641557895[24] = 0.0;
out_1755007343641557895[25] = 0.0;
out_1755007343641557895[26] = 0.0;
out_1755007343641557895[27] = 0.0;
out_1755007343641557895[28] = 0.0;
out_1755007343641557895[29] = 0.0;
out_1755007343641557895[30] = 1.0;
out_1755007343641557895[31] = 0.0;
out_1755007343641557895[32] = 0.0;
out_1755007343641557895[33] = 0.0;
out_1755007343641557895[34] = 0.0;
out_1755007343641557895[35] = 0.0;
out_1755007343641557895[36] = 0.0;
out_1755007343641557895[37] = 0.0;
out_1755007343641557895[38] = 0.0;
out_1755007343641557895[39] = 0.0;
out_1755007343641557895[40] = 1.0;
out_1755007343641557895[41] = 0.0;
out_1755007343641557895[42] = 0.0;
out_1755007343641557895[43] = 0.0;
out_1755007343641557895[44] = 0.0;
out_1755007343641557895[45] = 0.0;
out_1755007343641557895[46] = 0.0;
out_1755007343641557895[47] = 0.0;
out_1755007343641557895[48] = 0.0;
out_1755007343641557895[49] = 0.0;
out_1755007343641557895[50] = 1.0;
out_1755007343641557895[51] = 0.0;
out_1755007343641557895[52] = 0.0;
out_1755007343641557895[53] = 0.0;
out_1755007343641557895[54] = 0.0;
out_1755007343641557895[55] = 0.0;
out_1755007343641557895[56] = 0.0;
out_1755007343641557895[57] = 0.0;
out_1755007343641557895[58] = 0.0;
out_1755007343641557895[59] = 0.0;
out_1755007343641557895[60] = 1.0;
out_1755007343641557895[61] = 0.0;
out_1755007343641557895[62] = 0.0;
out_1755007343641557895[63] = 0.0;
out_1755007343641557895[64] = 0.0;
out_1755007343641557895[65] = 0.0;
out_1755007343641557895[66] = 0.0;
out_1755007343641557895[67] = 0.0;
out_1755007343641557895[68] = 0.0;
out_1755007343641557895[69] = 0.0;
out_1755007343641557895[70] = 1.0;
out_1755007343641557895[71] = 0.0;
out_1755007343641557895[72] = 0.0;
out_1755007343641557895[73] = 0.0;
out_1755007343641557895[74] = 0.0;
out_1755007343641557895[75] = 0.0;
out_1755007343641557895[76] = 0.0;
out_1755007343641557895[77] = 0.0;
out_1755007343641557895[78] = 0.0;
out_1755007343641557895[79] = 0.0;
out_1755007343641557895[80] = 1.0;
void H_mod_fun(double *state, double *out_7285069632640746526) {
out_7285069632640746526[0] = 1.0;
out_7285069632640746526[1] = 0.0;
out_7285069632640746526[2] = 0.0;
out_7285069632640746526[3] = 0.0;
out_7285069632640746526[4] = 0.0;
out_7285069632640746526[5] = 0.0;
out_7285069632640746526[6] = 0.0;
out_7285069632640746526[7] = 0.0;
out_7285069632640746526[8] = 0.0;
out_7285069632640746526[9] = 0.0;
out_7285069632640746526[10] = 1.0;
out_7285069632640746526[11] = 0.0;
out_7285069632640746526[12] = 0.0;
out_7285069632640746526[13] = 0.0;
out_7285069632640746526[14] = 0.0;
out_7285069632640746526[15] = 0.0;
out_7285069632640746526[16] = 0.0;
out_7285069632640746526[17] = 0.0;
out_7285069632640746526[18] = 0.0;
out_7285069632640746526[19] = 0.0;
out_7285069632640746526[20] = 1.0;
out_7285069632640746526[21] = 0.0;
out_7285069632640746526[22] = 0.0;
out_7285069632640746526[23] = 0.0;
out_7285069632640746526[24] = 0.0;
out_7285069632640746526[25] = 0.0;
out_7285069632640746526[26] = 0.0;
out_7285069632640746526[27] = 0.0;
out_7285069632640746526[28] = 0.0;
out_7285069632640746526[29] = 0.0;
out_7285069632640746526[30] = 1.0;
out_7285069632640746526[31] = 0.0;
out_7285069632640746526[32] = 0.0;
out_7285069632640746526[33] = 0.0;
out_7285069632640746526[34] = 0.0;
out_7285069632640746526[35] = 0.0;
out_7285069632640746526[36] = 0.0;
out_7285069632640746526[37] = 0.0;
out_7285069632640746526[38] = 0.0;
out_7285069632640746526[39] = 0.0;
out_7285069632640746526[40] = 1.0;
out_7285069632640746526[41] = 0.0;
out_7285069632640746526[42] = 0.0;
out_7285069632640746526[43] = 0.0;
out_7285069632640746526[44] = 0.0;
out_7285069632640746526[45] = 0.0;
out_7285069632640746526[46] = 0.0;
out_7285069632640746526[47] = 0.0;
out_7285069632640746526[48] = 0.0;
out_7285069632640746526[49] = 0.0;
out_7285069632640746526[50] = 1.0;
out_7285069632640746526[51] = 0.0;
out_7285069632640746526[52] = 0.0;
out_7285069632640746526[53] = 0.0;
out_7285069632640746526[54] = 0.0;
out_7285069632640746526[55] = 0.0;
out_7285069632640746526[56] = 0.0;
out_7285069632640746526[57] = 0.0;
out_7285069632640746526[58] = 0.0;
out_7285069632640746526[59] = 0.0;
out_7285069632640746526[60] = 1.0;
out_7285069632640746526[61] = 0.0;
out_7285069632640746526[62] = 0.0;
out_7285069632640746526[63] = 0.0;
out_7285069632640746526[64] = 0.0;
out_7285069632640746526[65] = 0.0;
out_7285069632640746526[66] = 0.0;
out_7285069632640746526[67] = 0.0;
out_7285069632640746526[68] = 0.0;
out_7285069632640746526[69] = 0.0;
out_7285069632640746526[70] = 1.0;
out_7285069632640746526[71] = 0.0;
out_7285069632640746526[72] = 0.0;
out_7285069632640746526[73] = 0.0;
out_7285069632640746526[74] = 0.0;
out_7285069632640746526[75] = 0.0;
out_7285069632640746526[76] = 0.0;
out_7285069632640746526[77] = 0.0;
out_7285069632640746526[78] = 0.0;
out_7285069632640746526[79] = 0.0;
out_7285069632640746526[80] = 1.0;
}
void f_fun(double *state, double dt, double *out_8527162516255122736) {
out_8527162516255122736[0] = state[0];
out_8527162516255122736[1] = state[1];
out_8527162516255122736[2] = state[2];
out_8527162516255122736[3] = state[3];
out_8527162516255122736[4] = state[4];
out_8527162516255122736[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
out_8527162516255122736[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
out_8527162516255122736[7] = state[7];
out_8527162516255122736[8] = state[8];
void f_fun(double *state, double dt, double *out_9063134164133415607) {
out_9063134164133415607[0] = state[0];
out_9063134164133415607[1] = state[1];
out_9063134164133415607[2] = state[2];
out_9063134164133415607[3] = state[3];
out_9063134164133415607[4] = state[4];
out_9063134164133415607[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
out_9063134164133415607[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
out_9063134164133415607[7] = state[7];
out_9063134164133415607[8] = state[8];
}
void F_fun(double *state, double dt, double *out_7094558340758265304) {
out_7094558340758265304[0] = 1;
out_7094558340758265304[1] = 0;
out_7094558340758265304[2] = 0;
out_7094558340758265304[3] = 0;
out_7094558340758265304[4] = 0;
out_7094558340758265304[5] = 0;
out_7094558340758265304[6] = 0;
out_7094558340758265304[7] = 0;
out_7094558340758265304[8] = 0;
out_7094558340758265304[9] = 0;
out_7094558340758265304[10] = 1;
out_7094558340758265304[11] = 0;
out_7094558340758265304[12] = 0;
out_7094558340758265304[13] = 0;
out_7094558340758265304[14] = 0;
out_7094558340758265304[15] = 0;
out_7094558340758265304[16] = 0;
out_7094558340758265304[17] = 0;
out_7094558340758265304[18] = 0;
out_7094558340758265304[19] = 0;
out_7094558340758265304[20] = 1;
out_7094558340758265304[21] = 0;
out_7094558340758265304[22] = 0;
out_7094558340758265304[23] = 0;
out_7094558340758265304[24] = 0;
out_7094558340758265304[25] = 0;
out_7094558340758265304[26] = 0;
out_7094558340758265304[27] = 0;
out_7094558340758265304[28] = 0;
out_7094558340758265304[29] = 0;
out_7094558340758265304[30] = 1;
out_7094558340758265304[31] = 0;
out_7094558340758265304[32] = 0;
out_7094558340758265304[33] = 0;
out_7094558340758265304[34] = 0;
out_7094558340758265304[35] = 0;
out_7094558340758265304[36] = 0;
out_7094558340758265304[37] = 0;
out_7094558340758265304[38] = 0;
out_7094558340758265304[39] = 0;
out_7094558340758265304[40] = 1;
out_7094558340758265304[41] = 0;
out_7094558340758265304[42] = 0;
out_7094558340758265304[43] = 0;
out_7094558340758265304[44] = 0;
out_7094558340758265304[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
out_7094558340758265304[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
out_7094558340758265304[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_7094558340758265304[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_7094558340758265304[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
out_7094558340758265304[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
out_7094558340758265304[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
out_7094558340758265304[52] = dt*stiffness_front*state[0]/(mass*state[1]);
out_7094558340758265304[53] = -9.8100000000000005*dt;
out_7094558340758265304[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
out_7094558340758265304[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
out_7094558340758265304[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_7094558340758265304[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_7094558340758265304[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
out_7094558340758265304[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
out_7094558340758265304[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
out_7094558340758265304[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_7094558340758265304[62] = 0;
out_7094558340758265304[63] = 0;
out_7094558340758265304[64] = 0;
out_7094558340758265304[65] = 0;
out_7094558340758265304[66] = 0;
out_7094558340758265304[67] = 0;
out_7094558340758265304[68] = 0;
out_7094558340758265304[69] = 0;
out_7094558340758265304[70] = 1;
out_7094558340758265304[71] = 0;
out_7094558340758265304[72] = 0;
out_7094558340758265304[73] = 0;
out_7094558340758265304[74] = 0;
out_7094558340758265304[75] = 0;
out_7094558340758265304[76] = 0;
out_7094558340758265304[77] = 0;
out_7094558340758265304[78] = 0;
out_7094558340758265304[79] = 0;
out_7094558340758265304[80] = 1;
void F_fun(double *state, double dt, double *out_6894033823067301907) {
out_6894033823067301907[0] = 1;
out_6894033823067301907[1] = 0;
out_6894033823067301907[2] = 0;
out_6894033823067301907[3] = 0;
out_6894033823067301907[4] = 0;
out_6894033823067301907[5] = 0;
out_6894033823067301907[6] = 0;
out_6894033823067301907[7] = 0;
out_6894033823067301907[8] = 0;
out_6894033823067301907[9] = 0;
out_6894033823067301907[10] = 1;
out_6894033823067301907[11] = 0;
out_6894033823067301907[12] = 0;
out_6894033823067301907[13] = 0;
out_6894033823067301907[14] = 0;
out_6894033823067301907[15] = 0;
out_6894033823067301907[16] = 0;
out_6894033823067301907[17] = 0;
out_6894033823067301907[18] = 0;
out_6894033823067301907[19] = 0;
out_6894033823067301907[20] = 1;
out_6894033823067301907[21] = 0;
out_6894033823067301907[22] = 0;
out_6894033823067301907[23] = 0;
out_6894033823067301907[24] = 0;
out_6894033823067301907[25] = 0;
out_6894033823067301907[26] = 0;
out_6894033823067301907[27] = 0;
out_6894033823067301907[28] = 0;
out_6894033823067301907[29] = 0;
out_6894033823067301907[30] = 1;
out_6894033823067301907[31] = 0;
out_6894033823067301907[32] = 0;
out_6894033823067301907[33] = 0;
out_6894033823067301907[34] = 0;
out_6894033823067301907[35] = 0;
out_6894033823067301907[36] = 0;
out_6894033823067301907[37] = 0;
out_6894033823067301907[38] = 0;
out_6894033823067301907[39] = 0;
out_6894033823067301907[40] = 1;
out_6894033823067301907[41] = 0;
out_6894033823067301907[42] = 0;
out_6894033823067301907[43] = 0;
out_6894033823067301907[44] = 0;
out_6894033823067301907[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
out_6894033823067301907[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
out_6894033823067301907[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_6894033823067301907[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_6894033823067301907[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
out_6894033823067301907[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
out_6894033823067301907[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
out_6894033823067301907[52] = dt*stiffness_front*state[0]/(mass*state[1]);
out_6894033823067301907[53] = -9.8100000000000005*dt;
out_6894033823067301907[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
out_6894033823067301907[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
out_6894033823067301907[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_6894033823067301907[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_6894033823067301907[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
out_6894033823067301907[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
out_6894033823067301907[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
out_6894033823067301907[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_6894033823067301907[62] = 0;
out_6894033823067301907[63] = 0;
out_6894033823067301907[64] = 0;
out_6894033823067301907[65] = 0;
out_6894033823067301907[66] = 0;
out_6894033823067301907[67] = 0;
out_6894033823067301907[68] = 0;
out_6894033823067301907[69] = 0;
out_6894033823067301907[70] = 1;
out_6894033823067301907[71] = 0;
out_6894033823067301907[72] = 0;
out_6894033823067301907[73] = 0;
out_6894033823067301907[74] = 0;
out_6894033823067301907[75] = 0;
out_6894033823067301907[76] = 0;
out_6894033823067301907[77] = 0;
out_6894033823067301907[78] = 0;
out_6894033823067301907[79] = 0;
out_6894033823067301907[80] = 1;
}
void h_25(double *state, double *unused, double *out_6286236977752489740) {
out_6286236977752489740[0] = state[6];
void h_25(double *state, double *unused, double *out_5814763937768226620) {
out_5814763937768226620[0] = state[6];
}
void H_25(double *state, double *unused, double *out_4084839440865213267) {
out_4084839440865213267[0] = 0;
out_4084839440865213267[1] = 0;
out_4084839440865213267[2] = 0;
out_4084839440865213267[3] = 0;
out_4084839440865213267[4] = 0;
out_4084839440865213267[5] = 0;
out_4084839440865213267[6] = 1;
out_4084839440865213267[7] = 0;
out_4084839440865213267[8] = 0;
void H_25(double *state, double *unused, double *out_6257982615884140250) {
out_6257982615884140250[0] = 0;
out_6257982615884140250[1] = 0;
out_6257982615884140250[2] = 0;
out_6257982615884140250[3] = 0;
out_6257982615884140250[4] = 0;
out_6257982615884140250[5] = 0;
out_6257982615884140250[6] = 1;
out_6257982615884140250[7] = 0;
out_6257982615884140250[8] = 0;
}
void h_24(double *state, double *unused, double *out_6918439556027581256) {
out_6918439556027581256[0] = state[4];
out_6918439556027581256[1] = state[5];
void h_24(double *state, double *unused, double *out_8584440790186238681) {
out_8584440790186238681[0] = state[4];
out_8584440790186238681[1] = state[5];
}
void H_24(double *state, double *unused, double *out_4929836049648908666) {
out_4929836049648908666[0] = 0;
out_4929836049648908666[1] = 0;
out_4929836049648908666[2] = 0;
out_4929836049648908666[3] = 0;
out_4929836049648908666[4] = 1;
out_4929836049648908666[5] = 0;
out_4929836049648908666[6] = 0;
out_4929836049648908666[7] = 0;
out_4929836049648908666[8] = 0;
out_4929836049648908666[9] = 0;
out_4929836049648908666[10] = 0;
out_4929836049648908666[11] = 0;
out_4929836049648908666[12] = 0;
out_4929836049648908666[13] = 0;
out_4929836049648908666[14] = 1;
out_4929836049648908666[15] = 0;
out_4929836049648908666[16] = 0;
out_4929836049648908666[17] = 0;
void H_24(double *state, double *unused, double *out_6654627920237999745) {
out_6654627920237999745[0] = 0;
out_6654627920237999745[1] = 0;
out_6654627920237999745[2] = 0;
out_6654627920237999745[3] = 0;
out_6654627920237999745[4] = 1;
out_6654627920237999745[5] = 0;
out_6654627920237999745[6] = 0;
out_6654627920237999745[7] = 0;
out_6654627920237999745[8] = 0;
out_6654627920237999745[9] = 0;
out_6654627920237999745[10] = 0;
out_6654627920237999745[11] = 0;
out_6654627920237999745[12] = 0;
out_6654627920237999745[13] = 0;
out_6654627920237999745[14] = 1;
out_6654627920237999745[15] = 0;
out_6654627920237999745[16] = 0;
out_6654627920237999745[17] = 0;
}
void h_30(double *state, double *unused, double *out_6443423646103618885) {
out_6443423646103618885[0] = state[4];
void h_30(double *state, double *unused, double *out_8994530607687302646) {
out_8994530607687302646[0] = state[4];
}
void H_30(double *state, double *unused, double *out_6603172399372461894) {
out_6603172399372461894[0] = 0;
out_6603172399372461894[1] = 0;
out_6603172399372461894[2] = 0;
out_6603172399372461894[3] = 0;
out_6603172399372461894[4] = 1;
out_6603172399372461894[5] = 0;
out_6603172399372461894[6] = 0;
out_6603172399372461894[7] = 0;
out_6603172399372461894[8] = 0;
void H_30(double *state, double *unused, double *out_3739649657376891623) {
out_3739649657376891623[0] = 0;
out_3739649657376891623[1] = 0;
out_3739649657376891623[2] = 0;
out_3739649657376891623[3] = 0;
out_3739649657376891623[4] = 1;
out_3739649657376891623[5] = 0;
out_3739649657376891623[6] = 0;
out_3739649657376891623[7] = 0;
out_3739649657376891623[8] = 0;
}
void h_26(double *state, double *unused, double *out_7270973478954575704) {
out_7270973478954575704[0] = state[7];
void h_26(double *state, double *unused, double *out_3809483594941292135) {
out_3809483594941292135[0] = state[7];
}
void H_26(double *state, double *unused, double *out_343336121991157043) {
out_343336121991157043[0] = 0;
out_343336121991157043[1] = 0;
out_343336121991157043[2] = 0;
out_343336121991157043[3] = 0;
out_343336121991157043[4] = 0;
out_343336121991157043[5] = 0;
out_343336121991157043[6] = 0;
out_343336121991157043[7] = 1;
out_343336121991157043[8] = 0;
void H_26(double *state, double *unused, double *out_2953456646123339649) {
out_2953456646123339649[0] = 0;
out_2953456646123339649[1] = 0;
out_2953456646123339649[2] = 0;
out_2953456646123339649[3] = 0;
out_2953456646123339649[4] = 0;
out_2953456646123339649[5] = 0;
out_2953456646123339649[6] = 0;
out_2953456646123339649[7] = 1;
out_2953456646123339649[8] = 0;
}
void h_27(double *state, double *unused, double *out_9123721044512729191) {
out_9123721044512729191[0] = state[3];
void h_27(double *state, double *unused, double *out_2777977886323893935) {
out_2777977886323893935[0] = state[3];
}
void H_27(double *state, double *unused, double *out_8826766470556405111) {
out_8826766470556405111[0] = 0;
out_8826766470556405111[1] = 0;
out_8826766470556405111[2] = 0;
out_8826766470556405111[3] = 1;
out_8826766470556405111[4] = 0;
out_8826766470556405111[5] = 0;
out_8826766470556405111[6] = 0;
out_8826766470556405111[7] = 0;
out_8826766470556405111[8] = 0;
void H_27(double *state, double *unused, double *out_1516055586192948406) {
out_1516055586192948406[0] = 0;
out_1516055586192948406[1] = 0;
out_1516055586192948406[2] = 0;
out_1516055586192948406[3] = 1;
out_1516055586192948406[4] = 0;
out_1516055586192948406[5] = 0;
out_1516055586192948406[6] = 0;
out_1516055586192948406[7] = 0;
out_1516055586192948406[8] = 0;
}
void h_29(double *state, double *unused, double *out_2352885818162378255) {
out_2352885818162378255[0] = state[1];
void h_29(double *state, double *unused, double *out_3992857340026457001) {
out_3992857340026457001[0] = state[1];
}
void H_29(double *state, double *unused, double *out_7113403743686854078) {
out_7113403743686854078[0] = 0;
out_7113403743686854078[1] = 1;
out_7113403743686854078[2] = 0;
out_7113403743686854078[3] = 0;
out_7113403743686854078[4] = 0;
out_7113403743686854078[5] = 0;
out_7113403743686854078[6] = 0;
out_7113403743686854078[7] = 0;
out_7113403743686854078[8] = 0;
void H_29(double *state, double *unused, double *out_3229418313062499439) {
out_3229418313062499439[0] = 0;
out_3229418313062499439[1] = 1;
out_3229418313062499439[2] = 0;
out_3229418313062499439[3] = 0;
out_3229418313062499439[4] = 0;
out_3229418313062499439[5] = 0;
out_3229418313062499439[6] = 0;
out_3229418313062499439[7] = 0;
out_3229418313062499439[8] = 0;
}
void h_28(double *state, double *unused, double *out_8180211191611066756) {
out_8180211191611066756[0] = state[0];
void h_28(double *state, double *unused, double *out_1087530051588212975) {
out_1087530051588212975[0] = state[0];
}
void H_28(double *state, double *unused, double *out_2031004726617323504) {
out_2031004726617323504[0] = 1;
out_2031004726617323504[1] = 0;
out_2031004726617323504[2] = 0;
out_2031004726617323504[3] = 0;
out_2031004726617323504[4] = 0;
out_2031004726617323504[5] = 0;
out_2031004726617323504[6] = 0;
out_2031004726617323504[7] = 0;
out_2031004726617323504[8] = 0;
void H_28(double *state, double *unused, double *out_8311817330132030013) {
out_8311817330132030013[0] = 1;
out_8311817330132030013[1] = 0;
out_8311817330132030013[2] = 0;
out_8311817330132030013[3] = 0;
out_8311817330132030013[4] = 0;
out_8311817330132030013[5] = 0;
out_8311817330132030013[6] = 0;
out_8311817330132030013[7] = 0;
out_8311817330132030013[8] = 0;
}
void h_31(double *state, double *unused, double *out_5572679169480766713) {
out_5572679169480766713[0] = state[8];
void h_31(double *state, double *unused, double *out_5539569875483720731) {
out_5539569875483720731[0] = state[8];
}
void H_31(double *state, double *unused, double *out_282871980242194433) {
out_282871980242194433[0] = 0;
out_282871980242194433[1] = 0;
out_282871980242194433[2] = 0;
out_282871980242194433[3] = 0;
out_282871980242194433[4] = 0;
out_282871980242194433[5] = 0;
out_282871980242194433[6] = 0;
out_282871980242194433[7] = 0;
out_282871980242194433[8] = 1;
void H_31(double *state, double *unused, double *out_818692634627677003) {
out_818692634627677003[0] = 0;
out_818692634627677003[1] = 0;
out_818692634627677003[2] = 0;
out_818692634627677003[3] = 0;
out_818692634627677003[4] = 0;
out_818692634627677003[5] = 0;
out_818692634627677003[6] = 0;
out_818692634627677003[7] = 0;
out_818692634627677003[8] = 1;
}
#include <eigen3/Eigen/Dense>
#include <iostream>
@@ -518,68 +518,68 @@ void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) {
update<1, 3, 0>(in_x, in_P, h_31, H_31, NULL, in_z, in_R, in_ea, MAHA_THRESH_31);
}
void car_err_fun(double *nom_x, double *delta_x, double *out_2367152293466283987) {
err_fun(nom_x, delta_x, out_2367152293466283987);
void car_err_fun(double *nom_x, double *delta_x, double *out_5479217515808027394) {
err_fun(nom_x, delta_x, out_5479217515808027394);
}
void car_inv_err_fun(double *nom_x, double *true_x, double *out_5829526074669369656) {
inv_err_fun(nom_x, true_x, out_5829526074669369656);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_8100295571519039240) {
inv_err_fun(nom_x, true_x, out_8100295571519039240);
}
void car_H_mod_fun(double *state, double *out_1755007343641557895) {
H_mod_fun(state, out_1755007343641557895);
void car_H_mod_fun(double *state, double *out_7285069632640746526) {
H_mod_fun(state, out_7285069632640746526);
}
void car_f_fun(double *state, double dt, double *out_8527162516255122736) {
f_fun(state, dt, out_8527162516255122736);
void car_f_fun(double *state, double dt, double *out_9063134164133415607) {
f_fun(state, dt, out_9063134164133415607);
}
void car_F_fun(double *state, double dt, double *out_7094558340758265304) {
F_fun(state, dt, out_7094558340758265304);
void car_F_fun(double *state, double dt, double *out_6894033823067301907) {
F_fun(state, dt, out_6894033823067301907);
}
void car_h_25(double *state, double *unused, double *out_6286236977752489740) {
h_25(state, unused, out_6286236977752489740);
void car_h_25(double *state, double *unused, double *out_5814763937768226620) {
h_25(state, unused, out_5814763937768226620);
}
void car_H_25(double *state, double *unused, double *out_4084839440865213267) {
H_25(state, unused, out_4084839440865213267);
void car_H_25(double *state, double *unused, double *out_6257982615884140250) {
H_25(state, unused, out_6257982615884140250);
}
void car_h_24(double *state, double *unused, double *out_6918439556027581256) {
h_24(state, unused, out_6918439556027581256);
void car_h_24(double *state, double *unused, double *out_8584440790186238681) {
h_24(state, unused, out_8584440790186238681);
}
void car_H_24(double *state, double *unused, double *out_4929836049648908666) {
H_24(state, unused, out_4929836049648908666);
void car_H_24(double *state, double *unused, double *out_6654627920237999745) {
H_24(state, unused, out_6654627920237999745);
}
void car_h_30(double *state, double *unused, double *out_6443423646103618885) {
h_30(state, unused, out_6443423646103618885);
void car_h_30(double *state, double *unused, double *out_8994530607687302646) {
h_30(state, unused, out_8994530607687302646);
}
void car_H_30(double *state, double *unused, double *out_6603172399372461894) {
H_30(state, unused, out_6603172399372461894);
void car_H_30(double *state, double *unused, double *out_3739649657376891623) {
H_30(state, unused, out_3739649657376891623);
}
void car_h_26(double *state, double *unused, double *out_7270973478954575704) {
h_26(state, unused, out_7270973478954575704);
void car_h_26(double *state, double *unused, double *out_3809483594941292135) {
h_26(state, unused, out_3809483594941292135);
}
void car_H_26(double *state, double *unused, double *out_343336121991157043) {
H_26(state, unused, out_343336121991157043);
void car_H_26(double *state, double *unused, double *out_2953456646123339649) {
H_26(state, unused, out_2953456646123339649);
}
void car_h_27(double *state, double *unused, double *out_9123721044512729191) {
h_27(state, unused, out_9123721044512729191);
void car_h_27(double *state, double *unused, double *out_2777977886323893935) {
h_27(state, unused, out_2777977886323893935);
}
void car_H_27(double *state, double *unused, double *out_8826766470556405111) {
H_27(state, unused, out_8826766470556405111);
void car_H_27(double *state, double *unused, double *out_1516055586192948406) {
H_27(state, unused, out_1516055586192948406);
}
void car_h_29(double *state, double *unused, double *out_2352885818162378255) {
h_29(state, unused, out_2352885818162378255);
void car_h_29(double *state, double *unused, double *out_3992857340026457001) {
h_29(state, unused, out_3992857340026457001);
}
void car_H_29(double *state, double *unused, double *out_7113403743686854078) {
H_29(state, unused, out_7113403743686854078);
void car_H_29(double *state, double *unused, double *out_3229418313062499439) {
H_29(state, unused, out_3229418313062499439);
}
void car_h_28(double *state, double *unused, double *out_8180211191611066756) {
h_28(state, unused, out_8180211191611066756);
void car_h_28(double *state, double *unused, double *out_1087530051588212975) {
h_28(state, unused, out_1087530051588212975);
}
void car_H_28(double *state, double *unused, double *out_2031004726617323504) {
H_28(state, unused, out_2031004726617323504);
void car_H_28(double *state, double *unused, double *out_8311817330132030013) {
H_28(state, unused, out_8311817330132030013);
}
void car_h_31(double *state, double *unused, double *out_5572679169480766713) {
h_31(state, unused, out_5572679169480766713);
void car_h_31(double *state, double *unused, double *out_5539569875483720731) {
h_31(state, unused, out_5539569875483720731);
}
void car_H_31(double *state, double *unused, double *out_282871980242194433) {
H_31(state, unused, out_282871980242194433);
void car_H_31(double *state, double *unused, double *out_818692634627677003) {
H_31(state, unused, out_818692634627677003);
}
void car_predict(double *in_x, double *in_P, double *in_Q, double dt) {
predict(in_x, in_P, in_Q, dt);
+21 -21
View File
@@ -9,27 +9,27 @@ void car_update_27(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void car_update_29(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_err_fun(double *nom_x, double *delta_x, double *out_2367152293466283987);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_5829526074669369656);
void car_H_mod_fun(double *state, double *out_1755007343641557895);
void car_f_fun(double *state, double dt, double *out_8527162516255122736);
void car_F_fun(double *state, double dt, double *out_7094558340758265304);
void car_h_25(double *state, double *unused, double *out_6286236977752489740);
void car_H_25(double *state, double *unused, double *out_4084839440865213267);
void car_h_24(double *state, double *unused, double *out_6918439556027581256);
void car_H_24(double *state, double *unused, double *out_4929836049648908666);
void car_h_30(double *state, double *unused, double *out_6443423646103618885);
void car_H_30(double *state, double *unused, double *out_6603172399372461894);
void car_h_26(double *state, double *unused, double *out_7270973478954575704);
void car_H_26(double *state, double *unused, double *out_343336121991157043);
void car_h_27(double *state, double *unused, double *out_9123721044512729191);
void car_H_27(double *state, double *unused, double *out_8826766470556405111);
void car_h_29(double *state, double *unused, double *out_2352885818162378255);
void car_H_29(double *state, double *unused, double *out_7113403743686854078);
void car_h_28(double *state, double *unused, double *out_8180211191611066756);
void car_H_28(double *state, double *unused, double *out_2031004726617323504);
void car_h_31(double *state, double *unused, double *out_5572679169480766713);
void car_H_31(double *state, double *unused, double *out_282871980242194433);
void car_err_fun(double *nom_x, double *delta_x, double *out_5479217515808027394);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_8100295571519039240);
void car_H_mod_fun(double *state, double *out_7285069632640746526);
void car_f_fun(double *state, double dt, double *out_9063134164133415607);
void car_F_fun(double *state, double dt, double *out_6894033823067301907);
void car_h_25(double *state, double *unused, double *out_5814763937768226620);
void car_H_25(double *state, double *unused, double *out_6257982615884140250);
void car_h_24(double *state, double *unused, double *out_8584440790186238681);
void car_H_24(double *state, double *unused, double *out_6654627920237999745);
void car_h_30(double *state, double *unused, double *out_8994530607687302646);
void car_H_30(double *state, double *unused, double *out_3739649657376891623);
void car_h_26(double *state, double *unused, double *out_3809483594941292135);
void car_H_26(double *state, double *unused, double *out_2953456646123339649);
void car_h_27(double *state, double *unused, double *out_2777977886323893935);
void car_H_27(double *state, double *unused, double *out_1516055586192948406);
void car_h_29(double *state, double *unused, double *out_3992857340026457001);
void car_H_29(double *state, double *unused, double *out_3229418313062499439);
void car_h_28(double *state, double *unused, double *out_1087530051588212975);
void car_H_28(double *state, double *unused, double *out_8311817330132030013);
void car_h_31(double *state, double *unused, double *out_5539569875483720731);
void car_H_31(double *state, double *unused, double *out_818692634627677003);
void car_predict(double *in_x, double *in_P, double *in_Q, double dt);
void car_set_mass(double x);
void car_set_rotational_inertia(double x);
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -5,18 +5,18 @@ void pose_update_4(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void pose_update_10(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_err_fun(double *nom_x, double *delta_x, double *out_228345055687174559);
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_3726714603593551859);
void pose_H_mod_fun(double *state, double *out_6712772131857650620);
void pose_f_fun(double *state, double dt, double *out_2706993655191654809);
void pose_F_fun(double *state, double dt, double *out_372841931129064371);
void pose_h_4(double *state, double *unused, double *out_3997723666308670841);
void pose_H_4(double *state, double *unused, double *out_4134113474779579353);
void pose_h_10(double *state, double *unused, double *out_6627456117207891484);
void pose_H_10(double *state, double *unused, double *out_1462818273599549569);
void pose_h_13(double *state, double *unused, double *out_2824244578095522440);
void pose_H_13(double *state, double *unused, double *out_921839649447246552);
void pose_h_14(double *state, double *unused, double *out_696698419016090920);
void pose_H_14(double *state, double *unused, double *out_7216901907074951649);
void pose_err_fun(double *nom_x, double *delta_x, double *out_2580540694739946519);
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_5357096832042119822);
void pose_H_mod_fun(double *state, double *out_7228847589067930749);
void pose_f_fun(double *state, double dt, double *out_8526672508847459198);
void pose_F_fun(double *state, double dt, double *out_4769745432950749149);
void pose_h_4(double *state, double *unused, double *out_6566956173213773055);
void pose_H_4(double *state, double *unused, double *out_2076329204028850014);
void pose_h_10(double *state, double *unused, double *out_6519103870371093687);
void pose_H_10(double *state, double *unused, double *out_1454480582190579456);
void pose_h_13(double *state, double *unused, double *out_8545332083251637040);
void pose_H_13(double *state, double *unused, double *out_1135944621303482787);
void pose_h_14(double *state, double *unused, double *out_529654494281334242);
void pose_H_14(double *state, double *unused, double *out_2511445730673733613);
void pose_predict(double *in_x, double *in_P, double *in_Q, double dt);
}
+88
View File
@@ -0,0 +1,88 @@
import glob
import json
import os
from SCons.Script import Value
from openpilot.common.file_chunker import chunk_file, get_chunk_paths
from tinygrad import Device
Import('env', 'arch')
chunker_file = File("#common/file_chunker.py")
lenv = env.Clone()
tinygrad_root = env.Dir("#").abspath
tinygrad_files = ["#"+x for x in glob.glob(env.Dir("#tinygrad_repo").relpath + "/**", recursive=True, root_dir=tinygrad_root)
if 'pycache' not in x and os.path.isfile(os.path.join(tinygrad_root, x))]
def estimate_pickle_max_size(onnx_size):
return 1.2 * onnx_size + 10 * 1024 * 1024 # 20% + 10MB is plenty
# THREADS=0 is need to prevent bug: https://github.com/tinygrad/tinygrad/issues/14689
# get fastest TG config
available = set(Device.get_available_devices())
# FIXME-SP: reset when we bump tg
if False: # 'CUDA' in available:
tg_backend = 'CUDA'
tg_flags = f'DEV={tg_backend}'
elif 'QCOM' in available:
tg_backend = 'QCOM'
tg_flags = f'DEV={tg_backend} FLOAT16=1 NOLOCALS=1 JIT_BATCH_SIZE=0'
else:
tg_backend = 'CPU' if arch == 'Darwin' else 'CPU CPU_LLVM=1' # FIXME-SP: reset when we bump tg
tg_flags = f'DEV={tg_backend} THREADS=0'
def write_tg_compiled_flags(target, source, env):
with open(str(target[0]), "w") as f:
json.dump({"DEV": tg_backend}, f)
f.write("\n")
compiled_flags_node = lenv.Command(
File("models/tg_compiled_flags.json").abspath,
tinygrad_files + [Value(tg_backend)],
write_tg_compiled_flags,
)
# tinygrad calls brew which needs a $HOME in the env
mac_brew_string = f'HOME={os.path.expanduser("~")}' if arch == 'Darwin' else ''
# Get model metadata
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
fn = File(f"models/{model_name}").abspath
script_files = [File(Dir("#selfdrive/modeld").File("get_model_metadata.py").abspath)]
cmd = f'{tg_flags} {mac_brew_string} python3 {Dir("#selfdrive/modeld").abspath}/get_model_metadata.py {fn}.onnx'
lenv.Command(fn + "_metadata.pkl", [fn + ".onnx"] + tinygrad_files + script_files + [compiled_flags_node], cmd)
image_flag = {
'larch64': 'IMAGE=2',
}.get(arch, 'IMAGE=0')
script_files = [File(Dir("#selfdrive/modeld").File("compile_warp.py").abspath)]
compile_warp_cmd = f'{tg_flags} {mac_brew_string} python3 {Dir("#selfdrive/modeld").abspath}/compile_warp.py '
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
warp_targets = []
for cam in [_ar_ox_fisheye, _os_fisheye]:
w, h = cam.width, cam.height
warp_targets += [File(f"models/warp_{w}x{h}_tinygrad.pkl").abspath, File(f"models/dm_warp_{w}x{h}_tinygrad.pkl").abspath]
lenv.Command(warp_targets, tinygrad_files + script_files + [compiled_flags_node], compile_warp_cmd)
def tg_compile(flags, model_name):
pythonpath_string = 'PYTHONPATH="${PYTHONPATH}:' + env.Dir("#tinygrad_repo").abspath + '"'
fn = File(f"models/{model_name}").abspath
pkl = fn + "_tinygrad.pkl"
onnx_path = fn + ".onnx"
chunk_targets = get_chunk_paths(pkl, estimate_pickle_max_size(os.path.getsize(onnx_path)))
compile_node = lenv.Command(
pkl,
[onnx_path] + tinygrad_files + [chunker_file, compiled_flags_node],
f'{pythonpath_string} {flags} {image_flag} python3 {Dir("#tinygrad_repo").abspath}/examples/openpilot/compile3.py {fn}.onnx {pkl}',
)
def do_chunk(target, source, env):
chunk_file(pkl, chunk_targets)
return lenv.Command(
chunk_targets,
compile_node,
do_chunk,
)
# Compile small models
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
tg_compile(tg_flags, model_name)
@@ -1 +0,0 @@
driving_policy.onnx
@@ -1 +0,0 @@
driving_vision.onnx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
Import('env', 'arch', 'common', 'messaging')
if arch != "Darwin":
libs = [common, messaging, 'pthread']
panda = env.Library('panda', ['panda.cc', 'spi.cc'])
env.Program('pandad', ['main.cc', 'pandad.cc', 'panda_safety.cc'], LIBS=[panda] + libs)
if GetOption('extras'):
env.Program('tests/test_pandad_canprotocol', ['tests/test_pandad_canprotocol.cc'], LIBS=[panda] + libs)
+201 -201
View File
@@ -73,25 +73,25 @@ def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM
if "REPLAY" in os.environ:
branch = "replay"
return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt)
return StartupAlert("警告:此分支未经测试", branch, alert_status=AlertStatus.userPrompt)
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
return NoEntryAlert(f"车速超过 {get_display_speed(CP.minEnableSpeed, metric)} 才可开启")
def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return Alert(
f"Steer Assist Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
f"转向辅助在 {get_display_speed(CP.minSteerSpeed, metric)} 以下不可用",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
first_word = 'Recalibrating' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else 'Calibrating'
first_word = '重新标定中' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else '标定中'
return Alert(
f"{first_word}: {sm['liveCalibration'].calPerc:.0f}%",
f"Drive Above {get_display_speed(MIN_SPEED_FILTER, metric)}",
f"{first_word}{sm['liveCalibration'].calPerc:.0f}%",
f"车速超过 {get_display_speed(MIN_SPEED_FILTER, metric)} 即可",
AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
@@ -99,8 +99,8 @@ def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messag
def audio_feedback_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
duration = FEEDBACK_MAX_DURATION - ((sm['audioFeedback'].blockNum + 1) * SAMPLE_BUFFER / SAMPLE_RATE)
return NormalPermanentAlert(
"Recording Audio Feedback",
f"{round(duration)} second{'s' if round(duration) != 1 else ''} remaining. Press again to save early.",
"正在录制语音反馈",
f"剩余 {round(duration)} 秒,再次按下可提前保存。",
priority=Priority.LOW)
@@ -108,57 +108,57 @@ def audio_feedback_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM
def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
full_perc = round(100. - sm['deviceState'].freeSpacePercent)
return NormalPermanentAlert("Out of Storage", f"{full_perc}% full")
return NormalPermanentAlert("存储空间不足", f"已用 {full_perc}%")
def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
mdl = sm['modelV2'].velocity.x[0] if len(sm['modelV2'].velocity.x) else math.nan
err = CS.vEgo - mdl
msg = f"Speed Error: {err:.1f} m/s"
return NoEntryAlert(msg, alert_text_1="Posenet Speed Invalid")
msg = f"速度误差:{err:.1f} m/s"
return NoEntryAlert(msg, alert_text_1="Posenet 速度无效")
def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning]
msg = ', '.join(not_running)
return NoEntryAlert(msg, alert_text_1="Process Not Running")
return NoEntryAlert(msg, alert_text_1="进程未运行")
def comm_issue_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
bs = [s for s in sm.data.keys() if not sm.all_checks([s, ])]
msg = ', '.join(bs[:4]) # can't fit too many on one line
return NoEntryAlert(msg, alert_text_1="Communication Issue Between Processes")
return NoEntryAlert(msg, alert_text_1="进程间通信异常")
def camera_malfunction_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
all_cams = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
bad_cams = [s.replace('State', '') for s in all_cams if s in sm.data.keys() and not sm.all_checks([s, ])]
return NormalPermanentAlert("Camera Malfunction", ', '.join(bad_cams))
return NormalPermanentAlert("摄像头故障", ''.join(bad_cams))
def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
rpy = sm['liveCalibration'].rpyCalib
yaw = math.degrees(rpy[2] if len(rpy) == 3 else math.nan)
pitch = math.degrees(rpy[1] if len(rpy) == 3 else math.nan)
angles = f"Remount Device (Pitch: {pitch:.1f}°, Yaw: {yaw:.1f}°)"
return NormalPermanentAlert("Calibration Invalid", angles)
angles = f"重新安装设备(俯仰:{pitch:.1f}°,偏航:{yaw:.1f}°"
return NormalPermanentAlert("标定无效", angles)
def paramsd_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
if not sm['liveParameters'].angleOffsetValid:
angle_offset_deg = sm['liveParameters'].angleOffsetDeg
title = "Steering misalignment detected"
text = f"Angle offset too high (Offset: {angle_offset_deg:.1f}°)"
title = "检测到转向偏移"
text = f"角度偏移过大(偏移:{angle_offset_deg:.1f}°"
elif not sm['liveParameters'].steerRatioValid:
steer_ratio = sm['liveParameters'].steerRatio
title = "Steer ratio mismatch"
text = f"Steering rack geometry may be off (Ratio: {steer_ratio:.1f})"
title = "转向比不匹配"
text = f"转向几何可能存在问题(比例:{steer_ratio:.1f}"
elif not sm['liveParameters'].stiffnessFactorValid:
stiffness_factor = sm['liveParameters'].stiffnessFactor
title = "Abnormal tire stiffness"
text = f"Check tires, pressure, or alignment (Factor: {stiffness_factor:.1f})"
title = "轮胎刚度异常"
text = f"检查轮胎、胎压或定位(系数:{stiffness_factor:.1f}"
else:
return NoEntryAlert("paramsd Temporary Error")
return NoEntryAlert("paramsd 临时错误")
return NoEntryAlert(alert_text_1=title, alert_text_2=text)
@@ -166,27 +166,27 @@ def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster,
cpu = max(sm['deviceState'].cpuTempC, default=0.)
gpu = max(sm['deviceState'].gpuTempC, default=0.)
temp = max((cpu, gpu, sm['deviceState'].memoryTempC))
return NormalPermanentAlert("System Overheated", f"{temp:.0f} °C")
return NormalPermanentAlert("系统过热", f"{temp:.0f} °C")
def low_memory_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NormalPermanentAlert("Low Memory", f"{sm['deviceState'].memoryUsagePercent}% used")
return NormalPermanentAlert("内存不足", f"已用 {sm['deviceState'].memoryUsagePercent}%")
def high_cpu_usage_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
x = max(sm['deviceState'].cpuUsagePercent, default=0.)
return NormalPermanentAlert("High CPU Usage", f"{x}% used")
return NormalPermanentAlert("CPU 负载过高", f"已用 {x}%")
def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NormalPermanentAlert("Driving Model Lagging", f"{sm['modelV2'].frameDropPerc:.1f}% frames dropped")
return NormalPermanentAlert("驾驶模型延迟", f"丢帧 {sm['modelV2'].frameDropPerc:.1f}%")
def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
gb = sm['carControl'].actuators.accel / 4.
steer = sm['carControl'].actuators.torque
vals = f"Gas: {round(gb * 100.)}%, Steer: {round(steer * 100.)}%"
return NormalPermanentAlert("Joystick Mode", vals)
vals = f"油门:{round(gb * 100.)}%,转向:{round(steer * 100.)}%"
return NormalPermanentAlert("摇杆模式", vals)
def longitudinal_maneuver_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
@@ -201,18 +201,18 @@ def longitudinal_maneuver_alert(CP: car.CarParams, CS: car.CarState, sm: messagi
def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
personality = str(personality).title()
return NormalPermanentAlert(f"Driving Personality: {personality}", duration=1.5)
return NormalPermanentAlert(f"驾驶风格:{personality}", duration=1.5)
def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
text = "Toggle stock LKAS on or off to engage"
text = "切换原车 LKAS 开关后即可开启"
if CP.brand == "tesla":
text = "Switch to Traffic-Aware Cruise Control to engage"
text = "切换到交通感知巡航控制后即可开启"
elif CP.brand == "mazda":
text = "Enable your car's LKAS to engage"
text = "开启车辆原车 LKAS 后即可开启"
elif CP.brand == "nissan":
text = "Disable your car's stock LKAS to engage"
return NormalPermanentAlert("Invalid LKAS setting", text)
text = "关闭原车 LKAS 后即可开启"
return NormalPermanentAlert("LKAS 设置无效", text)
@@ -226,26 +226,26 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.joystickDebug: {
ET.WARNING: joystick_alert,
ET.PERMANENT: NormalPermanentAlert("Joystick Mode"),
ET.PERMANENT: NormalPermanentAlert("摇杆模式"),
},
EventName.longitudinalManeuver: {
ET.WARNING: longitudinal_maneuver_alert,
ET.PERMANENT: NormalPermanentAlert("Longitudinal Maneuver Mode",
"Ensure road ahead is clear"),
ET.PERMANENT: NormalPermanentAlert("纵向操纵模式",
"确保前方道路空旷"),
},
EventName.lateralManeuver: {
ET.WARNING: longitudinal_maneuver_alert,
ET.PERMANENT: NormalPermanentAlert("Lateral Maneuver Mode"),
ET.PERMANENT: NormalPermanentAlert("横向操纵模式"),
},
EventName.selfdriveInitializing: {
ET.NO_ENTRY: NoEntryAlert("System Initializing"),
ET.NO_ENTRY: NoEntryAlert("系统初始化中"),
},
EventName.startup: {
ET.PERMANENT: StartupAlert("Be ready to take over at any time")
ET.PERMANENT: StartupAlert("随时准备接管")
},
EventName.startupMaster: {
@@ -253,28 +253,28 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
},
EventName.startupNoControl: {
ET.PERMANENT: StartupAlert("Dashcam mode"),
ET.NO_ENTRY: NoEntryAlert("Dashcam mode"),
ET.PERMANENT: StartupAlert("行车记录仪模式"),
ET.NO_ENTRY: NoEntryAlert("行车记录仪模式"),
},
EventName.startupNoCar: {
ET.PERMANENT: StartupAlert("Dashcam mode for unsupported car"),
ET.PERMANENT: StartupAlert("不支持的车型,进入行车记录仪模式"),
},
EventName.startupNoSecOcKey: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
"Security Key Not Available",
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
"安全密钥不可用",
priority=Priority.HIGH),
},
EventName.dashcamMode: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
priority=Priority.LOWEST),
},
EventName.invalidLkasSetting: {
ET.PERMANENT: invalid_lkas_setting_alert,
ET.NO_ENTRY: NoEntryAlert("Invalid LKAS setting"),
ET.NO_ENTRY: NoEntryAlert("LKAS 设置无效"),
},
EventName.cruiseMismatch: {
@@ -285,44 +285,44 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# read-only mode. This can be solved by adding your fingerprint.
# See https://github.com/commaai/openpilot/wiki/Fingerprinting for more information
EventName.carUnrecognized: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
"Car Unrecognized",
ET.PERMANENT: NormalPermanentAlert("行车记录仪模式",
"车型未识别",
priority=Priority.LOWEST),
},
EventName.aeb: {
ET.PERMANENT: Alert(
"BRAKE!",
"Emergency Braking: Risk of Collision",
"刹车!",
"紧急刹车:碰撞风险",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
ET.NO_ENTRY: NoEntryAlert("AEB: Risk of Collision"),
ET.NO_ENTRY: NoEntryAlert("AEB:碰撞风险"),
},
EventName.stockAeb: {
ET.PERMANENT: Alert(
"BRAKE!",
"Stock AEB: Risk of Collision",
"刹车!",
"原车 AEB:碰撞风险",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
ET.NO_ENTRY: NoEntryAlert("Stock AEB: Risk of Collision"),
ET.NO_ENTRY: NoEntryAlert("原车 AEB:碰撞风险"),
},
EventName.stockLkas: {
ET.NO_ENTRY: NoEntryAlert("Stock LKAS: Lane Departure Detected"),
ET.NO_ENTRY: NoEntryAlert("原车 LKAS:检测到车道偏离"),
},
EventName.fcw: {
ET.PERMANENT: Alert(
"BRAKE!",
"Risk of Collision",
"刹车!",
"碰撞风险",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
},
EventName.ldw: {
ET.PERMANENT: Alert(
"Lane Departure Detected",
"检测到车道偏离",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
@@ -332,7 +332,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.steerTempUnavailableSilent: {
ET.WARNING: Alert(
"Steering Assist Temporarily Unavailable",
"转向辅助暂时不可用",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.8),
@@ -340,7 +340,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.driverDistracted1: {
ET.PERMANENT: Alert(
"Pay Attention",
"请注意路况",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
@@ -348,23 +348,23 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.driverDistracted2: {
ET.PERMANENT: Alert(
"Pay Attention",
"Driver Distracted",
"请注意路况",
"驾驶分心",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverDistracted3: {
ET.PERMANENT: Alert(
"DISENGAGE IMMEDIATELY",
"Driver Distracted",
"立即退出",
"驾驶分心",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.driverUnresponsive1: {
ET.PERMANENT: Alert(
"Touch Steering Wheel: No Face Detected",
"请握住方向盘:未检测到面部",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1),
@@ -372,31 +372,31 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.driverUnresponsive2: {
ET.PERMANENT: Alert(
"Touch Steering Wheel",
"Driver Unresponsive",
"请握住方向盘",
"驾驶员无响应",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverUnresponsive3: {
ET.PERMANENT: Alert(
"DISENGAGE IMMEDIATELY",
"Driver Unresponsive",
"立即退出",
"驾驶员无响应",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.manualRestart: {
ET.WARNING: Alert(
"TAKE CONTROL",
"Resume Driving Manually",
"请接管",
"请手动恢复驾驶",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.resumeRequired: {
ET.WARNING: Alert(
"Press Resume to Exit Standstill",
" Resume 退出静止状态",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
@@ -408,7 +408,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.preLaneChangeLeft: {
ET.WARNING: Alert(
"Steer Left to Start Lane Change Once Safe",
"确认安全后左转方向盘开始变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
@@ -416,7 +416,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
"Steer Right to Start Lane Change Once Safe",
"确认安全后右转方向盘开始变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
@@ -424,7 +424,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
"Car Detected in Blindspot",
"盲区检测到车辆",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
@@ -432,7 +432,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.laneChange: {
ET.WARNING: Alert(
"Changing Lanes",
"正在变道",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
@@ -440,41 +440,41 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.steerSaturated: {
ET.WARNING: Alert(
"Take Control",
"Turn Exceeds Steering Limit",
"请接管",
"转向达到极限",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 2.),
},
# Thrown when the fan is driven at >50% but is not rotating
EventName.fanMalfunction: {
ET.PERMANENT: NormalPermanentAlert("Fan Malfunction", "Likely Hardware Issue"),
ET.PERMANENT: NormalPermanentAlert("风扇故障", "可能为硬件问题"),
},
# Camera is not outputting frames
EventName.cameraMalfunction: {
ET.PERMANENT: camera_malfunction_alert,
ET.SOFT_DISABLE: soft_disable_alert("Camera Malfunction"),
ET.NO_ENTRY: NoEntryAlert("Camera Malfunction: Reboot Your Device"),
ET.SOFT_DISABLE: soft_disable_alert("摄像头故障"),
ET.NO_ENTRY: NoEntryAlert("摄像头故障:请重启设备"),
},
# Camera framerate too low
EventName.cameraFrameRate: {
ET.PERMANENT: NormalPermanentAlert("Camera Frame Rate Low", "Reboot your Device"),
ET.SOFT_DISABLE: soft_disable_alert("Camera Frame Rate Low"),
ET.NO_ENTRY: NoEntryAlert("Camera Frame Rate Low: Reboot Your Device"),
ET.PERMANENT: NormalPermanentAlert("摄像头帧率过低", "请重启设备"),
ET.SOFT_DISABLE: soft_disable_alert("摄像头帧率过低"),
ET.NO_ENTRY: NoEntryAlert("摄像头帧率过低:请重启设备"),
},
# Unused
EventName.locationdTemporaryError: {
ET.NO_ENTRY: NoEntryAlert("locationd Temporary Error"),
ET.SOFT_DISABLE: soft_disable_alert("locationd Temporary Error"),
ET.NO_ENTRY: NoEntryAlert("locationd 临时错误"),
ET.SOFT_DISABLE: soft_disable_alert("locationd 临时错误"),
},
EventName.locationdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("locationd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("locationd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("locationd Permanent Error"),
ET.NO_ENTRY: NoEntryAlert("locationd 永久错误"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("locationd 永久错误"),
ET.PERMANENT: NormalPermanentAlert("locationd 永久错误"),
},
# openpilot tries to learn certain parameters about your car by observing
@@ -487,13 +487,13 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
EventName.paramsdTemporaryError: {
ET.NO_ENTRY: paramsd_invalid_alert,
ET.SOFT_DISABLE: soft_disable_alert("paramsd Temporary Error"),
ET.SOFT_DISABLE: soft_disable_alert("paramsd 临时错误"),
},
EventName.paramsdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("paramsd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("paramsd Permanent Error"),
ET.NO_ENTRY: NoEntryAlert("paramsd 永久错误"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd 永久错误"),
ET.PERMANENT: NormalPermanentAlert("paramsd 永久错误"),
},
# ********** events that affect controls state transitions **********
@@ -512,12 +512,12 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.buttonCancel: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Cancel Pressed"),
ET.NO_ENTRY: NoEntryAlert("已按下取消"),
},
EventName.brakeHold: {
ET.WARNING: Alert(
"Press Resume to Exit Brake Hold",
" Resume 退出刹车保持",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
@@ -525,23 +525,23 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.parkBrake: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
ET.NO_ENTRY: NoEntryAlert("手刹已拉起"),
},
EventName.pedalPressed: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Pedal Pressed",
ET.NO_ENTRY: NoEntryAlert("已踩下踏板",
visual_alert=VisualAlert.brakePressed),
},
EventName.steerDisengage: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Steering Pressed"),
ET.NO_ENTRY: NoEntryAlert("已转动方向盘"),
},
EventName.preEnableStandstill: {
ET.PRE_ENABLE: Alert(
"Release Brake to Engage",
"松开刹车以开启",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, creation_delay=1.),
@@ -569,27 +569,27 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
},
EventName.resumeBlocked: {
ET.NO_ENTRY: NoEntryAlert("Press Set to Engage"),
ET.NO_ENTRY: NoEntryAlert("按 Set 以开启"),
},
EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Adaptive Cruise Disabled"),
ET.NO_ENTRY: NoEntryAlert("自适应巡航已禁用"),
},
EventName.steerTempUnavailable: {
ET.SOFT_DISABLE: soft_disable_alert("Steering Assist Temporarily Unavailable"),
ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable"),
ET.SOFT_DISABLE: soft_disable_alert("转向辅助暂时不可用"),
ET.NO_ENTRY: NoEntryAlert("转向暂时不可用"),
},
EventName.steerTimeLimit: {
ET.SOFT_DISABLE: soft_disable_alert("Vehicle Steering Time Limit"),
ET.NO_ENTRY: NoEntryAlert("Vehicle Steering Time Limit"),
ET.SOFT_DISABLE: soft_disable_alert("车辆转向时间限制"),
ET.NO_ENTRY: NoEntryAlert("车辆转向时间限制"),
},
EventName.outOfSpace: {
ET.PERMANENT: out_of_space_alert,
ET.NO_ENTRY: NoEntryAlert("Out of Storage"),
ET.NO_ENTRY: NoEntryAlert("存储空间不足"),
},
EventName.belowEngageSpeed: {
@@ -598,35 +598,35 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.sensorDataInvalid: {
ET.PERMANENT: Alert(
"Sensor Data Invalid",
"Possible Hardware Issue",
"传感器数据无效",
"可能为硬件问题",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("Sensor Data Invalid"),
ET.SOFT_DISABLE: soft_disable_alert("Sensor Data Invalid"),
ET.NO_ENTRY: NoEntryAlert("传感器数据无效"),
ET.SOFT_DISABLE: soft_disable_alert("传感器数据无效"),
},
EventName.noGps: {
},
EventName.tooDistracted: {
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
ET.NO_ENTRY: NoEntryAlert("分心程度过高"),
},
EventName.excessiveActuation: {
ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"),
ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"),
ET.SOFT_DISABLE: soft_disable_alert("执行器过度动作"),
ET.NO_ENTRY: NoEntryAlert("执行器过度动作"),
},
EventName.overheat: {
ET.PERMANENT: overheat_alert,
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),
ET.NO_ENTRY: NoEntryAlert("System Overheated"),
ET.SOFT_DISABLE: soft_disable_alert("系统过热"),
ET.NO_ENTRY: NoEntryAlert("系统过热"),
},
EventName.wrongGear: {
ET.SOFT_DISABLE: user_soft_disable_alert("Gear not D"),
ET.NO_ENTRY: NoEntryAlert("Gear not D"),
ET.SOFT_DISABLE: user_soft_disable_alert("不在 D 档"),
ET.NO_ENTRY: NoEntryAlert("不在 D 档"),
},
# This alert is thrown when the calibration angles are outside of the acceptable range.
@@ -636,40 +636,40 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# See https://comma.ai/setup for more information
EventName.calibrationInvalid: {
ET.PERMANENT: calibration_invalid_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Invalid: Remount Device & Recalibrate"),
ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Remount Device & Recalibrate"),
ET.SOFT_DISABLE: soft_disable_alert("标定无效:重新安装设备并重新标定"),
ET.NO_ENTRY: NoEntryAlert("标定无效:重新安装设备并重新标定"),
},
EventName.calibrationIncomplete: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"),
ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"),
ET.SOFT_DISABLE: soft_disable_alert("标定未完成"),
ET.NO_ENTRY: NoEntryAlert("标定进行中"),
},
EventName.calibrationRecalibrating: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Device Remount Detected: Recalibrating"),
ET.NO_ENTRY: NoEntryAlert("Remount Detected: Recalibrating"),
ET.SOFT_DISABLE: soft_disable_alert("检测到设备重装:正在重新标定"),
ET.NO_ENTRY: NoEntryAlert("检测到重装:正在重新标定"),
},
EventName.doorOpen: {
ET.SOFT_DISABLE: user_soft_disable_alert("Door Open"),
ET.NO_ENTRY: NoEntryAlert("Door Open"),
ET.SOFT_DISABLE: user_soft_disable_alert("车门打开"),
ET.NO_ENTRY: NoEntryAlert("车门打开"),
},
EventName.seatbeltNotLatched: {
ET.SOFT_DISABLE: user_soft_disable_alert("Seatbelt Unlatched"),
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
ET.SOFT_DISABLE: user_soft_disable_alert("安全带未系"),
ET.NO_ENTRY: NoEntryAlert("安全带未系"),
},
EventName.espDisabled: {
ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Disabled"),
ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Disabled"),
ET.SOFT_DISABLE: soft_disable_alert("车身稳定系统已关闭"),
ET.NO_ENTRY: NoEntryAlert("车身稳定系统已关闭"),
},
EventName.lowBattery: {
ET.SOFT_DISABLE: soft_disable_alert("Low Battery"),
ET.NO_ENTRY: NoEntryAlert("Low Battery"),
ET.SOFT_DISABLE: soft_disable_alert("电池电量低"),
ET.NO_ENTRY: NoEntryAlert("电池电量低"),
},
# Different openpilot services communicate between each other at a certain
@@ -677,41 +677,41 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# is thrown. This can mean a service crashed, did not broadcast a message for
# ten times the regular interval, or the average interval is more than 10% too high.
EventName.commIssue: {
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue Between Processes"),
ET.SOFT_DISABLE: soft_disable_alert("进程间通信异常"),
ET.NO_ENTRY: comm_issue_alert,
},
EventName.commIssueAvgFreq: {
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate Between Processes"),
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate Between Processes"),
ET.SOFT_DISABLE: soft_disable_alert("进程间通信频率过低"),
ET.NO_ENTRY: NoEntryAlert("进程间通信频率过低"),
},
EventName.selfdrivedLagging: {
ET.SOFT_DISABLE: soft_disable_alert("System Lagging"),
ET.NO_ENTRY: NoEntryAlert("Selfdrive Process Lagging: Reboot Your Device"),
ET.SOFT_DISABLE: soft_disable_alert("系统延迟"),
ET.NO_ENTRY: NoEntryAlert("Selfdrive 进程延迟:请重启设备"),
},
# Thrown when manager detects a service exited unexpectedly while driving
EventName.processNotRunning: {
ET.NO_ENTRY: process_not_running_alert,
ET.SOFT_DISABLE: soft_disable_alert("Process Not Running"),
ET.SOFT_DISABLE: soft_disable_alert("进程未运行"),
},
EventName.radarFault: {
ET.SOFT_DISABLE: soft_disable_alert("Radar Error: Restart the Car"),
ET.NO_ENTRY: NoEntryAlert("Radar Error: Restart the Car"),
ET.SOFT_DISABLE: soft_disable_alert("雷达错误:请重启车辆"),
ET.NO_ENTRY: NoEntryAlert("雷达错误:请重启车辆"),
},
EventName.radarTempUnavailable: {
ET.SOFT_DISABLE: soft_disable_alert("Radar Temporarily Unavailable"),
ET.NO_ENTRY: NoEntryAlert("Radar Temporarily Unavailable"),
ET.SOFT_DISABLE: soft_disable_alert("雷达暂时不可用"),
ET.NO_ENTRY: NoEntryAlert("雷达暂时不可用"),
},
# Every frame from the camera should be processed by the model. If modeld
# is not processing frames fast enough they have to be dropped. This alert is
# thrown when over 20% of frames are dropped.
EventName.modeldLagging: {
ET.SOFT_DISABLE: soft_disable_alert("Driving Model Lagging"),
ET.NO_ENTRY: NoEntryAlert("Driving Model Lagging"),
ET.SOFT_DISABLE: soft_disable_alert("驾驶模型延迟"),
ET.NO_ENTRY: NoEntryAlert("驾驶模型延迟"),
ET.PERMANENT: modeld_lagging_alert,
},
@@ -721,45 +721,45 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# usually means the model has trouble understanding the scene. This is used
# as a heuristic to warn the driver.
EventName.posenetInvalid: {
ET.SOFT_DISABLE: soft_disable_alert("Posenet Speed Invalid"),
ET.SOFT_DISABLE: soft_disable_alert("Posenet 速度无效"),
ET.NO_ENTRY: posenet_invalid_alert,
},
# When the localizer detects an acceleration of more than 40 m/s^2 (~4G) we
# alert the driver the device might have fallen from the windshield.
EventName.deviceFalling: {
ET.SOFT_DISABLE: soft_disable_alert("Device Fell Off Mount"),
ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"),
ET.SOFT_DISABLE: soft_disable_alert("设备从支架掉落"),
ET.NO_ENTRY: NoEntryAlert("设备从支架掉落"),
},
EventName.lowMemory: {
ET.SOFT_DISABLE: soft_disable_alert("Low Memory: Reboot Your Device"),
ET.SOFT_DISABLE: soft_disable_alert("内存不足:请重启设备"),
ET.PERMANENT: low_memory_alert,
ET.NO_ENTRY: NoEntryAlert("Low Memory: Reboot Your Device"),
ET.NO_ENTRY: NoEntryAlert("内存不足:请重启设备"),
},
EventName.accFaulted: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"),
ET.PERMANENT: NormalPermanentAlert("Cruise Fault: Restart the car to engage"),
ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航故障:请重启车辆"),
ET.PERMANENT: NormalPermanentAlert("巡航故障:重启车辆后可开启"),
ET.NO_ENTRY: NoEntryAlert("巡航故障:请重启车辆"),
},
EventName.espActive: {
ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Active"),
ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Active"),
ET.SOFT_DISABLE: soft_disable_alert("车身稳定系统已激活"),
ET.NO_ENTRY: NoEntryAlert("车身稳定系统已激活"),
},
EventName.controlsMismatch: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch"),
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("控制不匹配"),
ET.NO_ENTRY: NoEntryAlert("控制不匹配"),
},
# Sometimes the USB stack on the device can get into a bad state
# causing the connection to the panda to be lost
EventName.usbError: {
ET.SOFT_DISABLE: soft_disable_alert("USB Error: Reboot Your Device"),
ET.PERMANENT: NormalPermanentAlert("USB Error: Reboot Your Device"),
ET.NO_ENTRY: NoEntryAlert("USB Error: Reboot Your Device"),
ET.SOFT_DISABLE: soft_disable_alert("USB 错误:请重启设备"),
ET.PERMANENT: NormalPermanentAlert("USB 错误:请重启设备"),
ET.NO_ENTRY: NoEntryAlert("USB 错误:请重启设备"),
},
# This alert can be thrown for the following reasons:
@@ -767,45 +767,45 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# - CAN data is received, but some message are not received at the right frequency
# If you're not writing a new car port, this is usually cause by faulty wiring
EventName.canError: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Unknown Vehicle Variant"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("未知车型变体"),
ET.PERMANENT: Alert(
"Unknown Vehicle Variant",
"未知车型变体",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("Unknown Vehicle Variant"),
ET.NO_ENTRY: NoEntryAlert("未知车型变体"),
},
EventName.canBusMissing: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Bus Disconnected"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN 总线断开"),
ET.PERMANENT: Alert(
"CAN Bus Disconnected: Likely Faulty Cable",
"CAN 总线断开:可能为线缆故障",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("CAN Bus Disconnected: Check Connections"),
ET.NO_ENTRY: NoEntryAlert("CAN 总线断开:请检查连接"),
},
EventName.steerUnavailable: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"),
ET.PERMANENT: NormalPermanentAlert("LKAS Fault: Restart the car to engage"),
ET.NO_ENTRY: NoEntryAlert("LKAS Fault: Restart the Car"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS故障:请重启车辆"),
ET.PERMANENT: NormalPermanentAlert("LKAS故障:重启车辆后可开启"),
ET.NO_ENTRY: NoEntryAlert("LKAS故障:请重启车辆"),
},
EventName.reverseGear: {
ET.PERMANENT: Alert(
"Reverse\nGear",
"倒车\n档位",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.USER_DISABLE: ImmediateDisableAlert("Reverse Gear"),
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
ET.USER_DISABLE: ImmediateDisableAlert("倒车档位"),
ET.NO_ENTRY: NoEntryAlert("倒车档位"),
},
# On cars that use stock ACC the car can decide to cancel ACC for various reasons.
# When this happens we can no long control the car so the user needs to be warned immediately.
EventName.cruiseDisabled: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Is Off"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("巡航已关闭"),
},
# When the relay in the harness box opens the CAN bus between the LKAS camera
@@ -813,15 +813,15 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# are received on the car side this usually means the relay hasn't opened correctly
# and this alert is thrown.
EventName.relayMalfunction: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Relay Malfunction"),
ET.PERMANENT: NormalPermanentAlert("Harness Relay Malfunction", "Check Hardware"),
ET.NO_ENTRY: NoEntryAlert("Harness Relay Malfunction"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("线束继电器故障"),
ET.PERMANENT: NormalPermanentAlert("线束继电器故障", "请检查硬件"),
ET.NO_ENTRY: NoEntryAlert("线束继电器故障"),
},
EventName.speedTooLow: {
ET.IMMEDIATE_DISABLE: Alert(
"openpilot Canceled",
"Speed too low",
"openpilot 已取消",
"速度过低",
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
},
@@ -829,17 +829,17 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# When the car is driving faster than most cars in the training data, the model outputs can be unpredictable.
EventName.speedTooHigh: {
ET.WARNING: Alert(
"Speed Too High",
"Model uncertain at this speed",
"速度过高",
"模型在此速度下不确定",
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
ET.NO_ENTRY: NoEntryAlert("Slow down to engage"),
ET.NO_ENTRY: NoEntryAlert("请减速后开启"),
},
EventName.vehicleSensorsInvalid: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Vehicle Sensors Invalid"),
ET.PERMANENT: NormalPermanentAlert("Vehicle Sensors Calibrating", "Drive to Calibrate"),
ET.NO_ENTRY: NoEntryAlert("Vehicle Sensors Calibrating"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("车辆传感器无效"),
ET.PERMANENT: NormalPermanentAlert("车辆传感器校准中", "行驶即可完成标定"),
ET.NO_ENTRY: NoEntryAlert("车辆传感器校准中"),
},
EventName.personalityChanged: {
@@ -847,7 +847,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
},
EventName.userBookmark: {
ET.PERMANENT: NormalPermanentAlert("Bookmark Saved", duration=1.5),
ET.PERMANENT: NormalPermanentAlert("书签已保存", duration=1.5),
},
EventName.audioFeedback: {
@@ -860,66 +860,66 @@ if HARDWARE.get_device_type() == 'mici':
EVENTS.update({
EventName.driverDistracted1: {
ET.PERMANENT: Alert(
"Pay Attention",
"请注意路况",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 2),
},
EventName.driverDistracted2: {
ET.PERMANENT: Alert(
"Pay Attention",
"Driver Distracted",
"请注意路况",
"驾驶分心",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, 1),
},
EventName.resumeRequired: {
ET.WARNING: Alert(
"Press Resume",
" Resume",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.preLaneChangeLeft: {
ET.WARNING: Alert(
"Steer Left",
"Confirm Lane Change",
"向左转向",
"确认变道",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
"Steer Right",
"Confirm Lane Change",
"向右转向",
"确认变道",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
"Car in Blindspot",
"盲区有车辆",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventName.steerSaturated: {
ET.WARNING: Alert(
"take control",
"turn exceeds limit",
"请接管",
"转向超过限制",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 2.),
},
EventName.calibrationIncomplete: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"),
ET.NO_ENTRY: NoEntryAlert("Calibrating"),
ET.SOFT_DISABLE: soft_disable_alert("标定未完成"),
ET.NO_ENTRY: NoEntryAlert("标定中"),
},
EventName.reverseGear: {
ET.PERMANENT: Alert(
"Reverse",
"倒车",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.USER_DISABLE: ImmediateDisableAlert("Reverse"),
ET.NO_ENTRY: NoEntryAlert("Reverse"),
ET.USER_DISABLE: ImmediateDisableAlert("倒车"),
ET.NO_ENTRY: NoEntryAlert("倒车"),
},
})
+953
View File
@@ -0,0 +1,953 @@
#!/usr/bin/env python3
import math
import os
from cereal import log, car
import cereal.messaging as messaging
from openpilot.common.constants import CV
from openpilot.common.git import get_short_branch
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.system.micd import SAMPLE_RATE, SAMPLE_BUFFER
from openpilot.selfdrive.ui.feedback.feedbackd import FEEDBACK_MAX_DURATION
from openpilot.system.hardware import HARDWARE
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
StartupAlert, AlertCallbackType, wrong_car_mode_alert
AlertSize = log.SelfdriveState.AlertSize
AlertStatus = log.SelfdriveState.AlertStatus
VisualAlert = car.CarControl.HUDControl.VisualAlert
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
EventName = log.OnroadEvent.EventName
# get event name from enum
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
class Events(EventsBase):
def __init__(self):
super().__init__()
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
return EVENTS
def get_event_name(self, event: int):
return EVENT_NAME[event]
def get_event_msg_type(self):
return log.OnroadEvent
# ********** helper functions **********
def get_display_speed(speed_ms: float, metric: bool) -> str:
speed = int(round(speed_ms * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)))
unit = 'km/h' if metric else 'mph'
return f"{speed} {unit}"
# ********** alert callback functions **********
def soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
if soft_disable_time < int(0.5 / DT_CTRL):
return ImmediateDisableAlert(alert_text_2)
return SoftDisableAlert(alert_text_2)
return func
def user_soft_disable_alert(alert_text_2: str) -> AlertCallbackType:
def func(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
if soft_disable_time < int(0.5 / DT_CTRL):
return ImmediateDisableAlert(alert_text_2)
return UserSoftDisableAlert(alert_text_2)
return func
def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
branch = get_short_branch() # Ensure get_short_branch is cached to avoid lags on startup
if "REPLAY" in os.environ:
branch = "replay"
return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt)
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return Alert(
f"Steer Assist Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
first_word = 'Recalibrating' if sm['liveCalibration'].calStatus == log.LiveCalibrationData.Status.recalibrating else 'Calibrating'
return Alert(
f"{first_word}: {sm['liveCalibration'].calPerc:.0f}%",
f"Drive Above {get_display_speed(MIN_SPEED_FILTER, metric)}",
AlertStatus.normal, AlertSize.mid,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2)
def audio_feedback_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
duration = FEEDBACK_MAX_DURATION - ((sm['audioFeedback'].blockNum + 1) * SAMPLE_BUFFER / SAMPLE_RATE)
return NormalPermanentAlert(
"Recording Audio Feedback",
f"{round(duration)} second{'s' if round(duration) != 1 else ''} remaining. Press again to save early.",
priority=Priority.LOW)
# *** debug alerts ***
def out_of_space_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
full_perc = round(100. - sm['deviceState'].freeSpacePercent)
return NormalPermanentAlert("Out of Storage", f"{full_perc}% full")
def posenet_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
mdl = sm['modelV2'].velocity.x[0] if len(sm['modelV2'].velocity.x) else math.nan
err = CS.vEgo - mdl
msg = f"Speed Error: {err:.1f} m/s"
return NoEntryAlert(msg, alert_text_1="Posenet Speed Invalid")
def process_not_running_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
not_running = [p.name for p in sm['managerState'].processes if not p.running and p.shouldBeRunning]
msg = ', '.join(not_running)
return NoEntryAlert(msg, alert_text_1="Process Not Running")
def comm_issue_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
bs = [s for s in sm.data.keys() if not sm.all_checks([s, ])]
msg = ', '.join(bs[:4]) # can't fit too many on one line
return NoEntryAlert(msg, alert_text_1="Communication Issue Between Processes")
def camera_malfunction_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
all_cams = ('roadCameraState', 'driverCameraState', 'wideRoadCameraState')
bad_cams = [s.replace('State', '') for s in all_cams if s in sm.data.keys() and not sm.all_checks([s, ])]
return NormalPermanentAlert("Camera Malfunction", ', '.join(bad_cams))
def calibration_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
rpy = sm['liveCalibration'].rpyCalib
yaw = math.degrees(rpy[2] if len(rpy) == 3 else math.nan)
pitch = math.degrees(rpy[1] if len(rpy) == 3 else math.nan)
angles = f"Remount Device (Pitch: {pitch:.1f}°, Yaw: {yaw:.1f}°)"
return NormalPermanentAlert("Calibration Invalid", angles)
def paramsd_invalid_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
if not sm['liveParameters'].angleOffsetValid:
angle_offset_deg = sm['liveParameters'].angleOffsetDeg
title = "Steering misalignment detected"
text = f"Angle offset too high (Offset: {angle_offset_deg:.1f}°)"
elif not sm['liveParameters'].steerRatioValid:
steer_ratio = sm['liveParameters'].steerRatio
title = "Steer ratio mismatch"
text = f"Steering rack geometry may be off (Ratio: {steer_ratio:.1f})"
elif not sm['liveParameters'].stiffnessFactorValid:
stiffness_factor = sm['liveParameters'].stiffnessFactor
title = "Abnormal tire stiffness"
text = f"Check tires, pressure, or alignment (Factor: {stiffness_factor:.1f})"
else:
return NoEntryAlert("paramsd Temporary Error")
return NoEntryAlert(alert_text_1=title, alert_text_2=text)
def overheat_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
cpu = max(sm['deviceState'].cpuTempC, default=0.)
gpu = max(sm['deviceState'].gpuTempC, default=0.)
temp = max((cpu, gpu, sm['deviceState'].memoryTempC))
return NormalPermanentAlert("System Overheated", f"{temp:.0f} °C")
def low_memory_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NormalPermanentAlert("Low Memory", f"{sm['deviceState'].memoryUsagePercent}% used")
def high_cpu_usage_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
x = max(sm['deviceState'].cpuUsagePercent, default=0.)
return NormalPermanentAlert("High CPU Usage", f"{x}% used")
def modeld_lagging_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
return NormalPermanentAlert("Driving Model Lagging", f"{sm['modelV2'].frameDropPerc:.1f}% frames dropped")
def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
gb = sm['carControl'].actuators.accel / 4.
steer = sm['carControl'].actuators.torque
vals = f"Gas: {round(gb * 100.)}%, Steer: {round(steer * 100.)}%"
return NormalPermanentAlert("Joystick Mode", vals)
def longitudinal_maneuver_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
ad = sm['alertDebug']
audible_alert = AudibleAlert.prompt if 'Active' in ad.alertText1 else AudibleAlert.none
alert_status = AlertStatus.userPrompt if 'Active' in ad.alertText1 else AlertStatus.normal
alert_size = AlertSize.mid if ad.alertText2 else AlertSize.small
return Alert(ad.alertText1, ad.alertText2,
alert_status, alert_size,
Priority.LOW, VisualAlert.none, audible_alert, 0.2)
def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
personality = str(personality).title()
return NormalPermanentAlert(f"Driving Personality: {personality}", duration=1.5)
def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
text = "Toggle stock LKAS on or off to engage"
if CP.brand == "tesla":
text = "Switch to Traffic-Aware Cruise Control to engage"
elif CP.brand == "mazda":
text = "Enable your car's LKAS to engage"
elif CP.brand == "nissan":
text = "Disable your car's stock LKAS to engage"
return NormalPermanentAlert("Invalid LKAS setting", text)
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# ********** events with no alerts **********
EventName.stockFcw: {},
EventName.actuatorsApiUnavailable: {},
# ********** events only containing alerts displayed in all states **********
EventName.joystickDebug: {
ET.WARNING: joystick_alert,
ET.PERMANENT: NormalPermanentAlert("Joystick Mode"),
},
EventName.longitudinalManeuver: {
ET.WARNING: longitudinal_maneuver_alert,
ET.PERMANENT: NormalPermanentAlert("Longitudinal Maneuver Mode",
"Ensure road ahead is clear"),
},
EventName.lateralManeuver: {
ET.WARNING: longitudinal_maneuver_alert,
ET.PERMANENT: NormalPermanentAlert("Lateral Maneuver Mode"),
},
EventName.selfdriveInitializing: {
ET.NO_ENTRY: NoEntryAlert("System Initializing"),
},
EventName.startup: {
ET.PERMANENT: StartupAlert("Be ready to take over at any time")
},
EventName.startupMaster: {
ET.PERMANENT: startup_master_alert,
},
EventName.startupNoControl: {
ET.PERMANENT: StartupAlert("Dashcam mode"),
ET.NO_ENTRY: NoEntryAlert("Dashcam mode"),
},
EventName.startupNoCar: {
ET.PERMANENT: StartupAlert("Dashcam mode for unsupported car"),
},
EventName.startupNoSecOcKey: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
"Security Key Not Available",
priority=Priority.HIGH),
},
EventName.dashcamMode: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
priority=Priority.LOWEST),
},
EventName.invalidLkasSetting: {
ET.PERMANENT: invalid_lkas_setting_alert,
ET.NO_ENTRY: NoEntryAlert("Invalid LKAS setting"),
},
EventName.cruiseMismatch: {
#ET.PERMANENT: ImmediateDisableAlert("openpilot failed to cancel cruise"),
},
# openpilot doesn't recognize the car. This switches openpilot into a
# read-only mode. This can be solved by adding your fingerprint.
# See https://github.com/commaai/openpilot/wiki/Fingerprinting for more information
EventName.carUnrecognized: {
ET.PERMANENT: NormalPermanentAlert("Dashcam Mode",
"Car Unrecognized",
priority=Priority.LOWEST),
},
EventName.aeb: {
ET.PERMANENT: Alert(
"BRAKE!",
"Emergency Braking: Risk of Collision",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
ET.NO_ENTRY: NoEntryAlert("AEB: Risk of Collision"),
},
EventName.stockAeb: {
ET.PERMANENT: Alert(
"BRAKE!",
"Stock AEB: Risk of Collision",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 2.),
ET.NO_ENTRY: NoEntryAlert("Stock AEB: Risk of Collision"),
},
EventName.stockLkas: {
ET.NO_ENTRY: NoEntryAlert("Stock LKAS: Lane Departure Detected"),
},
EventName.fcw: {
ET.PERMANENT: Alert(
"BRAKE!",
"Risk of Collision",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
},
EventName.ldw: {
ET.PERMANENT: Alert(
"Lane Departure Detected",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
},
# ********** events only containing alerts that display while engaged **********
EventName.steerTempUnavailableSilent: {
ET.WARNING: Alert(
"Steering Assist Temporarily Unavailable",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.8),
},
EventName.driverDistracted1: {
ET.PERMANENT: Alert(
"Pay Attention",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.driverDistracted2: {
ET.PERMANENT: Alert(
"Pay Attention",
"Driver Distracted",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverDistracted3: {
ET.PERMANENT: Alert(
"DISENGAGE IMMEDIATELY",
"Driver Distracted",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.driverUnresponsive1: {
ET.PERMANENT: Alert(
"Touch Steering Wheel: No Face Detected",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .1),
},
EventName.driverUnresponsive2: {
ET.PERMANENT: Alert(
"Touch Steering Wheel",
"Driver Unresponsive",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, .1),
},
EventName.driverUnresponsive3: {
ET.PERMANENT: Alert(
"DISENGAGE IMMEDIATELY",
"Driver Unresponsive",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.manualRestart: {
ET.WARNING: Alert(
"TAKE CONTROL",
"Resume Driving Manually",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.resumeRequired: {
ET.WARNING: Alert(
"Press Resume to Exit Standstill",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.belowSteerSpeed: {
ET.WARNING: below_steer_speed_alert,
},
EventName.preLaneChangeLeft: {
ET.WARNING: Alert(
"Steer Left to Start Lane Change Once Safe",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
"Steer Right to Start Lane Change Once Safe",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
"Car Detected in Blindspot",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventName.laneChange: {
ET.WARNING: Alert(
"Changing Lanes",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.steerSaturated: {
ET.WARNING: Alert(
"Take Control",
"Turn Exceeds Steering Limit",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 2.),
},
# Thrown when the fan is driven at >50% but is not rotating
EventName.fanMalfunction: {
ET.PERMANENT: NormalPermanentAlert("Fan Malfunction", "Likely Hardware Issue"),
},
# Camera is not outputting frames
EventName.cameraMalfunction: {
ET.PERMANENT: camera_malfunction_alert,
ET.SOFT_DISABLE: soft_disable_alert("Camera Malfunction"),
ET.NO_ENTRY: NoEntryAlert("Camera Malfunction: Reboot Your Device"),
},
# Camera framerate too low
EventName.cameraFrameRate: {
ET.PERMANENT: NormalPermanentAlert("Camera Frame Rate Low", "Reboot your Device"),
ET.SOFT_DISABLE: soft_disable_alert("Camera Frame Rate Low"),
ET.NO_ENTRY: NoEntryAlert("Camera Frame Rate Low: Reboot Your Device"),
},
# Unused
EventName.locationdTemporaryError: {
ET.NO_ENTRY: NoEntryAlert("locationd Temporary Error"),
ET.SOFT_DISABLE: soft_disable_alert("locationd Temporary Error"),
},
EventName.locationdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("locationd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("locationd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("locationd Permanent Error"),
},
# openpilot tries to learn certain parameters about your car by observing
# how the car behaves to steering inputs from both human and openpilot driving.
# This includes:
# - steer ratio: gear ratio of the steering rack. Steering angle divided by tire angle
# - tire stiffness: how much grip your tires have
# - angle offset: most steering angle sensors are offset and measure a non zero angle when driving straight
# This alert is thrown when any of these values exceed a sanity check. This can be caused by
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
EventName.paramsdTemporaryError: {
ET.NO_ENTRY: paramsd_invalid_alert,
ET.SOFT_DISABLE: soft_disable_alert("paramsd Temporary Error"),
},
EventName.paramsdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("paramsd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("paramsd Permanent Error"),
},
# ********** events that affect controls state transitions **********
EventName.pcmEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventName.buttonEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventName.pcmDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
},
EventName.buttonCancel: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Cancel Pressed"),
},
EventName.brakeHold: {
ET.WARNING: Alert(
"Press Resume to Exit Brake Hold",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.parkBrake: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
},
EventName.pedalPressed: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Pedal Pressed",
visual_alert=VisualAlert.brakePressed),
},
EventName.steerDisengage: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Steering Pressed"),
},
EventName.preEnableStandstill: {
ET.PRE_ENABLE: Alert(
"Release Brake to Engage",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1, creation_delay=1.),
},
EventName.gasPressedOverride: {
ET.OVERRIDE_LONGITUDINAL: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.steerOverride: {
ET.OVERRIDE_LATERAL: Alert(
"",
"",
AlertStatus.normal, AlertSize.none,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.wrongCarMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: wrong_car_mode_alert,
},
EventName.resumeBlocked: {
ET.NO_ENTRY: NoEntryAlert("Press Set to Engage"),
},
EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Adaptive Cruise Disabled"),
},
EventName.steerTempUnavailable: {
ET.SOFT_DISABLE: soft_disable_alert("Steering Assist Temporarily Unavailable"),
ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable"),
},
EventName.steerTimeLimit: {
ET.SOFT_DISABLE: soft_disable_alert("Vehicle Steering Time Limit"),
ET.NO_ENTRY: NoEntryAlert("Vehicle Steering Time Limit"),
},
EventName.outOfSpace: {
ET.PERMANENT: out_of_space_alert,
ET.NO_ENTRY: NoEntryAlert("Out of Storage"),
},
EventName.belowEngageSpeed: {
ET.NO_ENTRY: below_engage_speed_alert,
},
EventName.sensorDataInvalid: {
ET.PERMANENT: Alert(
"Sensor Data Invalid",
"Possible Hardware Issue",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("Sensor Data Invalid"),
ET.SOFT_DISABLE: soft_disable_alert("Sensor Data Invalid"),
},
EventName.noGps: {
},
EventName.tooDistracted: {
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
},
EventName.excessiveActuation: {
ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"),
ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"),
},
EventName.overheat: {
ET.PERMANENT: overheat_alert,
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),
ET.NO_ENTRY: NoEntryAlert("System Overheated"),
},
EventName.wrongGear: {
ET.SOFT_DISABLE: user_soft_disable_alert("Gear not D"),
ET.NO_ENTRY: NoEntryAlert("Gear not D"),
},
# This alert is thrown when the calibration angles are outside of the acceptable range.
# For example if the device is pointed too much to the left or the right.
# Usually this can only be solved by removing the mount from the windshield completely,
# and attaching while making sure the device is pointed straight forward and is level.
# See https://comma.ai/setup for more information
EventName.calibrationInvalid: {
ET.PERMANENT: calibration_invalid_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Invalid: Remount Device & Recalibrate"),
ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Remount Device & Recalibrate"),
},
EventName.calibrationIncomplete: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"),
ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"),
},
EventName.calibrationRecalibrating: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Device Remount Detected: Recalibrating"),
ET.NO_ENTRY: NoEntryAlert("Remount Detected: Recalibrating"),
},
EventName.doorOpen: {
ET.SOFT_DISABLE: user_soft_disable_alert("Door Open"),
ET.NO_ENTRY: NoEntryAlert("Door Open"),
},
EventName.seatbeltNotLatched: {
ET.SOFT_DISABLE: user_soft_disable_alert("Seatbelt Unlatched"),
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
},
EventName.espDisabled: {
ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Disabled"),
ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Disabled"),
},
EventName.lowBattery: {
ET.SOFT_DISABLE: soft_disable_alert("Low Battery"),
ET.NO_ENTRY: NoEntryAlert("Low Battery"),
},
# Different openpilot services communicate between each other at a certain
# interval. If communication does not follow the regular schedule this alert
# is thrown. This can mean a service crashed, did not broadcast a message for
# ten times the regular interval, or the average interval is more than 10% too high.
EventName.commIssue: {
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue Between Processes"),
ET.NO_ENTRY: comm_issue_alert,
},
EventName.commIssueAvgFreq: {
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate Between Processes"),
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate Between Processes"),
},
EventName.selfdrivedLagging: {
ET.SOFT_DISABLE: soft_disable_alert("System Lagging"),
ET.NO_ENTRY: NoEntryAlert("Selfdrive Process Lagging: Reboot Your Device"),
},
# Thrown when manager detects a service exited unexpectedly while driving
EventName.processNotRunning: {
ET.NO_ENTRY: process_not_running_alert,
ET.SOFT_DISABLE: soft_disable_alert("Process Not Running"),
},
EventName.radarFault: {
ET.SOFT_DISABLE: soft_disable_alert("Radar Error: Restart the Car"),
ET.NO_ENTRY: NoEntryAlert("Radar Error: Restart the Car"),
},
EventName.radarTempUnavailable: {
ET.SOFT_DISABLE: soft_disable_alert("Radar Temporarily Unavailable"),
ET.NO_ENTRY: NoEntryAlert("Radar Temporarily Unavailable"),
},
# Every frame from the camera should be processed by the model. If modeld
# is not processing frames fast enough they have to be dropped. This alert is
# thrown when over 20% of frames are dropped.
EventName.modeldLagging: {
ET.SOFT_DISABLE: soft_disable_alert("Driving Model Lagging"),
ET.NO_ENTRY: NoEntryAlert("Driving Model Lagging"),
ET.PERMANENT: modeld_lagging_alert,
},
# Besides predicting the path, lane lines and lead car data the model also
# predicts the current velocity and rotation speed of the car. If the model is
# very uncertain about the current velocity while the car is moving, this
# usually means the model has trouble understanding the scene. This is used
# as a heuristic to warn the driver.
EventName.posenetInvalid: {
ET.SOFT_DISABLE: soft_disable_alert("Posenet Speed Invalid"),
ET.NO_ENTRY: posenet_invalid_alert,
},
# When the localizer detects an acceleration of more than 40 m/s^2 (~4G) we
# alert the driver the device might have fallen from the windshield.
EventName.deviceFalling: {
ET.SOFT_DISABLE: soft_disable_alert("Device Fell Off Mount"),
ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"),
},
EventName.lowMemory: {
ET.SOFT_DISABLE: soft_disable_alert("Low Memory: Reboot Your Device"),
ET.PERMANENT: low_memory_alert,
ET.NO_ENTRY: NoEntryAlert("Low Memory: Reboot Your Device"),
},
EventName.accFaulted: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"),
ET.PERMANENT: NormalPermanentAlert("Cruise Fault: Restart the car to engage"),
ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"),
},
EventName.espActive: {
ET.SOFT_DISABLE: soft_disable_alert("Electronic Stability Control Active"),
ET.NO_ENTRY: NoEntryAlert("Electronic Stability Control Active"),
},
EventName.controlsMismatch: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch"),
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch"),
},
# Sometimes the USB stack on the device can get into a bad state
# causing the connection to the panda to be lost
EventName.usbError: {
ET.SOFT_DISABLE: soft_disable_alert("USB Error: Reboot Your Device"),
ET.PERMANENT: NormalPermanentAlert("USB Error: Reboot Your Device"),
ET.NO_ENTRY: NoEntryAlert("USB Error: Reboot Your Device"),
},
# This alert can be thrown for the following reasons:
# - No CAN data received at all
# - CAN data is received, but some message are not received at the right frequency
# If you're not writing a new car port, this is usually cause by faulty wiring
EventName.canError: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Unknown Vehicle Variant"),
ET.PERMANENT: Alert(
"Unknown Vehicle Variant",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("Unknown Vehicle Variant"),
},
EventName.canBusMissing: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Bus Disconnected"),
ET.PERMANENT: Alert(
"CAN Bus Disconnected: Likely Faulty Cable",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert("CAN Bus Disconnected: Check Connections"),
},
EventName.steerUnavailable: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"),
ET.PERMANENT: NormalPermanentAlert("LKAS Fault: Restart the car to engage"),
ET.NO_ENTRY: NoEntryAlert("LKAS Fault: Restart the Car"),
},
EventName.reverseGear: {
ET.PERMANENT: Alert(
"Reverse\nGear",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.USER_DISABLE: ImmediateDisableAlert("Reverse Gear"),
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
},
# On cars that use stock ACC the car can decide to cancel ACC for various reasons.
# When this happens we can no long control the car so the user needs to be warned immediately.
EventName.cruiseDisabled: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Is Off"),
},
# When the relay in the harness box opens the CAN bus between the LKAS camera
# and the rest of the car is separated. When messages from the LKAS camera
# are received on the car side this usually means the relay hasn't opened correctly
# and this alert is thrown.
EventName.relayMalfunction: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Relay Malfunction"),
ET.PERMANENT: NormalPermanentAlert("Harness Relay Malfunction", "Check Hardware"),
ET.NO_ENTRY: NoEntryAlert("Harness Relay Malfunction"),
},
EventName.speedTooLow: {
ET.IMMEDIATE_DISABLE: Alert(
"openpilot Canceled",
"Speed too low",
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
},
# When the car is driving faster than most cars in the training data, the model outputs can be unpredictable.
EventName.speedTooHigh: {
ET.WARNING: Alert(
"Speed Too High",
"Model uncertain at this speed",
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
ET.NO_ENTRY: NoEntryAlert("Slow down to engage"),
},
EventName.vehicleSensorsInvalid: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Vehicle Sensors Invalid"),
ET.PERMANENT: NormalPermanentAlert("Vehicle Sensors Calibrating", "Drive to Calibrate"),
ET.NO_ENTRY: NoEntryAlert("Vehicle Sensors Calibrating"),
},
EventName.personalityChanged: {
ET.WARNING: personality_changed_alert,
},
EventName.userBookmark: {
ET.PERMANENT: NormalPermanentAlert("Bookmark Saved", duration=1.5),
},
EventName.audioFeedback: {
ET.PERMANENT: audio_feedback_alert,
},
}
if HARDWARE.get_device_type() == 'mici':
EVENTS.update({
EventName.driverDistracted1: {
ET.PERMANENT: Alert(
"Pay Attention",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, 2),
},
EventName.driverDistracted2: {
ET.PERMANENT: Alert(
"Pay Attention",
"Driver Distracted",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.promptDistracted, 1),
},
EventName.resumeRequired: {
ET.WARNING: Alert(
"Press Resume",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.preLaneChangeLeft: {
ET.WARNING: Alert(
"Steer Left",
"Confirm Lane Change",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.preLaneChangeRight: {
ET.WARNING: Alert(
"Steer Right",
"Confirm Lane Change",
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1),
},
EventName.laneChangeBlocked: {
ET.WARNING: Alert(
"Car in Blindspot",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventName.steerSaturated: {
ET.WARNING: Alert(
"take control",
"turn exceeds limit",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 2.),
},
EventName.calibrationIncomplete: {
ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: soft_disable_alert("Calibration Incomplete"),
ET.NO_ENTRY: NoEntryAlert("Calibrating"),
},
EventName.reverseGear: {
ET.PERMANENT: Alert(
"Reverse",
"",
AlertStatus.normal, AlertSize.full,
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
ET.USER_DISABLE: ImmediateDisableAlert("Reverse"),
ET.NO_ENTRY: NoEntryAlert("Reverse"),
},
})
if __name__ == '__main__':
# print all alerts by type and priority
from cereal.services import SERVICE_LIST
from collections import defaultdict
event_names = {v: k for k, v in EventName.schema.enumerants.items()}
alerts_by_type: dict[str, dict[Priority, list[str]]] = defaultdict(lambda: defaultdict(list))
CP = car.CarParams.new_message()
CS = car.CarState.new_message()
sm = messaging.SubMaster(list(SERVICE_LIST.keys()))
for i, alerts in EVENTS.items():
for et, alert in alerts.items():
if not isinstance(alert, Alert):
alert = alert(CP, CS, sm, False, 1, log.LongitudinalPersonality.standard)
alerts_by_type[et][alert.priority].append(event_names[i])
all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {}
for et, priority_alerts in alerts_by_type.items():
all_alerts[et] = sorted(priority_alerts.items(), key=lambda x: x[0], reverse=True)
for status, evs in sorted(all_alerts.items(), key=lambda x: x[0]):
print(f"**** {status} ****")
for p, alert_list in evs:
print(f" {repr(p)}:")
print(" ", ', '.join(alert_list), "\n")
+55
View File
@@ -0,0 +1,55 @@
from pathlib import Path
Import('env', 'arch', 'common')
# build the fonts
generator = File("#selfdrive/assets/fonts/process.py")
source_files = Glob("#selfdrive/assets/fonts/*.ttf") + Glob("#selfdrive/assets/fonts/*.otf")
output_files = [
(f"#{Path(f.path).with_suffix('.fnt')}", f"#{Path(f.path).with_suffix('.png')}")
for f in source_files
if "NotoColor" not in f.name
]
env.Command(
target=output_files,
source=[generator, source_files],
action=f"python3 {generator}",
)
if GetOption('extras') and arch == "larch64":
# build installers
raylib_env = env.Clone()
raylib_env['LIBPATH'] += [f'#third_party/raylib/{arch}/']
raylib_env['LINKFLAGS'].append('-Wl,-strip-debug')
raylib_libs = common + ["raylib"]
if arch == "larch64":
raylib_libs += ["GLESv2", "EGL", "gbm", "drm"]
else:
raylib_libs += ["GL"]
release = "release3"
installers = [
("openpilot", release),
("openpilot_test", f"{release}-staging"),
("openpilot_nightly", "nightly"),
("openpilot_internal", "nightly-dev"),
]
cont = raylib_env.Command("installer/continue_openpilot.o", "installer/continue_openpilot.sh",
"ld -r -b binary -o $TARGET $SOURCE")
inter = raylib_env.Command("installer/inter_ttf.o", "installer/inter-ascii.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
inter_bold = raylib_env.Command("installer/inter_bold.o", "../assets/fonts/Inter-Bold.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
inter_light = raylib_env.Command("installer/inter_light.o", "../assets/fonts/Inter-Light.ttf",
"ld -r -b binary -o $TARGET $SOURCE")
for name, branch in installers:
d = {'BRANCH': f"'\"{branch}\"'"}
if "internal" in name:
d['INTERNAL'] = "1"
obj = raylib_env.Object(f"installer/installers/installer_{name}.o", ["installer/installer.cc"], CPPDEFINES=d)
f = raylib_env.Program(f"installer/installers/installer_{name}", [obj, cont, inter, inter_bold, inter_light], LIBS=raylib_libs)
# keep installers small
assert f[0].get_size() < 2500*1e3, f[0].get_size()
+19 -2
View File
@@ -181,8 +181,25 @@ class HomeLayout(Widget):
gui_label(version_rect, self._version_text, 48, rl.WHITE, alignment=rl.GuiTextAlignment.TEXT_ALIGN_RIGHT)
def _render_home_content(self):
self._render_left_column()
self._render_right_column()
# Display welcome text centered in content area
font = gui_app.font(FontWeight.BOLD)
text = "欢迎选用 MR.ONE"
subtitle = "这不是自动驾驶,请注意行车安全"
font_size = 100
text_size = measure_text_cached(font, text, font_size)
sub_size = measure_text_cached(font, subtitle, font_size)
cx = self.content_rect.x + self.content_rect.width / 2
cy = self.content_rect.y + self.content_rect.height / 2
x = int(cx - text_size.x / 2)
y = int(cy - text_size.y - sub_size.y / 2 - 15)
rl.draw_text_ex(font, text, rl.Vector2(x, y), font_size, 0, rl.WHITE)
sx = int(cx - sub_size.x / 2)
sy = int(cy + text_size.y / 2 + 15)
rl.draw_text_ex(font, subtitle, rl.Vector2(sx, sy), font_size, 0, rl.Color(255, 50, 50, 255))
def _render_update_view(self):
self.update_alert.render(self.content_rect)
+3 -3
View File
@@ -60,7 +60,7 @@ class SettingsLayout(Widget):
PanelType.NETWORK: PanelInfo(tr_noop("Network"), NetworkUI(wifi_manager)),
PanelType.TOGGLES: PanelInfo(tr_noop("Toggles"), TogglesLayout()),
PanelType.SOFTWARE: PanelInfo(tr_noop("Software"), SoftwareLayout()),
PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout()),
# PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout()),
PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayout()),
}
@@ -124,11 +124,11 @@ class SettingsLayout(Widget):
text_color = TEXT_SELECTED if is_selected else TEXT_NORMAL
# Draw button text (right-aligned)
panel_name = tr(panel_info.name)
text_size = measure_text_cached(self._font_medium, panel_name, 65)
text_size = measure_text_cached(self._font_medium, panel_name, 85)
text_pos = rl.Vector2(
button_rect.x + button_rect.width - text_size.x, button_rect.y + (button_rect.height - text_size.y) / 2
)
rl.draw_text_ex(self._font_medium, panel_name, text_pos, 65, 0, text_color)
rl.draw_text_ex(self._font_medium, panel_name, text_pos, 85, 0, text_color)
# Store button rect for click detection
panel_info.button_rect = button_rect
+9 -4
View File
@@ -123,21 +123,26 @@ class Sidebar(Widget, SidebarSP):
self._net_strength = max(0, min(5, strength.raw + 1)) if strength.raw > 0 else 0
def _update_temperature_status(self, device_state):
# Get max CPU temperature across all cores
cpu_temps = device_state.cpuTempC
max_temp = max(cpu_temps) if cpu_temps else 0.0
temp_str = f"{max_temp:.0f}°C"
thermal_status = device_state.thermalStatus
if thermal_status == ThermalStatus.green:
self._temp_status.update(tr_noop("TEMP"), tr_noop("GOOD"), Colors.GOOD)
self._temp_status.update(tr_noop("TEMP"), temp_str, Colors.GOOD)
elif thermal_status == ThermalStatus.yellow:
self._temp_status.update(tr_noop("TEMP"), tr_noop("OK"), Colors.WARNING)
self._temp_status.update(tr_noop("TEMP"), temp_str, Colors.WARNING)
else:
self._temp_status.update(tr_noop("TEMP"), tr_noop("HIGH"), Colors.DANGER)
self._temp_status.update(tr_noop("TEMP"), temp_str, Colors.DANGER)
def _update_connection_status(self, device_state):
last_ping = device_state.lastAthenaPingTime
if last_ping == 0:
self._connect_status.update(tr_noop("CONNECT"), tr_noop("OFFLINE"), Colors.WARNING)
elif time.monotonic_ns() - last_ping < 80_000_000_000: # 80 seconds in nanoseconds
self._connect_status.update(tr_noop("CONNECT"), tr_noop("ONLINE"), Colors.GOOD)
self._connect_status.update("远程", "在线", Colors.GOOD)
else:
self._connect_status.update(tr_noop("CONNECT"), tr_noop("ERROR"), Colors.DANGER)
+6 -6
View File
@@ -60,7 +60,7 @@ class TrainingGuidePreDMTutorial(NavScroller):
continue_button.set_click_callback(continue_callback)
self._scroller.add_widgets([
GreyBigButton("driver monitoring\ncheck", "scroll to continue",
GreyBigButton(tr("driver monitoring\ncheck"), "scroll to continue",
gui_app.texture("icons_mici/setup/green_dm.png", 64, 64)),
GreyBigButton("", "Next, we'll check if comma four can detect the driver properly."),
GreyBigButton("", "sunnypilot uses the cabin camera to check if the driver is distracted."),
@@ -82,7 +82,7 @@ class DMBadFaceDetected(NavScroller):
back_button.set_click_callback(self.dismiss)
self._scroller.add_widgets([
GreyBigButton("looking for driver", "make sure comma\nfour can see your face",
GreyBigButton(tr("looking for driver"), "make sure comma\nfour can see your face",
gui_app.texture("icons_mici/setup/orange_dm.png", 64, 64)),
GreyBigButton("", "Remount if your face is blocked, or driver monitoring has difficulty tracking your face."),
back_button,
@@ -233,7 +233,7 @@ class TrainingGuideRecordFront(NavScroller):
exit_on_confirm=False)
self._scroller.add_widgets([
GreyBigButton("driver camera data", "do you want to share video data for training?",
GreyBigButton(tr("driver camera data"), "do you want to share video data for training?",
gui_app.texture("icons_mici/setup/green_dm.png", 64, 64)),
GreyBigButton("", "Sharing your data with comma helps improve openpilot and sunnypilot for everyone."),
self._accept_button,
@@ -249,7 +249,7 @@ class TrainingGuideAttentionNotice(Scroller):
continue_button.set_click_callback(continue_callback)
self._scroller.add_widgets([
GreyBigButton("what is sunnypilot?", "scroll to continue",
GreyBigButton(tr("what is sunnypilot?"), "scroll to continue",
gui_app.texture("icons_mici/setup/green_info.png", 64, 64)),
GreyBigButton("", "1. sunnypilot is a driver assistance system."),
GreyBigButton("", "2. You must pay attention at all times."),
@@ -320,13 +320,13 @@ class TermsPage(Scroller):
self._decline_button = BigConfirmationCircleButton("decline &\nuninstall", gui_app.texture("icons_mici/setup/cancel.png", 64, 64), on_decline,
red=True, exit_on_confirm=False)
self._terms_header = GreyBigButton("terms of\nservice", "scroll to continue",
self._terms_header = GreyBigButton(tr("terms of\nservice"), "scroll to continue",
gui_app.texture("icons_mici/setup/green_info.png", 64, 64))
self._must_accept_card = GreyBigButton("", "You must accept the Terms of Service to use sunnypilot.")
self._scroller.add_widgets([
self._terms_header,
GreyBigButton("swipe for QR code", "or go to https://sunnypilot.ai/terms",
GreyBigButton(tr("swipe for QR code"), "or go to https://sunnypilot.ai/terms",
gui_app.texture("icons_mici/setup/small_slider/slider_arrow.png", 64, 56, flip_x=True)),
QRCodeWidget("https://sunnypilot.ai/terms"),
self._must_accept_card,
@@ -1,4 +1,5 @@
from openpilot.common.time_helpers import system_time_valid
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigToggle, BigParamControl, BigCircleParamControl
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigInputDialog
@@ -42,26 +43,26 @@ class DeveloperLayoutMici(NavScroller):
txt_ssh = gui_app.texture("icons_mici/settings/developer/ssh.png", 56, 64)
github_username = ui_state.params.get("GithubUsername") or ""
self._ssh_keys_btn = BigButton("SSH keys", "Not set" if not github_username else github_username, icon=txt_ssh)
self._ssh_keys_btn = BigButton(tr("SSH keys"), "Not set" if not github_username else github_username, icon=txt_ssh)
self._ssh_keys_btn.set_click_callback(ssh_keys_callback)
# adb, ssh, ssh keys, debug mode, joystick debug mode, longitudinal maneuver mode, ip address
# ******** Main Scroller ********
self._adb_toggle = BigCircleParamControl(gui_app.texture("icons_mici/adb_short.png", 82, 82), "AdbEnabled", icon_offset=(0, 12))
self._ssh_toggle = BigCircleParamControl(gui_app.texture("icons_mici/ssh_short.png", 82, 82), "SshEnabled", icon_offset=(0, 12))
self._joystick_toggle = BigToggle("joystick debug mode",
self._joystick_toggle = BigToggle(tr("joystick debug mode"),
initial_state=ui_state.params.get_bool("JoystickDebugMode"),
toggle_callback=self._on_joystick_debug_mode)
self._long_maneuver_toggle = BigToggle("longitudinal maneuver mode",
self._long_maneuver_toggle = BigToggle(tr("longitudinal maneuver mode"),
initial_state=ui_state.params.get_bool("LongitudinalManeuverMode"),
toggle_callback=self._on_long_maneuver_mode)
self._lat_maneuver_toggle = BigToggle("lateral maneuver mode",
self._lat_maneuver_toggle = BigToggle(tr("lateral maneuver mode"),
initial_state=ui_state.params.get_bool("LateralManeuverMode"),
toggle_callback=self._on_lat_maneuver_mode)
self._alpha_long_toggle = BigToggle("alpha longitudinal",
self._alpha_long_toggle = BigToggle(tr("alpha longitudinal"),
initial_state=ui_state.params.get_bool("AlphaLongitudinalEnabled"),
toggle_callback=self._on_alpha_long_enabled)
self._debug_mode_toggle = BigParamControl("ui debug mode", "ShowDebugInfo",
self._debug_mode_toggle = BigParamControl(tr("ui debug mode"), "ShowDebugInfo",
toggle_callback=lambda checked: (gui_app.set_show_touches(checked),
gui_app.set_show_fps(checked)))
+10 -10
View File
@@ -130,7 +130,7 @@ class UpdaterState(IntEnum):
class PairBigButton(BigButton):
def __init__(self):
super().__init__("pair", "connect.comma.ai", gui_app.texture("icons_mici/settings/comma_icon.png", 33, 60))
super().__init__(tr("pair"), "connect.comma.ai", gui_app.texture("icons_mici/settings/comma_icon.png", 33, 60))
def _get_label_font_size(self):
return 64
@@ -139,13 +139,13 @@ class PairBigButton(BigButton):
super()._update_state()
if ui_state.prime_state.is_paired():
self.set_text("paired")
self.set_text(tr("paired"))
if ui_state.prime_state.is_prime():
self.set_value("subscribed")
self.set_value(tr("subscribed"))
else:
self.set_value("upgrade to prime")
self.set_value(tr("upgrade to prime"))
else:
self.set_text("pair")
self.set_text(tr("pair"))
self.set_value("connect.comma.ai")
def _handle_mouse_release(self, mouse_pos: MousePos):
@@ -172,7 +172,7 @@ class UpdateOpenpilotBigButton(BigButton):
self._txt_update_icon = gui_app.texture("icons_mici/settings/device/update.png", 64, 75)
self._txt_reboot_icon = gui_app.texture("icons_mici/settings/device/reboot.png", 64, 70)
self._txt_up_to_date_icon = gui_app.texture("icons_mici/settings/device/up_to_date.png", 64, 64)
super().__init__("update sunnypilot", "", self._txt_update_icon)
super().__init__(tr("update sunnypilot"), "", self._txt_update_icon)
self._waiting_for_updater_t: float | None = None
self._hide_value_t: float | None = None
@@ -323,18 +323,18 @@ class DeviceLayoutMici(NavScroller):
power_off_callback, exit_on_confirm=False, red=True)
self._power_off_btn.set_visible(lambda: not ui_state.ignition)
regulatory_btn = BigButton("regulatory info", "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
regulatory_btn = BigButton(tr("regulatory info"), "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
regulatory_btn.set_click_callback(self._on_regulatory)
driver_cam_btn = BigButton("driver\ncamera preview", "", gui_app.texture("icons_mici/settings/device/cameras.png", 64, 64))
driver_cam_btn = BigButton(tr("driver\ncamera preview"), "", gui_app.texture("icons_mici/settings/device/cameras.png", 64, 64))
driver_cam_btn.set_click_callback(lambda: gui_app.push_widget(DriverCameraDialog()))
driver_cam_btn.set_enabled(lambda: ui_state.is_offroad())
review_training_guide_btn = BigButton("review\ntraining guide", "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
review_training_guide_btn = BigButton(tr("review\ntraining guide"), "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
review_training_guide_btn.set_click_callback(lambda: gui_app.push_widget(ReviewTrainingGuide(completed_callback=lambda: gui_app.pop_widgets_to(self))))
review_training_guide_btn.set_enabled(lambda: ui_state.is_offroad())
terms_btn = BigButton("terms &\nconditions", "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
terms_btn = BigButton(tr("terms &\nconditions"), "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
terms_btn.set_click_callback(lambda: gui_app.push_widget(ReviewTermsPage()))
self._scroller.add_widgets([
@@ -1,3 +1,4 @@
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.selfdrive.ui.mici.layouts.settings.network import WifiNetworkButton
from openpilot.selfdrive.ui.mici.layouts.settings.network.wifi_ui import WifiUIMici
@@ -28,7 +29,7 @@ class NetworkLayoutMici(NavScroller):
self._network_metered_btn.set_enabled(False)
self._wifi_manager.set_tethering_active(checked)
self._tethering_toggle_btn = BigToggle("enable tethering", "", toggle_callback=tethering_toggle_callback)
self._tethering_toggle_btn = BigToggle(tr("enable tethering"), "", toggle_callback=tethering_toggle_callback)
def tethering_password_callback(password: str):
if password:
@@ -43,7 +44,7 @@ class NetworkLayoutMici(NavScroller):
gui_app.push_widget(dlg)
txt_tethering = gui_app.texture("icons_mici/settings/network/tethering.png", 64, 54)
self._tethering_password_btn = BigButton("tethering password", "", txt_tethering)
self._tethering_password_btn = BigButton(tr("tethering password"), "", txt_tethering)
self._tethering_password_btn.set_click_callback(tethering_password_clicked)
# ******** Network Metered ********
@@ -58,7 +59,7 @@ class NetworkLayoutMici(NavScroller):
# TODO: signal for current network metered type when changing networks, this is wrong until you press it once
# TODO: disable when not connected
self._network_metered_btn = BigMultiToggle("network usage", ["default", "metered", "unmetered"], select_callback=network_metered_callback)
self._network_metered_btn = BigMultiToggle(tr("network usage"), ["default", "metered", "unmetered"], select_callback=network_metered_callback)
self._network_metered_btn.set_enabled(False)
self._wifi_button = WifiNetworkButton(self._wifi_manager)
@@ -66,14 +67,14 @@ class NetworkLayoutMici(NavScroller):
# ******** Advanced settings ********
# ******** Roaming toggle ********
self._roaming_btn = BigParamControl("enable roaming", "GsmRoaming", toggle_callback=self._toggle_roaming)
self._roaming_btn = BigParamControl(tr("enable roaming"), "GsmRoaming", toggle_callback=self._toggle_roaming)
# ******** APN settings ********
self._apn_btn = BigButton("apn settings", "edit")
self._apn_btn = BigButton(tr("apn settings"), "edit")
self._apn_btn.set_click_callback(self._edit_apn)
# ******** Cellular metered toggle ********
self._cellular_metered_btn = BigParamControl("cellular metered", "GsmMetered", toggle_callback=self._toggle_cellular_metered)
self._cellular_metered_btn = BigParamControl(tr("cellular metered"), "GsmMetered", toggle_callback=self._toggle_cellular_metered)
# Main scroller ----------------------------------
self._scroller.add_widgets([
@@ -1,4 +1,5 @@
from openpilot.common.params import Params
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
from openpilot.selfdrive.ui.mici.layouts.settings.toggles import TogglesLayoutMici
@@ -20,23 +21,23 @@ class SettingsLayout(NavScroller):
self._params = Params()
toggles_panel = TogglesLayoutMici()
toggles_btn = SettingsBigButton("toggles", "", gui_app.texture("icons_mici/settings.png", 64, 64))
toggles_btn = SettingsBigButton(tr("toggles"), "", gui_app.texture("icons_mici/settings.png", 64, 64))
toggles_btn.set_click_callback(lambda: gui_app.push_widget(toggles_panel))
network_panel = NetworkLayoutMici()
network_btn = SettingsBigButton("network", "", gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 76, 56))
network_btn = SettingsBigButton(tr("network"), "", gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 76, 56))
network_btn.set_click_callback(lambda: gui_app.push_widget(network_panel))
device_panel = DeviceLayoutMici()
device_btn = SettingsBigButton("device", "", gui_app.texture("icons_mici/settings/device_icon.png", 72, 58))
device_btn = SettingsBigButton(tr("device"), "", gui_app.texture("icons_mici/settings/device_icon.png", 72, 58))
device_btn.set_click_callback(lambda: gui_app.push_widget(device_panel))
developer_panel = DeveloperLayoutMici()
developer_btn = SettingsBigButton("developer", "", gui_app.texture("icons_mici/settings/developer_icon.png", 64, 60))
developer_btn = SettingsBigButton(tr("developer"), "", gui_app.texture("icons_mici/settings/developer_icon.png", 64, 60))
developer_btn.set_click_callback(lambda: gui_app.push_widget(developer_panel))
firehose_panel = FirehoseLayout()
firehose_btn = SettingsBigButton("firehose", "", gui_app.texture("icons_mici/settings/firehose.png", 52, 62))
firehose_btn = SettingsBigButton(tr("firehose"), "", gui_app.texture("icons_mici/settings/firehose.png", 52, 62))
firehose_btn.set_click_callback(lambda: gui_app.push_widget(firehose_panel))
self._scroller.add_widgets([
@@ -1,5 +1,6 @@
from cereal import log
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.selfdrive.ui.mici.widgets.button import BigParamControl, BigMultiParamToggle
from openpilot.system.ui.lib.application import gui_app
@@ -13,14 +14,14 @@ class TogglesLayoutMici(NavScroller):
def __init__(self):
super().__init__()
self._personality_toggle = BigMultiParamToggle("driving personality", "LongitudinalPersonality", ["aggressive", "standard", "relaxed"])
self._experimental_btn = BigParamControl("experimental mode", "ExperimentalMode")
is_metric_toggle = BigParamControl("use metric units", "IsMetric")
ldw_toggle = BigParamControl("lane departure warnings", "IsLdwEnabled")
always_on_dm_toggle = BigParamControl("always-on driver monitor", "AlwaysOnDM")
record_front = BigParamControl("record & upload driver camera", "RecordFront", toggle_callback=restart_needed_callback)
record_mic = BigParamControl("record & upload mic audio", "RecordAudio", toggle_callback=restart_needed_callback)
enable_openpilot = BigParamControl("enable sunnypilot", "OpenpilotEnabledToggle", toggle_callback=restart_needed_callback)
self._personality_toggle = BigMultiParamToggle(tr("driving personality"), "LongitudinalPersonality", ["aggressive", "standard", "relaxed"])
self._experimental_btn = BigParamControl(tr("experimental mode"), "ExperimentalMode")
is_metric_toggle = BigParamControl(tr("use metric units"), "IsMetric")
ldw_toggle = BigParamControl(tr("lane departure warnings"), "IsLdwEnabled")
always_on_dm_toggle = BigParamControl(tr("always-on driver monitor"), "AlwaysOnDM")
record_front = BigParamControl(tr("record & upload driver camera"), "RecordFront", toggle_callback=restart_needed_callback)
record_mic = BigParamControl(tr("record & upload mic audio"), "RecordAudio", toggle_callback=restart_needed_callback)
enable_openpilot = BigParamControl(tr("enable sunnypilot"), "OpenpilotEnabledToggle", toggle_callback=restart_needed_callback)
self._scroller.add_widgets([
self._personality_toggle,
@@ -42,11 +42,11 @@ class OSMLayout(Widget):
self._update_map_size()
self._progress.set_visible(False)
self._state_btn.set_visible(False)
self._mapd_version.action_item.set_text(ui_state.params.get("MapdVersion") or "Loading...")
self._mapd_version.action_item.set_text(ui_state.params.get("MapdVersion") or tr("Loading..."))
self._scroller = Scroller(self.items, line_separator=True, spacing=0)
def _initialize_items(self):
self._mapd_version = text_item(tr("Mapd Version"), lambda: ui_state.params.get("MapdVersion") or "Loading...")
self._mapd_version = text_item(tr("Mapd Version"), lambda: ui_state.params.get("MapdVersion") or tr("Loading..."))
self._delete_maps_btn = ListItemSP(tr("Downloaded Maps"), action_item=NoElideButtonAction(tr("DELETE"), enabled=True), callback=self._delete_maps)
self._progress = progress_item(tr("Downloading Map"))
self._update_btn = ListItemSP(tr("Database Update"), action_item=NoElideButtonAction(tr("CHECK"), enabled=True), callback=self._update_db)
@@ -88,7 +88,7 @@ class OSMLayout(Widget):
def _on_confirm_delete_maps(self):
self._delete_maps_btn.action_item.set_enabled(False)
self._delete_maps_btn.action_item.set_text("DELETING...")
self._delete_maps_btn.action_item.set_text(tr("DELETING..."))
threading.Thread(target=self._do_delete_maps).start()
def _delete_maps(self):
@@ -25,7 +25,7 @@ from openpilot.selfdrive.ui.sunnypilot.layouts.settings.trips import TripsLayout
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.vehicle import VehicleLayout
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.visuals import VisualsLayout
from openpilot.system.ui.lib.application import gui_app, MousePos
from openpilot.system.ui.lib.multilang import tr_noop
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.lib.wifi_manager import WifiManager
from openpilot.system.ui.sunnypilot.lib.styles import style
@@ -71,7 +71,7 @@ class NavButton(Widget):
is_selected = self.panel_type == self.parent._current_panel
text_color = OP.TEXT_SELECTED if is_selected else OP.TEXT_NORMAL
content_x = rect.x + 90
text_size = measure_text_cached(self.parent._font_medium, self.panel_info.name, 65)
text_size = measure_text_cached(self.parent._font_medium, tr(self.panel_info.name), 65)
# Draw background if selected
if is_selected:
@@ -90,7 +90,7 @@ class NavButton(Widget):
content_x,
rect.y + (OP.NAV_BTN_HEIGHT - text_size.y) / 2
)
rl.draw_text_ex(self.parent._font_medium, self.panel_info.name, text_pos, 55, 0, text_color)
rl.draw_text_ex(self.parent._font_medium, tr(self.panel_info.name), text_pos, 55, 0, text_color)
# Store button rect for click detection
self.panel_info.button_rect = rect
@@ -109,22 +109,22 @@ class SettingsLayoutSP(OP.SettingsLayout):
wifi_manager.set_active(False)
self._panels = {
OP.PanelType.DEVICE: PanelInfo(tr_noop("Device"), DeviceLayoutSP(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_home.png"),
OP.PanelType.NETWORK: PanelInfo(tr_noop("Network"), NetworkUISP(wifi_manager), icon="icons/network.png"),
OP.PanelType.SUNNYLINK: PanelInfo(tr_noop("sunnylink"), SunnylinkLayout(), icon="icons/wifi_strength_full.png"),
OP.PanelType.TOGGLES: PanelInfo(tr_noop("Toggles"), TogglesLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_toggle.png"),
OP.PanelType.SOFTWARE: PanelInfo(tr_noop("Software"), SoftwareLayoutSP(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_software.png"),
OP.PanelType.MODELS: PanelInfo(tr_noop("Models"), ModelsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_models.png"),
OP.PanelType.STEERING: PanelInfo(tr_noop("Steering"), SteeringLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_lateral.png"),
OP.PanelType.CRUISE: PanelInfo(tr_noop("Cruise"), CruiseLayout(), icon="icons/speed_limit.png"),
OP.PanelType.VISUALS: PanelInfo(tr_noop("Visuals"), VisualsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_visuals.png"),
OP.PanelType.DISPLAY: PanelInfo(tr_noop("Display"), DisplayLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_display.png"),
OP.PanelType.OSM: PanelInfo(tr_noop("OSM"), OSMLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
# OP.PanelType.NAVIGATION: PanelInfo(tr_noop("Navigation"), NavigationLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
OP.PanelType.TRIPS: PanelInfo(tr_noop("Trips"), TripsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"),
OP.PanelType.VEHICLE: PanelInfo(tr_noop("Vehicle"), VehicleLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"),
OP.PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_firehose.png"),
OP.PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayoutSP(), icon="icons/shell.png"),
OP.PanelType.DEVICE: PanelInfo(tr("Device"), DeviceLayoutSP(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_home.png"),
OP.PanelType.NETWORK: PanelInfo(tr("Network"), NetworkUISP(wifi_manager), icon="icons/network.png"),
# OP.PanelType.SUNNYLINK: PanelInfo(tr("sunnylink"), SunnylinkLayout(), icon="icons/wifi_strength_full.png"),
OP.PanelType.TOGGLES: PanelInfo(tr("Toggles"), TogglesLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_toggle.png"),
OP.PanelType.SOFTWARE: PanelInfo(tr("Software"), SoftwareLayoutSP(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_software.png"),
# OP.PanelType.MODELS: PanelInfo(tr("Models"), ModelsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_models.png"),
OP.PanelType.STEERING: PanelInfo(tr("Steering"), SteeringLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_lateral.png"),
OP.PanelType.CRUISE: PanelInfo(tr("Cruise"), CruiseLayout(), icon="icons/speed_limit.png"),
OP.PanelType.VISUALS: PanelInfo(tr("Visuals"), VisualsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_visuals.png"),
OP.PanelType.DISPLAY: PanelInfo(tr("Display"), DisplayLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_display.png"),
# OP.PanelType.OSM: PanelInfo(tr("OSM"), OSMLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
# OP.PanelType.NAVIGATION: PanelInfo(tr("Navigation"), NavigationLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
# OP.PanelType.TRIPS: PanelInfo(tr("Trips"), TripsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"),
OP.PanelType.VEHICLE: PanelInfo(tr("Vehicle"), VehicleLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"),
# OP.PanelType.FIREHOSE: PanelInfo(tr("Firehose"), FirehoseLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_firehose.png"),
OP.PanelType.DEVELOPER: PanelInfo(tr("Developer"), DeveloperLayoutSP(), icon="icons/shell.png"),
}
def _draw_sidebar(self, rect: rl.Rectangle):
@@ -28,7 +28,7 @@ class SunnylinkHeader(Widget):
super().__init__()
self._title = UnifiedLabel(
text="🚀 sunnylink 🚀",
text=tr("🚀 sunnylink 🚀"),
font_size=90,
font_weight=FontWeight.AUDIOWIDE,
text_color=rl.WHITE,
@@ -223,14 +223,14 @@ class SunnylinkLayout(Widget):
gui_app.push_widget(self._sunnylink_pairing_dialog)
def _handle_backup_btn(self):
backup_dialog = ConfirmDialog(text=tr("Are you sure you want to backup your current sunnypilot settings?"), confirm_text="Backup",
backup_dialog = ConfirmDialog(text=tr("Are you sure you want to backup your current sunnypilot settings?"), confirm_text=tr("Backup"),
callback=self._backup_handler)
gui_app.push_widget(backup_dialog)
def _handle_restore_btn(self):
self._restore_btn.set_enabled(False)
restore_dialog = ConfirmDialog(text=tr("Are you sure you want to restore the last backed up sunnypilot settings?"),
confirm_text="Restore", callback=self._restore_handler)
confirm_text=tr("Restore"), callback=self._restore_handler)
gui_app.push_widget(restore_dialog)
def _backup_handler(self, dialog_result: int):
+1 -1
View File
@@ -79,7 +79,7 @@ class SidebarSP:
self._sunnylink_status.update(tr_noop("SUNNYLINK"), status, color)
def _draw_metrics_w_sunnylink(self, rect: rl.Rectangle, _temp, _panda, _connect):
metrics = [_temp, _panda, _connect, self._sunnylink_status]
metrics = [_temp, _panda, _connect]
start_y = int(rect.y) + METRIC_START_Y
available_height = max(0, int(HOME_BTN.y) - METRIC_MARGIN - METRIC_HEIGHT - start_y)
spacing = available_height / max(1, len(metrics) - 1)
@@ -7,6 +7,7 @@ See the LICENSE.md file in the root directory for more details.
from collections.abc import Callable
from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationCircleButton
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.mici_setup import GreyBigButton
from openpilot.system.ui.widgets.scroller import NavScroller
@@ -16,14 +17,14 @@ class SunnylinkConsentPage(NavScroller):
def __init__(self, on_accept: Callable | None = None, on_decline: Callable | None = None):
super().__init__()
self._accept_button = BigConfirmationCircleButton("enable\nsunnylink", gui_app.texture("icons_mici/setup/driver_monitoring/dm_check.png", 64, 64),
self._accept_button = BigConfirmationCircleButton(tr("enable\nsunnylink"), gui_app.texture("icons_mici/setup/driver_monitoring/dm_check.png", 64, 64),
on_accept, exit_on_confirm=False)
self._decline_button = BigConfirmationCircleButton("disable\nsunnylink", gui_app.texture("icons_mici/setup/cancel.png", 64, 64),
self._decline_button = BigConfirmationCircleButton(tr("disable\nsunnylink"), gui_app.texture("icons_mici/setup/cancel.png", 64, 64),
on_decline, red=True, exit_on_confirm=False)
self._scroller.add_widgets([
GreyBigButton("sunnylink", "scroll to continue",
GreyBigButton(tr("sunnylink"), "scroll to continue",
gui_app.texture("../../sunnypilot/selfdrive/assets/logo.png", 64, 64)),
GreyBigButton("", "sunnylink enables secured remote access to your comma device from anywhere."),
self._accept_button,

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