mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-07-19 16:52:05 +08:00
Compare commits
161 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a77d1f7eb0 | |||
| 6eb6af5785 | |||
| 7471bd4029 | |||
| 767f057112 | |||
| 6ef47dafcf | |||
| 3f6ac7e77a | |||
| d8040eea3f | |||
| d223135ee3 | |||
| 8f29ddba45 | |||
| b7c3072a4c | |||
| 3cba24f93a | |||
| f2edd589ba | |||
| bf0a7b4494 | |||
| 19b96003dc | |||
| 10ee25d199 | |||
| cd6fb642bd | |||
| 3d35164287 | |||
| a9ca9bbdf8 | |||
| 0737f311b8 | |||
| dc45d3043c | |||
| 2eefd0aaf5 | |||
| cb9d92dc3c | |||
| 2525fdc350 | |||
| 9eb36a0b7e | |||
| b5a5d94a2c | |||
| a93dc0047d | |||
| 25d195df72 | |||
| 3fc2f70eb8 | |||
| 64058c4b7c | |||
| 3044aa6133 | |||
| f39f76182a | |||
| 15567bf605 | |||
| 3b090e0b01 | |||
| df3e848965 | |||
| b3e3d1b384 | |||
| b13356d267 | |||
| 0089096d12 | |||
| 3d135f9831 | |||
| a219046981 | |||
| 2c9ffdbf03 | |||
| 5014b42650 | |||
| c1f897168a | |||
| 301174b19a | |||
| 1b139c4ca1 | |||
| 745e7b0b28 | |||
| 1f328c9fda | |||
| eab69c0f3d | |||
| 97fda2f918 | |||
| 03e10db82e | |||
| 2f5f708c2b | |||
| 413fc15cf8 | |||
| bd8a93af8b | |||
| 928bec2acc | |||
| c08b18936d | |||
| 5f94110b7a | |||
| bca0e7862f | |||
| 45c47d0c48 | |||
| ab8dd45cda | |||
| 66eb3a2532 | |||
| 59b68e42f6 | |||
| 976c9ac9bf | |||
| c65c8a535c | |||
| 5e79eb774b | |||
| 0735fd5553 | |||
| 5ad8b46158 | |||
| 3f4e372c34 | |||
| 7fde68ecf9 | |||
| df1ef23280 | |||
| 378eb8a4d2 | |||
| 40259cd22a | |||
| 3f29ccbd99 | |||
| 189e883116 | |||
| 01e06df542 | |||
| b1e8824187 | |||
| cb1240846b | |||
| fa6ee806f5 | |||
| fefb6a3a25 | |||
| 13cb725652 | |||
| b219e07ac1 | |||
| 90d38a7968 | |||
| bb83e1fe8f | |||
| baf0506033 | |||
| a3db53044e | |||
| 8673c31e46 | |||
| 5f2396d490 | |||
| e2ff34417f | |||
| 4ac4fc855f | |||
| cea20d1945 | |||
| 353aa611e7 | |||
| 391a3160a0 | |||
| 6b4ef00ae6 | |||
| d937062724 | |||
| f94eeb9780 | |||
| c6474fc3ad | |||
| d7f0e8dd04 | |||
| f3d94fc291 | |||
| c205497b15 | |||
| 45f3c70596 | |||
| 21793721cc | |||
| d01b02b185 | |||
| f4af0aa422 | |||
| d3ecdbb850 | |||
| 1f39c4ccfb | |||
| a56e1e6e69 | |||
| e630546250 | |||
| 85faddc7af | |||
| 223abdc536 | |||
| dd12f86804 | |||
| dff2a5796d | |||
| 70918ccff3 | |||
| f6ef036158 | |||
| 67692babdc | |||
| ea6cd3429b | |||
| 635b15f2bc | |||
| b42c060b2e | |||
| 1c1ef06489 | |||
| 1b2586914f | |||
| a8deaa69b8 | |||
| c34a21980e | |||
| 6e86d242cd | |||
| 7113d4a76a | |||
| 5074881d6d | |||
| bf3350b7f2 | |||
| c64b679704 | |||
| f645e2cdb0 | |||
| 426d41a0a7 | |||
| de305a81d5 | |||
| e4c29a2c58 | |||
| c3fde45000 | |||
| e7d27f0bb9 | |||
| 12981e02f7 | |||
| e1cf216c89 | |||
| cc507a5cd9 | |||
| 87ca1513f4 | |||
| 1d422ce5cf | |||
| cb04017945 | |||
| 7d6c9d1a8c | |||
| ba6559d32a | |||
| c0c74e3761 | |||
| 898f5b89ed | |||
| f861e8d678 | |||
| fd6ec85e20 | |||
| 4a46bccc20 | |||
| 73e658bf8c | |||
| ec25ca070a | |||
| 84b6af094f | |||
| 55b6eae92e | |||
| 760e7e847a | |||
| 4b64f85f85 | |||
| 8dd750fd83 | |||
| 5e62ccad12 | |||
| 2fb0545344 | |||
| 684431e3f6 | |||
| ba9fbd52d7 | |||
| 1dfaf347f8 | |||
| 91922fb9b6 | |||
| c4ed5a4617 | |||
| 90435f0a92 | |||
| 3c434e78e2 | |||
| 75f6f73798 | |||
| c5524c6d42 |
@@ -1,3 +1,2 @@
|
||||
Wen
|
||||
REGIST
|
||||
PullRequest
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
name: Nightly Branch Reset and PR Squash
|
||||
|
||||
env:
|
||||
DEFAULT_SOURCE_BRANCH: "master-new"
|
||||
DEFAULT_TARGET_BRANCH: "nightly"
|
||||
PR_LABEL: "dev-c3"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_branch:
|
||||
description: 'Source branch to reset from'
|
||||
required: true
|
||||
default: 'master-new'
|
||||
type: string
|
||||
target_branch:
|
||||
description: 'Target branch to reset and squash into'
|
||||
required: true
|
||||
default: 'master-dev-c3-new'
|
||||
type: string
|
||||
# schedule:
|
||||
# - cron: '0 0 * * *' # Run at midnight UTC for nightly
|
||||
|
||||
jobs:
|
||||
reset-and-squash:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all branches
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install PyGithub
|
||||
|
||||
- name: Check branches exist
|
||||
run: |
|
||||
# Check if source branch exists
|
||||
if ! git ls-remote --heads origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} | grep -q "${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"; then
|
||||
echo "Source branch ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }} does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure we have the latest source branch
|
||||
git fetch origin ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
|
||||
# Check if target branch exists
|
||||
if ! git ls-remote --heads origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} | grep -q "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"; then
|
||||
echo "Target branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} does not exist, creating it from ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
||||
git checkout -b ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
git push origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
||||
else
|
||||
# Fetch target branch if it exists
|
||||
git fetch origin ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}
|
||||
fi
|
||||
|
||||
- name: Reset target branch
|
||||
run: |
|
||||
echo "Resetting ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} to match ${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}"
|
||||
# Delete if exists and recreate pointing to source
|
||||
git branch -D ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} || true
|
||||
git branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} origin/${{ inputs.source_branch || env.DEFAULT_SOURCE_BRANCH }}
|
||||
|
||||
- name: Get PRs to squash
|
||||
id: get-prs
|
||||
run: |
|
||||
# Use GitHub API to get PRs with specific label, ordered by creation date
|
||||
PR_LIST=$(gh api graphql -f query='
|
||||
query($label:String!) {
|
||||
search(query: $label, type:ISSUE, first:100) {
|
||||
nodes {
|
||||
... on PullRequest {
|
||||
number
|
||||
headRefName
|
||||
title
|
||||
createdAt
|
||||
commits(last: 1) {
|
||||
nodes {
|
||||
commit {
|
||||
statusCheckRollup {
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -F label="is:pr is:open label:${PR_LABEL} sort:created-asc")
|
||||
|
||||
echo "PR_LIST=${PR_LIST}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Process PRs
|
||||
run: |
|
||||
python3 ${{ github.workspace }}/release/ci/squash_and_merge_prs.py \
|
||||
--pr-data '${{ steps.get-prs.outputs.PR_LIST }}' \
|
||||
--target-branch ${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }} \
|
||||
--squash-script-path '${{ github.workspace }}/release/ci/squash_and_merge.py'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push changes if there are diffs
|
||||
id: push-changes # Add an id so we can reference this step
|
||||
run: |
|
||||
TARGET_BRANCH="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
|
||||
# Fetch the latest from remote
|
||||
git fetch origin $TARGET_BRANCH
|
||||
|
||||
# Check for diffs between local and remote
|
||||
if git diff $TARGET_BRANCH origin/$TARGET_BRANCH --quiet; then
|
||||
echo "No changes to push - local and remote branches are identical"
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If we get here, there are diffs, so push
|
||||
if ! git push origin $TARGET_BRANCH --force; then
|
||||
echo "Failed to push changes to $TARGET_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Branch $TARGET_BRANCH has been reset and updated with squashed PRs"
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Trigger and wait for selfdrive tests
|
||||
if: steps.push-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
echo "Triggering selfdrive tests..."
|
||||
gh workflow run selfdrive_tests.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
|
||||
echo "Sleeping for 120s to give plenty of time for the action to start and then we wait"
|
||||
sleep 120
|
||||
|
||||
echo "Getting latest run ID..."
|
||||
RUN_ID=$(gh run list --workflow=selfdrive_tests.yaml --branch="${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}" --limit=1 --json databaseId --jq '.[0].databaseId')
|
||||
|
||||
echo "Watching run ID: $RUN_ID"
|
||||
gh run watch "$RUN_ID"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Trigger prebuilt workflow
|
||||
if: success() && steps.push-changes.outputs.has_changes == 'true'
|
||||
run: |
|
||||
gh workflow run sunnypilot-build-prebuilt.yaml --ref "${{ inputs.target_branch || env.DEFAULT_TARGET_BRANCH }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
run: >-
|
||||
sudo apt-get install -y imagemagick
|
||||
|
||||
scenes="homescreen settings_device settings_network settings_network_advanced settings_software settings_sunnylink settings_toggles settings_sunnypilot settings_sunnypilot_mads settings_trips settings_developer offroad_alert update_available prime onroad onroad_disengaged onroad_override onroad_sidebar onroad_wide onroad_wide_sidebar onroad_alert_small onroad_alert_mid onroad_alert_full driver_camera body keyboard keyboard_uppercase"
|
||||
scenes="homescreen settings_device settings_software settings_sunnylink settings_toggles settings_sunnypilot settings_sunnypilot_mads settings_trips settings_developer offroad_alert update_available prime onroad onroad_disengaged onroad_override onroad_sidebar onroad_wide onroad_wide_sidebar onroad_alert_small onroad_alert_mid onroad_alert_full driver_camera body keyboard keyboard_uppercase"
|
||||
A=($scenes)
|
||||
|
||||
DIFF=""
|
||||
|
||||
+18
-52
@@ -10,23 +10,23 @@ $Cxx.namespace("cereal");
|
||||
# DO rename the structs
|
||||
# DON'T change the identifier (e.g. @0x81c2f05a394cf4af)
|
||||
|
||||
struct ModularAssistiveDrivingSystem {
|
||||
state @0 :ModularAssistiveDrivingSystemState;
|
||||
enabled @1 :Bool;
|
||||
active @2 :Bool;
|
||||
available @3 :Bool;
|
||||
|
||||
enum ModularAssistiveDrivingSystemState {
|
||||
disabled @0;
|
||||
paused @1;
|
||||
enabled @2;
|
||||
softDisabling @3;
|
||||
overriding @4;
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfdriveStateSP @0x81c2f05a394cf4af {
|
||||
mads @0 :ModularAssistiveDrivingSystem;
|
||||
|
||||
struct ModularAssistiveDrivingSystem {
|
||||
state @0 :ModularAssistiveDrivingSystemState;
|
||||
enabled @1 :Bool;
|
||||
active @2 :Bool;
|
||||
available @3 :Bool;
|
||||
|
||||
enum ModularAssistiveDrivingSystemState {
|
||||
disabled @0;
|
||||
paused @1;
|
||||
enabled @2;
|
||||
softDisabling @3;
|
||||
overriding @4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||
@@ -81,7 +81,6 @@ struct ModelManagerSP @0xaedffd8f31e7b55d {
|
||||
generation @5 :UInt32;
|
||||
environment @6 :Text;
|
||||
runner @7 :Runner;
|
||||
is20hz @8 :Bool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,46 +99,13 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
}
|
||||
}
|
||||
|
||||
struct OnroadEventSP @0xda96579883444c35 {
|
||||
name @0 :EventName;
|
||||
|
||||
# event types
|
||||
enable @1 :Bool;
|
||||
noEntry @2 :Bool;
|
||||
warning @3 :Bool; # alerts presented only when enabled or soft disabling
|
||||
userDisable @4 :Bool;
|
||||
softDisable @5 :Bool;
|
||||
immediateDisable @6 :Bool;
|
||||
preEnable @7 :Bool;
|
||||
permanent @8 :Bool; # alerts presented regardless of openpilot state
|
||||
overrideLateral @10 :Bool;
|
||||
overrideLongitudinal @9 :Bool;
|
||||
|
||||
enum EventName {
|
||||
lkasEnable @0;
|
||||
lkasDisable @1;
|
||||
manualSteeringRequired @2;
|
||||
manualLongitudinalRequired @3;
|
||||
silentLkasEnable @4;
|
||||
silentLkasDisable @5;
|
||||
silentBrakeHold @6;
|
||||
silentWrongGear @7;
|
||||
silentReverseGear @8;
|
||||
silentDoorOpen @9;
|
||||
silentSeatbeltNotLatched @10;
|
||||
silentParkBrake @11;
|
||||
controlsMismatchLateral @12;
|
||||
hyundaiRadarTracksConfirmed @13;
|
||||
experimentalModeSwitched @14;
|
||||
}
|
||||
struct CustomReserved3 @0xda96579883444c35 {
|
||||
}
|
||||
|
||||
struct CarParamsSP @0x80ae746ee2596b11 {
|
||||
flags @0 :UInt32; # flags for car specific quirks in sunnypilot
|
||||
struct CustomReserved4 @0x80ae746ee2596b11 {
|
||||
}
|
||||
|
||||
struct CarControlSP @0xa5cd762cd951a455 {
|
||||
mads @0 :ModularAssistiveDrivingSystem;
|
||||
struct CustomReserved5 @0xa5cd762cd951a455 {
|
||||
}
|
||||
|
||||
struct CustomReserved6 @0xf98d843bfd7004a3 {
|
||||
|
||||
+79
-4
@@ -125,6 +125,81 @@ struct OnroadEvent @0xc4fa6047f024e718 {
|
||||
espActive @90;
|
||||
personalityChanged @91;
|
||||
aeb @92;
|
||||
eventReserved93 @93;
|
||||
eventReserved94 @94;
|
||||
eventReserved95 @95;
|
||||
eventReserved96 @96;
|
||||
eventReserved97 @97;
|
||||
eventReserved98 @98;
|
||||
eventReserved99 @99;
|
||||
eventReserved100 @100;
|
||||
eventReserved101 @101;
|
||||
eventReserved102 @102;
|
||||
eventReserved103 @103;
|
||||
eventReserved104 @104;
|
||||
eventReserved105 @105;
|
||||
eventReserved106 @106;
|
||||
eventReserved107 @107;
|
||||
eventReserved108 @108;
|
||||
eventReserved109 @109;
|
||||
eventReserved110 @110;
|
||||
eventReserved111 @111;
|
||||
eventReserved112 @112;
|
||||
eventReserved113 @113;
|
||||
eventReserved114 @114;
|
||||
eventReserved115 @115;
|
||||
eventReserved116 @116;
|
||||
eventReserved117 @117;
|
||||
eventReserved118 @118;
|
||||
eventReserved119 @119;
|
||||
eventReserved120 @120;
|
||||
eventReserved121 @121;
|
||||
eventReserved122 @122;
|
||||
eventReserved123 @123;
|
||||
eventReserved124 @124;
|
||||
eventReserved125 @125;
|
||||
eventReserved126 @126;
|
||||
eventReserved127 @127;
|
||||
eventReserved128 @128;
|
||||
eventReserved129 @129;
|
||||
eventReserved130 @130;
|
||||
eventReserved131 @131;
|
||||
eventReserved132 @132;
|
||||
eventReserved133 @133;
|
||||
eventReserved134 @134;
|
||||
eventReserved135 @135;
|
||||
eventReserved136 @136;
|
||||
eventReserved137 @137;
|
||||
eventReserved138 @138;
|
||||
eventReserved139 @139;
|
||||
eventReserved140 @140;
|
||||
eventReserved141 @141;
|
||||
eventReserved142 @142;
|
||||
eventReserved143 @143;
|
||||
eventReserved144 @144;
|
||||
eventReserved145 @145;
|
||||
eventReserved146 @146;
|
||||
eventReserved147 @147;
|
||||
eventReserved148 @148;
|
||||
eventReserved149 @149;
|
||||
eventReserved150 @150;
|
||||
|
||||
# sunnypilot
|
||||
lkasEnable @151;
|
||||
lkasDisable @152;
|
||||
manualSteeringRequired @153;
|
||||
manualLongitudinalRequired @154;
|
||||
silentLkasEnable @155;
|
||||
silentLkasDisable @156;
|
||||
silentBrakeHold @157;
|
||||
silentWrongGear @158;
|
||||
silentReverseGear @159;
|
||||
silentDoorOpen @160;
|
||||
silentSeatbeltNotLatched @161;
|
||||
silentParkBrake @162;
|
||||
controlsMismatchLateral @163;
|
||||
hyundaiRadarTracksConfirmed @164;
|
||||
experimentalModeSwitched @165;
|
||||
|
||||
soundsUnavailableDEPRECATED @47;
|
||||
}
|
||||
@@ -590,6 +665,7 @@ struct PandaState @0xa7649e2575e4591e {
|
||||
|
||||
# safety stuff
|
||||
controlsAllowed @3 :Bool;
|
||||
controlsAllowedLat @5 :Bool;
|
||||
safetyRxInvalid @19 :UInt32;
|
||||
safetyTxBlocked @24 :UInt32;
|
||||
safetyModel @14 :Car.CarParams.SafetyModel;
|
||||
@@ -697,7 +773,6 @@ struct PandaState @0xa7649e2575e4591e {
|
||||
}
|
||||
|
||||
gasInterceptorDetectedDEPRECATED @4 :Bool;
|
||||
startedSignalDetectedDEPRECATED @5 :Bool;
|
||||
hasGpsDEPRECATED @6 :Bool;
|
||||
gmlanSendErrsDEPRECATED @9 :UInt32;
|
||||
fanSpeedRpmDEPRECATED @11 :UInt16;
|
||||
@@ -2568,9 +2643,9 @@ struct Event {
|
||||
selfdriveStateSP @107 :Custom.SelfdriveStateSP;
|
||||
modelManagerSP @108 :Custom.ModelManagerSP;
|
||||
longitudinalPlanSP @109 :Custom.LongitudinalPlanSP;
|
||||
onroadEventsSP @110 :List(Custom.OnroadEventSP);
|
||||
carParamsSP @111 :Custom.CarParamsSP;
|
||||
carControlSP @112 :Custom.CarControlSP;
|
||||
customReserved3 @110 :Custom.CustomReserved3;
|
||||
customReserved4 @111 :Custom.CustomReserved4;
|
||||
customReserved5 @112 :Custom.CustomReserved5;
|
||||
customReserved6 @113 :Custom.CustomReserved6;
|
||||
customReserved7 @114 :Custom.CustomReserved7;
|
||||
customReserved8 @115 :Custom.CustomReserved8;
|
||||
|
||||
@@ -78,9 +78,6 @@ _services: dict[str, tuple] = {
|
||||
"modelManagerSP": (False, 1., 1),
|
||||
"selfdriveStateSP": (True, 100., 10),
|
||||
"longitudinalPlanSP": (True, 20., 10),
|
||||
"onroadEventsSP": (True, 1., 1),
|
||||
"carParamsSP": (True, 0.02, 1),
|
||||
"carControlSP": (True, 100., 10),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
|
||||
@@ -8,7 +8,6 @@ import uuid
|
||||
import socket
|
||||
import logging
|
||||
import traceback
|
||||
import numpy as np
|
||||
from threading import local
|
||||
from collections import OrderedDict
|
||||
from contextlib import contextmanager
|
||||
@@ -16,8 +15,6 @@ from contextlib import contextmanager
|
||||
LOG_TIMESTAMPS = "LOG_TIMESTAMPS" in os.environ
|
||||
|
||||
def json_handler(obj):
|
||||
if isinstance(obj, np.bool_):
|
||||
return bool(obj)
|
||||
# if isinstance(obj, (datetime.date, datetime.time)):
|
||||
# return obj.isoformat()
|
||||
return repr(obj)
|
||||
|
||||
@@ -89,7 +89,6 @@ private:
|
||||
|
||||
std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG},
|
||||
{"AdbEnabled", PERSISTENT},
|
||||
{"AlwaysOnDM", PERSISTENT},
|
||||
{"ApiCache_Device", PERSISTENT},
|
||||
{"AssistNowToken", PERSISTENT},
|
||||
@@ -203,13 +202,8 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
|
||||
// --- sunnypilot params --- //
|
||||
{"ApiCache_DriveStats", PERSISTENT},
|
||||
{"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"CarParamsSPCache", CLEAR_ON_MANAGER_START},
|
||||
{"CarParamsSPPersistent", PERSISTENT},
|
||||
{"EnableGithubRunner", PERSISTENT | BACKUP},
|
||||
{"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION},
|
||||
{"OffroadMode", CLEAR_ON_MANAGER_START},
|
||||
{"OffroadMode_Status", CLEAR_ON_MANAGER_START},
|
||||
|
||||
// MADS params
|
||||
{"Mads", PERSISTENT | BACKUP},
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|26 mph|25 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|26 mph|12 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-21">Buy Here</a></sub></details>||
|
||||
|Acura|RDX 2019-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Acura&model=RDX 2019-22">Buy Here</a></sub></details>||
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|
||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|
||||
@@ -128,7 +128,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Kia|Carnival 2022-24[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|Carnival (China only) 2023[<sup>5</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019-21">Buy Here</a></sub></details>||
|
||||
|Kia|Ceed 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>5</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (with HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
|Kia|EV6 (without HDA II) 2022-24[<sup>5</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Kia&model=EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>||
|
||||
@@ -260,7 +260,7 @@ A supported vehicle is one that just works when you install a comma device. All
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|
||||
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Toyota|RAV4 Hybrid 2023-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=RAV4 Hybrid 2023-24">Buy Here</a></sub></details>||
|
||||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Toyota&model=Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[](##)|[](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|
||||
|
||||
@@ -63,12 +63,3 @@ A good pull request has all of the following:
|
||||
* Connect your device to Wi-Fi regularly, so that we can pull data for training better driving models.
|
||||
* Run the `nightly` branch and report issues. This branch is like `master` but it's built just like a release.
|
||||
* Annotate images in the [comma10k dataset](https://github.com/commaai/comma10k).
|
||||
|
||||
## Contributing Training Data
|
||||
|
||||
### A guide for forks
|
||||
|
||||
In order for your fork's data to be eligible for the training set:
|
||||
* **Your cereal messaging structs must be [compatible](../cereal#custom-forks)**
|
||||
* **The definitions of all the stock messaging structs must not change**: Do not change how any of the fields are set, including everything from `selfdriveState.enabled` to `carState.steeringAngleDeg`. Instead, create your own structs and set them however you'd like.
|
||||
* **Do not include cars that are not supported in upstream platforms**: Instead, create new opendbc platforms for cars that you'd like to support outside of upstream, even if it's just a trim-level difference.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
|
||||
if [ -z "$AGNOS_VERSION" ]; then
|
||||
export AGNOS_VERSION="11.6"
|
||||
export AGNOS_VERSION="11.4"
|
||||
fi
|
||||
|
||||
export STAGING_ROOT="/data/safe_staging"
|
||||
|
||||
+1
-1
Submodule msgq_repo updated: 102befe731...5bb86f8bc7
+1
-1
Submodule opendbc_repo updated: a280fed7a3...038c84a84e
+1
-1
Submodule panda updated: 4ca963345a...d3252abcc4
+1
-1
@@ -165,7 +165,7 @@ testpaths = [
|
||||
[tool.codespell]
|
||||
quiet-level = 3
|
||||
# if you've got a short variable name that's getting flagged, add it here
|
||||
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead,TGE,abl"
|
||||
ignore-words-list = "bu,ro,te,ue,alo,hda,ois,nam,nams,ned,som,parm,setts,inout,warmup,bumb,nd,sie,preints,whit,indexIn,ws,uint,grey,deque,stdio,amin,BA,LITE,atEnd,UIs,errorString,arange,FocusIn,od,tim,relA,hist,copyable,jupyter,thead"
|
||||
builtin = "clear,rare,informal,code,names,en-GB_to_en-US"
|
||||
skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, ./opendbc/*, ./opendbc_repo/*, ./rednose/*, ./rednose_repo/*, ./teleoprtc/*, ./teleoprtc_repo/*, *.ts, uv.lock, *.onnx, ./cereal/gen/*, */c_generated_code/*"
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ def workspace_manager(original_branch: str):
|
||||
if temp_branch:
|
||||
run_command(f"git branch -D {temp_branch}")
|
||||
print("\nOperation interrupted, but changes were already restored.")
|
||||
sys.exit(3)
|
||||
sys.exit(1)
|
||||
|
||||
# First, switch back to original branch
|
||||
current = get_current_branch()
|
||||
@@ -139,12 +139,12 @@ def workspace_manager(original_branch: str):
|
||||
|
||||
if signum:
|
||||
print("\nOperation interrupted. Cleaned up and restored original state.")
|
||||
sys.exit(4)
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during cleanup: {e}")
|
||||
if signum:
|
||||
sys.exit(5)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
# Set up signal handlers
|
||||
@@ -275,7 +275,7 @@ def squash_and_merge(source_branch: str, target_branch: str, manual_title: str |
|
||||
return False
|
||||
|
||||
print(f"Attempting to merge changes from {temp_branch}...")
|
||||
code, _, error = run_command(f"git rebase {temp_branch}")
|
||||
code, _, error = run_command(f"git merge {temp_branch}")
|
||||
|
||||
if code != 0:
|
||||
print(f"\nMerge failed with error: {error}")
|
||||
@@ -344,7 +344,7 @@ def main():
|
||||
parser.add_argument('--push', action='store_true',
|
||||
help='Push changes to remote after squashing')
|
||||
|
||||
args, unknown = parser.parse_known_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
# Determine source branch early
|
||||
source_branch = args.source
|
||||
@@ -354,7 +354,7 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
if not squash_and_merge(source_branch, args.target, args.title, args.backup, args.push):
|
||||
sys.exit(2)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def setup_argument_parser():
|
||||
parser = argparse.ArgumentParser(description='Process and squash GitHub PRs')
|
||||
parser.add_argument('--pr-data', type=str, help='PR data in JSON format')
|
||||
parser.add_argument('--source-branch', type=str, default='master-new',
|
||||
help='Source branch for merging')
|
||||
parser.add_argument('--target-branch', type=str, default='master-dev-c3-new-test',
|
||||
help='Target branch for merging')
|
||||
parser.add_argument('--squash-script-path', type=str, required=True,
|
||||
help='Path to the squash_and_merge.py script')
|
||||
return parser
|
||||
|
||||
|
||||
def validate_squash_script(script_path):
|
||||
if not os.path.isfile(script_path):
|
||||
raise FileNotFoundError(f"Squash script not found at: {script_path}")
|
||||
if not os.access(script_path, os.X_OK):
|
||||
raise PermissionError(f"Squash script is not executable: {script_path}")
|
||||
|
||||
|
||||
def sort_prs_by_creation(pr_data):
|
||||
"""Sort PRs by creation date"""
|
||||
nodes = (pr_data.get('data', {}).get('search', {}).get('nodes', []))
|
||||
|
||||
return sorted(
|
||||
nodes,
|
||||
key=lambda x: datetime.fromisoformat(x.get('createdAt', '').replace('Z', '+00:00'))
|
||||
)
|
||||
|
||||
|
||||
def add_pr_comment(pr_number, comment):
|
||||
"""Add a comment to a PR using gh cli"""
|
||||
try:
|
||||
subprocess.run(
|
||||
['gh', 'pr', 'comment', str(pr_number), '--body', comment],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to add comment to PR #{pr_number}: {e.stderr}")
|
||||
|
||||
|
||||
def validate_pr(pr):
|
||||
"""Validate a PR and return (is_valid, skip_reason)"""
|
||||
pr_number = pr.get('number', 'UNKNOWN')
|
||||
branch = pr.get('headRefName', '')
|
||||
|
||||
if not branch:
|
||||
return False, f"Missing branch name for PR #{pr_number}"
|
||||
|
||||
# Check if checks have passed
|
||||
commits = pr.get('commits', {}).get('nodes', [])
|
||||
if not commits:
|
||||
return False, "No commit data found"
|
||||
|
||||
status = commits[0].get('commit', {}).get('statusCheckRollup', {})
|
||||
if not status or status.get('state') != 'SUCCESS':
|
||||
return False, "Not all checks have passed"
|
||||
|
||||
# Check for merge conflicts
|
||||
merge_status = subprocess.run(['gh', 'pr', 'view', str(pr_number), '--json', 'mergeable,mergeStateStatus'], capture_output=True, text=True)
|
||||
merge_data = json.loads(merge_status.stdout)
|
||||
if not merge_data.get('mergeable'):
|
||||
return False, "Merge conflicts detected"
|
||||
|
||||
if (mergeStateStatus := merge_data.get('mergeStateStatus')) == "BEHIND":
|
||||
return False, f"Branch is `{mergeStateStatus}`"
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
def process_pr(pr_data, source_branch, target_branch, squash_script_path):
|
||||
try:
|
||||
nodes = sort_prs_by_creation(pr_data)
|
||||
if not nodes:
|
||||
print("No PRs to squash")
|
||||
return 0
|
||||
|
||||
print(f"Deleting target branch {target_branch}")
|
||||
subprocess.run(['git', 'branch', '-D', target_branch], check=False)
|
||||
subprocess.run(['git', 'branch', target_branch, f'origin/{source_branch}'], check=True)
|
||||
success_count = 0
|
||||
for pr in nodes:
|
||||
pr_number = pr.get('number', 'UNKNOWN')
|
||||
branch = pr.get('headRefName', '')
|
||||
title = pr.get('title', '')
|
||||
is_valid, skip_reason = validate_pr(pr)
|
||||
|
||||
if not is_valid:
|
||||
print(f"Warning: {skip_reason} for PR #{pr_number}, skipping")
|
||||
add_pr_comment(pr_number, f"⚠️ This PR was skipped in the automated `{target_branch}` squash because {skip_reason}.")
|
||||
continue
|
||||
|
||||
try:
|
||||
# Fetch PR branch
|
||||
subprocess.run(['git', 'fetch', 'origin', branch], check=True)
|
||||
# Delete branch if it exists (ignore errors if it doesn't)
|
||||
subprocess.run(['git', 'branch', '-D', branch], check=False)
|
||||
# Create new branch pointing to origin's branch
|
||||
subprocess.run(['git', 'branch', branch, f'origin/{branch}'], check=True)
|
||||
|
||||
# Run squash script
|
||||
subprocess.run([
|
||||
squash_script_path,
|
||||
'--target', target_branch,
|
||||
'--source', branch,
|
||||
'--title', f"{title} (#{pr_number})",
|
||||
], check=True)
|
||||
|
||||
print(f"Successfully processed PR #{pr_number}")
|
||||
success_count += 1
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error processing PR #{pr_number}:")
|
||||
print(f"Command failed with exit code {e.returncode}")
|
||||
error_output = getattr(e, 'stderr', 'No error output available')
|
||||
print(f"Error output: {error_output}")
|
||||
add_pr_comment(pr_number, f"⚠️ Error during automated {target_branch} squash:\n```\n{error_output}\n```")
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"Unexpected error processing PR #{pr_number}: {str(e)}")
|
||||
continue
|
||||
|
||||
return success_count
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"Error in process_pr: {str(e)}")
|
||||
print("Full traceback:")
|
||||
print(traceback.format_exc())
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = setup_argument_parser()
|
||||
try:
|
||||
args = parser.parse_args()
|
||||
validate_squash_script(args.squash_script_path)
|
||||
pr_data_json = json.loads(args.pr_data)
|
||||
|
||||
# Process the PRs
|
||||
success_count = process_pr(pr_data_json, args.source_branch, args.target_branch, args.squash_script_path)
|
||||
print(f"Successfully processed {success_count} PRs")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fatal error: {str(e)}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+12
-31
@@ -5,7 +5,7 @@ import threading
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log, custom
|
||||
from cereal import car, log
|
||||
|
||||
from panda import ALTERNATIVE_EXPERIENCE
|
||||
|
||||
@@ -21,7 +21,6 @@ from opendbc.car.interfaces import CarInterfaceBase, RadarInterfaceBase
|
||||
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
|
||||
from openpilot.selfdrive.car.cruise import VCruiseHelper
|
||||
from openpilot.selfdrive.car.car_specific import MockCarState
|
||||
from openpilot.selfdrive.car.helpers import convert_carControlSP, convert_to_capnp
|
||||
|
||||
from openpilot.sunnypilot.mads.mads import MadsParams
|
||||
from openpilot.sunnypilot.selfdrive.car import interfaces
|
||||
@@ -67,13 +66,11 @@ class Car:
|
||||
CI: CarInterfaceBase
|
||||
RI: RadarInterfaceBase
|
||||
CP: car.CarParams
|
||||
CP_SP: structs.CarParamsSP
|
||||
CP_SP_capnp: custom.CarParamsSP
|
||||
|
||||
def __init__(self, CI=None, RI=None) -> None:
|
||||
self.can_sock = messaging.sub_sock('can', timeout=20)
|
||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'] + ['carControlSP'])
|
||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'] + ['carParamsSP'])
|
||||
self.sm = messaging.SubMaster(['pandaStates', 'carControl', 'onroadEvents'])
|
||||
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'liveTracks'])
|
||||
|
||||
self.can_rcv_cum_timeout_counter = 0
|
||||
|
||||
@@ -105,15 +102,14 @@ class Car:
|
||||
cached_params = _cached_params
|
||||
|
||||
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params)
|
||||
interfaces.setup_car_interface_sp(self.CI.CP, self.CI.CP_SP, self.params)
|
||||
self.RI = get_radar_interface(self.CI.CP, self.CI.CP_SP)
|
||||
interfaces.setup_car_interface_sp(self.CI.CP, self.params)
|
||||
self.RI = get_radar_interface(self.CI.CP)
|
||||
self.CP = self.CI.CP
|
||||
self.CP_SP = self.CI.CP_SP
|
||||
|
||||
# continue onto next fingerprinting step in pandad
|
||||
self.params.put_bool("FirmwareQueryDone", True)
|
||||
else:
|
||||
self.CI, self.CP, self.CP_SP = CI, CI.CP, CI.CP_SP
|
||||
self.CI, self.CP = CI, CI.CP
|
||||
self.RI = RI
|
||||
|
||||
# set alternative experiences from parameters
|
||||
@@ -124,7 +120,7 @@ class Car:
|
||||
|
||||
# mads
|
||||
MadsParams().set_alternative_experience(self.CP)
|
||||
MadsParams().set_car_specific_params(self.CP, self.CP_SP)
|
||||
MadsParams().set_car_specific_params(self.CP)
|
||||
|
||||
# Dynamic Experimental Control
|
||||
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
|
||||
@@ -171,14 +167,6 @@ class Car:
|
||||
self.params.put_nonblocking("CarParamsCache", cp_bytes)
|
||||
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
|
||||
|
||||
# Write CarParamsSP for controls
|
||||
# convert to pycapnp representation for caching and logging
|
||||
self.CP_SP_capnp = convert_to_capnp(self.CP_SP)
|
||||
cp_sp_bytes = self.CP_SP_capnp.to_bytes()
|
||||
self.params.put("CarParamsSP", cp_sp_bytes)
|
||||
self.params.put_nonblocking("CarParamsSPCache", cp_sp_bytes)
|
||||
self.params.put_nonblocking("CarParamsSPPersistent", cp_sp_bytes)
|
||||
|
||||
self.mock_carstate = MockCarState()
|
||||
self.v_cruise_helper = VCruiseHelper(self.CP)
|
||||
|
||||
@@ -257,28 +245,21 @@ class Car:
|
||||
tracks_msg.liveTracks = RD
|
||||
self.pm.send('liveTracks', tracks_msg)
|
||||
|
||||
# carParamsSP - logged every 50 seconds (> 1 per segment)
|
||||
if self.sm.frame % int(50. / DT_CTRL) == 0:
|
||||
cp_sp_send = messaging.new_message('carParamsSP')
|
||||
cp_sp_send.valid = True
|
||||
cp_sp_send.carParamsSP = self.CP_SP_capnp
|
||||
self.pm.send('carParamsSP', cp_sp_send)
|
||||
|
||||
def controls_update(self, CS: car.CarState, CC: car.CarControl, CC_SP: custom.CarControlSP):
|
||||
def controls_update(self, CS: car.CarState, CC: car.CarControl):
|
||||
"""control update loop, driven by carControl"""
|
||||
|
||||
if not self.initialized_prev:
|
||||
# Initialize CarInterface, once controls are ready
|
||||
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
|
||||
self.CI.init(self.CP, self.CP_SP, *self.can_callbacks)
|
||||
interfaces.initialize_car_interface_sp(self.CP, self.CP_SP, self.params, *self.can_callbacks)
|
||||
self.CI.init(self.CP, *self.can_callbacks)
|
||||
interfaces.initialize_car_interface_sp(self.CP, self.params, *self.can_callbacks)
|
||||
# signal pandad to switch to car safety mode
|
||||
self.params.put_bool_nonblocking("ControlsReady", True)
|
||||
|
||||
if self.sm.all_alive(['carControl']):
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
self.last_actuators_output, can_sends = self.CI.apply(CC, convert_carControlSP(CC_SP), now_nanos)
|
||||
self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
|
||||
|
||||
self.CC_prev = CC
|
||||
@@ -291,7 +272,7 @@ class Car:
|
||||
initialized = (not any(e.name == EventName.selfdriveInitializing for e in self.sm['onroadEvents']) and
|
||||
self.sm.seen['onroadEvents'])
|
||||
if not self.CP.passive and initialized:
|
||||
self.controls_update(CS, self.sm['carControl'], self.sm['carControlSP'])
|
||||
self.controls_update(CS, self.sm['carControl'])
|
||||
|
||||
self.initialized_prev = initialized
|
||||
self.CS_prev = CS
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
import capnp
|
||||
from typing import Any
|
||||
|
||||
from cereal import custom
|
||||
from opendbc.car import structs
|
||||
|
||||
_FIELDS = '__dataclass_fields__' # copy of dataclasses._FIELDS
|
||||
|
||||
|
||||
def is_dataclass(obj):
|
||||
"""Similar to dataclasses.is_dataclass without instance type check checking"""
|
||||
return hasattr(obj, _FIELDS)
|
||||
|
||||
|
||||
def _asdictref_inner(obj) -> dict[str, Any] | Any:
|
||||
if is_dataclass(obj):
|
||||
ret = {}
|
||||
for field in getattr(obj, _FIELDS): # similar to dataclasses.fields()
|
||||
ret[field] = _asdictref_inner(getattr(obj, field))
|
||||
return ret
|
||||
elif isinstance(obj, (tuple, list)):
|
||||
return type(obj)(_asdictref_inner(v) for v in obj)
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def asdictref(obj) -> dict[str, Any]:
|
||||
"""
|
||||
Similar to dataclasses.asdict without recursive type checking and copy.deepcopy
|
||||
Note that the resulting dict will contain references to the original struct as a result
|
||||
"""
|
||||
if not is_dataclass(obj):
|
||||
raise TypeError("asdictref() should be called on dataclass instances")
|
||||
|
||||
return _asdictref_inner(obj)
|
||||
|
||||
|
||||
def convert_to_capnp(struct: structs.CarParamsSP) -> capnp.lib.capnp._DynamicStructBuilder:
|
||||
struct_dict = asdictref(struct)
|
||||
|
||||
if isinstance(struct, structs.CarParamsSP):
|
||||
struct_capnp = custom.CarParamsSP.new_message(**struct_dict)
|
||||
else:
|
||||
raise ValueError(f"Unsupported struct type: {type(struct)}")
|
||||
|
||||
return struct_capnp
|
||||
|
||||
|
||||
def convert_carControlSP(struct: capnp.lib.capnp._DynamicStructReader) -> structs.CarControlSP:
|
||||
# TODO: recursively handle any car struct as needed
|
||||
def remove_deprecated(s: dict) -> dict:
|
||||
return {k: v for k, v in s.items() if not k.endswith('DEPRECATED')}
|
||||
|
||||
struct_dict = struct.to_dict()
|
||||
struct_dataclass = structs.CarControlSP(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
|
||||
|
||||
struct_dataclass.mads = structs.ModularAssistiveDrivingSystem(**remove_deprecated(struct_dict.get('mads', {})))
|
||||
|
||||
return struct_dataclass
|
||||
@@ -4,7 +4,7 @@ import hypothesis.strategies as st
|
||||
from hypothesis import Phase, given, settings
|
||||
from parameterized import parameterized
|
||||
|
||||
from cereal import car, custom
|
||||
from cereal import car
|
||||
from opendbc.car import DT_CTRL
|
||||
from opendbc.car.car_helpers import interfaces
|
||||
from opendbc.car.structs import CarParams
|
||||
@@ -12,7 +12,6 @@ from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args
|
||||
from opendbc.car.fingerprints import all_known_cars
|
||||
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
|
||||
from opendbc.car.mock.values import CAR as MOCK
|
||||
from openpilot.selfdrive.car.helpers import convert_carControlSP
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
@@ -41,12 +40,9 @@ class TestCarInterfaces:
|
||||
|
||||
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
|
||||
experimental_long=args['experimental_long'], docs=False)
|
||||
car_params_sp = CarInterface.get_params_sp(car_params, car_name, args['fingerprints'], args['car_fw'],
|
||||
experimental_long=args['experimental_long'], docs=False)
|
||||
car_params = car_params.as_reader()
|
||||
car_interface = CarInterface(car_params, car_params_sp, CarController, CarState)
|
||||
car_interface = CarInterface(car_params, CarController, CarState)
|
||||
assert car_params
|
||||
assert car_params_sp
|
||||
assert car_interface
|
||||
|
||||
assert car_params.mass > 1
|
||||
@@ -73,16 +69,13 @@ class TestCarInterfaces:
|
||||
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
|
||||
|
||||
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
|
||||
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.CarControlSP, real_floats=True)
|
||||
# Run car interface
|
||||
now_nanos = 0
|
||||
CC = car.CarControl.new_message(**cc_msg)
|
||||
CC = CC.as_reader()
|
||||
CC_SP = custom.CarControlSP.new_message(**cc_sp_msg)
|
||||
CC_SP = convert_carControlSP(CC_SP.as_reader())
|
||||
for _ in range(10):
|
||||
car_interface.update([])
|
||||
car_interface.apply(CC, CC_SP, now_nanos)
|
||||
car_interface.apply(CC, now_nanos)
|
||||
now_nanos += DT_CTRL * 1e9 # 10 ms
|
||||
|
||||
CC = car.CarControl.new_message(**cc_msg)
|
||||
@@ -90,7 +83,7 @@ class TestCarInterfaces:
|
||||
CC = CC.as_reader()
|
||||
for _ in range(10):
|
||||
car_interface.update([])
|
||||
car_interface.apply(CC, CC_SP, now_nanos)
|
||||
car_interface.apply(CC, now_nanos)
|
||||
now_nanos += DT_CTRL * 1e9 # 10ms
|
||||
|
||||
# Test controller initialization
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import capnp
|
||||
import copy
|
||||
import os
|
||||
import pytest
|
||||
import random
|
||||
@@ -159,9 +158,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
cls.CarInterface, cls.CarController, cls.CarState, cls.RadarInterface = interfaces[cls.platform]
|
||||
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
cls.CP_SP = cls.CarInterface.get_params_sp(cls.CP, cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
|
||||
assert cls.CP
|
||||
assert cls.CP_SP
|
||||
assert cls.CP.carFingerprint == cls.platform
|
||||
|
||||
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
|
||||
@@ -171,7 +168,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
del cls.can_msgs
|
||||
|
||||
def setUp(self):
|
||||
self.CI = self.CarInterface(self.CP.copy(), copy.deepcopy(self.CP_SP), self.CarController, self.CarState)
|
||||
self.CI = self.CarInterface(self.CP.copy(), self.CarController, self.CarState)
|
||||
assert self.CI
|
||||
|
||||
Params().put_bool("OpenpilotEnabledToggle", self.openpilot_enabled)
|
||||
@@ -205,11 +202,10 @@ class TestCarModelBase(unittest.TestCase):
|
||||
can_invalid_cnt = 0
|
||||
can_valid = False
|
||||
CC = structs.CarControl().as_reader()
|
||||
CC_SP = structs.CarControlSP()
|
||||
|
||||
for i, msg in enumerate(self.can_msgs):
|
||||
CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
|
||||
self.CI.apply(CC, CC_SP, msg.logMonoTime)
|
||||
self.CI.apply(CC, msg.logMonoTime)
|
||||
|
||||
if CS.canValid:
|
||||
can_valid = True
|
||||
@@ -221,7 +217,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
self.assertEqual(can_invalid_cnt, 0)
|
||||
|
||||
def test_radar_interface(self):
|
||||
RI = self.RadarInterface(self.CP, self.CP_SP)
|
||||
RI = self.RadarInterface(self.CP)
|
||||
assert RI
|
||||
|
||||
# Since OBD port is multiplexed to bus 1 (commonly radar bus) while fingerprinting,
|
||||
@@ -278,13 +274,13 @@ class TestCarModelBase(unittest.TestCase):
|
||||
if self.CP.notCar:
|
||||
self.skipTest("Skipping test for notCar")
|
||||
|
||||
def test_car_controller(car_control, car_control_sp):
|
||||
def test_car_controller(car_control):
|
||||
now_nanos = 0
|
||||
msgs_sent = 0
|
||||
CI = self.CarInterface(self.CP, self.CP_SP, self.CarController, self.CarState)
|
||||
CI = self.CarInterface(self.CP, self.CarController, self.CarState)
|
||||
for _ in range(round(10.0 / DT_CTRL)): # make sure we hit the slowest messages
|
||||
CI.update([])
|
||||
_, sendcan = CI.apply(car_control, car_control_sp, now_nanos)
|
||||
_, sendcan = CI.apply(car_control, now_nanos)
|
||||
|
||||
now_nanos += DT_CTRL * 1e9
|
||||
msgs_sent += len(sendcan)
|
||||
@@ -297,18 +293,17 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
# Make sure we can send all messages while inactive
|
||||
CC = structs.CarControl()
|
||||
CC_SP = structs.CarControlSP()
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
test_car_controller(CC.as_reader())
|
||||
|
||||
# Test cancel + general messages (controls_allowed=False & cruise_engaged=True)
|
||||
self.safety.set_cruise_engaged_prev(True)
|
||||
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(cancel=True))
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
test_car_controller(CC.as_reader())
|
||||
|
||||
# Test resume + general messages (controls_allowed=True & cruise_engaged=True)
|
||||
self.safety.set_controls_allowed(True)
|
||||
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(resume=True))
|
||||
test_car_controller(CC.as_reader(), CC_SP)
|
||||
test_car_controller(CC.as_reader())
|
||||
|
||||
# Skip stdout/stderr capture with pytest, causes elevated memory usage
|
||||
@pytest.mark.nocapture
|
||||
@@ -392,7 +387,7 @@ class TestCarModelBase(unittest.TestCase):
|
||||
controls_allowed_prev = False
|
||||
CS_prev = car.CarState.new_message()
|
||||
checks = defaultdict(int)
|
||||
selfdrived = SelfdriveD(CP=self.CP, CP_SP=self.CP_SP)
|
||||
selfdrived = SelfdriveD(CP=self.CP)
|
||||
selfdrived.initialized = True
|
||||
for idx, can in enumerate(self.can_msgs):
|
||||
CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))).as_reader()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import math
|
||||
from typing import SupportsFloat
|
||||
|
||||
from cereal import car, log, custom
|
||||
from cereal import car, log
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
@@ -19,6 +19,8 @@ from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
||||
|
||||
from opendbc.sunnypilot import SunnypilotParamFlags
|
||||
|
||||
State = log.SelfdriveState.OpenpilotState
|
||||
LaneChangeState = log.LaneChangeState
|
||||
LaneChangeDirection = log.LaneChangeDirection
|
||||
@@ -32,17 +34,12 @@ class Controls:
|
||||
self.CP = messaging.log_from_bytes(self.params.get("CarParams", block=True), car.CarParams)
|
||||
cloudlog.info("controlsd got CarParams")
|
||||
|
||||
cloudlog.info("controlsd is waiting for CarParamsSP")
|
||||
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
|
||||
cloudlog.info("controlsd got CarParamsSP")
|
||||
|
||||
self.CI = get_car_interface(self.CP, self.CP_SP)
|
||||
self.CI = get_car_interface(self.CP)
|
||||
|
||||
self.sm = messaging.SubMaster(['liveParameters', 'liveTorqueParameters', 'modelV2', 'selfdriveState',
|
||||
'liveCalibration', 'livePose', 'longitudinalPlan', 'carState', 'carOutput',
|
||||
'driverMonitoringState', 'onroadEvents', 'driverAssistance'] + ['selfdriveStateSP'],
|
||||
poll='selfdriveState')
|
||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + ['carControlSP'])
|
||||
'driverMonitoringState', 'onroadEvents', 'driverAssistance'], poll='selfdriveState')
|
||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'])
|
||||
|
||||
self.steer_limited = False
|
||||
self.desired_curvature = 0.0
|
||||
@@ -60,6 +57,9 @@ class Controls:
|
||||
elif self.CP.lateralTuning.which() == 'torque':
|
||||
self.LaC = LatControlTorque(self.CP, self.CI)
|
||||
|
||||
data_services = list(self.sm.data.keys()) + ['selfdriveStateSP']
|
||||
self.sm = messaging.SubMaster(data_services, poll='selfdriveState')
|
||||
|
||||
def update(self):
|
||||
self.sm.update(15)
|
||||
if self.sm.updated["liveCalibration"]:
|
||||
@@ -94,7 +94,9 @@ class Controls:
|
||||
standstill = abs(CS.vEgo) <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
|
||||
|
||||
ss_sp = self.sm['selfdriveStateSP']
|
||||
CC.madsEnabled = ss_sp.mads.enabled
|
||||
if ss_sp.mads.available:
|
||||
CC.sunnypilotParams |= SunnypilotParamFlags.ENABLE_MADS.value
|
||||
_lat_active = ss_sp.mads.active
|
||||
else:
|
||||
_lat_active = self.sm['selfdriveState'].active
|
||||
@@ -137,12 +139,9 @@ class Controls:
|
||||
cloudlog.error(f"actuators.{p} not finite {actuators.to_dict()}")
|
||||
setattr(actuators, p, 0.0)
|
||||
|
||||
CC_SP = custom.CarControlSP.new_message()
|
||||
CC_SP.mads = ss_sp.mads
|
||||
return CC, lac_log
|
||||
|
||||
return CC, CC_SP, lac_log
|
||||
|
||||
def publish(self, CC, CC_SP, lac_log):
|
||||
def publish(self, CC, lac_log):
|
||||
CS = self.sm['carState']
|
||||
|
||||
# Orientation and angle rates can be useful for carcontroller
|
||||
@@ -218,18 +217,12 @@ class Controls:
|
||||
cc_send.carControl = CC
|
||||
self.pm.send('carControl', cc_send)
|
||||
|
||||
# carControlSP
|
||||
cc_sp_send = messaging.new_message('carControlSP')
|
||||
cc_sp_send.valid = CS.canValid
|
||||
cc_sp_send.carControlSP = CC_SP
|
||||
self.pm.send('carControlSP', cc_sp_send)
|
||||
|
||||
def run(self):
|
||||
rk = Ratekeeper(100, print_delay_threshold=None)
|
||||
while True:
|
||||
self.update()
|
||||
CC, CC_SP, lac_log = self.state_control()
|
||||
self.publish(CC, CC_SP, lac_log)
|
||||
CC, lac_log = self.state_control()
|
||||
self.publish(CC, lac_log)
|
||||
rk.monitor_time()
|
||||
|
||||
def main():
|
||||
|
||||
@@ -19,8 +19,7 @@ class TestLatControl:
|
||||
def test_saturation(self, car_name, controller):
|
||||
CarInterface, CarController, CarState, RadarInterface = interfaces[car_name]
|
||||
CP = CarInterface.get_non_essential_params(car_name)
|
||||
CP_SP = CarInterface.get_non_essential_params_sp(CP, car_name)
|
||||
CI = CarInterface(CP, CP_SP, CarController, CarState)
|
||||
CI = CarInterface(CP, CarController, CarState)
|
||||
VM = VehicleModel(CP)
|
||||
|
||||
controller = controller(CP.as_reader(), CI)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from pathlib import Path
|
||||
|
||||
MODEL_PATH = Path(__file__).parent / 'models/supercombo.onnx'
|
||||
MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl'
|
||||
METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl'
|
||||
|
||||
@@ -26,7 +26,6 @@ from openpilot.common.transformations.model import dmonitoringmodel_intrinsics,
|
||||
from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame
|
||||
from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid
|
||||
from openpilot.system import sentry
|
||||
|
||||
MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE
|
||||
CALIB_LEN = 3
|
||||
@@ -38,7 +37,6 @@ SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
MODEL_PATH = Path(__file__).parent / 'models/dmonitoring_model.onnx'
|
||||
MODEL_PKL_PATH = Path(__file__).parent / 'models/dmonitoring_model_tinygrad.pkl'
|
||||
|
||||
|
||||
class DriverStateResult(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("face_orientation", ctypes.c_float*3),
|
||||
@@ -57,7 +55,6 @@ class DriverStateResult(ctypes.Structure):
|
||||
("ready_prob", ctypes.c_float*4),
|
||||
("not_ready_prob", ctypes.c_float*2)]
|
||||
|
||||
|
||||
class DMonitoringModelResult(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("driver_state_lhd", DriverStateResult),
|
||||
@@ -66,7 +63,6 @@ class DMonitoringModelResult(ctypes.Structure):
|
||||
("wheel_on_right_prob", ctypes.c_float),
|
||||
("features", ctypes.c_float*FEATURE_LEN)]
|
||||
|
||||
|
||||
class ModelState:
|
||||
inputs: dict[str, np.ndarray]
|
||||
output: np.ndarray
|
||||
@@ -86,7 +82,7 @@ class ModelState:
|
||||
else:
|
||||
self.onnx_cpu_runner = make_onnx_cpu_runner(MODEL_PATH)
|
||||
|
||||
def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]:
|
||||
def run(self, buf:VisionBuf, calib:np.ndarray, transform:np.ndarray) -> tuple[np.ndarray, float]:
|
||||
self.numpy_inputs['calib'][0,:] = calib
|
||||
|
||||
t1 = time.perf_counter()
|
||||
@@ -123,7 +119,6 @@ def fill_driver_state(msg, ds_result: DriverStateResult):
|
||||
msg.readyProb = [float(sigmoid(x)) for x in ds_result.ready_prob]
|
||||
msg.notReadyProb = [float(sigmoid(x)) for x in ds_result.not_ready_prob]
|
||||
|
||||
|
||||
def get_driverstate_packet(model_output: np.ndarray, frame_id: int, location_ts: int, execution_time: float, gpu_execution_time: float):
|
||||
model_result = ctypes.cast(model_output.ctypes.data, ctypes.POINTER(DMonitoringModelResult)).contents
|
||||
msg = messaging.new_message('driverStateV2', valid=True)
|
||||
@@ -144,9 +139,6 @@ def main():
|
||||
setproctitle(PROCESS_NAME)
|
||||
set_realtime_priority(1)
|
||||
|
||||
sentry.set_tag("daemon", PROCESS_NAME)
|
||||
cloudlog.bind(daemon=PROCESS_NAME)
|
||||
|
||||
cl_context = CLContext()
|
||||
model = ModelState(cl_context)
|
||||
cloudlog.warning("models loaded, dmonitoringmodeld starting")
|
||||
@@ -185,10 +177,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
cloudlog.warning(f"child {PROCESS_NAME} got SIGINT")
|
||||
except Exception:
|
||||
sentry.capture_exception()
|
||||
raise
|
||||
main()
|
||||
|
||||
@@ -2,33 +2,13 @@ import os
|
||||
import capnp
|
||||
import numpy as np
|
||||
from cereal import log
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan, Meta
|
||||
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
|
||||
ConfidenceClass = log.ModelDataV2.ConfidenceClass
|
||||
|
||||
|
||||
def curv_from_psis(psi_target, psi_rate, vego, delay):
|
||||
vego = np.clip(vego, MIN_SPEED, np.inf)
|
||||
curv_from_psi = psi_target / (vego * delay) # epsilon to prevent divide-by-zero
|
||||
return 2 * curv_from_psi - psi_rate / vego
|
||||
|
||||
|
||||
def get_curvature_from_plan(plan, vego, delay):
|
||||
psi_target = np.interp(delay, ModelConstants.T_IDXS, plan[:, Plan.T_FROM_CURRENT_EULER][:, 2])
|
||||
psi_rate = plan[:, Plan.ORIENTATION_RATE][0, 2]
|
||||
return curv_from_psis(psi_target, psi_rate, vego, delay)
|
||||
|
||||
|
||||
def get_curvature_from_output(output, vego, delay):
|
||||
if desired_curv := output.get('desired_curvature'): # If the model outputs the desired curvature, use that directly
|
||||
return float(desired_curv[0, 0])
|
||||
|
||||
return float(get_curvature_from_plan(output['plan'][0], vego, delay))
|
||||
|
||||
|
||||
class PublishState:
|
||||
def __init__(self):
|
||||
self.disengage_buffer = np.zeros(ModelConstants.CONFIDENCE_BUFFER_LEN*ModelConstants.DISENGAGE_WIDTH, dtype=np.float32)
|
||||
@@ -79,21 +59,21 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
net_output_data: dict[str, np.ndarray], v_ego: float, delay: float,
|
||||
publish_state: PublishState, vipc_frame_id: int, vipc_frame_id_extra: int,
|
||||
frame_id: int, frame_drop: float, timestamp_eof: int, model_execution_time: float,
|
||||
valid: bool, model_meta) -> None:
|
||||
valid: bool) -> None:
|
||||
frame_age = frame_id - vipc_frame_id if frame_id > vipc_frame_id else 0
|
||||
frame_drop_perc = frame_drop * 100
|
||||
extended_msg.valid = valid
|
||||
base_msg.valid = valid
|
||||
|
||||
desired_curvature = float(get_curvature_from_output(net_output_data, v_ego, delay))
|
||||
|
||||
driving_model_data = base_msg.drivingModelData
|
||||
|
||||
driving_model_data.frameId = vipc_frame_id
|
||||
driving_model_data.frameIdExtra = vipc_frame_id_extra
|
||||
driving_model_data.frameDropPerc = frame_drop_perc
|
||||
driving_model_data.modelExecutionTime = model_execution_time
|
||||
driving_model_data.action.desiredCurvature = desired_curvature
|
||||
|
||||
action = driving_model_data.action
|
||||
action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
||||
|
||||
modelV2 = extended_msg.modelV2
|
||||
modelV2.frameId = vipc_frame_id
|
||||
@@ -104,11 +84,16 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
modelV2.modelExecutionTime = model_execution_time
|
||||
|
||||
# plan
|
||||
fill_xyzt(modelV2.position, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.POSITION].T, *net_output_data['plan_stds'][0,:,Plan.POSITION].T)
|
||||
fill_xyzt(modelV2.velocity, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.VELOCITY].T)
|
||||
fill_xyzt(modelV2.acceleration, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ACCELERATION].T)
|
||||
fill_xyzt(modelV2.orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
|
||||
fill_xyzt(modelV2.orientationRate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
||||
position = modelV2.position
|
||||
fill_xyzt(position, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.POSITION].T, *net_output_data['plan_stds'][0,:,Plan.POSITION].T)
|
||||
velocity = modelV2.velocity
|
||||
fill_xyzt(velocity, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.VELOCITY].T)
|
||||
acceleration = modelV2.acceleration
|
||||
fill_xyzt(acceleration, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ACCELERATION].T)
|
||||
orientation = modelV2.orientation
|
||||
fill_xyzt(orientation, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.T_FROM_CURRENT_EULER].T)
|
||||
orientation_rate = modelV2.orientationRate
|
||||
fill_xyzt(orientation_rate, ModelConstants.T_IDXS, *net_output_data['plan'][0,:,Plan.ORIENTATION_RATE].T)
|
||||
|
||||
# temporal pose
|
||||
temporal_pose = modelV2.temporalPose
|
||||
@@ -118,10 +103,12 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
temporal_pose.rotStd = net_output_data['plan_stds'][0,0,Plan.ORIENTATION_RATE].tolist()
|
||||
|
||||
# poly path
|
||||
fill_xyz_poly(driving_model_data.path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
||||
poly_path = driving_model_data.path
|
||||
fill_xyz_poly(poly_path, ModelConstants.POLY_PATH_DEGREE, *net_output_data['plan'][0,:,Plan.POSITION].T)
|
||||
|
||||
# lateral planning
|
||||
modelV2.action.desiredCurvature = desired_curvature
|
||||
action = modelV2.action
|
||||
action.desiredCurvature = float(net_output_data['desired_curvature'][0,0])
|
||||
|
||||
# times at X_IDXS according to model plan
|
||||
PLAN_T_IDXS = [np.nan] * ModelConstants.IDX_N
|
||||
@@ -150,7 +137,8 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
modelV2.laneLineStds = net_output_data['lane_lines_stds'][0,:,0,0].tolist()
|
||||
modelV2.laneLineProbs = net_output_data['lane_lines_prob'][0,1::2].tolist()
|
||||
|
||||
fill_lane_line_meta(driving_model_data.laneLineMeta, modelV2.laneLines, modelV2.laneLineProbs)
|
||||
lane_line_meta = driving_model_data.laneLineMeta
|
||||
fill_lane_line_meta(lane_line_meta, modelV2.laneLines, modelV2.laneLineProbs)
|
||||
|
||||
# road edges
|
||||
modelV2.init('roadEdges', 2)
|
||||
@@ -171,25 +159,23 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
meta = modelV2.meta
|
||||
meta.desireState = net_output_data['desire_state'][0].reshape(-1).tolist()
|
||||
meta.desirePrediction = net_output_data['desire_pred'][0].reshape(-1).tolist()
|
||||
meta.engagedProb = net_output_data['meta'][0,model_meta.ENGAGED].item()
|
||||
meta.engagedProb = net_output_data['meta'][0,Meta.ENGAGED].item()
|
||||
meta.init('disengagePredictions')
|
||||
disengage_predictions = meta.disengagePredictions
|
||||
disengage_predictions.t = ModelConstants.META_T_IDXS
|
||||
disengage_predictions.brakeDisengageProbs = net_output_data['meta'][0,model_meta.BRAKE_DISENGAGE].tolist()
|
||||
disengage_predictions.gasDisengageProbs = net_output_data['meta'][0,model_meta.GAS_DISENGAGE].tolist()
|
||||
disengage_predictions.steerOverrideProbs = net_output_data['meta'][0,model_meta.STEER_OVERRIDE].tolist()
|
||||
disengage_predictions.brake3MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_3].tolist()
|
||||
disengage_predictions.brake4MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_4].tolist()
|
||||
disengage_predictions.brake5MetersPerSecondSquaredProbs = net_output_data['meta'][0,model_meta.HARD_BRAKE_5].tolist()
|
||||
|
||||
if hasattr(model_meta, 'GAS_PRESS') and hasattr(model_meta, 'BRAKE_PRESS'):
|
||||
disengage_predictions.gasPressProbs = net_output_data['meta'][0,model_meta.GAS_PRESS].tolist()
|
||||
disengage_predictions.brakePressProbs = net_output_data['meta'][0,model_meta.BRAKE_PRESS].tolist()
|
||||
disengage_predictions.brakeDisengageProbs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE].tolist()
|
||||
disengage_predictions.gasDisengageProbs = net_output_data['meta'][0,Meta.GAS_DISENGAGE].tolist()
|
||||
disengage_predictions.steerOverrideProbs = net_output_data['meta'][0,Meta.STEER_OVERRIDE].tolist()
|
||||
disengage_predictions.brake3MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_3].tolist()
|
||||
disengage_predictions.brake4MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_4].tolist()
|
||||
disengage_predictions.brake5MetersPerSecondSquaredProbs = net_output_data['meta'][0,Meta.HARD_BRAKE_5].tolist()
|
||||
#disengage_predictions.gasPressProbs = net_output_data['meta'][0,Meta.GAS_PRESS].tolist()
|
||||
#disengage_predictions.brakePressProbs = net_output_data['meta'][0,Meta.BRAKE_PRESS].tolist()
|
||||
|
||||
publish_state.prev_brake_5ms2_probs[:-1] = publish_state.prev_brake_5ms2_probs[1:]
|
||||
publish_state.prev_brake_5ms2_probs[-1] = net_output_data['meta'][0,model_meta.HARD_BRAKE_5][0]
|
||||
publish_state.prev_brake_5ms2_probs[-1] = net_output_data['meta'][0,Meta.HARD_BRAKE_5][0]
|
||||
publish_state.prev_brake_3ms2_probs[:-1] = publish_state.prev_brake_3ms2_probs[1:]
|
||||
publish_state.prev_brake_3ms2_probs[-1] = net_output_data['meta'][0,model_meta.HARD_BRAKE_3][0]
|
||||
publish_state.prev_brake_3ms2_probs[-1] = net_output_data['meta'][0,Meta.HARD_BRAKE_3][0]
|
||||
hard_brake_predicted = (publish_state.prev_brake_5ms2_probs > ModelConstants.FCW_THRESHOLDS_5MS2).all() and \
|
||||
(publish_state.prev_brake_3ms2_probs > ModelConstants.FCW_THRESHOLDS_3MS2).all()
|
||||
meta.hardBrakePredicted = hard_brake_predicted.item()
|
||||
@@ -197,9 +183,9 @@ def fill_model_msg(base_msg: capnp._DynamicStructBuilder, extended_msg: capnp._D
|
||||
# confidence
|
||||
if vipc_frame_id % (2*ModelConstants.MODEL_FREQ) == 0:
|
||||
# any disengage prob
|
||||
brake_disengage_probs = net_output_data['meta'][0,model_meta.BRAKE_DISENGAGE]
|
||||
gas_disengage_probs = net_output_data['meta'][0,model_meta.GAS_DISENGAGE]
|
||||
steer_override_probs = net_output_data['meta'][0,model_meta.STEER_OVERRIDE]
|
||||
brake_disengage_probs = net_output_data['meta'][0,Meta.BRAKE_DISENGAGE]
|
||||
gas_disengage_probs = net_output_data['meta'][0,Meta.GAS_DISENGAGE]
|
||||
steer_override_probs = net_output_data['meta'][0,Meta.STEER_OVERRIDE]
|
||||
any_disengage_probs = 1-((1-brake_disengage_probs)*(1-gas_disengage_probs)*(1-steer_override_probs))
|
||||
# independent disengage prob for each 2s slice
|
||||
ind_disengage_probs = np.r_[any_disengage_probs[0], np.diff(any_disengage_probs) / (1 - any_disengage_probs[:-1])]
|
||||
|
||||
+65
-63
@@ -1,11 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
from openpilot.system.hardware import TICI
|
||||
|
||||
#
|
||||
if TICI:
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.dtype import dtypes
|
||||
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
||||
os.environ['QCOM'] = '1'
|
||||
else:
|
||||
from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner
|
||||
import time
|
||||
import pickle
|
||||
import numpy as np
|
||||
import cereal.messaging as messaging
|
||||
from cereal import car, log
|
||||
from pathlib import Path
|
||||
from setproctitle import setproctitle
|
||||
from cereal.messaging import PubMaster, SubMaster
|
||||
from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf
|
||||
@@ -23,11 +33,13 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
|
||||
|
||||
from openpilot.sunnypilot.modeld_v2.meta_helper import load_meta_constants
|
||||
from openpilot.sunnypilot.modeld_v2.model_runner import ONNXRunner, TinygradRunner
|
||||
|
||||
PROCESS_NAME = "selfdrive.modeld.modeld"
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
|
||||
MODEL_PATH = Path(__file__).parent / 'models/supercombo.onnx'
|
||||
MODEL_PKL_PATH = Path(__file__).parent / 'models/supercombo_tinygrad.pkl'
|
||||
METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl'
|
||||
|
||||
class FrameMeta:
|
||||
frame_id: int = 0
|
||||
@@ -45,35 +57,39 @@ class ModelState:
|
||||
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
||||
|
||||
def __init__(self, context: CLContext):
|
||||
try:
|
||||
self.model_runner = TinygradRunner() if TICI else ONNXRunner()
|
||||
except Exception as e:
|
||||
cloudlog.exception(f"Failed to initialize model runner: {str(e)}")
|
||||
|
||||
buffer_length = 5 if self.model_runner.is_20hz else 2
|
||||
self.frames = {'input_imgs': DrivingModelFrame(context, buffer_length), 'big_input_imgs': DrivingModelFrame(context, buffer_length)}
|
||||
self.frames = {'input_imgs': DrivingModelFrame(context), 'big_input_imgs': DrivingModelFrame(context)}
|
||||
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
|
||||
if self.model_runner.is_20hz:
|
||||
self.full_features_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
|
||||
self.desire_20Hz = np.zeros((ModelConstants.FULL_HISTORY_BUFFER_LEN + 1, ModelConstants.DESIRE_LEN), dtype=np.float32)
|
||||
|
||||
# img buffers are managed in openCL transform code
|
||||
self.numpy_inputs = {}
|
||||
self.numpy_inputs = {
|
||||
'desire': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.DESIRE_LEN), dtype=np.float32),
|
||||
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32),
|
||||
'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32),
|
||||
'prev_desired_curv': np.zeros((1, (ModelConstants.FULL_HISTORY_BUFFER_LEN+1), ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32),
|
||||
'features_buffer': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
|
||||
}
|
||||
|
||||
for key, shape in self.model_runner.input_shapes.items():
|
||||
if key not in self.frames: # Managed by opencl
|
||||
self.numpy_inputs[key] = np.zeros(shape, dtype=np.float32)
|
||||
with open(METADATA_PATH, 'rb') as f:
|
||||
model_metadata = pickle.load(f)
|
||||
self.input_shapes = model_metadata['input_shapes']
|
||||
|
||||
self.output_slices = model_metadata['output_slices']
|
||||
net_output_size = model_metadata['output_shapes']['outputs'][1]
|
||||
self.output = np.zeros(net_output_size, dtype=np.float32)
|
||||
self.parser = Parser()
|
||||
|
||||
if self.model_runner.is_20hz:
|
||||
net_output_size = self.model_runner.model_metadata['output_shapes']['outputs'][1]
|
||||
self.output = np.zeros(net_output_size, dtype=np.float32)
|
||||
if TICI:
|
||||
self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()}
|
||||
with open(MODEL_PKL_PATH, "rb") as f:
|
||||
self.model_run = pickle.load(f)
|
||||
else:
|
||||
self.onnx_cpu_runner = make_onnx_cpu_runner(MODEL_PATH)
|
||||
|
||||
num_elements = self.numpy_inputs['features_buffer'].shape[1]
|
||||
step_size = int(-100 / num_elements)
|
||||
self.full_features_20Hz_idxs = np.arange(step_size, step_size * (num_elements + 1), step_size)[::-1]
|
||||
self.desire_reshape_dims = (self.numpy_inputs['desire'].shape[0], self.numpy_inputs['desire'].shape[1], -1, self.numpy_inputs['desire'].shape[2])
|
||||
def slice_outputs(self, model_outputs: np.ndarray) -> dict[str, np.ndarray]:
|
||||
parsed_model_outputs = {k: model_outputs[np.newaxis, v] for k,v in self.output_slices.items()}
|
||||
if SEND_RAW_PRED:
|
||||
parsed_model_outputs['raw_pred'] = model_outputs.copy()
|
||||
return parsed_model_outputs
|
||||
|
||||
def run(self, buf: VisionBuf, wbuf: VisionBuf, transform: np.ndarray, transform_wide: np.ndarray,
|
||||
inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
|
||||
@@ -82,53 +98,40 @@ class ModelState:
|
||||
new_desire = np.where(inputs['desire'] - self.prev_desire > .99, inputs['desire'], 0)
|
||||
self.prev_desire[:] = inputs['desire']
|
||||
|
||||
if self.model_runner.is_20hz:
|
||||
self.desire_20Hz[:-1] = self.desire_20Hz[1:]
|
||||
self.desire_20Hz[-1] = new_desire
|
||||
self.numpy_inputs['desire'][:] = self.desire_20Hz.reshape(self.desire_reshape_dims).max(axis=2)
|
||||
else:
|
||||
length = inputs['desire'].shape[0]
|
||||
self.numpy_inputs['desire'][0, :-1] = self.numpy_inputs['desire'][0, 1:]
|
||||
self.numpy_inputs['desire'][0, -1, :length] = new_desire[:length]
|
||||
|
||||
for key in self.numpy_inputs:
|
||||
if key in inputs and key not in ['desire']:
|
||||
self.numpy_inputs[key][:] = inputs[key]
|
||||
self.numpy_inputs['desire'][0,:-1] = self.numpy_inputs['desire'][0,1:]
|
||||
self.numpy_inputs['desire'][0,-1] = new_desire
|
||||
|
||||
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
|
||||
self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
|
||||
imgs_cl = {'input_imgs': self.frames['input_imgs'].prepare(buf, transform.flatten()),
|
||||
'big_input_imgs': self.frames['big_input_imgs'].prepare(wbuf, transform_wide.flatten())}
|
||||
|
||||
# Prepare inputs using the model runner
|
||||
self.model_runner.prepare_inputs(imgs_cl, self.numpy_inputs, self.frames)
|
||||
if TICI:
|
||||
# The imgs tensors are backed by opencl memory, only need init once
|
||||
for key in imgs_cl:
|
||||
if key not in self.tensor_inputs:
|
||||
self.tensor_inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=dtypes.uint8)
|
||||
else:
|
||||
for key in imgs_cl:
|
||||
self.numpy_inputs[key] = self.frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]).astype(dtype=np.float32)
|
||||
|
||||
if prepare_only:
|
||||
return None
|
||||
|
||||
# Run model inference
|
||||
self.output = self.model_runner.run_model()
|
||||
outputs = self.parser.parse_outputs(self.model_runner.slice_outputs(self.output))
|
||||
|
||||
if self.model_runner.is_20hz:
|
||||
self.full_features_20Hz[:-1] = self.full_features_20Hz[1:]
|
||||
self.full_features_20Hz[-1] = outputs['hidden_state'][0, :]
|
||||
self.numpy_inputs['features_buffer'][:] = self.full_features_20Hz[self.full_features_20Hz_idxs]
|
||||
if TICI:
|
||||
self.output = self.model_run(**self.tensor_inputs).numpy().flatten()
|
||||
else:
|
||||
feature_len = outputs['hidden_state'].shape[1]
|
||||
self.numpy_inputs['features_buffer'][0, :-1] = self.numpy_inputs['features_buffer'][0, 1:]
|
||||
self.numpy_inputs['features_buffer'][0, -1, :feature_len] = outputs['hidden_state'][0, :feature_len]
|
||||
self.output = self.onnx_cpu_runner.run(None, self.numpy_inputs)[0].flatten()
|
||||
|
||||
if "desired_curvature" in outputs:
|
||||
input_name_prev = None
|
||||
outputs = self.parser.parse_outputs(self.slice_outputs(self.output))
|
||||
|
||||
if "prev_desired_curvs" in self.numpy_inputs.keys():
|
||||
input_name_prev = 'prev_desired_curvs'
|
||||
elif "prev_desired_curv" in self.numpy_inputs.keys():
|
||||
input_name_prev = 'prev_desired_curv'
|
||||
self.numpy_inputs['features_buffer'][0,:-1] = self.numpy_inputs['features_buffer'][0,1:]
|
||||
self.numpy_inputs['features_buffer'][0,-1] = outputs['hidden_state'][0, :]
|
||||
|
||||
if input_name_prev is not None:
|
||||
length = outputs['desired_curvature'][0].size
|
||||
self.numpy_inputs[input_name_prev][0, :-length, 0] = self.numpy_inputs[input_name_prev][0, length:, 0]
|
||||
self.numpy_inputs[input_name_prev][0, -length:, 0] = outputs['desired_curvature'][0]
|
||||
|
||||
# TODO model only uses last value now
|
||||
self.numpy_inputs['prev_desired_curv'][0,:-1] = self.numpy_inputs['prev_desired_curv'][0,1:]
|
||||
self.numpy_inputs['prev_desired_curv'][0,-1,:] = outputs['desired_curvature'][0, :]
|
||||
return outputs
|
||||
|
||||
|
||||
@@ -239,6 +242,7 @@ def main(demo=False):
|
||||
is_rhd = sm["driverMonitoringState"].isRHD
|
||||
frame_id = sm["roadCameraState"].frameId
|
||||
v_ego = max(sm["carState"].vEgo, 0.)
|
||||
lateral_control_params = np.array([v_ego, steer_delay], dtype=np.float32)
|
||||
if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']:
|
||||
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
|
||||
dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))]
|
||||
@@ -269,10 +273,8 @@ def main(demo=False):
|
||||
inputs:dict[str, np.ndarray] = {
|
||||
'desire': vec_desire,
|
||||
'traffic_convention': traffic_convention,
|
||||
}
|
||||
|
||||
if "lateral_control_params" in model.numpy_inputs.keys():
|
||||
inputs['lateral_control_params'] = np.array([v_ego, steer_delay], dtype=np.float32)
|
||||
'lateral_control_params': lateral_control_params,
|
||||
}
|
||||
|
||||
mt1 = time.perf_counter()
|
||||
model_output = model.run(buf_main, buf_extra, model_transform_main, model_transform_extra, inputs, prepare_only)
|
||||
@@ -285,7 +287,7 @@ def main(demo=False):
|
||||
posenet_send = messaging.new_message('cameraOdometry')
|
||||
fill_model_msg(drivingdata_send, modelv2_send, model_output, v_ego, steer_delay,
|
||||
publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
|
||||
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen, load_meta_constants())
|
||||
frame_drop_ratio, meta_main.timestamp_eof, model_execution_time, live_calib_seen)
|
||||
|
||||
desire_state = modelv2_send.modelV2.meta.desireState
|
||||
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
|
||||
#include "common/clutil.h"
|
||||
|
||||
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context, uint8_t buffer_length) : ModelFrame(device_id, context), buffer_length(buffer_length) {
|
||||
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context) : ModelFrame(device_id, context) {
|
||||
input_frames = std::make_unique<uint8_t[]>(buf_size);
|
||||
input_frames_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buf_size, NULL, &err));
|
||||
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_length*frame_size_bytes, NULL, &err));
|
||||
region.origin = (buffer_length - 1) * frame_size_bytes;
|
||||
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, 2*frame_size_bytes, NULL, &err));
|
||||
region.origin = 1 * frame_size_bytes;
|
||||
region.size = frame_size_bytes;
|
||||
last_img_cl = CL_CHECK_ERR(clCreateSubBuffer(img_buffer_20hz_cl, CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®ion, &err));
|
||||
// printf("Buffer length: %d, region origin: %lu, region size: %lu\n", buffer_length, region.origin, region.size);
|
||||
|
||||
loadyuv_init(&loadyuv, context, device_id, MODEL_WIDTH, MODEL_HEIGHT);
|
||||
init_transform(device_id, context, MODEL_WIDTH, MODEL_HEIGHT);
|
||||
@@ -21,7 +20,7 @@ DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context,
|
||||
cl_mem* DrivingModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) {
|
||||
run_transform(yuv_cl, MODEL_WIDTH, MODEL_HEIGHT, frame_width, frame_height, frame_stride, frame_uv_offset, projection);
|
||||
|
||||
for (int i = 0; i < (buffer_length - 1); i++) {
|
||||
for (int i = 0; i < 1; i++) {
|
||||
CL_CHECK(clEnqueueCopyBuffer(q, img_buffer_20hz_cl, img_buffer_20hz_cl, (i+1)*frame_size_bytes, i*frame_size_bytes, frame_size_bytes, 0, nullptr, nullptr));
|
||||
}
|
||||
loadyuv_queue(&loadyuv, q, y_cl, u_cl, v_cl, last_img_cl);
|
||||
|
||||
@@ -64,7 +64,7 @@ protected:
|
||||
|
||||
class DrivingModelFrame : public ModelFrame {
|
||||
public:
|
||||
DrivingModelFrame(cl_device_id device_id, cl_context context, uint8_t buffer_length);
|
||||
DrivingModelFrame(cl_device_id device_id, cl_context context);
|
||||
~DrivingModelFrame();
|
||||
cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection);
|
||||
|
||||
@@ -73,7 +73,6 @@ public:
|
||||
const int MODEL_FRAME_SIZE = MODEL_WIDTH * MODEL_HEIGHT * 3 / 2;
|
||||
const int buf_size = MODEL_FRAME_SIZE * 2;
|
||||
const size_t frame_size_bytes = MODEL_FRAME_SIZE * sizeof(uint8_t);
|
||||
const uint8_t buffer_length;
|
||||
|
||||
private:
|
||||
LoadYUVState loadyuv;
|
||||
|
||||
@@ -20,7 +20,7 @@ cdef extern from "selfdrive/modeld/models/commonmodel.h":
|
||||
|
||||
cppclass DrivingModelFrame:
|
||||
int buf_size
|
||||
DrivingModelFrame(cl_device_id, cl_context, unsigned char)
|
||||
DrivingModelFrame(cl_device_id, cl_context)
|
||||
|
||||
cppclass MonitoringModelFrame:
|
||||
int buf_size
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import numpy as np
|
||||
cimport numpy as cnp
|
||||
from libc.string cimport memcpy
|
||||
from libc.stdint cimport uintptr_t, uint8_t
|
||||
from libc.stdint cimport uintptr_t
|
||||
|
||||
from msgq.visionipc.visionipc cimport cl_mem
|
||||
from msgq.visionipc.visionipc_pyx cimport VisionBuf, CLContext as BaseCLContext
|
||||
@@ -59,8 +59,8 @@ cdef class ModelFrame:
|
||||
cdef class DrivingModelFrame(ModelFrame):
|
||||
cdef cppDrivingModelFrame * _frame
|
||||
|
||||
def __cinit__(self, CLContext context, int buffer_length=2):
|
||||
self._frame = new cppDrivingModelFrame(context.device_id, context.context, buffer_length)
|
||||
def __cinit__(self, CLContext context):
|
||||
self._frame = new cppDrivingModelFrame(context.device_id, context.context)
|
||||
self.frame = <cppModelFrame*>(self._frame)
|
||||
self.buf_size = self._frame.buf_size
|
||||
|
||||
|
||||
@@ -81,8 +81,3 @@ void PandaSafety::setSafetyMode(const std::string ¶ms_string) {
|
||||
pandas_[i]->set_safety_model(safety_model, safety_param);
|
||||
}
|
||||
}
|
||||
|
||||
bool PandaSafety::getOffroadMode() {
|
||||
auto offroad_mode = params_.getBool("OffroadMode");
|
||||
return offroad_mode;
|
||||
}
|
||||
|
||||
+14
-22
@@ -105,6 +105,9 @@ void can_send_thread(std::vector<Panda *> pandas, bool fake_send) {
|
||||
while (!do_exit && check_all_connected(pandas)) {
|
||||
std::unique_ptr<Message> msg(subscriber->receive());
|
||||
if (!msg) {
|
||||
if (errno == EINTR) {
|
||||
do_exit = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -155,6 +158,7 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda
|
||||
ps.setIgnitionLine(health.ignition_line_pkt);
|
||||
ps.setIgnitionCan(health.ignition_can_pkt);
|
||||
ps.setControlsAllowed(health.controls_allowed_pkt);
|
||||
ps.setControlsAllowedLat(health.controls_allowed_lat_pkt);
|
||||
ps.setTxBufferOverflow(health.tx_buffer_overflow_pkt);
|
||||
ps.setRxBufferOverflow(health.rx_buffer_overflow_pkt);
|
||||
ps.setPandaType(hw_type);
|
||||
@@ -202,7 +206,7 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const
|
||||
cs.setCanCoreResetCnt(can_health.can_core_reset_cnt);
|
||||
}
|
||||
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started, PandaSafety *panda_safety) {
|
||||
std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *> &pandas, bool spoofing_started) {
|
||||
bool ignition_local = false;
|
||||
const uint32_t pandas_cnt = pandas.size();
|
||||
|
||||
@@ -250,7 +254,7 @@ std::optional<bool> send_panda_states(PubMaster *pm, const std::vector<Panda *>
|
||||
health.ignition_line_pkt = 0;
|
||||
}
|
||||
|
||||
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0)) && !panda_safety->getOffroadMode();
|
||||
ignition_local |= ((health.ignition_line_pkt != 0) || (health.ignition_can_pkt != 0));
|
||||
|
||||
pandaStates.push_back(health);
|
||||
}
|
||||
@@ -337,15 +341,16 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) {
|
||||
pm->send("peripheralState", msg);
|
||||
}
|
||||
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool spoofing_started,
|
||||
PandaSafety *panda_safety) {
|
||||
void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool spoofing_started) {
|
||||
static SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
|
||||
|
||||
std::vector<std::string> connected_serials;
|
||||
for (Panda *p : pandas) {
|
||||
connected_serials.push_back(p->hw_serial());
|
||||
}
|
||||
|
||||
{
|
||||
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started, panda_safety);
|
||||
auto ignition_opt = send_panda_states(pm, pandas, spoofing_started);
|
||||
if (!ignition_opt) {
|
||||
LOGE("Failed to get ignition_opt");
|
||||
return;
|
||||
@@ -374,6 +379,9 @@ void process_panda_state(std::vector<Panda *> &pandas, PubMaster *pm, bool engag
|
||||
}
|
||||
}
|
||||
|
||||
sm.update(0);
|
||||
const bool engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
|
||||
const bool engaged_mads = process_mads_heartbeat(&sm);
|
||||
for (const auto &panda : pandas) {
|
||||
panda->send_heartbeat(engaged, engaged_mads);
|
||||
}
|
||||
@@ -439,12 +447,9 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
std::thread send_thread(can_send_thread, pandas, fake_send);
|
||||
|
||||
RateKeeper rk("pandad", 100);
|
||||
SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"});
|
||||
PubMaster pm({"can", "pandaStates", "peripheralState"});
|
||||
PandaSafety panda_safety(pandas);
|
||||
Panda *peripheral_panda = pandas[0];
|
||||
bool engaged = false;
|
||||
bool engaged_mads = false;
|
||||
|
||||
// Main loop: receive CAN data and process states
|
||||
while (!do_exit && check_all_connected(pandas)) {
|
||||
@@ -457,10 +462,7 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
|
||||
// Process panda state at 10 Hz
|
||||
if (rk.frame() % 10 == 0) {
|
||||
sm.update(0);
|
||||
engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled();
|
||||
engaged_mads = process_mads_heartbeat(&sm);
|
||||
process_panda_state(pandas, &pm, engaged, engaged_mads, spoofing_started, &panda_safety);
|
||||
process_panda_state(pandas, &pm, spoofing_started);
|
||||
panda_safety.configureSafetyMode();
|
||||
}
|
||||
|
||||
@@ -472,16 +474,6 @@ void pandad_run(std::vector<Panda *> &pandas) {
|
||||
rk.keepTime();
|
||||
}
|
||||
|
||||
// Close relay on exit to prevent a fault
|
||||
const bool is_onroad = Params().getBool("IsOnroad");
|
||||
if (is_onroad && !engaged) {
|
||||
for (auto &p : pandas) {
|
||||
if (p->connected()) {
|
||||
p->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_thread.join();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ class PandaSafety {
|
||||
public:
|
||||
PandaSafety(const std::vector<Panda *> &pandas) : pandas_(pandas) {}
|
||||
void configureSafetyMode();
|
||||
bool getOffroadMode();
|
||||
|
||||
private:
|
||||
void updateMultiplexingMode();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import os
|
||||
import usb1
|
||||
import time
|
||||
import signal
|
||||
import subprocess
|
||||
from typing import NoReturn
|
||||
|
||||
from panda import Panda, PandaDFU, PandaProtocolMismatch, FW_PATH
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
@@ -61,25 +61,13 @@ def flash_panda(panda_serial: str) -> Panda:
|
||||
return panda
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# signal pandad to close the relay and exit
|
||||
def signal_handler(signum, frame):
|
||||
cloudlog.info(f"Caught signal {signum}, exiting")
|
||||
nonlocal do_exit
|
||||
do_exit = True
|
||||
if process is not None:
|
||||
process.send_signal(signal.SIGINT)
|
||||
|
||||
process = None
|
||||
do_exit = False
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
def main() -> NoReturn:
|
||||
count = 0
|
||||
first_run = True
|
||||
params = Params()
|
||||
no_internal_panda_count = 0
|
||||
|
||||
while not do_exit:
|
||||
while True:
|
||||
try:
|
||||
count += 1
|
||||
cloudlog.event("pandad.flash_and_connect", count=count)
|
||||
@@ -171,9 +159,8 @@ def main() -> None:
|
||||
|
||||
# run pandad with all connected serials as arguments
|
||||
os.environ['MANAGER_DAEMON'] = 'pandad'
|
||||
process = subprocess.Popen(["./pandad", *panda_serials], cwd=os.path.join(BASEDIR, "selfdrive/pandad"))
|
||||
process.wait()
|
||||
|
||||
os.chdir(os.path.join(BASEDIR, "selfdrive/pandad"))
|
||||
subprocess.run(["./pandad", *panda_serials], check=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -6,8 +6,7 @@ from dataclasses import dataclass
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.selfdrived.events import Alert
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EmptyAlert
|
||||
from openpilot.selfdrive.selfdrived.events import Alert, EmptyAlert
|
||||
|
||||
|
||||
with open(os.path.join(BASEDIR, "selfdrive/selfdrived/alerts_offroad.json")) as f:
|
||||
|
||||
@@ -44,9 +44,5 @@
|
||||
"Offroad_Recalibration": {
|
||||
"text": "openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.",
|
||||
"severity": 0
|
||||
},
|
||||
"OffroadMode_Status": {
|
||||
"text": "sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to \"Settings\" -> \"Device\" to exit Always Offroad mode.",
|
||||
"severity": 1
|
||||
}
|
||||
}
|
||||
|
||||
+291
-13
@@ -1,6 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
import bisect
|
||||
import math
|
||||
import os
|
||||
from enum import IntEnum
|
||||
from collections.abc import Callable
|
||||
|
||||
from cereal import log, car
|
||||
import cereal.messaging as messaging
|
||||
@@ -9,11 +12,6 @@ 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.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
|
||||
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
|
||||
StartupAlert, AlertCallbackType
|
||||
|
||||
|
||||
AlertSize = log.SelfdriveState.AlertSize
|
||||
AlertStatus = log.SelfdriveState.AlertStatus
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
@@ -21,23 +19,201 @@ AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
EventName = log.OnroadEvent.EventName
|
||||
|
||||
|
||||
# Alert priorities
|
||||
class Priority(IntEnum):
|
||||
LOWEST = 0
|
||||
LOWER = 1
|
||||
LOW = 2
|
||||
MID = 3
|
||||
HIGH = 4
|
||||
HIGHEST = 5
|
||||
|
||||
|
||||
# Event types
|
||||
class ET:
|
||||
ENABLE = 'enable'
|
||||
PRE_ENABLE = 'preEnable'
|
||||
OVERRIDE_LATERAL = 'overrideLateral'
|
||||
OVERRIDE_LONGITUDINAL = 'overrideLongitudinal'
|
||||
NO_ENTRY = 'noEntry'
|
||||
WARNING = 'warning'
|
||||
USER_DISABLE = 'userDisable'
|
||||
SOFT_DISABLE = 'softDisable'
|
||||
IMMEDIATE_DISABLE = 'immediateDisable'
|
||||
PERMANENT = 'permanent'
|
||||
|
||||
|
||||
# get event name from enum
|
||||
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
|
||||
|
||||
|
||||
class Events(EventsBase):
|
||||
class Events:
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.events: list[int] = []
|
||||
self.static_events: list[int] = []
|
||||
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
|
||||
|
||||
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
|
||||
return EVENTS
|
||||
@property
|
||||
def names(self) -> list[int]:
|
||||
return self.events
|
||||
|
||||
def get_event_name(self, event: int):
|
||||
return EVENT_NAME[event]
|
||||
def __len__(self) -> int:
|
||||
return len(self.events)
|
||||
|
||||
def get_event_msg_type(self):
|
||||
return log.OnroadEvent
|
||||
def add(self, event_name: int, static: bool=False) -> None:
|
||||
if static:
|
||||
bisect.insort(self.static_events, event_name)
|
||||
bisect.insort(self.events, event_name)
|
||||
|
||||
def clear(self) -> None:
|
||||
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
|
||||
self.events = self.static_events.copy()
|
||||
|
||||
def contains(self, event_type: str) -> bool:
|
||||
return any(event_type in EVENTS.get(e, {}) for e in self.events)
|
||||
|
||||
def create_alerts(self, event_types: list[str], callback_args=None):
|
||||
if callback_args is None:
|
||||
callback_args = []
|
||||
|
||||
ret = []
|
||||
for e in self.events:
|
||||
types = EVENTS[e].keys()
|
||||
for et in event_types:
|
||||
if et in types:
|
||||
alert = EVENTS[e][et]
|
||||
if not isinstance(alert, Alert):
|
||||
alert = alert(*callback_args)
|
||||
|
||||
if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
|
||||
alert.alert_type = f"{EVENT_NAME[e]}/{et}"
|
||||
alert.event_type = et
|
||||
ret.append(alert)
|
||||
return ret
|
||||
|
||||
def add_from_msg(self, events):
|
||||
for e in events:
|
||||
bisect.insort(self.events, e.name.raw)
|
||||
|
||||
def to_msg(self):
|
||||
ret = []
|
||||
for event_name in self.events:
|
||||
event = log.OnroadEvent.new_message()
|
||||
event.name = event_name
|
||||
for event_type in EVENTS.get(event_name, {}):
|
||||
setattr(event, event_type, True)
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
||||
def has(self, event_name: int) -> bool:
|
||||
return event_name in self.events
|
||||
|
||||
def contains_in_list(self, events_list: list[int]) -> bool:
|
||||
return any(event_name in self.events for event_name in events_list)
|
||||
|
||||
def remove(self, event_name: int, static: bool = False) -> None:
|
||||
if static and event_name in self.static_events:
|
||||
self.static_events.remove(event_name)
|
||||
|
||||
if event_name in self.events:
|
||||
self.event_counters[event_name] = self.event_counters[event_name] + 1
|
||||
self.events.remove(event_name)
|
||||
|
||||
def replace(self, prev_event_name: int, cur_event_name: int, static: bool = False) -> None:
|
||||
self.remove(prev_event_name, static)
|
||||
self.add(cur_event_name, static)
|
||||
|
||||
|
||||
class Alert:
|
||||
def __init__(self,
|
||||
alert_text_1: str,
|
||||
alert_text_2: str,
|
||||
alert_status: log.SelfdriveState.AlertStatus,
|
||||
alert_size: log.SelfdriveState.AlertSize,
|
||||
priority: Priority,
|
||||
visual_alert: car.CarControl.HUDControl.VisualAlert,
|
||||
audible_alert: car.CarControl.HUDControl.AudibleAlert,
|
||||
duration: float,
|
||||
creation_delay: float = 0.):
|
||||
|
||||
self.alert_text_1 = alert_text_1
|
||||
self.alert_text_2 = alert_text_2
|
||||
self.alert_status = alert_status
|
||||
self.alert_size = alert_size
|
||||
self.priority = priority
|
||||
self.visual_alert = visual_alert
|
||||
self.audible_alert = audible_alert
|
||||
|
||||
self.duration = int(duration / DT_CTRL)
|
||||
|
||||
self.creation_delay = creation_delay
|
||||
|
||||
self.alert_type = ""
|
||||
self.event_type: str | None = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
|
||||
|
||||
def __gt__(self, alert2) -> bool:
|
||||
if not isinstance(alert2, Alert):
|
||||
return False
|
||||
return self.priority > alert2.priority
|
||||
|
||||
EmptyAlert = Alert("" , "", AlertStatus.normal, AlertSize.none, Priority.LOWEST,
|
||||
VisualAlert.none, AudibleAlert.none, 0)
|
||||
|
||||
class NoEntryAlert(Alert):
|
||||
def __init__(self, alert_text_2: str,
|
||||
alert_text_1: str = "openpilot Unavailable",
|
||||
visual_alert: car.CarControl.HUDControl.VisualAlert=VisualAlert.none):
|
||||
super().__init__(alert_text_1, alert_text_2, AlertStatus.normal,
|
||||
AlertSize.mid, Priority.LOW, visual_alert,
|
||||
AudibleAlert.refuse, 3.)
|
||||
|
||||
|
||||
class SoftDisableAlert(Alert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
|
||||
AlertStatus.userPrompt, AlertSize.full,
|
||||
Priority.MID, VisualAlert.steerRequired,
|
||||
AudibleAlert.warningSoft, 2.),
|
||||
|
||||
|
||||
# less harsh version of SoftDisable, where the condition is user-triggered
|
||||
class UserSoftDisableAlert(SoftDisableAlert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__(alert_text_2),
|
||||
self.alert_text_1 = "openpilot will disengage"
|
||||
|
||||
|
||||
class ImmediateDisableAlert(Alert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
|
||||
AlertStatus.critical, AlertSize.full,
|
||||
Priority.HIGHEST, VisualAlert.steerRequired,
|
||||
AudibleAlert.warningImmediate, 4.),
|
||||
|
||||
|
||||
class EngagementAlert(Alert):
|
||||
def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert):
|
||||
super().__init__("", "",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.MID, VisualAlert.none,
|
||||
audible_alert, .2),
|
||||
|
||||
|
||||
class NormalPermanentAlert(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str = "", duration: float = 0.2, priority: Priority = Priority.LOWER, creation_delay: float = 0.):
|
||||
super().__init__(alert_text_1, alert_text_2,
|
||||
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
|
||||
priority, VisualAlert.none, AudibleAlert.none, duration, creation_delay=creation_delay),
|
||||
|
||||
|
||||
class StartupAlert(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str = "Always keep hands on wheel and eyes on road", alert_status=AlertStatus.normal):
|
||||
super().__init__(alert_text_1, alert_text_2,
|
||||
alert_status, AlertSize.mid,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
|
||||
|
||||
|
||||
# ********** helper functions **********
|
||||
@@ -49,6 +225,8 @@ def get_display_speed(speed_ms: float, metric: bool) -> str:
|
||||
|
||||
# ********** alert callback functions **********
|
||||
|
||||
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], Alert]
|
||||
|
||||
|
||||
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:
|
||||
@@ -794,6 +972,106 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
ET.WARNING: personality_changed_alert,
|
||||
},
|
||||
|
||||
# sunnypilot
|
||||
EventName.lkasEnable: {
|
||||
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
|
||||
},
|
||||
|
||||
EventName.lkasDisable: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||||
},
|
||||
|
||||
EventName.manualSteeringRequired: {
|
||||
ET.USER_DISABLE: Alert(
|
||||
"Automatic Lane Centering is OFF",
|
||||
"Manual Steering Required",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.disengage, 1.),
|
||||
},
|
||||
|
||||
EventName.manualLongitudinalRequired: {
|
||||
ET.WARNING: Alert(
|
||||
"Smart/Adaptive Cruise Control: OFF",
|
||||
"Manual Speed Control Required",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1.),
|
||||
},
|
||||
|
||||
EventName.silentLkasEnable: {
|
||||
ET.ENABLE: EngagementAlert(AudibleAlert.none),
|
||||
},
|
||||
|
||||
EventName.silentLkasDisable: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
|
||||
},
|
||||
|
||||
EventName.silentBrakeHold: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
|
||||
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
|
||||
},
|
||||
|
||||
EventName.silentWrongGear: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: Alert(
|
||||
"Gear not D",
|
||||
"openpilot Unavailable",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
},
|
||||
|
||||
EventName.silentReverseGear: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Reverse\nGear",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.full,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
|
||||
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
|
||||
},
|
||||
|
||||
EventName.silentDoorOpen: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Door Open"),
|
||||
},
|
||||
|
||||
EventName.silentSeatbeltNotLatched: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
|
||||
},
|
||||
|
||||
EventName.silentParkBrake: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
|
||||
},
|
||||
|
||||
EventName.controlsMismatchLateral: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch: Lateral"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch: Lateral"),
|
||||
},
|
||||
|
||||
EventName.hyundaiRadarTracksConfirmed: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Radar tracks available. Restart the car to initialize")
|
||||
},
|
||||
|
||||
EventName.experimentalModeSwitched: {
|
||||
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import threading
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log, custom
|
||||
from cereal import car, log
|
||||
from msgq.visionipc import VisionIpcClient, VisionStreamType
|
||||
from panda import ALTERNATIVE_EXPERIENCE
|
||||
|
||||
@@ -25,8 +25,7 @@ from openpilot.system.version import get_build_metadata
|
||||
|
||||
from openpilot.sunnypilot.mads.mads import ModularAssistiveDrivingSystem
|
||||
from openpilot.sunnypilot.selfdrive.car.car_specific import CarSpecificEventsSP
|
||||
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||
from openpilot.sunnypilot.selfdrive.car.experimental_switcher import ExperimentalSwitcher
|
||||
|
||||
REPLAY = "REPLAY" in os.environ
|
||||
SIMULATION = "SIMULATION" in os.environ
|
||||
@@ -46,8 +45,8 @@ SafetyModel = car.CarParams.SafetyModel
|
||||
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
||||
|
||||
|
||||
class SelfdriveD(CruiseHelper):
|
||||
def __init__(self, CP=None, CP_SP=None):
|
||||
class SelfdriveD(ExperimentalSwitcher):
|
||||
def __init__(self, CP=None):
|
||||
self.params = Params()
|
||||
|
||||
# Ensure the current branch is cached, otherwise the first cycle lags
|
||||
@@ -60,18 +59,11 @@ class SelfdriveD(CruiseHelper):
|
||||
else:
|
||||
self.CP = CP
|
||||
|
||||
if CP_SP is None:
|
||||
cloudlog.info("selfdrived is waiting for CarParamsSP")
|
||||
self.CP_SP = messaging.log_from_bytes(self.params.get("CarParamsSP", block=True), custom.CarParamsSP)
|
||||
cloudlog.info("selfdrived got CarParamsSP")
|
||||
else:
|
||||
self.CP_SP = CP_SP
|
||||
|
||||
self.car_events = CarSpecificEvents(self.CP)
|
||||
self.disengage_on_accelerator = not (self.CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS)
|
||||
|
||||
# Setup sockets
|
||||
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP'])
|
||||
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'])
|
||||
|
||||
self.gps_location_service = get_gps_location_service(self.params)
|
||||
self.gps_packets = [self.gps_location_service]
|
||||
@@ -143,20 +135,18 @@ class SelfdriveD(CruiseHelper):
|
||||
elif self.CP.passive:
|
||||
self.events.add(EventName.dashcamMode, static=True)
|
||||
|
||||
self.events_sp = EventsSP()
|
||||
self.events_sp_prev = []
|
||||
|
||||
self.mads = ModularAssistiveDrivingSystem(self)
|
||||
sock_services = list(self.pm.sock.keys()) + ['selfdriveStateSP']
|
||||
self.pm = messaging.PubMaster(sock_services)
|
||||
|
||||
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params)
|
||||
|
||||
CruiseHelper.__init__(self, self.CP)
|
||||
ExperimentalSwitcher.__init__(self, self.params)
|
||||
|
||||
def update_events(self, CS):
|
||||
"""Compute onroadEvents from carState"""
|
||||
|
||||
self.events.clear()
|
||||
self.events_sp.clear()
|
||||
|
||||
if self.sm['controlsState'].lateralControlState.which() == 'debugState':
|
||||
self.events.add(EventName.joystickDebug)
|
||||
@@ -194,7 +184,7 @@ class SelfdriveD(CruiseHelper):
|
||||
self.events.add_from_msg(car_events)
|
||||
|
||||
car_events_sp = self.car_events_sp.update().to_msg()
|
||||
self.events_sp.add_from_msg(car_events_sp)
|
||||
self.events.add_from_msg(car_events_sp)
|
||||
|
||||
if self.CP.notCar:
|
||||
# wait for everything to init first
|
||||
@@ -380,7 +370,9 @@ class SelfdriveD(CruiseHelper):
|
||||
if self.sm['modelV2'].frameDropPerc > 20:
|
||||
self.events.add(EventName.modeldLagging)
|
||||
|
||||
CruiseHelper.update(self, CS, self.events_sp, self.experimental_mode)
|
||||
# toggle experimental mode once on distance button hold
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
ExperimentalSwitcher.update(self, CS, self.events, self.experimental_mode)
|
||||
|
||||
# decrement personality on distance button press
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
@@ -446,13 +438,9 @@ class SelfdriveD(CruiseHelper):
|
||||
clear_event_types.add(ET.NO_ENTRY)
|
||||
|
||||
pers = LONGITUDINAL_PERSONALITY_MAP[self.personality]
|
||||
callback_args = [self.CP, CS, self.sm, self.is_metric,
|
||||
self.state_machine.soft_disable_timer, pers]
|
||||
|
||||
alerts = self.events.create_alerts(self.state_machine.current_alert_types, callback_args)
|
||||
alerts_sp = self.events_sp.create_alerts(self.state_machine.current_alert_types, callback_args)
|
||||
|
||||
self.AM.add_many(self.sm.frame, alerts + alerts_sp)
|
||||
alerts = self.events.create_alerts(self.state_machine.current_alert_types, [self.CP, CS, self.sm, self.is_metric,
|
||||
self.state_machine.soft_disable_timer, pers])
|
||||
self.AM.add_many(self.sm.frame, alerts)
|
||||
self.AM.process_alerts(self.sm.frame, clear_event_types)
|
||||
|
||||
def publish_selfdriveState(self, CS):
|
||||
@@ -497,21 +485,13 @@ class SelfdriveD(CruiseHelper):
|
||||
|
||||
self.pm.send('selfdriveStateSP', ss_sp_msg)
|
||||
|
||||
# onroadEventsSP - logged every second or on change
|
||||
if (self.sm.frame % int(1. / DT_CTRL) == 0) or (self.events_sp.names != self.events_sp_prev):
|
||||
ce_send_sp = messaging.new_message('onroadEventsSP', len(self.events_sp))
|
||||
ce_send_sp.valid = True
|
||||
ce_send_sp.onroadEventsSP = self.events_sp.to_msg()
|
||||
self.pm.send('onroadEventsSP', ce_send_sp)
|
||||
self.events_sp_prev = self.events_sp.names.copy()
|
||||
|
||||
def step(self):
|
||||
CS = self.data_sample()
|
||||
self.update_events(CS)
|
||||
if not self.CP.passive and self.initialized:
|
||||
self.enabled, self.active = self.state_machine.update(self.events)
|
||||
if not self.CP.notCar:
|
||||
self.mads.update(CS)
|
||||
self.mads.update(CS, self.sm)
|
||||
self.update_alerts(CS)
|
||||
|
||||
self.publish_selfdriveState(CS)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import random
|
||||
|
||||
from openpilot.selfdrive.selfdrived.events import Alert, EVENTS
|
||||
from openpilot.selfdrive.selfdrived.events import Alert, EmptyAlert, EVENTS
|
||||
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EmptyAlert
|
||||
|
||||
|
||||
class TestAlertManager:
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ from itertools import zip_longest
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from tabulate import tabulate
|
||||
|
||||
from openpilot.common.git import get_commit
|
||||
from openpilot.system.hardware import PC
|
||||
@@ -31,11 +30,6 @@ API_TOKEN = os.getenv("GITHUB_COMMENTS_TOKEN","")
|
||||
MODEL_REPLAY_BUCKET="model_replay_master"
|
||||
GITHUB = GithubUtils(API_TOKEN, DATA_TOKEN)
|
||||
|
||||
EXEC_TIMINGS = [
|
||||
# model, instant max, average max
|
||||
("modelV2", 0.03, 0.025),
|
||||
("driverStateV2", 0.02, 0.015),
|
||||
]
|
||||
|
||||
def get_log_fn(test_route, ref="master"):
|
||||
return f"{test_route}_model_tici_{ref}.zst"
|
||||
@@ -162,33 +156,7 @@ def model_replay(lr, frs):
|
||||
del frs['roadCameraState'].frames
|
||||
del frs['wideRoadCameraState'].frames
|
||||
dmonitoringmodeld_msgs = replay_process(dmonitoringmodeld, dmodeld_logs, frs)
|
||||
|
||||
msgs = modeld_msgs + dmonitoringmodeld_msgs
|
||||
|
||||
header = ['model', 'max instant', 'max instant allowed', 'average', 'max average allowed', 'test result']
|
||||
rows = []
|
||||
timings_ok = True
|
||||
for (s, instant_max, avg_max) in EXEC_TIMINGS:
|
||||
ts = [getattr(m, s).modelExecutionTime for m in msgs if m.which() == s]
|
||||
# TODO some init can happen in first iteration
|
||||
ts = ts[1:]
|
||||
|
||||
errors = []
|
||||
if np.max(ts) > instant_max:
|
||||
errors.append("❌ FAILED MAX TIMING CHECK ❌")
|
||||
if np.mean(ts) > avg_max:
|
||||
errors.append("❌ FAILED AVG TIMING CHECK ❌")
|
||||
|
||||
timings_ok = not errors and timings_ok
|
||||
rows.append([s, np.max(ts), instant_max, np.mean(ts), avg_max, "\n".join(errors) or "✅"])
|
||||
|
||||
print("------------------------------------------------")
|
||||
print("----------------- Model Timing -----------------")
|
||||
print("------------------------------------------------")
|
||||
print(tabulate(rows, header, tablefmt="simple_grid", stralign="center", numalign="center", floatfmt=".4f"))
|
||||
assert timings_ok
|
||||
|
||||
return msgs
|
||||
return modeld_msgs + dmonitoringmodeld_msgs
|
||||
|
||||
|
||||
def get_frames():
|
||||
|
||||
@@ -23,7 +23,7 @@ from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.common.timeout import Timeout
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from panda.python import ALTERNATIVE_EXPERIENCE
|
||||
from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp
|
||||
from openpilot.selfdrive.car.card import can_comm_callbacks
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
|
||||
from openpilot.selfdrive.test.process_replay.migration import migrate_all
|
||||
@@ -344,7 +344,6 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
|
||||
if fingerprint:
|
||||
CarInterface, _, _, _ = interfaces[fingerprint]
|
||||
CP = CarInterface.get_non_essential_params(fingerprint)
|
||||
CP_SP = CarInterface.get_non_essential_params_sp(CP, fingerprint)
|
||||
else:
|
||||
can = DummySocket()
|
||||
sendcan = DummySocket()
|
||||
@@ -365,14 +364,12 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
|
||||
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
|
||||
cached_params = _cached_params
|
||||
|
||||
_CI = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params)
|
||||
CP, CP_SP = _CI.CP, _CI.CP_SP
|
||||
CP = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params).CP
|
||||
|
||||
if not params.get_bool("DisengageOnAccelerator"):
|
||||
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
||||
|
||||
params.put("CarParams", CP.to_bytes())
|
||||
params.put("CarParamsSP", convert_to_capnp(CP_SP).to_bytes())
|
||||
|
||||
|
||||
def selfdrived_rcv_callback(msg, cfg, frame):
|
||||
|
||||
@@ -74,6 +74,7 @@ if GetOption('extras'):
|
||||
qt_src.remove("main.cc") # replaced by test_runner
|
||||
qt_env.Program('tests/test_translations', [asset_obj, 'tests/test_runner.cc', 'tests/test_translations.cc'] + qt_src, LIBS=qt_libs)
|
||||
|
||||
if GetOption('extras'):
|
||||
qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs)
|
||||
|
||||
# spinner and text window
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdlib>
|
||||
@@ -10,7 +11,6 @@
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/installer/installer.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
@@ -36,6 +36,14 @@ const QString CACHE_PATH = "/data/openpilot.cache";
|
||||
extern const uint8_t str_continue[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_start");
|
||||
extern const uint8_t str_continue_end[] asm("_binary_selfdrive_ui_installer_continue_openpilot_sh_end");
|
||||
|
||||
bool time_valid() {
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
|
||||
struct tm * sys_time = gmtime(&rawtime);
|
||||
return (1900 + sys_time->tm_year) >= 2020;
|
||||
}
|
||||
|
||||
void run(const char* cmd) {
|
||||
int err = std::system(cmd);
|
||||
assert(err == 0);
|
||||
@@ -95,7 +103,7 @@ void Installer::updateProgress(int percent) {
|
||||
|
||||
void Installer::doInstall() {
|
||||
// wait for valid time
|
||||
while (!util::system_time_valid()) {
|
||||
while (!time_valid()) {
|
||||
usleep(500 * 1000);
|
||||
qDebug() << "Waiting for valid time";
|
||||
}
|
||||
|
||||
@@ -29,11 +29,6 @@ HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
|
||||
body = new BodyWindow(this);
|
||||
slayout->addWidget(body);
|
||||
|
||||
driver_view = new DriverViewWindow(this);
|
||||
connect(driver_view, &DriverViewWindow::done, [=] {
|
||||
showDriverView(false);
|
||||
});
|
||||
slayout->addWidget(driver_view);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &HomeWindow::updateState);
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &HomeWindow::offroadTransition);
|
||||
@@ -64,16 +59,6 @@ void HomeWindow::offroadTransition(bool offroad) {
|
||||
}
|
||||
}
|
||||
|
||||
void HomeWindow::showDriverView(bool show) {
|
||||
if (show) {
|
||||
emit closeSettings();
|
||||
slayout->setCurrentWidget(driver_view);
|
||||
} else {
|
||||
slayout->setCurrentWidget(home);
|
||||
}
|
||||
sidebar->setVisible(show == false);
|
||||
}
|
||||
|
||||
void HomeWindow::mousePressEvent(QMouseEvent* e) {
|
||||
// Handle sidebar collapsing
|
||||
if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/ui.h"
|
||||
#include "selfdrive/ui/qt/offroad/driverview.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
@@ -41,7 +40,6 @@ signals:
|
||||
|
||||
public slots:
|
||||
void offroadTransition(bool offroad);
|
||||
void showDriverView(bool show);
|
||||
void showSidebar(bool show);
|
||||
|
||||
protected:
|
||||
@@ -52,7 +50,6 @@ protected:
|
||||
OffroadHome *home;
|
||||
OnroadWindow *onroad;
|
||||
BodyWindow *body;
|
||||
DriverViewWindow *driver_view;
|
||||
QStackedLayout *slayout;
|
||||
|
||||
protected slots:
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
void setPrimeType(PrimeState::Type type);
|
||||
WifiManager* wifi = nullptr;
|
||||
|
||||
protected:
|
||||
private:
|
||||
QStackedLayout* main_layout = nullptr;
|
||||
QWidget* wifiScreen = nullptr;
|
||||
AdvancedNetworking* an = nullptr;
|
||||
|
||||
@@ -29,13 +29,6 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
});
|
||||
addItem(longManeuverToggle);
|
||||
|
||||
alphaLongToggle = new ParamControl("ExperimentalLongitudinalEnabled", tr("openpilot Longitudinal Control (Alpha)"), "", "../assets/offroad/icon_speed_limit.png");
|
||||
QObject::connect(alphaLongToggle, &ParamControl::toggleFlipped, [=](bool state) {
|
||||
updateToggles(offroad);
|
||||
});
|
||||
addItem(alphaLongToggle);
|
||||
alphaLongToggle->setConfirmation(true, false);
|
||||
|
||||
// TODO-SP: Move to Vehicles panel when ported back
|
||||
hyundaiRadarTracksToggle = new ParamControl(
|
||||
"HyundaiRadarTracksToggle",
|
||||
@@ -71,33 +64,12 @@ void DeveloperPanel::updateToggles(bool _offroad) {
|
||||
capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size()));
|
||||
cereal::CarParams::Reader CP = cmsg.getRoot<cereal::CarParams>();
|
||||
|
||||
const QString alpha_long_description = QString("<b>%1</b><br><br>%2")
|
||||
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
|
||||
.arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
|
||||
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha."));
|
||||
alphaLongToggle->setDescription("<b>" + alpha_long_description + "</b>");
|
||||
|
||||
if (!CP.getExperimentalLongitudinalAvailable() && !CP.getOpenpilotLongitudinalControl()) {
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
alphaLongToggle->setEnabled(false);
|
||||
alphaLongToggle->setDescription("<b>" + tr("openpilot longitudinal control may come in a future update.") + "</b>");
|
||||
}
|
||||
|
||||
// if is a release branch or if the car already have long control the alphaLongToggle should not be visible
|
||||
if (is_release || CP.getOpenpilotLongitudinalControl()) {
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
alphaLongToggle->setVisible(false);
|
||||
}
|
||||
|
||||
alphaLongToggle->refresh();
|
||||
|
||||
auto hyundai = CP.getCarName() == "hyundai";
|
||||
auto hyundai_mando_radar = hyundai && (CP.getFlags() & 4096);
|
||||
|
||||
longManeuverToggle->setEnabled(hasLongitudinalControl(CP) && _offroad);
|
||||
hyundaiRadarTracksToggle->setVisible(hyundai_mando_radar && hasLongitudinalControl(CP));
|
||||
} else {
|
||||
alphaLongToggle->setVisible(false);
|
||||
longManeuverToggle->setEnabled(false);
|
||||
hyundaiRadarTracksToggle->setVisible(false);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@ private:
|
||||
Params params;
|
||||
ParamControl* joystickToggle;
|
||||
ParamControl* longManeuverToggle;
|
||||
ParamControl* alphaLongToggle;
|
||||
ParamControl* hyundaiRadarTracksToggle;
|
||||
|
||||
bool is_release;
|
||||
bool offroad;
|
||||
|
||||
|
||||
@@ -6,24 +6,6 @@
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
|
||||
DriverViewWindow::DriverViewWindow(QWidget* parent) : CameraWidget("camerad", VISION_STREAM_DRIVER, parent) {
|
||||
QObject::connect(this, &CameraWidget::clicked, this, &DriverViewWindow::done);
|
||||
QObject::connect(device(), &Device::interactiveTimeout, this, [this]() {
|
||||
if (isVisible()) {
|
||||
emit done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DriverViewWindow::showEvent(QShowEvent* event) {
|
||||
params.putBool("IsDriverViewEnabled", true);
|
||||
device()->resetInteractiveTimeout(60);
|
||||
CameraWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void DriverViewWindow::hideEvent(QHideEvent* event) {
|
||||
params.putBool("IsDriverViewEnabled", false);
|
||||
stopVipcThread();
|
||||
CameraWidget::hideEvent(event);
|
||||
}
|
||||
|
||||
void DriverViewWindow::paintGL() {
|
||||
@@ -80,3 +62,20 @@ mat4 DriverViewWindow::calcFrameMatrix() {
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
}};
|
||||
}
|
||||
|
||||
DriverViewDialog::DriverViewDialog(QWidget *parent) : DialogBase(parent) {
|
||||
Params().putBool("IsDriverViewEnabled", true);
|
||||
device()->resetInteractiveTimeout(60);
|
||||
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(0, 0, 0, 0);
|
||||
auto camera = new DriverViewWindow(this);
|
||||
main_layout->addWidget(camera);
|
||||
QObject::connect(camera, &DriverViewWindow::clicked, this, &DialogBase::accept);
|
||||
QObject::connect(device(), &Device::interactiveTimeout, this, &DialogBase::accept);
|
||||
}
|
||||
|
||||
void DriverViewDialog::done(int r) {
|
||||
Params().putBool("IsDriverViewEnabled", false);
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
@@ -2,22 +2,20 @@
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/cameraview.h"
|
||||
#include "selfdrive/ui/qt/onroad/driver_monitoring.h"
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
|
||||
class DriverViewWindow : public CameraWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DriverViewWindow(QWidget *parent);
|
||||
|
||||
signals:
|
||||
void done();
|
||||
|
||||
protected:
|
||||
mat4 calcFrameMatrix() override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void paintGL() override;
|
||||
|
||||
Params params;
|
||||
mat4 calcFrameMatrix() override;
|
||||
DriverMonitorRenderer driver_monitor;
|
||||
};
|
||||
|
||||
class DriverViewDialog : public DialogBase {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DriverViewDialog(QWidget *parent);
|
||||
void done(int r) override;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/qt/offroad/driverview.h"
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
#include "selfdrive/ui/qt/offroad/settings.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
@@ -24,6 +25,15 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
tr("Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off."),
|
||||
"../assets/img_chffr_wheel.png",
|
||||
},
|
||||
{
|
||||
"ExperimentalLongitudinalEnabled",
|
||||
tr("openpilot Longitudinal Control (Alpha)"),
|
||||
QString("<b>%1</b><br><br>%2")
|
||||
.arg(tr("WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB)."))
|
||||
.arg(tr("On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. "
|
||||
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.")),
|
||||
"../assets/offroad/icon_speed_limit.png",
|
||||
},
|
||||
{
|
||||
"ExperimentalMode",
|
||||
tr("Experimental Mode"),
|
||||
@@ -100,6 +110,11 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
toggles["ExperimentalMode"]->setActiveIcon("../assets/img_experimental.svg");
|
||||
#endif
|
||||
toggles["ExperimentalMode"]->setConfirmation(true, true);
|
||||
toggles["ExperimentalLongitudinalEnabled"]->setConfirmation(true, false);
|
||||
|
||||
connect(toggles["ExperimentalLongitudinalEnabled"], &ToggleControl::toggleFlipped, [=]() {
|
||||
updateToggles();
|
||||
});
|
||||
}
|
||||
|
||||
void TogglesPanel::updateState(const UIState &s) {
|
||||
@@ -124,6 +139,7 @@ void TogglesPanel::showEvent(QShowEvent *event) {
|
||||
|
||||
void TogglesPanel::updateToggles() {
|
||||
auto experimental_mode_toggle = toggles["ExperimentalMode"];
|
||||
auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"];
|
||||
const QString e2e_description = QString("%1<br>"
|
||||
"<h4>%2</h4><br>"
|
||||
"%3<br>"
|
||||
@@ -147,6 +163,7 @@ void TogglesPanel::updateToggles() {
|
||||
if (!CP.getExperimentalLongitudinalAvailable() || is_release) {
|
||||
params.remove("ExperimentalLongitudinalEnabled");
|
||||
}
|
||||
op_long_toggle->setVisible(CP.getExperimentalLongitudinalAvailable() && !is_release);
|
||||
if (hasLongitudinalControl(CP)) {
|
||||
// normal description and toggle
|
||||
experimental_mode_toggle->setEnabled(true);
|
||||
@@ -175,6 +192,7 @@ void TogglesPanel::updateToggles() {
|
||||
experimental_mode_toggle->refresh();
|
||||
} else {
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
op_long_toggle->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +218,12 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
|
||||
auto dcamBtn = new ButtonControl(tr("Driver Camera"), tr("PREVIEW"),
|
||||
tr("Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)"));
|
||||
connect(dcamBtn, &ButtonControl::clicked, [=]() { emit showDriverView(); });
|
||||
connect(dcamBtn, &ButtonControl::clicked, [this, dcamBtn]() {
|
||||
dcamBtn->setEnabled(false);
|
||||
DriverViewDialog driver_view(this);
|
||||
driver_view.exec();
|
||||
dcamBtn->setEnabled(true);
|
||||
});
|
||||
addItem(dcamBtn);
|
||||
#endif
|
||||
|
||||
@@ -374,7 +397,6 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) {
|
||||
// setup panels
|
||||
DevicePanel *device = new DevicePanel(this);
|
||||
QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide);
|
||||
QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView);
|
||||
|
||||
TogglesPanel *toggles = new TogglesPanel(this);
|
||||
QObject::connect(this, &SettingsWindow::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
|
||||
@@ -40,7 +40,6 @@ protected:
|
||||
signals:
|
||||
void closeSettings();
|
||||
void reviewTrainingGuide();
|
||||
void showDriverView();
|
||||
void expandToggleDescription(const QString ¶m);
|
||||
|
||||
protected:
|
||||
@@ -57,7 +56,6 @@ public:
|
||||
|
||||
signals:
|
||||
void reviewTrainingGuide();
|
||||
void showDriverView();
|
||||
|
||||
protected slots:
|
||||
void poweroff();
|
||||
|
||||
@@ -79,9 +79,7 @@ CameraWidget::~CameraWidget() {
|
||||
glDeleteVertexArrays(1, &frame_vao);
|
||||
glDeleteBuffers(1, &frame_vbo);
|
||||
glDeleteBuffers(1, &frame_ibo);
|
||||
#ifndef QCOM2
|
||||
glDeleteTextures(2, textures);
|
||||
#endif
|
||||
}
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
|
||||
const QString BACKSPACE_KEY = "⌫";
|
||||
const QString ENTER_KEY = "→";
|
||||
const QString SHIFT_KEY = "⇧";
|
||||
const QString CAPS_LOCK_KEY = "⇪";
|
||||
|
||||
const QMap<QString, int> KEY_STRETCH = {{" ", 3}, {ENTER_KEY, 2}};
|
||||
|
||||
const QStringList CONTROL_BUTTONS = {SHIFT_KEY, CAPS_LOCK_KEY, "ABC", "#+=", "123", BACKSPACE_KEY, ENTER_KEY};
|
||||
const QStringList CONTROL_BUTTONS = {"↑", "↓", "ABC", "#+=", "123", BACKSPACE_KEY, ENTER_KEY};
|
||||
|
||||
const float key_spacing_vertical = 20;
|
||||
const float key_spacing_horizontal = 15;
|
||||
@@ -108,7 +106,7 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
|
||||
std::vector<QVector<QString>> lowercase = {
|
||||
{"q", "w", "e", "r", "t", "y", "u", "i", "o", "p"},
|
||||
{"a", "s", "d", "f", "g", "h", "j", "k", "l"},
|
||||
{SHIFT_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY},
|
||||
{"↑", "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY},
|
||||
{"123", "/", "-", " ", ".", ENTER_KEY},
|
||||
};
|
||||
main_layout->addWidget(new KeyboardLayout(this, lowercase));
|
||||
@@ -117,7 +115,7 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
|
||||
std::vector<QVector<QString>> uppercase = {
|
||||
{"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"},
|
||||
{"A", "S", "D", "F", "G", "H", "J", "K", "L"},
|
||||
{SHIFT_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY},
|
||||
{"↓", "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY},
|
||||
{"123", "/", "-", " ", ".", ENTER_KEY},
|
||||
};
|
||||
main_layout->addWidget(new KeyboardLayout(this, uppercase));
|
||||
@@ -143,39 +141,26 @@ Keyboard::Keyboard(QWidget *parent) : QFrame(parent) {
|
||||
main_layout->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void Keyboard::handleCapsPress() {
|
||||
shift_state = (shift_state + 1) % 3;
|
||||
bool is_uppercase = shift_state > 0;
|
||||
main_layout->setCurrentIndex(is_uppercase);
|
||||
|
||||
for (KeyButton* btn : main_layout->currentWidget()->findChildren<KeyButton*>()) {
|
||||
if (btn->text() == SHIFT_KEY || btn->text() == CAPS_LOCK_KEY) {
|
||||
btn->setText(shift_state == 2 ? CAPS_LOCK_KEY : SHIFT_KEY);
|
||||
btn->setStyleSheet(is_uppercase ? "background-color: #465BEA;" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::handleButton(QAbstractButton* btn) {
|
||||
const QString &key = btn->text();
|
||||
if (CONTROL_BUTTONS.contains(key)) {
|
||||
if (key == "ABC" || key == "123" || key == "#+=") {
|
||||
int index = (key == "ABC") ? 0 : (key == "123" ? 2 : 3);
|
||||
main_layout->setCurrentIndex(index);
|
||||
shift_state = 0;
|
||||
} else if (key == SHIFT_KEY || key == CAPS_LOCK_KEY) {
|
||||
handleCapsPress();
|
||||
if (key == "↓" || key == "ABC") {
|
||||
main_layout->setCurrentIndex(0);
|
||||
} else if (key == "↑") {
|
||||
main_layout->setCurrentIndex(1);
|
||||
} else if (key == "123") {
|
||||
main_layout->setCurrentIndex(2);
|
||||
} else if (key == "#+=") {
|
||||
main_layout->setCurrentIndex(3);
|
||||
} else if (key == ENTER_KEY) {
|
||||
main_layout->setCurrentIndex(0);
|
||||
shift_state = 0;
|
||||
emit emitEnter();
|
||||
} else if (key == BACKSPACE_KEY) {
|
||||
emit emitBackspace();
|
||||
}
|
||||
} else {
|
||||
if (shift_state == 1 && "A" <= key && key <= "Z") {
|
||||
if ("A" <= key && key <= "Z") {
|
||||
main_layout->setCurrentIndex(0);
|
||||
shift_state = 0;
|
||||
}
|
||||
emit emitKey(key);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,9 @@ public:
|
||||
|
||||
private:
|
||||
QStackedLayout* main_layout;
|
||||
int shift_state = 0;
|
||||
|
||||
private slots:
|
||||
void handleButton(QAbstractButton* m_button);
|
||||
void handleCapsPress();
|
||||
|
||||
signals:
|
||||
void emitKey(const QString &s);
|
||||
|
||||
@@ -23,9 +23,6 @@ MainWindow::MainWindow(QWidget *parent, HomeWindow *hw, SettingsWindow *sw) :
|
||||
onboardingWindow->showTrainingGuide();
|
||||
main_layout->setCurrentWidget(onboardingWindow);
|
||||
});
|
||||
QObject::connect(settingsWindow, &SettingsWindow::showDriverView, [=] {
|
||||
homeWindow->showDriverView(true);
|
||||
});
|
||||
|
||||
onboardingWindow = new OnboardingWindow(this);
|
||||
main_layout->addWidget(onboardingWindow);
|
||||
|
||||
@@ -4,7 +4,6 @@ widgets_src = [
|
||||
"sunnypilot/qt/widgets/drive_stats.cc",
|
||||
"sunnypilot/qt/widgets/prime.cc",
|
||||
"sunnypilot/qt/widgets/scrollview.cc",
|
||||
"sunnypilot/qt/network/networking.cc",
|
||||
]
|
||||
|
||||
qt_util = [
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QStackedLayout>
|
||||
|
||||
NetworkingSP::NetworkingSP(QWidget *parent) : Networking(parent) {
|
||||
auto vlayout = wifiScreen->findChild<QVBoxLayout*>();
|
||||
auto hlayout = new QHBoxLayout();
|
||||
|
||||
// Create and setup scan button
|
||||
auto scanButton = new QPushButton(tr("Scan"));
|
||||
scanButton->setObjectName("scan_btn");
|
||||
scanButton->setFixedSize(400, 100);
|
||||
|
||||
connect(wifi, &WifiManager::refreshSignal, this, [=]() { scanButton->setText(tr("Scan")); scanButton->setEnabled(true); });
|
||||
connect(scanButton, &QPushButton::clicked, [=]() { scanButton->setText(tr("Scanning...")); scanButton->setEnabled(false); wifi->requestScan(); });
|
||||
|
||||
hlayout->addWidget(scanButton);
|
||||
hlayout->addStretch(1);
|
||||
|
||||
// Look for an existing Advanced button
|
||||
QPushButton* existingAdvanced = wifiScreen->findChild<QPushButton*>("advanced_btn");
|
||||
if (existingAdvanced) {
|
||||
hlayout->addWidget(existingAdvanced);
|
||||
}
|
||||
|
||||
// Insert our new layout at the top of vlayout
|
||||
vlayout->setMargin(40);
|
||||
vlayout->insertLayout(0, hlayout);
|
||||
|
||||
// Add our scan button to the existing style selectors
|
||||
auto newStyleSheet = styleSheet().replace(
|
||||
", #advanced_btn ",
|
||||
", #advanced_btn, #scan_btn "
|
||||
).replace(
|
||||
", #advanced_btn:pressed",
|
||||
", #advanced_btn:pressed, #scan_btn:pressed"
|
||||
).append(R"(
|
||||
#scan_btn:disabled {
|
||||
background-color: #121212;
|
||||
color: #33FFFFFF;
|
||||
}
|
||||
)");
|
||||
setStyleSheet(newStyleSheet);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
*
|
||||
* This file is part of sunnypilot and is licensed under the MIT License.
|
||||
* See the LICENSE.md file in the root directory for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
|
||||
|
||||
class NetworkingSP : public Networking {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NetworkingSP(QWidget *parent = nullptr);
|
||||
};
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
||||
|
||||
#include "common/watchdog.h"
|
||||
#include "selfdrive/ui/qt/offroad/driverview.h"
|
||||
#include "selfdrive/ui/qt/qt_window.h"
|
||||
|
||||
DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
@@ -40,7 +41,12 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
}
|
||||
}
|
||||
|
||||
connect(buttons["dcamBtn"], &PushButtonSP::clicked, [=]() { emit showDriverView(); });
|
||||
connect(buttons["dcamBtn"], &PushButtonSP::clicked, [this]() {
|
||||
buttons["dcamBtn"]->setEnabled(false);
|
||||
DriverViewDialog driver_view(this);
|
||||
driver_view.exec();
|
||||
buttons["dcamBtn"]->setEnabled(true);
|
||||
});
|
||||
|
||||
connect(buttons["retrainingBtn"], &PushButtonSP::clicked, [=]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to review the training guide?"), tr("Review"), this)) {
|
||||
@@ -68,17 +74,23 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
|
||||
addItem(device_grid_layout);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
for (auto btn : findChildren<PushButtonSP*>()) {
|
||||
btn->setEnabled(offroad);
|
||||
}
|
||||
});
|
||||
|
||||
// offroad mode and power buttons
|
||||
|
||||
QHBoxLayout *power_layout = new QHBoxLayout();
|
||||
power_layout->setSpacing(5);
|
||||
|
||||
PushButtonSP *rebootBtn = new PushButtonSP(tr("Reboot"), 720, this);
|
||||
QPushButton *rebootBtn = new PushButtonSP(tr("Reboot"), 720, this);
|
||||
rebootBtn->setStyleSheet(rebootButtonStyle);
|
||||
power_layout->addWidget(rebootBtn);
|
||||
QObject::connect(rebootBtn, &PushButtonSP::clicked, this, &DevicePanelSP::reboot);
|
||||
|
||||
PushButtonSP *poweroffBtn = new PushButtonSP(tr("Power Off"), 720, this);
|
||||
QPushButton *poweroffBtn = new PushButtonSP(tr("Power Off"), 720, this);
|
||||
poweroffBtn->setStyleSheet(powerOffButtonStyle);
|
||||
power_layout->addWidget(poweroffBtn);
|
||||
QObject::connect(poweroffBtn, &PushButtonSP::clicked, this, &DevicePanelSP::poweroff);
|
||||
@@ -87,60 +99,5 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) {
|
||||
connect(uiState(), &UIState::offroadTransition, poweroffBtn, &PushButtonSP::setVisible);
|
||||
}
|
||||
|
||||
offroadBtn = new PushButtonSP(tr("Offroad Mode"));
|
||||
offroadBtn->setFixedWidth(power_layout->sizeHint().width());
|
||||
QObject::connect(offroadBtn, &PushButtonSP::clicked, this, &DevicePanelSP::setOffroadMode);
|
||||
|
||||
QVBoxLayout *power_group_layout = new QVBoxLayout();
|
||||
power_group_layout->setSpacing(30);
|
||||
power_group_layout->addWidget(offroadBtn, 0, Qt::AlignHCenter);
|
||||
power_group_layout->addLayout(power_layout);
|
||||
|
||||
addItem(power_group_layout);
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) {
|
||||
for (auto btn : findChildren<PushButtonSP*>()) {
|
||||
if (btn != rebootBtn && btn != poweroffBtn && btn != offroadBtn) {
|
||||
btn->setEnabled(offroad);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DevicePanelSP::setOffroadMode() {
|
||||
if (!uiState()->engaged()) {
|
||||
if (params.getBool("OffroadMode")) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to exit Always Offroad mode?"), tr("Confirm"), this)) {
|
||||
// Check engaged again in case it changed while the dialog was open
|
||||
if (!uiState()->engaged()) {
|
||||
params.remove("OffroadMode");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to enter Always Offroad mode?"), tr("Confirm"), this)) {
|
||||
// Check engaged again in case it changed while the dialog was open
|
||||
if (!uiState()->engaged()) {
|
||||
params.putBool("OffroadMode", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConfirmationDialog::alert(tr("Disengage to Enter Always Offroad Mode"), this);
|
||||
}
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
void DevicePanelSP::showEvent(QShowEvent *event) {
|
||||
updateState();
|
||||
}
|
||||
|
||||
void DevicePanelSP::updateState() {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool offroad_mode_param = params.getBool("OffroadMode");
|
||||
offroadBtn->setText(offroad_mode_param ? tr("Exit Always Offroad") : tr("Always Offroad"));
|
||||
offroadBtn->setStyleSheet(offroad_mode_param ? alwaysOffroadStyle : autoOffroadStyle);
|
||||
addItem(power_layout);
|
||||
}
|
||||
|
||||
@@ -15,43 +15,9 @@ class DevicePanelSP : public DevicePanel {
|
||||
|
||||
public:
|
||||
explicit DevicePanelSP(SettingsWindowSP *parent = 0);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void setOffroadMode();
|
||||
void updateState();
|
||||
|
||||
private:
|
||||
std::map<QString, PushButtonSP*> buttons;
|
||||
PushButtonSP *offroadBtn;
|
||||
|
||||
const QString alwaysOffroadStyle = R"(
|
||||
PushButtonSP {
|
||||
border-radius: 20px;
|
||||
font-size: 50px;
|
||||
font-weight: 450;
|
||||
height: 150px;
|
||||
padding: 0 25px 0 25px;
|
||||
color: #FFFFFF;
|
||||
background-color: #393939;
|
||||
}
|
||||
PushButtonSP:pressed {
|
||||
background-color: #4A4A4A;
|
||||
}
|
||||
)";
|
||||
|
||||
const QString autoOffroadStyle = R"(
|
||||
PushButtonSP {
|
||||
border-radius: 20px;
|
||||
font-size: 50px;
|
||||
font-weight: 450;
|
||||
height: 150px;
|
||||
padding: 0 25px 0 25px;
|
||||
color: #FFFFFF;
|
||||
background-color: #E22C2C;
|
||||
}
|
||||
PushButtonSP:pressed {
|
||||
background-color: #FF2424;
|
||||
}
|
||||
)";
|
||||
|
||||
const QString rebootButtonStyle = R"(
|
||||
PushButtonSP {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h"
|
||||
|
||||
#include "selfdrive/ui/qt/network/networking.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
#include "selfdrive/ui/qt/offroad/developer_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/network/networking.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
|
||||
@@ -62,13 +62,12 @@ SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) {
|
||||
// setup panels
|
||||
DevicePanelSP *device = new DevicePanelSP(this);
|
||||
QObject::connect(device, &DevicePanelSP::reviewTrainingGuide, this, &SettingsWindowSP::reviewTrainingGuide);
|
||||
QObject::connect(device, &DevicePanelSP::showDriverView, this, &SettingsWindowSP::showDriverView);
|
||||
|
||||
TogglesPanelSP *toggles = new TogglesPanelSP(this);
|
||||
QObject::connect(this, &SettingsWindowSP::expandToggleDescription, toggles, &TogglesPanel::expandToggleDescription);
|
||||
|
||||
auto networking = new NetworkingSP(this);
|
||||
QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &NetworkingSP::setPrimeType);
|
||||
auto networking = new Networking(this);
|
||||
QObject::connect(uiState()->prime_state, &PrimeState::changed, networking, &Networking::setPrimeType);
|
||||
|
||||
QList<PanelInfo> panels = {
|
||||
PanelInfo(" " + tr("Device"), device, "../../sunnypilot/selfdrive/assets/offroad/icon_home.svg"),
|
||||
|
||||
@@ -40,14 +40,6 @@ def setup_homescreen(click, pm: PubMaster, scroll=None):
|
||||
def setup_settings_device(click, pm: PubMaster, scroll=None):
|
||||
click(100, 100)
|
||||
|
||||
def setup_settings_network(click, pm: PubMaster, scroll=None):
|
||||
setup_settings_device(click, pm)
|
||||
click(278, 405)
|
||||
|
||||
def setup_settings_network_advanced(click, pm: PubMaster, scroll=None):
|
||||
setup_settings_network(click, pm)
|
||||
click(1913, 90)
|
||||
|
||||
def setup_settings_toggles(click, pm: PubMaster, scroll=None):
|
||||
setup_settings_device(click, pm)
|
||||
click(278, 632)
|
||||
@@ -220,8 +212,6 @@ CASES = {
|
||||
"prime": setup_homescreen,
|
||||
"pair_device": setup_pair_device,
|
||||
"settings_device": setup_settings_device,
|
||||
"settings_network": setup_settings_network,
|
||||
"settings_network_advanced": setup_settings_network_advanced,
|
||||
"settings_toggles": setup_settings_toggles,
|
||||
"settings_software": setup_settings_software,
|
||||
"settings_developer": setup_settings_developer,
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation>وضع المناورة الطولية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>التحكم الطولي openpilot (ألفا)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>قد يتم الحصول على التحكم الطولي في openpilot في عمليات التحديث المستقبلية.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">التنظيمية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">إعادة التشغيل</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">التنظيمية</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">هل أنت متأكد أنك تريد مراجعة دليل التدريب؟</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">اختر لغة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">إعادة التشغيل</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">إيقاف التشغيل</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">تأكيد</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>القيادة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ساعات</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>كامل الوقت</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>الأسبوع الماضي</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>كم</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ميل</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -457,10 +413,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -492,6 +444,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -523,17 +479,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>كلمة مرور خاطئة</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -582,10 +527,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation>لقد اكتشف openpilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -645,7 +586,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>يرجى الاتصال بشبكة الواي فاي لإكمال الاقتران الأولي</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -663,11 +604,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">تمكين</translation>
|
||||
<translation>تمكين</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">إلغاء</translation>
|
||||
<translation>إلغاء</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -836,40 +777,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">الجهاز</translation>
|
||||
<translation>الجهاز</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">الشبكة</translation>
|
||||
<translation>الشبكة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>المثبتتات</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>البرنامج</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>المطور</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">المثبتتات</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">البرنامج</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">المطور</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1160,16 +1101,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">اختيار</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">إعادة ضبط المعايرة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">متابعة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1188,6 +1145,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1204,24 +1177,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1229,7 +1190,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">إلغاء</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1240,30 +1205,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">إعادة ضبط المعايرة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">متابعة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">إلغاء</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1322,11 +1263,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">غير متاح</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1334,12 +1275,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">غير متاح</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1348,10 +1293,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1414,6 +1355,18 @@ This may take up to a minute.</source>
|
||||
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
|
||||
<translation>عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>التحكم الطولي openpilot (ألفا)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental Mode</source>
|
||||
<translation>الوضع التجريبي</translation>
|
||||
|
||||
@@ -124,19 +124,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<source>Enable GitHub runner service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -147,14 +139,6 @@
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable GitHub runner service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DevicePanel</name>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Rechtliche Hinweise</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Neustart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Rechtliche Hinweise</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">Sprache wählen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Neustart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">Ausschalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">Bestätigen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Fahrten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Stunden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Gesamtzeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Letzte Woche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>KM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Meilen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -453,10 +409,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -488,6 +440,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>Falsches Passwort</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">Aktivieren</translation>
|
||||
<source>Cancel</source>
|
||||
<translation>Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Abbrechen</translation>
|
||||
<source>Enable</source>
|
||||
<translation>Aktivieren</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -818,40 +759,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">x</translation>
|
||||
<translation>x</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">Gerät</translation>
|
||||
<translation>Gerät</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">Netzwerk</translation>
|
||||
<translation>Netzwerk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Schalter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">Schalter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1144,16 +1085,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">AUSWÄHLEN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Neu kalibrieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Fortsetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1172,6 +1129,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1188,24 +1161,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1213,7 +1174,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1224,30 +1189,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Neu kalibrieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Fortsetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Abbrechen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1306,11 +1247,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">Nicht verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1318,12 +1259,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">Nicht verfügbar</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1332,10 +1277,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1418,6 +1359,14 @@ This may take up to a minute.</source>
|
||||
<source>Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.</source>
|
||||
<translation>Der experimentelle Modus ist momentan für dieses Auto nicht verfügbar da es den eingebauten adaptiven Tempomaten des Autos benutzt.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1434,6 +1383,10 @@ This may take up to a minute.</source>
|
||||
<source>Driving Personality</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>End-to-End Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation>Modo de maniobra longitudinal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Control longitudinal de openpilot (fase experimental)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>El control longitudinal de openpilot podrá llegar en futuras actualizaciones.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Regulador</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Reiniciar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Regulador</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">¿Seguro que quiere revisar la guía de entrenamiento?</translation>
|
||||
@@ -329,42 +317,10 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Reiniciar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">Apagar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">Confirmar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -455,7 +411,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation type="unfinished">Nota: Para vehículos sin botón de LFA/LKAS, deshabilitar este ajuste evitará que se active el control lateral.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>Contraseña incorrecta</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -578,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation>openpilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -641,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>Conéctese a Wi-Fi para completar el emparejamiento inicial</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -659,11 +600,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">Activar</translation>
|
||||
<translation>Activar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -820,40 +761,40 @@ Esto puede tardar un minuto.</translation>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">Dispositivo</translation>
|
||||
<translation>Dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">Red</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Red</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">Ajustes</translation>
|
||||
<translation>Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">Software</translation>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>Desarrollador</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation>sunnylink</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">Desarrollador</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1044,7 +985,7 @@ Esto puede tardar un minuto.</translation>
|
||||
<name>SidebarSP</name>
|
||||
<message>
|
||||
<source>DISABLED</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>DESHABILITADO</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>OFFLINE</source>
|
||||
@@ -1052,19 +993,19 @@ Esto puede tardar un minuto.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>REGIST...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>REGIST...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ONLINE</source>
|
||||
<translation type="unfinished">EN LÍNEA</translation>
|
||||
<translation>EN LÍNEA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ERROR</source>
|
||||
<translation type="unfinished">ERROR</translation>
|
||||
<translation>ERROR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SUNNYLINK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SUNNYLINK</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1144,94 +1085,14 @@ Esto puede tardar un minuto.</translation>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">SELECCIONAR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Navigation</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Metadata</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>downloaded</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ready</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>We STRONGLY suggest you to reset calibration.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Formatear Calibración</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1244,10 +1105,90 @@ Esto puede tardar un minuto.</translation>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation>modelo de %1 [%2] pendiente...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation>Obteniendo modelos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation>Descarga de modelo iniciada en segundo plano.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation>Modelo Actual</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving</source>
|
||||
<translation>Conducción</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Navigation</source>
|
||||
<translation>Navegación</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Metadata</source>
|
||||
<translation>Metadatos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation>Descargando modelo de %1 [%2]... (%3%)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation>Falló descarga modelo de %1 [%2]</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation>Selecciona un Modelo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation>Modelo de %1 [%2] %3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>downloaded</source>
|
||||
<translation>descargado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ready</source>
|
||||
<translation>listo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>from cache</source>
|
||||
<translation>desde caché</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation>Por Defecto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<translation>No hay ningún modelo personalizado elegido!.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default</source>
|
||||
<translation>Por Defecto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>We STRONGLY suggest you to reset calibration.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1299,31 +1240,35 @@ Esto puede tardar un minuto.</translation>
|
||||
<name>SunnylinkPanel</name>
|
||||
<message>
|
||||
<source>This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Este es el interruptor principal; te permitirá desactivar completamente cualquier connectividad de sunnylink si así lo deseas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device ID</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Habilitar sunnylink</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation>🎉¡Bienvenido de vuelta! Nos alegra que hayas reactivado sunnylink. 🚀</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device ID</source>
|
||||
<translation>ID del dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation>👋No te mentiremos, nos entristece que hayas desactivado sunnylink 😢. Estaremos aquí cuando estes listo para volver 🎉.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1332,10 +1277,6 @@ Esto puede tardar un minuto.</translation>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1366,6 +1307,18 @@ Esto puede tardar un minuto.</translation>
|
||||
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
|
||||
<translation>Utilice el sistema openpilot para acceder a un autocrucero adaptativo y asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Cambiar esta configuración solo tendrá efecto con el auto apagado.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Control longitudinal de openpilot (fase experimental)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental Mode</source>
|
||||
<translation>Modo Experimental</translation>
|
||||
|
||||
@@ -117,27 +117,11 @@
|
||||
<name>DeveloperPanel</name>
|
||||
<message>
|
||||
<source>Joystick Debug Mode</source>
|
||||
<translation>Mode débogage au joystick</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Longitudinal Maneuver Mode</source>
|
||||
<translation>Mode manœuvre longitudinale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Contrôle longitudinal openpilot (Alpha)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d'urgence automatique (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d'openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d'activer le mode expérimental lors de l'activation du contrôle longitudinal openpilot alpha.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>Le contrôle longitudinal openpilot pourrait être disponible dans une future mise à jour.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
@@ -292,11 +276,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair Device</source>
|
||||
<translation>Associer l'appareil</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAIR</source>
|
||||
<translation>ASSOCIER</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -337,34 +321,6 @@
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">Éteindre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">Confirmer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -519,21 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>Mot de passe incorrect</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Advanced</source>
|
||||
<translation type="obsolete">Avancé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -582,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation>openpilot a détecté un changement dans la position de montage de l'appareil. Assurez-vous que l'appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -606,23 +543,23 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>OnroadAlerts</name>
|
||||
<message>
|
||||
<source>openpilot Unavailable</source>
|
||||
<translation>openpilot indisponible</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TAKE CONTROL IMMEDIATELY</source>
|
||||
<translation>REPRENEZ LE CONTRÔLE IMMÉDIATEMENT</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot Device</source>
|
||||
<translation>Redémarrer l'appareil</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Waiting to start</source>
|
||||
<translation>En attente de démarrage</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>System Unresponsive</source>
|
||||
<translation>Système inopérant</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -645,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>Connectez-vous au Wi-Fi pour terminer l'appairage initial</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -698,7 +635,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Remote snapshots</source>
|
||||
<translation>Captures à distance</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -749,7 +686,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>now</source>
|
||||
<translation>maintenant</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -790,7 +727,7 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.</source>
|
||||
<translation>Réinitialisation système déclenchée. Appuyez sur confirmer pour effacer tout le contenu et les paramètres. Appuyez sur annuler pour reprendre le démarrage.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -817,7 +754,7 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>Dév.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -844,7 +781,7 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">Dév.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
@@ -943,15 +880,15 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Choose Software to Install</source>
|
||||
<translation>Choisir le logiciel à installer</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot</source>
|
||||
<translation>openpilot</translation>
|
||||
<translation type="unfinished">openpilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Software</source>
|
||||
<translation>Logiciel personnalisé</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1370,6 +1307,18 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
|
||||
<translation>Utilisez le système openpilot pour le régulateur de vitesse adaptatif et l'assistance au maintien de voie. Votre attention est requise en permanence pour utiliser cette fonctionnalité. La modification de ce paramètre prend effet lorsque la voiture est éteinte.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Contrôle longitudinal openpilot (Alpha)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d'urgence automatique (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d'openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d'activer le mode expérimental lors de l'activation du contrôle longitudinal openpilot alpha.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental Mode</source>
|
||||
<translation>Mode expérimental</translation>
|
||||
@@ -1456,7 +1405,7 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button.</source>
|
||||
<translation>Le mode Standard est recommandé. En mode Agressif, openpilot suivra les véhicules de plus près et sera plus dynamique avec l'accélérateur et le frein. En mode Détendu, openpilot maintiendra une distance plus importante avec les véhicules qui précèdent. Sur les véhicules compatibles, vous pouvez alterner entre ces personnalités à l'aide du bouton de distance au volant.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.</source>
|
||||
@@ -1464,11 +1413,11 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always-On Driver Monitoring</source>
|
||||
<translation>Surveillance continue du conducteur</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable driver monitoring even when openpilot is not engaged.</source>
|
||||
<translation>Activer la surveillance conducteur lorsque openpilot n'est pas actif.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Dynamic Experimental Control</source>
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Tethering</source>
|
||||
<translation>テザリング有効</translation>
|
||||
<translation>テザリングを有効化</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tethering Password</source>
|
||||
<translation>テザリングパスワード</translation>
|
||||
<translation>テザリングパスワード</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EDIT</source>
|
||||
@@ -40,23 +40,23 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>IP Address</source>
|
||||
<translation>IPアドレス</translation>
|
||||
<translation>IP アドレス</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Roaming</source>
|
||||
<translation>ローミング有効</translation>
|
||||
<translation>ローミングを有効化</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>APN Setting</source>
|
||||
<translation>APN設定</translation>
|
||||
<translation>APN 設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter APN</source>
|
||||
<translation>APNを入力</translation>
|
||||
<translation>APN を入力</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>leave blank for automatic configuration</source>
|
||||
<translation>自動で設定するには空白のままにしてください</translation>
|
||||
<translation>自動で設定するには、空白のままにしてください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cellular Metered</source>
|
||||
@@ -64,27 +64,27 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Prevent large data uploads when on a metered connection</source>
|
||||
<translation>大量のデータのアップロードを防止する</translation>
|
||||
<translation>大量のデータのアップロードを防止します。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hidden Network</source>
|
||||
<translation>ネットワーク非表示</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CONNECT</source>
|
||||
<translation>接続</translation>
|
||||
<translation type="unfinished">接続</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter SSID</source>
|
||||
<translation>SSIDを入力</translation>
|
||||
<translation type="unfinished">SSID を入力</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter password</source>
|
||||
<translation>パスワードを入力</translation>
|
||||
<translation type="unfinished">パスワードを入力</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>for "%1"</source>
|
||||
<translation>[%1]</translation>
|
||||
<translation type="unfinished">ネットワーク名:%1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -102,7 +102,7 @@
|
||||
<name>DeclinePage</name>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions in order to use openpilot.</source>
|
||||
<translation>openpilotを使用するためには利用規約に同意する必要があります</translation>
|
||||
<translation>openpilot をご利用される前に、利用規約に同意する必要があります。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
@@ -110,34 +110,18 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline, uninstall %1</source>
|
||||
<translation>同意しない(%1をアンインストール)</translation>
|
||||
<translation>拒否して %1 をアンインストール</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DeveloperPanel</name>
|
||||
<message>
|
||||
<source>Joystick Debug Mode</source>
|
||||
<translation>ジョイスティックデバッグモード</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Longitudinal Maneuver Mode</source>
|
||||
<translation>アクセル制御マニューバー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>openpilotアクセル制御(Alpha)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>この車ではopenpilotのアクセル制御はアルファ版であり、自動緊急ブレーキ(AEB)が無効化されます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>この車では、openpilotは車両内蔵のACC(アダプティブクルーズコントロール)をデフォルトとして使用し、openpilotのアクセル制御は無効化されています。アクセル制御をopenpilotに切り替えるにはこの設定を有効にしてください。また同時にExperimentalモードを推奨します。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>openpilotのアクセル制御は、将来のアップデートで利用できる可能性があります。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
@@ -160,11 +144,11 @@
|
||||
<name>DevicePanel</name>
|
||||
<message>
|
||||
<source>Dongle ID</source>
|
||||
<translation>ドングルID</translation>
|
||||
<translation>ドングル番号 (Dongle ID)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation>該当なし</translation>
|
||||
<translation>N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Serial</source>
|
||||
@@ -180,47 +164,47 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)</source>
|
||||
<translation>車内カメラでドライバー監視システムのカメラ画像を確認できます。(車両のパワーOFF時の機能です)</translation>
|
||||
<translation>車内カメラをプレビューして、ドライバー監視システムの視界を確認ができます。(車両の電源を切る必要があります)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation>キャリブレーションリセット</translation>
|
||||
<translation>キャリブレーションをリセット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RESET</source>
|
||||
<translation>リセット</translation>
|
||||
<translation>リセット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset calibration?</source>
|
||||
<translation>キャリブレーションをリセットしますか?</translation>
|
||||
<translation>キャリブレーションをリセットしてもよろしいですか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Review Training Guide</source>
|
||||
<translation>トレーニングガイドを見る</translation>
|
||||
<translation>使い方の確認</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>REVIEW</source>
|
||||
<translation>確認</translation>
|
||||
<translation>見る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Review the rules, features, and limitations of openpilot</source>
|
||||
<translation>openpilotのルール、機能、および制限を確認してください</translation>
|
||||
<translation>openpilot の特徴を見る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation>トレーニングガイドを始めてもよろしいですか?</translation>
|
||||
<translation>使い方の確認をしますか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation>規約</translation>
|
||||
<translation>認証情報</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>VIEW</source>
|
||||
<translation>確認</translation>
|
||||
<translation>見る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change Language</source>
|
||||
<translation>多言語対応</translation>
|
||||
<translation>言語を変更</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CHANGE</source>
|
||||
@@ -236,11 +220,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation>パワーオフ</translation>
|
||||
<translation>電源を切る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. openpilot is continuously calibrating, resetting is rarely required.</source>
|
||||
<translation>openpilotの本体は左右4°以内、上5°下9°以内の角度で取付ける必要があります。常にキャリブレーションされておりリセットはほとんど必要ありません。</translation>
|
||||
<translation>openpilotの本体は、左右4°以内、上5°、下9°以内の角度で取付ける必要があります。継続してキャリブレーションを続けているので、手動でリセットを行う必要はほぼありません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> Your device is pointed %1° %2 and %3° %4.</source>
|
||||
@@ -268,15 +252,15 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Reboot</source>
|
||||
<translation>再起動するには車を一旦停止してください</translation>
|
||||
<translation>openpilot をキャンセルして再起動ができます</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to power off?</source>
|
||||
<translation>パワーオフしてもよろしいですか?</translation>
|
||||
<translation>シャットダウンしてもよろしいですか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Power Off</source>
|
||||
<translation>パワーオフするには車を一旦停止してください</translation>
|
||||
<translation>openpilot をキャンセルしてシャットダウンができます</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
@@ -284,19 +268,19 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Review</source>
|
||||
<translation>見る</translation>
|
||||
<translation>確認</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
|
||||
<translation>デバイスをcommaコネクト(connect.comma.ai)でペアリングしてcommaプライムの特典を受け取ってください。</translation>
|
||||
<translation>デバイスを comma connect (connect.comma.ai)でペアリングし、comma primeの特典を申請してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair Device</source>
|
||||
<translation>デバイスのペアリング</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAIR</source>
|
||||
<translation>OK</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -337,34 +321,6 @@
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">電源を切る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">確認</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
@@ -397,18 +353,18 @@
|
||||
<name>DriverViewWindow</name>
|
||||
<message>
|
||||
<source>camera starting</source>
|
||||
<translation>カメラ起動中</translation>
|
||||
<translation>カメラを起動しています</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
<message>
|
||||
<source>EXPERIMENTAL MODE ON</source>
|
||||
<translation>EXPERIMENTALモード</translation>
|
||||
<translation>実験モード</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>CHILL MODE ON</source>
|
||||
<translation>CHILLモード</translation>
|
||||
<translation>チルモード</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -423,7 +379,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>MAX</source>
|
||||
<translation>最大速度</translation>
|
||||
<translation>最高速度</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -435,7 +391,7 @@
|
||||
<message numerus="yes">
|
||||
<source>Need at least %n character(s)!</source>
|
||||
<translation>
|
||||
<numerusform>%n文字以上にして下さい!</numerusform>
|
||||
<numerusform>%n文字以上でお願いします!</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -443,7 +399,7 @@
|
||||
<name>Installer</name>
|
||||
<message>
|
||||
<source>Installing...</source>
|
||||
<translation>インストール中...</translation>
|
||||
<translation>インストールしています...</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -511,78 +467,58 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>for "%1"</source>
|
||||
<translation>[%1]</translation>
|
||||
<translation>ネットワーク名:%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Wrong password</source>
|
||||
<translation>パスワードが違います</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Advanced</source>
|
||||
<translation type="obsolete">詳細</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>パスワードが間違っています</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
<source>Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1</source>
|
||||
<translation>インターネットへ接続してアップデートを確認してください。未接続のままではopenpilotを使用できなくなります。あと[%1]</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates.</source>
|
||||
<translation>インターネットに接続してアップデートを確認してください。接続するまでopenpilotは使用できません。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to download updates
|
||||
%1</source>
|
||||
<translation>更新をダウンロードできませんでした
|
||||
%1</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Taking camera snapshots. System won't start until finished.</source>
|
||||
<translation>スナップショットを撮影中です。完了するまでシステムは起動しません。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.</source>
|
||||
<translation>オペレーティングシステムがバックグラウンドでダウンロードされています。インストールの準備が整うと更新を促されます。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support.</source>
|
||||
<translation>登録に失敗しました。このデバイスはcomma.aiのサーバーに接続したりデータをアップロードしたりできません。またcomma.aiのサポートも受けられません。公式デバイスである場合は https://comma.ai/support に問い合わせて下さい。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>NVMe drive not mounted.</source>
|
||||
<translation>SSDドライブ(NVMe)がマウントされていません。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe.</source>
|
||||
<translation>非サポートのSSDドライブ(NVMe)が検出されました。このドライブを使用するとデバイスが多大な電力を消費し過熱する可能性があります。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.</source>
|
||||
<translation>openpilotが車両を識別できませんでした。車が未対応またはECUが認識されていない可能性があります。該当車両のファームウェアバージョンを追加するためにプルリクエストしてください。サポートが必要な場合は discord.comma.ai に参加することができます。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation>openpilotがデバイスの取り付け位置にずれを検出しました。デバイスの固定とマウントがフロントガラスにしっかりと取り付けられていることを確認してください。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>デバイスの温度が高すぎるためシステム起動前の冷却中です。現在のデバイス内部温度: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -605,46 +541,46 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>OnroadAlerts</name>
|
||||
<message>
|
||||
<source>openpilot Unavailable</source>
|
||||
<translation>openpilotは使用できません</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TAKE CONTROL IMMEDIATELY</source>
|
||||
<translation>直ちに車の運転に戻って下さい</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot Device</source>
|
||||
<translation>デバイスを再起動してください</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Waiting to start</source>
|
||||
<translation>始動を待機しています</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>System Unresponsive</source>
|
||||
<translation>システムが応答しません</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PairingPopup</name>
|
||||
<message>
|
||||
<source>Pair your device to your comma account</source>
|
||||
<translation>デバイスとcommaアカウントを連携して下さい</translation>
|
||||
<translation>デバイスと comma アカウントを連携する</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go to https://connect.comma.ai on your phone</source>
|
||||
<translation>スマートフォンで https://connect.comma.ai にアクセスしてください</translation>
|
||||
<translation>スマートフォンで「https://connect.comma.ai」にアクセスしてください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click "add new device" and scan the QR code on the right</source>
|
||||
<translation>「add new device」を押して右側のQRコードをスキャンしてください</translation>
|
||||
<translation>「新しいデバイスを追加」を押し、右側のQRコードをスキャンしてください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Bookmark connect.comma.ai to your home screen to use it like an app</source>
|
||||
<translation>connect.comma.aiのサイトをホーム画面に追加して、アプリのように使うことができます。</translation>
|
||||
<translation>「connect.comma.ai」をホーム画面に追加して、アプリのように使うことができます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>最初にペアリングするため、Wi-Fiに接続してください</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -655,7 +591,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation>有効にする</translation>
|
||||
<translation>を有効化</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -673,15 +609,15 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>PrimeAdWidget</name>
|
||||
<message>
|
||||
<source>Upgrade Now</source>
|
||||
<translation>今すぐアップグレード</translation>
|
||||
<translation>今すぐアップグレート</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Become a comma prime member at connect.comma.ai</source>
|
||||
<translation>connect.comma.ai からプライム会員に登録できます</translation>
|
||||
<translation>connect.comma.ai でプライム会員に登録できます</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PRIME FEATURES:</source>
|
||||
<translation>特典:</translation>
|
||||
<translation>特典:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remote access</source>
|
||||
@@ -689,26 +625,26 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>24/7 LTE connectivity</source>
|
||||
<translation>24時間365日のLTE接続</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>1 year of drive storage</source>
|
||||
<translation>1年間分のドライブストレージ</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remote snapshots</source>
|
||||
<translation>リモートスナップショット</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PrimeUserWidget</name>
|
||||
<message>
|
||||
<source>✓ SUBSCRIBED</source>
|
||||
<translation>✓ 有効です</translation>
|
||||
<translation>✓ 入会しました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>comma prime</source>
|
||||
<translation>commaプライム</translation>
|
||||
<translation>comma prime</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -728,24 +664,24 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<message numerus="yes">
|
||||
<source>%n minute(s) ago</source>
|
||||
<translation>
|
||||
<numerusform>%n分前</numerusform>
|
||||
<numerusform>%n 分前</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>%n hour(s) ago</source>
|
||||
<translation>
|
||||
<numerusform>%n時間前</numerusform>
|
||||
<numerusform>%n 時間前</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>%n day(s) ago</source>
|
||||
<translation>
|
||||
<numerusform>%n日前</numerusform>
|
||||
<numerusform>%n 日前</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>now</source>
|
||||
<translation>たった今</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -776,17 +712,16 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device.</source>
|
||||
<translation>Dataパーティションをマウントできません。パーティションが破損している可能性があります。デバイスを消去してリセットしますので確認を押して下さい。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Resetting device...
|
||||
This may take up to a minute.</source>
|
||||
<translation>デバイスをリセットしています…
|
||||
この処理には最大で1分ほどかかる場合があります。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.</source>
|
||||
<translation>システムリセットの準備が整いました。すべてのデータと設定を消去するには「確認」を押してください。「キャンセル」を押すとブートを再開します。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -801,19 +736,19 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation>ネット</translation>
|
||||
<translation>ネットワーク</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>機能</translation>
|
||||
<translation>機能設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>ソフト</translation>
|
||||
<translation>ソフトウェア</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>開発</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -840,7 +775,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">開発</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
@@ -859,11 +794,11 @@ This may take up to a minute.</source>
|
||||
<name>Setup</name>
|
||||
<message>
|
||||
<source>WARNING: Low Voltage</source>
|
||||
<translation>警告:電圧低下</translation>
|
||||
<translation>警告:低電圧</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power your device in a car with a harness or proceed at your own risk.</source>
|
||||
<translation>ハーネスを使って車でデバイスに電源を供給するか、自己責任でこのまま継続して下さい。</translation>
|
||||
<translation>自己責任で実行を継続するか、ハーネスから電源を供給してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power off</source>
|
||||
@@ -879,11 +814,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Before we get on the road, let’s finish installation and cover some details.</source>
|
||||
<translation>出発する前に、インストールを完了させて少し詳細を確認しましょう。</translation>
|
||||
<translation>道路に向かう前に、インストールを完了して使い方を確認しましょう。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connect to Wi-Fi</source>
|
||||
<translation>Wi-Fiに接続</translation>
|
||||
<translation>Wi-Fi に接続</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Back</source>
|
||||
@@ -891,7 +826,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue without Wi-Fi</source>
|
||||
<translation>Wi-Fiに接続せずに続行</translation>
|
||||
<translation>Wi-Fi に接続せずに続行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Waiting for internet</source>
|
||||
@@ -899,7 +834,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enter URL</source>
|
||||
<translation>URLの入力</translation>
|
||||
<translation>URL を入力</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>for Custom Software</source>
|
||||
@@ -911,11 +846,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Failed</source>
|
||||
<translation>ダウンロードに失敗しました</translation>
|
||||
<translation>ダウンロード失敗</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ensure the entered URL is valid, and the device’s internet connection is good.</source>
|
||||
<translation>入力されたURLが正しいかどうか、インターネットに正常に接続できているかを確認してください。</translation>
|
||||
<translation>入力された URL を確認し、デバイスがインターネットに接続されていることを確認してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot device</source>
|
||||
@@ -923,15 +858,15 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Start over</source>
|
||||
<translation>やり直す</translation>
|
||||
<translation>最初からやり直す</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom software found at this URL.</source>
|
||||
<translation>このURLはカスタムソフトウェアではありません。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Something went wrong. Reboot the device.</source>
|
||||
<translation>何かの問題が発生しました。デバイスを再起動してください。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a language</source>
|
||||
@@ -939,30 +874,30 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Choose Software to Install</source>
|
||||
<translation>インストールするソフトウェアを選択してください。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot</source>
|
||||
<translation>openpilot</translation>
|
||||
<translation type="unfinished">openpilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Software</source>
|
||||
<translation>カスタムソフトウェア</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SetupWidget</name>
|
||||
<message>
|
||||
<source>Finish Setup</source>
|
||||
<translation>セットアップの完了</translation>
|
||||
<translation>セットアップ完了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
|
||||
<translation>デバイスをcommaコネクト(connect.comma.ai)でペアリングしてcommaプライムの特典を受け取ってください。</translation>
|
||||
<translation>デバイスを comma connect (connect.comma.ai)でペアリングし、comma primeの特典を申請してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair device</source>
|
||||
<translation>デバイスのペアリング</translation>
|
||||
<translation>デバイスをペアリング</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1071,7 +1006,7 @@ This may take up to a minute.</source>
|
||||
<name>SoftwarePanel</name>
|
||||
<message>
|
||||
<source>Updates are only downloaded while the car is off.</source>
|
||||
<translation>車の電源がオフの間のみアップデートがダウンロードできます。</translation>
|
||||
<translation>車の電源がオフの間のみ、アップデートのダウンロードが行われます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Version</source>
|
||||
@@ -1123,23 +1058,23 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>failed to check for update</source>
|
||||
<translation>アップデートの確認に失敗しました。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>up to date, last checked %1</source>
|
||||
<translation>最新の状態です。最終確認日時:%1</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DOWNLOAD</source>
|
||||
<translation>ダウンロード</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>update available</source>
|
||||
<translation>アップデートが利用可能です</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>never</source>
|
||||
<translation>無効</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1277,7 +1212,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Username '%1' has no keys on GitHub</source>
|
||||
<translation>ユーザー名“%1”は GitHub に公開鍵がありません</translation>
|
||||
<translation>ユーザー名 “%1” は GitHub に鍵がありません</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Request timed out</source>
|
||||
@@ -1285,14 +1220,14 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Username '%1' doesn't exist on GitHub</source>
|
||||
<translation>ユーザー名”%1”は GitHub に存在しません</translation>
|
||||
<translation>ユーザー名 '%1' は GitHub に存在しません</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshToggle</name>
|
||||
<message>
|
||||
<source>Enable SSH</source>
|
||||
<translation>SSHの有効化</translation>
|
||||
<translation>SSH を有効化</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1364,19 +1299,19 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.</source>
|
||||
<translation>openpilotによるアダプティブクルーズコントロールとレーンキープアシストを利用します。この機能を利用する際は常に前方への注意が必要です。この設定を変更は車の電源が必要です。</translation>
|
||||
<translation>openpilotによるアダプティブクルーズコントロールとレーンキーピングドライバーアシストを利用します。この機能を利用する際は、常に前方への注意が必要です。この設定を変更すると、車の電源が切れた時に反映されます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Lane Departure Warnings</source>
|
||||
<translation>車線逸脱警報機能の有効化</translation>
|
||||
<translation>車線逸脱警報機能を有効化</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h).</source>
|
||||
<translation>時速31マイル(50km)以上のスピードで走行中、ウインカーを作動させずに検出したレーン上に車両が触れた場合、手動で車線内に戻るように警告を行います。</translation>
|
||||
<translation>時速31マイル(50km)を超えるスピードで走行中、ウインカーを作動させずに検出された車線ライン上に車両が触れた場合、手動で車線内に戻るように警告を行います。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Metric System</source>
|
||||
<translation>メートル法の使用</translation>
|
||||
<translation>メートル法を使用</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display speed in km/h instead of mph.</source>
|
||||
@@ -1392,7 +1327,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage on Accelerator Pedal</source>
|
||||
<translation>アクセルを踏むと運転サポートを中断</translation>
|
||||
<translation>アクセルを踏むと openpilot を中断</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
|
||||
@@ -1400,11 +1335,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental Mode</source>
|
||||
<translation>Experimentalモード</translation>
|
||||
<translation>実験モード</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below:</source>
|
||||
<translation>openpilotは標準ではゆっくりとくつろげる運転を提供します。このExperimental(実験)モードを有効にすると、以下のアグレッシブな開発中の機能を利用する事ができます。</translation>
|
||||
<translation>openpilotは標準ではゆっくりとくつろげる運転を提供します。この実験モードを有効にすると、以下のくつろげる段階ではない開発中の機能を利用する事ができます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected.</source>
|
||||
@@ -1416,55 +1351,67 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.</source>
|
||||
<translation>車両の標準ACC(アダプティブ・クルーズ・コントロール)がアクセル制御に使用されているため、現在Experimentalモードは利用できません。</translation>
|
||||
<translation>この車のACCがアクセル制御を行うため実験モードを利用することができません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>アグレッシブ</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Standard</source>
|
||||
<translation>標準</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Relaxed</source>
|
||||
<translation>リラックス</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Personality</source>
|
||||
<translation>運転傾向</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>End-to-End Longitudinal Control</source>
|
||||
<translation>End-to-Endアクセル制御</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>openpilotのアクセル制御は将来のアップデートで提供される可能性があります。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches.</source>
|
||||
<translation>openpilotのアルファ版アクセル制御は、Experimentalモードと共に非リリースのブランチでテストすることができます。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode.</source>
|
||||
<translation>openpilotのアクセル制御機能(アルファ)を有効にして、Experimentalモードを許可してください。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button.</source>
|
||||
<translation>標準モードが推奨されます。アグレッシブモードではopenpilotは先行車に近づいて追従し、アクセルとブレーキがより強気になります。リラックスモードではopenpilotは先行車から距離を取って走行します。サポートされている車両ではステアリングホイールの距離ボタンでこれらのモードを切り替えることができます。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner.</source>
|
||||
<translation>運転時の画面効果として、低速時にカーブをより良く表示するために道路用の広角カメラに切り替わります。またExperimentalモードのロゴが右上隅に表示されます。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always-On Driver Monitoring</source>
|
||||
<translation>運転者の常時モニタリング</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable driver monitoring even when openpilot is not engaged.</source>
|
||||
<translation>openpilotが作動していない場合でも運転者モニタリングを有効にする。</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Dynamic Experimental Control</source>
|
||||
@@ -1483,11 +1430,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB.</source>
|
||||
<translation>OSのアップデートが必要です。Wi-Fiに接続してアップデートする事をお勧めします。ダウンロードサイズは約1GBです。</translation>
|
||||
<translation>オペレーティングシステムのアップデートが必要です。Wi-Fi に接続してアップデートする事をお勧めします。ダウンロードサイズは約 1GB です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connect to Wi-Fi</source>
|
||||
<translation>Wi-Fiに接続</translation>
|
||||
<translation>Wi-Fi に接続</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Install</source>
|
||||
@@ -1514,23 +1461,23 @@ This may take up to a minute.</source>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Setup Wi-Fi</source>
|
||||
<translation>Wi-Fiセットアップ</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connect to Wi-Fi to upload driving data and help improve openpilot</source>
|
||||
<translation>ドライブデータをアップロードしてopenpilotの改善に役立てるためにWi-Fi接続してください</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Settings</source>
|
||||
<translation>設定を開く</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ready to upload</source>
|
||||
<translation>アップロード準備完了</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Training data will be pulled periodically while your device is on Wi-Fi</source>
|
||||
<translation>デバイスがWi-Fiに接続されている間、トレーニングデータが定期的に送信されます</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1549,7 +1496,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Forget Wi-Fi Network "%1"?</source>
|
||||
<translation>Wi-Fiネットワーク%1を削除してもよろしいですか?</translation>
|
||||
<translation>Wi-Fiネットワーク%1を削除してもよろしいですか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Forget</source>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation>롱컨 기동 모드</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished">openpilot 가감속 제어 (알파)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished">경고: openpilot 가감속 제어 알파 기능으로 차량의 자동긴급제동(AEB)을 비활성화합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished">이 차량은 openpilot 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. openpilot의 가감속 제어로 전환하려면 이 기능을 활성화하세요. openpilot 가감속 제어 알파를 활성화하는 경우 실험 모드 활성화를 권장합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation type="unfinished">openpilot 가감속 제어는 향후 업데이트에서 지원될 수 있습니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -184,7 +168,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation>캘리브레이션</translation>
|
||||
<translation>캘리브레이션 초기화</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>RESET</source>
|
||||
@@ -196,7 +180,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Review Training Guide</source>
|
||||
<translation>트레이닝 가이드</translation>
|
||||
<translation>트레이닝 가이드 다시보기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>REVIEW</source>
|
||||
@@ -288,7 +272,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
|
||||
<translation>장치를 comma connect (connect.comma.ai)에서 동기화하고 comma prime 무료 이용권을 사용하세요.</translation>
|
||||
<translation>장치를 comma connect (connect.comma.ai)에서 페어링하고 comma prime 무료 이용권을 사용하세요.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair Device</source>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">규제</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">재부팅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">규제</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">트레이닝 가이드를 다시 확인하시겠습니까?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">언어를 선택하세요</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">재부팅</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">전원 끄기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">확인</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>주행</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>시간</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>전체</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>지난 주</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>km</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>마일</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -452,10 +408,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>비밀번호가 틀렸습니다</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>장치 온도가 너무 높습니다. 시작하기 전에 온도를 낮춰주세요. 현재 내부 부품 온도: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -640,7 +581,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>초기 동기화를 완료하려면 Wi-Fi에 연결하세요.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">활성화</translation>
|
||||
<source>Cancel</source>
|
||||
<translation>취소</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">취소</translation>
|
||||
<source>Enable</source>
|
||||
<translation>활성화</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">장치</translation>
|
||||
<translation>장치</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">네트워크</translation>
|
||||
<translation>네트워크</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>토글</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>소프트웨어</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>개발자</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">토글</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">소프트웨어</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">개발자</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -954,11 +895,11 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.</source>
|
||||
<translation>장치를 comma connect (connect.comma.ai)에서 동기화하고 comma prime 무료 이용권을 사용하세요.</translation>
|
||||
<translation>장치를 comma connect (connect.comma.ai)에서 페어링하고 comma prime 무료 이용권을 사용하세요.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Pair device</source>
|
||||
<translation>장치 동기화</translation>
|
||||
<translation>장치 페어링</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">선택</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">캘리브레이션 초기화</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">계속</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">취소</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">캘리브레이션</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">계속</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">취소</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>openpilot 가감속 제어는 향후 업데이트에서 지원될 수 있습니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>openpilot 가감속 제어 (알파)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>경고: openpilot 가감속 제어 알파 기능으로 차량의 자동긴급제동(AEB)을 비활성화합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>이 차량은 openpilot 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. openpilot의 가감속 제어로 전환하려면 이 기능을 활성화하세요. openpilot 가감속 제어 알파를 활성화하는 경우 실험 모드 활성화를 권장합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>공격적</translation>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation>Modo Longitudinal Maneuver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Controle Longitudinal openpilot (Embrionário)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>O controle longitudinal openpilot poderá vir em uma atualização futura.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Regulatório</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Reiniciar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Regulatório</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">Tem certeza que quer rever o treinamento?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">Selecione o Idioma</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Reiniciar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">Desligar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">Confirmar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dirigidas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Horas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>TOTAL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SEMANA PASSADA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>KM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Milhas</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -453,10 +409,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -488,6 +440,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -519,17 +475,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>Senha incorreta</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -578,10 +523,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -641,7 +582,7 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
</message>
|
||||
<message>
|
||||
<source>Please connect to Wi-Fi to complete initial pairing</source>
|
||||
<translation>Por favor conecte ao Wi-Fi para completar o pareamento inicial</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -658,12 +599,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">Ativar</translation>
|
||||
<source>Cancel</source>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
<source>Enable</source>
|
||||
<translation>Ativar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -820,40 +761,40 @@ Isso pode levar até um minuto.</translation>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">Dispositivo</translation>
|
||||
<translation>Dispositivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">Rede</translation>
|
||||
<translation>Rede</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation>Desenvdor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">Ajustes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">Software</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished">Desenvdor</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1144,16 +1085,32 @@ Isso pode levar até um minuto.</translation>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">SELECIONE</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Reinicializar Calibragem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Continuar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1172,6 +1129,22 @@ Isso pode levar até um minuto.</translation>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1188,24 +1161,12 @@ Isso pode levar até um minuto.</translation>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1213,7 +1174,11 @@ Isso pode levar até um minuto.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1224,30 +1189,6 @@ Isso pode levar até um minuto.</translation>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Reinicializar Calibragem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Continuar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1306,11 +1247,11 @@ Isso pode levar até um minuto.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1318,12 +1259,16 @@ Isso pode levar até um minuto.</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1332,10 +1277,6 @@ Isso pode levar até um minuto.</translation>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1422,6 +1363,18 @@ Isso pode levar até um minuto.</translation>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>O controle longitudinal openpilot poderá vir em uma atualização futura.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>Controle Longitudinal openpilot (Embrionário)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>Disputa</translation>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished">ระบบควบคุมการเร่ง/เบรคโดย openpilot (Alpha)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished">คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในสถานะ alpha และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished">โดยปกติสำหรับรถคันนี้ openpilot จะควบคุมการเร่ง/เบรคด้วยระบบ ACC จากโรงงาน แทนการควยคุมโดย openpilot เปิดสวิตซ์นี้เพื่อให้ openpilot ควบคุมการเร่ง/เบรค แนะนำให้เปิดโหมดทดลองเมื่อต้องการให้ openpilot ควบคุมการเร่ง/เบรค ซึ่งอยู่ในสถานะ alpha</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation type="unfinished">ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">ระเบียบข้อบังคับ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">รีบูต</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">ระเบียบข้อบังคับ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">คุณแน่ใจหรือไม่ว่าต้องการทบทวนคู่มือการใช้งาน?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">เลือกภาษา</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">รีบูต</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">ปิดเครื่อง</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">ยืนยัน</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>การขับขี่</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ชั่วโมง</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ทั้งหมด</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>สัปดาห์ที่ผ่านมา</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>กิโลเมตร</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ไมล์</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -452,10 +408,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>รหัสผ่านผิด</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation>openpilot ตรวจพบการเปลี่ยนแปลงของตำแหน่งที่ติดตั้ง กรุณาตรวจสอบว่าได้เลื่อนอุปกรณ์เข้ากับจุดติดตั้งจนสุดแล้ว และจุดติดตั้งได้ยึดติดกับกระจกหน้าอย่างแน่นหนา</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -658,11 +599,11 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">เปิดใช้งาน</translation>
|
||||
<translation>เปิดใช้งาน</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">ยกเลิก</translation>
|
||||
<translation>ยกเลิก</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">อุปกรณ์</translation>
|
||||
<translation>อุปกรณ์</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">เครือข่าย</translation>
|
||||
<translation>เครือข่าย</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>ตัวเลือก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>ซอฟต์แวร์</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">ตัวเลือก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">ซอฟต์แวร์</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">เลือก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">รีเซ็ตการคาลิเบรท</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">ดำเนินการต่อ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">ยกเลิก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">รีเซ็ตการคาลิเบรท</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">ดำเนินการต่อ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">ยกเลิก</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">ไม่มี</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">ไม่มี</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>ระบบควบคุมการเร่ง/เบรคโดย openpilot (Alpha)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในสถานะ alpha และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>โดยปกติสำหรับรถคันนี้ openpilot จะควบคุมการเร่ง/เบรคด้วยระบบ ACC จากโรงงาน แทนการควยคุมโดย openpilot เปิดสวิตซ์นี้เพื่อให้ openpilot ควบคุมการเร่ง/เบรค แนะนำให้เปิดโหมดทดลองเมื่อต้องการให้ openpilot ควบคุมการเร่ง/เบรค ซึ่งอยู่ในสถานะ alpha</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>ดุดัน</translation>
|
||||
|
||||
@@ -124,19 +124,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<source>Enable GitHub runner service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -147,14 +139,6 @@
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable GitHub runner service</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DevicePanel</name>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Mevzuat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Yeniden başlat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">Mevzuat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">Eğitim kılavuzunu incelemek istediğinizden emin misiniz?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">Dil seçin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">Yeniden başlat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">Sistemi kapat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">Onayla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sürücüler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Saat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>TÜM ZAMANLAR</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>GEÇEN HAFTA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>KM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mil</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -452,10 +408,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>Yalnış parola</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -576,10 +521,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -814,40 +755,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">x</translation>
|
||||
<translation>x</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">Cihaz</translation>
|
||||
<translation>Cihaz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">Ağ</translation>
|
||||
<translation>Ağ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>Değiştirme</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>Yazılım</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">Değiştirme</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">Yazılım</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1138,16 +1079,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Kalibrasyonu sıfırla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Devam et</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1166,6 +1123,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1182,24 +1155,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1207,7 +1168,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1218,30 +1183,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">Kalibrasyonu sıfırla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Devam et</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1300,11 +1241,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1312,12 +1253,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1326,10 +1271,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1388,6 +1329,14 @@ This may take up to a minute.</source>
|
||||
<source>When enabled, pressing the accelerator pedal will disengage openpilot.</source>
|
||||
<translation>Aktifleştirilirse eğer gaz pedalına basınca openpilot devre dışı kalır.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Experimental Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1412,6 +1361,10 @@ This may take up to a minute.</source>
|
||||
<source>Driving Personality</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished">openpilot纵向控制(Alpha 版)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished">警告:此车辆的 openpilot 纵向控制功能目前处于Alpha版本,使用此功能将会停用自动紧急制动(AEB)功能。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished">在这辆车上,openpilot 默认使用车辆内建的主动巡航控制(ACC),而非 openpilot 的纵向控制。启用此项功能可切换至 openpilot 的纵向控制。当启用 openpilot 纵向控制 Alpha 版本时,建议同时启用实验性模式(Experimental mode)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation type="unfinished">openpilot纵向控制可能会在未来的更新中提供。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">监管信息</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">重启</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">监管信息</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">您确定要查看新手指南吗?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">选择语言</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">重启</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">关机</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">确认</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>旅程数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>小时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>全部</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>过去一周</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>公里</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>英里</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -452,10 +408,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>密码错误</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>设备温度过高。系统正在冷却中,等冷却完毕后才会启动。目前内部组件温度:%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">启用</translation>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
<source>Enable</source>
|
||||
<translation>启用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">设备</translation>
|
||||
<translation>设备</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">网络</translation>
|
||||
<translation>网络</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>设定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>软件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">设定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">软件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">选择</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">重置设备校准</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">继续</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">重置设备校准</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">继续</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">N/A</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>openpilot纵向控制可能会在未来的更新中提供。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>openpilot纵向控制(Alpha 版)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>警告:此车辆的 openpilot 纵向控制功能目前处于Alpha版本,使用此功能将会停用自动紧急制动(AEB)功能。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>在这辆车上,openpilot 默认使用车辆内建的主动巡航控制(ACC),而非 openpilot 的纵向控制。启用此项功能可切换至 openpilot 的纵向控制。当启用 openpilot 纵向控制 Alpha 版本时,建议同时启用实验性模式(Experimental mode)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>积极</translation>
|
||||
|
||||
@@ -124,27 +124,7 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished">openpilot 縱向控制 (Alpha 版)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished">警告:此車輛的 openpilot 縱向控制功能目前處於 Alpha 版本,使用此功能將會停用自動緊急煞車(AEB)功能。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished">在這輛車上,openpilot 預設使用車輛內建的主動巡航控制(ACC),而非 openpilot 的縱向控制。啟用此項功能可切換至 openpilot 的縱向控制。當啟用 openpilot 縱向控制 Alpha 版本時,建議同時啟用實驗性模式(Experimental mode)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation type="unfinished">openpilot 縱向控制可能會在未來的更新中提供。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -152,7 +132,11 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enables or disables the github runner service.</source>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable this to attempt to enable radar tracks for Hyundai, Kia, and Genesis models equipped with the supported Mando SCC radar. This allows sunnypilot to use radar data for improved lead tracking and overall longitudinal performance.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -309,14 +293,18 @@
|
||||
<source>Training Guide</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">法規/監管</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Language</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">重新啟動</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Regulatory</source>
|
||||
<translation type="unfinished">法規/監管</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to review the training guide?</source>
|
||||
<translation type="unfinished">您確定要觀看使用教學嗎?</translation>
|
||||
@@ -329,68 +317,36 @@
|
||||
<source>Select a language</source>
|
||||
<translation type="unfinished">選擇語言</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reboot</source>
|
||||
<translation type="unfinished">重新啟動</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power Off</source>
|
||||
<translation type="unfinished">關機</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to exit Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Confirm</source>
|
||||
<translation type="unfinished">確認</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to enter Always Offroad mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disengage to Enter Always Offroad Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Always Offroad</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>DriveStats</name>
|
||||
<message>
|
||||
<source>Drives</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>旅程</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>小時</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ALL TIME</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>總共</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PAST WEEK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>上週</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KM</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>公里</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Miles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>英里</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -452,10 +408,6 @@
|
||||
<source>Toggle with Main Cruise</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unified Engagement Mode (UEM)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -487,6 +439,10 @@ Remain Active: ALC will remain active even after the brake pedal is pressed.
|
||||
Pause Steering: ALC will be paused after the brake pedal is manually pressed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiOptionDialog</name>
|
||||
@@ -518,17 +474,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<translation>密碼錯誤</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NetworkingSP</name>
|
||||
<message>
|
||||
<source>Scan</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scanning...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadAlert</name>
|
||||
<message>
|
||||
@@ -577,10 +522,6 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<source>Device temperature too high. System cooling down before starting. Current internal component temperature: %1</source>
|
||||
<translation>裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot is now in Always Offroad mode. sunnypilot won't start until Always Offroad mode is disabled. Go to "Settings" -> "Device" to exit Always Offroad mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>OffroadHome</name>
|
||||
@@ -657,12 +598,12 @@ Pause Steering: ALC will be paused after the brake pedal is manually pressed.</s
|
||||
<context>
|
||||
<name>ParamControlSP</name>
|
||||
<message>
|
||||
<source>Enable</source>
|
||||
<translation type="unfinished">啟用</translation>
|
||||
<source>Cancel</source>
|
||||
<translation>取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
<source>Enable</source>
|
||||
<translation>啟用</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -816,40 +757,40 @@ This may take up to a minute.</source>
|
||||
<name>SettingsWindowSP</name>
|
||||
<message>
|
||||
<source>×</source>
|
||||
<translation type="unfinished">×</translation>
|
||||
<translation>×</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Device</source>
|
||||
<translation type="unfinished">裝置</translation>
|
||||
<translation>裝置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">網路</translation>
|
||||
<translation>網路</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation>設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation>軟體</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation>sunnypilot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnylink</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Toggles</source>
|
||||
<translation type="unfinished">設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Software</source>
|
||||
<translation type="unfinished">軟體</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sunnypilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trips</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Developer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Setup</name>
|
||||
@@ -1140,16 +1081,32 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>SoftwarePanelSP</name>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SELECT</source>
|
||||
<translation type="unfinished">選取</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No custom model selected!</source>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">重設校準</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">繼續</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Current Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1168,6 +1125,22 @@ This may take up to a minute.</source>
|
||||
<source>Downloading %1 model [%2]... (%3%)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] %3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1184,24 +1157,12 @@ This may take up to a minute.</source>
|
||||
<source>from cache</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] download failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 model [%2] pending...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching models...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Default</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select a Model</source>
|
||||
<source>No custom model selected!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1209,7 +1170,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Model download has started in the background.</source>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1220,30 +1185,6 @@ This may take up to a minute.</source>
|
||||
<source>Would you like to do that now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset Calibration</source>
|
||||
<translation type="unfinished">重設校準</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Driving Model Selector</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Warning: You are on a metered connection!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">繼續</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>on Metered</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SshControl</name>
|
||||
@@ -1302,11 +1243,11 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">無法使用</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<source>🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1314,12 +1255,16 @@ This may take up to a minute.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished">無法使用</translation>
|
||||
<source>👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SunnypilotPanel</name>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Modular Assistive Driving System (MADS)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -1328,10 +1273,6 @@ This may take up to a minute.</source>
|
||||
<source>Enable the beloved MADS feature. Disable toggle to revert back to stock openpilot engagement/disengagement.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Customize MADS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
@@ -1418,6 +1359,18 @@ This may take up to a minute.</source>
|
||||
<source>openpilot longitudinal control may come in a future update.</source>
|
||||
<translation>openpilot 縱向控制可能會在未來的更新中提供。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation>openpilot 縱向控制 (Alpha 版)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation>警告:此車輛的 openpilot 縱向控制功能目前處於 Alpha 版本,使用此功能將會停用自動緊急煞車(AEB)功能。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation>在這輛車上,openpilot 預設使用車輛內建的主動巡航控制(ACC),而非 openpilot 的縱向控制。啟用此項功能可切換至 openpilot 的縱向控制。當啟用 openpilot 縱向控制 Alpha 版本時,建議同時啟用實驗性模式(Experimental mode)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Aggressive</source>
|
||||
<translation>積極</translation>
|
||||
|
||||
+2
-2
@@ -75,8 +75,8 @@ void UIState::updateStatus() {
|
||||
auto state = ss.getState();
|
||||
auto state_mads = mads.getState();
|
||||
if (state == cereal::SelfdriveState::OpenpilotState::PRE_ENABLED || state == cereal::SelfdriveState::OpenpilotState::OVERRIDING ||
|
||||
state_mads == cereal::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::PAUSED ||
|
||||
state_mads == cereal::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::OVERRIDING) {
|
||||
state_mads == cereal::SelfdriveStateSP::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::PAUSED ||
|
||||
state_mads == cereal::SelfdriveStateSP::ModularAssistiveDrivingSystem::ModularAssistiveDrivingSystemState::OVERRIDING) {
|
||||
status = STATUS_OVERRIDE;
|
||||
} else {
|
||||
if (mads.getAvailable()) {
|
||||
|
||||
@@ -48,13 +48,13 @@ class MadsParams:
|
||||
if pause_lateral_on_brake:
|
||||
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISENGAGE_LATERAL_ON_BRAKE
|
||||
|
||||
def set_car_specific_params(self, CP, CP_SP):
|
||||
def set_car_specific_params(self, CP):
|
||||
if CP.carName == "hyundai":
|
||||
# TODO-SP: This should be separated from MADS module for future implementations
|
||||
# Use "HyundaiLongitudinalMainCruiseToggleable" param
|
||||
hyundai_cruise_main_toggleable = True
|
||||
if hyundai_cruise_main_toggleable:
|
||||
CP_SP.flags |= HyundaiFlagsSP.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE.value
|
||||
CP.sunnypilotFlags |= HyundaiFlagsSP.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE.value
|
||||
CP.safetyConfigs[-1].safetyParam |= Panda.FLAG_HYUNDAI_LONG_MAIN_CRUISE_TOGGLEABLE
|
||||
|
||||
# MADS is currently not supported in Tesla due to lack of consistent states to engage controls
|
||||
|
||||
+37
-27
@@ -24,7 +24,7 @@ THE SOFTWARE.
|
||||
Last updated: July 29, 2024
|
||||
"""
|
||||
|
||||
from cereal import car, log, custom
|
||||
from cereal import messaging, car, log, custom
|
||||
|
||||
from opendbc.car.hyundai.values import HyundaiFlags
|
||||
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
@@ -32,10 +32,9 @@ from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
from openpilot.sunnypilot.mads.helpers import MadsParams
|
||||
from openpilot.sunnypilot.mads.state import StateMachine, GEARS_ALLOW_PAUSED_SILENT
|
||||
|
||||
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = log.OnroadEvent.EventName
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
|
||||
SET_SPEED_BUTTONS = (ButtonType.accelCruise, ButtonType.resumeCruise, ButtonType.decelCruise, ButtonType.setCruise)
|
||||
@@ -49,15 +48,15 @@ class ModularAssistiveDrivingSystem:
|
||||
self.enabled = False
|
||||
self.active = False
|
||||
self.available = False
|
||||
self.mismatch_counter = 0
|
||||
self.allow_always = False
|
||||
self.selfdrive = selfdrive
|
||||
self.selfdrive.enabled_prev = False
|
||||
self.state_machine = StateMachine(self)
|
||||
self.events = self.selfdrive.events
|
||||
self.events_sp = self.selfdrive.events_sp
|
||||
|
||||
if self.selfdrive.CP.carName == "hyundai":
|
||||
if (self.selfdrive.CP_SP.flags & HyundaiFlagsSP.HAS_LFA_BUTTON) or \
|
||||
if (self.selfdrive.CP.sunnypilotFlags & HyundaiFlagsSP.HAS_LFA_BUTTON) or \
|
||||
(self.selfdrive.CP.flags & HyundaiFlags.CANFD):
|
||||
self.allow_always = True
|
||||
|
||||
@@ -71,7 +70,20 @@ class ModularAssistiveDrivingSystem:
|
||||
self.main_enabled_toggle = self.mads_params.read_param("MadsMainCruiseAllowed")
|
||||
self.unified_engagement_mode = self.mads_params.read_param("MadsUnifiedEngagementMode")
|
||||
|
||||
def update_events(self, CS: car.CarState):
|
||||
def update_controls_mismatch(self, sm: messaging.SubMaster):
|
||||
heartbeat_engaged = self.active if self.pause_lateral_on_brake_toggle else self.enabled
|
||||
|
||||
if not heartbeat_engaged:
|
||||
self.mismatch_counter = 0
|
||||
|
||||
if heartbeat_engaged and any(not ps.controlsAllowedLat for ps in sm['pandaStates']
|
||||
if ps.safetyModel not in IGNORED_SAFETY_MODES):
|
||||
self.mismatch_counter += 1
|
||||
|
||||
if self.mismatch_counter >= 200:
|
||||
self.events.add(EventName.controlsMismatchLateral)
|
||||
|
||||
def update_events(self, CS: car.CarState, sm: messaging.SubMaster):
|
||||
def update_unified_engagement_mode():
|
||||
uem_blocked = self.enabled or (self.selfdrive.enabled and self.selfdrive.enabled_prev)
|
||||
if (self.unified_engagement_mode and uem_blocked) or not self.unified_engagement_mode:
|
||||
@@ -80,30 +92,26 @@ class ModularAssistiveDrivingSystem:
|
||||
|
||||
def transition_paused_state():
|
||||
if self.state_machine.state != State.paused:
|
||||
self.events_sp.add(EventNameSP.silentLkasDisable)
|
||||
|
||||
def replace_event(old_event: int, new_event: int):
|
||||
self.events.remove(old_event)
|
||||
self.events_sp.add(new_event)
|
||||
self.events.add(EventName.silentLkasDisable)
|
||||
|
||||
if not self.selfdrive.enabled and self.enabled:
|
||||
if self.events.has(EventName.doorOpen):
|
||||
replace_event(EventName.doorOpen, EventNameSP.silentDoorOpen)
|
||||
self.events.replace(EventName.doorOpen, EventName.silentDoorOpen)
|
||||
transition_paused_state()
|
||||
if self.events.has(EventName.seatbeltNotLatched):
|
||||
replace_event(EventName.seatbeltNotLatched, EventNameSP.silentSeatbeltNotLatched)
|
||||
self.events.replace(EventName.seatbeltNotLatched, EventName.silentSeatbeltNotLatched)
|
||||
transition_paused_state()
|
||||
if self.events.has(EventName.wrongGear):
|
||||
replace_event(EventName.wrongGear, EventNameSP.silentWrongGear)
|
||||
self.events.replace(EventName.wrongGear, EventName.silentWrongGear)
|
||||
transition_paused_state()
|
||||
if self.events.has(EventName.reverseGear):
|
||||
replace_event(EventName.reverseGear, EventNameSP.silentReverseGear)
|
||||
self.events.replace(EventName.reverseGear, EventName.silentReverseGear)
|
||||
transition_paused_state()
|
||||
if self.events.has(EventName.brakeHold):
|
||||
replace_event(EventName.brakeHold, EventNameSP.silentBrakeHold)
|
||||
self.events.replace(EventName.brakeHold, EventName.silentBrakeHold)
|
||||
transition_paused_state()
|
||||
if self.events.has(EventName.parkBrake):
|
||||
replace_event(EventName.parkBrake, EventNameSP.silentParkBrake)
|
||||
self.events.replace(EventName.parkBrake, EventName.silentParkBrake)
|
||||
transition_paused_state()
|
||||
|
||||
if self.pause_lateral_on_brake_toggle:
|
||||
@@ -113,7 +121,7 @@ class ModularAssistiveDrivingSystem:
|
||||
if not (self.pause_lateral_on_brake_toggle and CS.brakePressed) and \
|
||||
not self.events.contains_in_list(GEARS_ALLOW_PAUSED_SILENT):
|
||||
if self.state_machine.state == State.paused:
|
||||
self.events_sp.add(EventNameSP.silentLkasEnable)
|
||||
self.events.add(EventName.silentLkasEnable)
|
||||
|
||||
self.events.remove(EventName.preEnableStandstill)
|
||||
self.events.remove(EventName.belowEngageSpeed)
|
||||
@@ -126,25 +134,25 @@ class ModularAssistiveDrivingSystem:
|
||||
else:
|
||||
if self.main_enabled_toggle:
|
||||
if CS.cruiseState.available and not self.selfdrive.CS_prev.cruiseState.available:
|
||||
self.events_sp.add(EventNameSP.lkasEnable)
|
||||
self.events.add(EventName.lkasEnable)
|
||||
|
||||
for be in CS.buttonEvents:
|
||||
if be.type == ButtonType.cancel:
|
||||
if not self.selfdrive.enabled and self.selfdrive.enabled_prev:
|
||||
self.events_sp.add(EventNameSP.manualLongitudinalRequired)
|
||||
self.events.add(EventName.manualLongitudinalRequired)
|
||||
if be.type == ButtonType.lkas and be.pressed and (CS.cruiseState.available or self.allow_always):
|
||||
if self.enabled:
|
||||
if self.selfdrive.enabled:
|
||||
self.events_sp.add(EventNameSP.manualSteeringRequired)
|
||||
self.events.add(EventName.manualSteeringRequired)
|
||||
else:
|
||||
self.events_sp.add(EventNameSP.lkasDisable)
|
||||
self.events.add(EventName.lkasDisable)
|
||||
else:
|
||||
self.events_sp.add(EventNameSP.lkasEnable)
|
||||
self.events.add(EventName.lkasEnable)
|
||||
|
||||
if not CS.cruiseState.available:
|
||||
self.events.remove(EventName.buttonEnable)
|
||||
if self.selfdrive.CS_prev.cruiseState.available:
|
||||
self.events_sp.add(EventNameSP.lkasDisable)
|
||||
self.events.add(EventName.lkasDisable)
|
||||
|
||||
self.events.remove(EventName.pcmDisable)
|
||||
self.events.remove(EventName.buttonCancel)
|
||||
@@ -153,14 +161,16 @@ class ModularAssistiveDrivingSystem:
|
||||
if not any(be.type in SET_SPEED_BUTTONS for be in CS.buttonEvents):
|
||||
self.events.remove(EventName.wrongCarMode)
|
||||
|
||||
def update(self, CS: car.CarState):
|
||||
self.update_controls_mismatch(sm)
|
||||
|
||||
def update(self, CS: car.CarState, sm: messaging.SubMaster):
|
||||
if not self.enabled_toggle:
|
||||
return
|
||||
|
||||
self.update_events(CS)
|
||||
self.update_events(CS, sm)
|
||||
|
||||
if not self.selfdrive.CP.passive and self.selfdrive.initialized:
|
||||
self.enabled, self.active = self.state_machine.update(self.events, self.events_sp)
|
||||
self.enabled, self.active = self.state_machine.update(self.events)
|
||||
|
||||
# Copy of previous SelfdriveD states for MADS events handling
|
||||
self.selfdrive.enabled_prev = self.selfdrive.enabled
|
||||
|
||||
+19
-34
@@ -29,17 +29,14 @@ from openpilot.selfdrive.selfdrived.events import ET, Events
|
||||
from openpilot.selfdrive.selfdrived.state import SOFT_DISABLE_TIME
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||
|
||||
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
EventName = log.OnroadEvent.EventName
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
|
||||
ACTIVE_STATES = (State.enabled, State.softDisabling, State.overriding)
|
||||
ENABLED_STATES = (State.paused, *ACTIVE_STATES)
|
||||
|
||||
GEARS_ALLOW_PAUSED_SILENT = [EventNameSP.silentWrongGear, EventNameSP.silentReverseGear, EventNameSP.silentBrakeHold,
|
||||
EventNameSP.silentDoorOpen, EventNameSP.silentSeatbeltNotLatched, EventNameSP.silentParkBrake]
|
||||
GEARS_ALLOW_PAUSED_SILENT = [EventName.silentWrongGear, EventName.silentReverseGear, EventName.silentBrakeHold,
|
||||
EventName.silentDoorOpen, EventName.silentSeatbeltNotLatched, EventName.silentParkBrake]
|
||||
GEARS_ALLOW_PAUSED = [EventName.wrongGear, EventName.reverseGear, EventName.brakeHold,
|
||||
EventName.doorOpen, EventName.seatbeltNotLatched, EventName.parkBrake,
|
||||
*GEARS_ALLOW_PAUSED_SILENT]
|
||||
@@ -52,57 +49,45 @@ class StateMachine:
|
||||
|
||||
self.state = State.disabled
|
||||
|
||||
self._events = Events()
|
||||
self._events_sp = EventsSP()
|
||||
|
||||
def add_current_alert_types(self, alert_type):
|
||||
if not self.selfdrive.enabled:
|
||||
self.ss_state_machine.current_alert_types.append(alert_type)
|
||||
|
||||
def check_contains(self, event_type: str) -> bool:
|
||||
return bool(self._events.contains(event_type) or self._events_sp.contains(event_type))
|
||||
|
||||
def check_contains_in_list(self, events_list: list[int]) -> bool:
|
||||
return bool(self._events.contains_in_list(events_list) or self._events_sp.contains_in_list(events_list))
|
||||
|
||||
def update(self, events: Events, events_sp: EventsSP):
|
||||
def update(self, events: Events):
|
||||
# soft disable timer and current alert types are from the state machine of openpilot
|
||||
# decrement the soft disable timer at every step, as it's reset on
|
||||
# entrance in SOFT_DISABLING state
|
||||
|
||||
self._events = events
|
||||
self._events_sp = events_sp
|
||||
|
||||
# ENABLED, SOFT DISABLING, PAUSED, OVERRIDING
|
||||
if self.state != State.disabled:
|
||||
# user and immediate disable always have priority in a non-disabled state
|
||||
if self.check_contains(ET.USER_DISABLE):
|
||||
if events_sp.has(EventNameSP.silentLkasDisable) or events_sp.has(EventNameSP.silentBrakeHold):
|
||||
if events.contains(ET.USER_DISABLE):
|
||||
if events.has(EventName.silentLkasDisable) or events.has(EventName.silentBrakeHold):
|
||||
self.state = State.paused
|
||||
else:
|
||||
self.state = State.disabled
|
||||
self.ss_state_machine.current_alert_types.append(ET.USER_DISABLE)
|
||||
|
||||
elif self.check_contains(ET.IMMEDIATE_DISABLE):
|
||||
elif events.contains(ET.IMMEDIATE_DISABLE):
|
||||
self.state = State.disabled
|
||||
self.add_current_alert_types(ET.IMMEDIATE_DISABLE)
|
||||
|
||||
else:
|
||||
# ENABLED
|
||||
if self.state == State.enabled:
|
||||
if self.check_contains(ET.SOFT_DISABLE):
|
||||
if events.contains(ET.SOFT_DISABLE):
|
||||
self.state = State.softDisabling
|
||||
if not self.selfdrive.enabled:
|
||||
self.ss_state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
|
||||
self.ss_state_machine.current_alert_types.append(ET.SOFT_DISABLE)
|
||||
|
||||
elif self.check_contains(ET.OVERRIDE_LATERAL):
|
||||
elif events.contains(ET.OVERRIDE_LATERAL):
|
||||
self.state = State.overriding
|
||||
self.add_current_alert_types(ET.OVERRIDE_LATERAL)
|
||||
|
||||
# SOFT DISABLING
|
||||
elif self.state == State.softDisabling:
|
||||
if not self.check_contains(ET.SOFT_DISABLE):
|
||||
if not events.contains(ET.SOFT_DISABLE):
|
||||
# no more soft disabling condition, so go back to ENABLED
|
||||
self.state = State.enabled
|
||||
|
||||
@@ -114,12 +99,12 @@ class StateMachine:
|
||||
|
||||
# PAUSED
|
||||
elif self.state == State.paused:
|
||||
if self.check_contains(ET.ENABLE):
|
||||
if self.check_contains(ET.NO_ENTRY):
|
||||
if events.contains(ET.ENABLE):
|
||||
if events.contains(ET.NO_ENTRY):
|
||||
self.add_current_alert_types(ET.NO_ENTRY)
|
||||
|
||||
else:
|
||||
if self.check_contains(ET.OVERRIDE_LATERAL):
|
||||
if events.contains(ET.OVERRIDE_LATERAL):
|
||||
self.state = State.overriding
|
||||
else:
|
||||
self.state = State.enabled
|
||||
@@ -127,26 +112,26 @@ class StateMachine:
|
||||
|
||||
# OVERRIDING
|
||||
elif self.state == State.overriding:
|
||||
if self.check_contains(ET.SOFT_DISABLE):
|
||||
if events.contains(ET.SOFT_DISABLE):
|
||||
self.state = State.softDisabling
|
||||
if not self.selfdrive.enabled:
|
||||
self.ss_state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
|
||||
self.ss_state_machine.current_alert_types.append(ET.SOFT_DISABLE)
|
||||
elif not self.check_contains(ET.OVERRIDE_LATERAL):
|
||||
elif not events.contains(ET.OVERRIDE_LATERAL):
|
||||
self.state = State.enabled
|
||||
else:
|
||||
self.ss_state_machine.current_alert_types += [ET.OVERRIDE_LATERAL]
|
||||
|
||||
# DISABLED
|
||||
elif self.state == State.disabled:
|
||||
if self.check_contains(ET.ENABLE):
|
||||
if self.check_contains(ET.NO_ENTRY):
|
||||
if self.check_contains_in_list(GEARS_ALLOW_PAUSED):
|
||||
if events.contains(ET.ENABLE):
|
||||
if events.contains(ET.NO_ENTRY):
|
||||
if events.contains_in_list(GEARS_ALLOW_PAUSED):
|
||||
self.state = State.paused
|
||||
self.add_current_alert_types(ET.NO_ENTRY)
|
||||
|
||||
else:
|
||||
if self.check_contains(ET.OVERRIDE_LATERAL):
|
||||
if events.contains(ET.OVERRIDE_LATERAL):
|
||||
self.state = State.overriding
|
||||
else:
|
||||
self.state = State.enabled
|
||||
|
||||
@@ -27,14 +27,13 @@ Last updated: July 29, 2024
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from cereal import custom
|
||||
from cereal import log, custom
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from openpilot.sunnypilot.mads.state import StateMachine, SOFT_DISABLE_TIME, GEARS_ALLOW_PAUSED
|
||||
from openpilot.selfdrive.selfdrived.events import ET, NormalPermanentAlert
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EVENTS_SP
|
||||
from openpilot.selfdrive.selfdrived.events import Events, ET, EVENTS, NormalPermanentAlert
|
||||
|
||||
State = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
State = custom.SelfdriveStateSP.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState
|
||||
EventName = log.OnroadEvent.EventName
|
||||
|
||||
# The event types that maintain the current state
|
||||
MAINTAIN_STATES = {State.enabled: (None,), State.disabled: (None,), State.softDisabling: (ET.SOFT_DISABLE,),
|
||||
@@ -48,7 +47,7 @@ def make_event(event_types):
|
||||
event = {}
|
||||
for ev in event_types:
|
||||
event[ev] = NormalPermanentAlert("alert")
|
||||
EVENTS_SP[0] = event
|
||||
EVENTS[0] = event
|
||||
return 0
|
||||
|
||||
|
||||
@@ -63,93 +62,87 @@ class TestMADSStateMachine:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_method(self, mocker: MockerFixture):
|
||||
self.mads = MockMADS(mocker)
|
||||
self.events = Events()
|
||||
self.state_machine = StateMachine(self.mads)
|
||||
self.events = self.state_machine._events
|
||||
self.events_sp = self.state_machine._events_sp
|
||||
self.mads.selfdrive.state_machine.soft_disable_timer = int(SOFT_DISABLE_TIME / DT_CTRL)
|
||||
|
||||
def reset(self):
|
||||
self.events.clear()
|
||||
self.events_sp.clear()
|
||||
self.state_machine.state = State.disabled
|
||||
|
||||
def test_immediate_disable(self):
|
||||
for state in ALL_STATES:
|
||||
for et in MAINTAIN_STATES[state]:
|
||||
self.events_sp.add(make_event([et, ET.IMMEDIATE_DISABLE]))
|
||||
self.events.add(make_event([et, ET.IMMEDIATE_DISABLE]))
|
||||
self.state_machine.state = state
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.state_machine.update(self.events)
|
||||
assert State.disabled == self.state_machine.state
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
def test_user_disable(self):
|
||||
for state in ALL_STATES:
|
||||
for et in MAINTAIN_STATES[state]:
|
||||
self.events_sp.add(make_event([et, ET.USER_DISABLE]))
|
||||
self.events.add(make_event([et, ET.USER_DISABLE]))
|
||||
self.state_machine.state = state
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.state_machine.update(self.events)
|
||||
assert State.disabled == self.state_machine.state
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
def test_user_disable_to_paused(self):
|
||||
paused_events = (EventNameSP.silentLkasDisable, EventNameSP.silentBrakeHold)
|
||||
paused_events = (EventName.silentLkasDisable, EventName.silentBrakeHold)
|
||||
for state in ALL_STATES:
|
||||
for et in MAINTAIN_STATES[state]:
|
||||
self.events_sp.add(make_event([et, ET.USER_DISABLE]))
|
||||
self.events.add(make_event([et, ET.USER_DISABLE]))
|
||||
for en in paused_events:
|
||||
self.events_sp.add(en)
|
||||
self.events.add(en)
|
||||
self.state_machine.state = state
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
final_state = State.paused if self.events_sp.has(en) and state != State.disabled else State.disabled
|
||||
self.state_machine.update(self.events)
|
||||
final_state = State.paused if self.events.has(en) and state != State.disabled else State.disabled
|
||||
assert self.state_machine.state == final_state
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
def test_soft_disable(self):
|
||||
for state in ALL_STATES:
|
||||
if state == State.paused: # paused considers USER_DISABLE instead
|
||||
continue
|
||||
for et in MAINTAIN_STATES[state]:
|
||||
self.events_sp.add(make_event([et, ET.SOFT_DISABLE]))
|
||||
self.events.add(make_event([et, ET.SOFT_DISABLE]))
|
||||
self.state_machine.state = state
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == State.disabled if state == State.disabled else State.softDisabling
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
def test_soft_disable_timer(self):
|
||||
self.state_machine.state = State.enabled
|
||||
self.events_sp.add(make_event([ET.SOFT_DISABLE]))
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([ET.SOFT_DISABLE]))
|
||||
self.state_machine.update(self.events)
|
||||
for _ in range(int(SOFT_DISABLE_TIME / DT_CTRL)):
|
||||
assert self.state_machine.state == State.softDisabling
|
||||
self.mads.selfdrive.state_machine.soft_disable_timer -= 1
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.state_machine.update(self.events)
|
||||
|
||||
assert self.state_machine.state == State.disabled
|
||||
|
||||
def test_no_entry(self):
|
||||
for et in ENABLE_EVENT_TYPES:
|
||||
self.events_sp.add(make_event([ET.NO_ENTRY, et]))
|
||||
if not self.state_machine.check_contains_in_list(GEARS_ALLOW_PAUSED):
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([ET.NO_ENTRY, et]))
|
||||
if not self.events.contains_in_list(GEARS_ALLOW_PAUSED):
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == State.disabled
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
def test_no_entry_paused(self):
|
||||
self.state_machine.state = State.paused
|
||||
self.events_sp.add(make_event([ET.NO_ENTRY]))
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([ET.NO_ENTRY]))
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == State.paused
|
||||
|
||||
def test_override_lateral(self):
|
||||
self.state_machine.state = State.enabled
|
||||
self.events_sp.add(make_event([ET.OVERRIDE_LATERAL]))
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([ET.OVERRIDE_LATERAL]))
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == State.overriding
|
||||
|
||||
def test_paused_to_enabled(self):
|
||||
self.state_machine.state = State.paused
|
||||
self.events_sp.add(make_event([ET.ENABLE]))
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([ET.ENABLE]))
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == State.enabled
|
||||
|
||||
def test_maintain_states(self):
|
||||
@@ -157,7 +150,7 @@ class TestMADSStateMachine:
|
||||
for et in MAINTAIN_STATES[state]:
|
||||
self.state_machine.state = state
|
||||
if et is not None:
|
||||
self.events_sp.add(make_event([et]))
|
||||
self.state_machine.update(self.events, self.events_sp)
|
||||
self.events.add(make_event([et]))
|
||||
self.state_machine.update(self.events)
|
||||
assert self.state_machine.state == state
|
||||
self.reset()
|
||||
self.events.clear()
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from openpilot.selfdrive.modeld.constants import Meta
|
||||
|
||||
|
||||
class Meta20hz(Meta):
|
||||
ENGAGED = slice(0, 1)
|
||||
# next 2, 4, 6, 8, 10 seconds
|
||||
GAS_DISENGAGE = slice(1, 31, 6)
|
||||
BRAKE_DISENGAGE = slice(2, 31, 6)
|
||||
STEER_OVERRIDE = slice(3, 31, 6)
|
||||
HARD_BRAKE_3 = slice(4, 31, 6)
|
||||
HARD_BRAKE_4 = slice(5, 31, 6)
|
||||
HARD_BRAKE_5 = slice(6, 31, 6)
|
||||
# next 0, 2, 4, 6, 8, 10 seconds
|
||||
GAS_PRESS = slice(31, 55, 4)
|
||||
BRAKE_PRESS = slice(32, 55, 4)
|
||||
LEFT_BLINKER = slice(33, 55, 4)
|
||||
RIGHT_BLINKER = slice(34, 55, 4)
|
||||
@@ -1,26 +0,0 @@
|
||||
from openpilot.selfdrive.modeld.constants import Meta
|
||||
from cereal import custom
|
||||
from openpilot.sunnypilot.modeld_v2.meta_20hz import Meta20hz
|
||||
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
||||
|
||||
ModelBundle = custom.ModelManagerSP.ModelBundle
|
||||
|
||||
|
||||
def load_meta_constants():
|
||||
"""
|
||||
Determines and loads the appropriate meta model class based on the metadata provided. The function checks
|
||||
specific keys and conditions within the provided metadata dictionary to identify the corresponding meta
|
||||
model class to return.
|
||||
|
||||
:param model_metadata: Dictionary containing metadata about the model. It includes
|
||||
details such as input shapes, output slices, and other configurations for identifying
|
||||
metadata-dependent meta model classes.
|
||||
:type model_metadata: dict
|
||||
:return: The appropriate meta model class (Meta, MetaSimPose, or MetaTombRaider)
|
||||
based on the conditions and metadata provided.
|
||||
:rtype: type
|
||||
"""
|
||||
if (bundle := get_active_bundle()) and bundle.is20hz:
|
||||
return Meta20hz
|
||||
|
||||
return Meta # Default
|
||||
@@ -1,134 +0,0 @@
|
||||
import os
|
||||
import pickle
|
||||
from abc import ABC, abstractmethod
|
||||
import numpy as np
|
||||
|
||||
from cereal import custom
|
||||
from openpilot.selfdrive.modeld import MODEL_PATH, MODEL_PKL_PATH, METADATA_PATH
|
||||
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLMem
|
||||
from openpilot.selfdrive.modeld.runners.ort_helpers import make_onnx_cpu_runner, ORT_TYPES_TO_NP_TYPES
|
||||
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
|
||||
from openpilot.system.hardware import TICI
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
|
||||
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
||||
from tinygrad.tensor import Tensor
|
||||
|
||||
if TICI:
|
||||
os.environ['QCOM'] = '1'
|
||||
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
CUSTOM_MODEL_PATH = Paths.model_root()
|
||||
ModelManager = custom.ModelManagerSP
|
||||
|
||||
|
||||
class ModelRunner(ABC):
|
||||
"""Abstract base class for model runners that defines the interface for running ML models."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the model runner with paths to model and metadata files."""
|
||||
metadata_path = METADATA_PATH
|
||||
self.is_20hz = None
|
||||
self._drive_model = None
|
||||
self._metadata_model = None
|
||||
|
||||
if bundle := get_active_bundle():
|
||||
bundle_models = {model.type.raw: model for model in bundle.models}
|
||||
self._drive_model = bundle_models.get(ModelManager.Type.drive)
|
||||
self._metadata_model = bundle_models.get(ModelManager.Type.metadata)
|
||||
self.is_20hz = bundle.is20hz
|
||||
|
||||
# Override the metadata path if a metadata model is found in the active bundle
|
||||
if self._metadata_model:
|
||||
metadata_path = f"{CUSTOM_MODEL_PATH}/{self._metadata_model.fileName}"
|
||||
|
||||
with open(metadata_path, 'rb') as f:
|
||||
self.model_metadata = pickle.load(f)
|
||||
|
||||
self.input_shapes = self.model_metadata['input_shapes']
|
||||
self.output_slices = self.model_metadata['output_slices']
|
||||
self.inputs: dict = {}
|
||||
|
||||
@abstractmethod
|
||||
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
|
||||
"""Prepare inputs for model inference."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def run_model(self):
|
||||
"""Run model inference with prepared inputs."""
|
||||
|
||||
def slice_outputs(self, model_outputs: np.ndarray) -> dict:
|
||||
"""Slice model outputs according to metadata configuration."""
|
||||
parsed_outputs = {k: model_outputs[np.newaxis, v] for k, v in self.output_slices.items()}
|
||||
if SEND_RAW_PRED:
|
||||
parsed_outputs['raw_pred'] = model_outputs.copy()
|
||||
return parsed_outputs
|
||||
|
||||
|
||||
class TinygradRunner(ModelRunner):
|
||||
"""Tinygrad implementation of model runner for TICI hardware."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
model_pkl_path = MODEL_PKL_PATH
|
||||
if self._drive_model:
|
||||
model_pkl_path = f"{CUSTOM_MODEL_PATH}/{self._drive_model.fileName}"
|
||||
assert model_pkl_path.endswith('_tinygrad.pkl'), f"Invalid model file: {model_pkl_path} for TinygradRunner"
|
||||
|
||||
# Load Tinygrad model
|
||||
with open(model_pkl_path, "rb") as f:
|
||||
try:
|
||||
self.model_run = pickle.load(f)
|
||||
except FileNotFoundError as e:
|
||||
assert "/dev/kgsl-3d0" not in str(e), "Model was built on C3 or C3X, but is being loaded on PC"
|
||||
raise
|
||||
|
||||
self.input_to_dtype = {}
|
||||
self.input_to_device = {}
|
||||
|
||||
for idx, name in enumerate(self.model_run.captured.expected_names):
|
||||
self.input_to_dtype[name] = self.model_run.captured.expected_st_vars_dtype_device[idx][2] # 2 is the dtype
|
||||
self.input_to_device[name] = self.model_run.captured.expected_st_vars_dtype_device[idx][3] # 3 is the device
|
||||
|
||||
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
|
||||
# Initialize image tensors if not already done
|
||||
for key in imgs_cl:
|
||||
if TICI and key not in self.inputs:
|
||||
self.inputs[key] = qcom_tensor_from_opencl_address(imgs_cl[key].mem_address, self.input_shapes[key], dtype=self.input_to_dtype[key])
|
||||
elif not TICI:
|
||||
shape = frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key])
|
||||
self.inputs[key] = Tensor(shape, device=self.input_to_device[key], dtype=self.input_to_dtype[key]).realize()
|
||||
|
||||
# Update numpy inputs
|
||||
for key, value in numpy_inputs.items():
|
||||
if key not in imgs_cl:
|
||||
self.inputs[key] = Tensor(value, device=self.input_to_device[key], dtype=self.input_to_dtype[key]).realize()
|
||||
|
||||
return self.inputs
|
||||
|
||||
def run_model(self):
|
||||
return self.model_run(**self.inputs).numpy().flatten()
|
||||
|
||||
|
||||
class ONNXRunner(ModelRunner):
|
||||
"""ONNX implementation of model runner for non-TICI hardware."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.runner = make_onnx_cpu_runner(MODEL_PATH)
|
||||
|
||||
self.input_to_nptype = {
|
||||
model_input.name: ORT_TYPES_TO_NP_TYPES[model_input.type]
|
||||
for model_input in self.runner.get_inputs()
|
||||
}
|
||||
|
||||
def prepare_inputs(self, imgs_cl: dict[str, CLMem], numpy_inputs: dict[str, np.ndarray], frames: dict[str, DrivingModelFrame]) -> dict:
|
||||
self.inputs = numpy_inputs
|
||||
for key in imgs_cl:
|
||||
self.inputs[key] = frames[key].buffer_from_cl(imgs_cl[key]).reshape(self.input_shapes[key]).astype(dtype=self.input_to_nptype[key])
|
||||
return self.inputs
|
||||
|
||||
def run_model(self):
|
||||
return self.runner.run(None, self.inputs)[0].flatten()
|
||||
@@ -72,12 +72,13 @@ class ModelParser:
|
||||
model_bundle.generation = int(value["generation"])
|
||||
model_bundle.environment = value["environment"]
|
||||
model_bundle.runner = value.get("runner", custom.ModelManagerSP.Runner.snpe)
|
||||
model_bundle.is20hz = value.get("is_20hz", False)
|
||||
|
||||
return model_bundle
|
||||
|
||||
@staticmethod
|
||||
def parse_models(json_data: dict) -> list[custom.ModelManagerSP.ModelBundle]:
|
||||
# TODO-SP: Remove the following filter once we add support for tinygrad model switcher
|
||||
json_data = {k: v for k, v in json_data.items() if v.get("runner", -1) == custom.ModelManagerSP.Runner.snpe}
|
||||
return [ModelParser._parse_bundle(key, value) for key, value in json_data.items()]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from cereal import car, log
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventName = log.OnroadEvent.EventName
|
||||
|
||||
|
||||
class ButtonHoldTracker:
|
||||
def __init__(self):
|
||||
self.button_frame_counts = {}
|
||||
|
||||
def update(self, CS) -> None:
|
||||
if CS.cruiseState.available:
|
||||
self.update_button_timers(CS)
|
||||
|
||||
def update_button_timers(self, CS) -> None:
|
||||
for button_type, held_frames in self.button_frame_counts.items():
|
||||
if held_frames > 0:
|
||||
self.button_frame_counts[button_type] += 1
|
||||
|
||||
for event in CS.buttonEvents:
|
||||
event_type = event.type.raw
|
||||
if not (event.pressed and self.button_frame_counts.get(event_type, 0) > 0): # No need to reset if the button is "pulsing" always "pressed"
|
||||
self.button_frame_counts[event_type] = int(event.pressed)
|
||||
|
||||
def get_hold_duration(self, button_type):
|
||||
return self.button_frame_counts.get(button_type, 0)
|
||||
@@ -5,12 +5,12 @@ This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from cereal import custom
|
||||
from cereal import log
|
||||
from opendbc.car import structs
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||
from openpilot.selfdrive.selfdrived.events import Events
|
||||
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
EventName = log.OnroadEvent.EventName
|
||||
|
||||
|
||||
class CarSpecificEventsSP:
|
||||
@@ -26,9 +26,9 @@ class CarSpecificEventsSP:
|
||||
self.hyundai_radar_tracks_confirmed = self.params.get_bool("HyundaiRadarTracksConfirmed")
|
||||
|
||||
def update(self):
|
||||
events = EventsSP()
|
||||
events = Events()
|
||||
if self.CP.carName == 'hyundai':
|
||||
if self.hyundai_radar_tracks and not self.hyundai_radar_tracks_confirmed:
|
||||
events.add(EventNameSP.hyundaiRadarTracksConfirmed)
|
||||
events.add(EventName.hyundaiRadarTracksConfirmed)
|
||||
|
||||
return events
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from cereal import car, custom
|
||||
from opendbc.car import structs
|
||||
from openpilot.common.params import Params
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
|
||||
DISTANCE_LONG_PRESS = 50
|
||||
|
||||
|
||||
class CruiseHelper:
|
||||
def __init__(self, CP: structs.CarParams):
|
||||
self.CP = CP
|
||||
self.params = Params()
|
||||
|
||||
self.button_frame_counts = {ButtonType.gapAdjustCruise: 0}
|
||||
self._experimental_mode = False
|
||||
self.experimental_mode_switched = False
|
||||
|
||||
def update(self, CS, events, experimental_mode) -> None:
|
||||
if self.CP.openpilotLongitudinalControl:
|
||||
if CS.cruiseState.available:
|
||||
self.update_button_frame_counts(CS)
|
||||
|
||||
# toggle experimental mode once on distance button hold
|
||||
self.update_experimental_mode(events, experimental_mode)
|
||||
|
||||
def update_button_frame_counts(self, CS) -> None:
|
||||
for button in self.button_frame_counts:
|
||||
if self.button_frame_counts[button] > 0:
|
||||
self.button_frame_counts[button] += 1
|
||||
|
||||
for button_event in CS.buttonEvents:
|
||||
button = button_event.type.raw
|
||||
if button in self.button_frame_counts:
|
||||
self.button_frame_counts[button] = int(button_event.pressed)
|
||||
|
||||
def update_experimental_mode(self, events, experimental_mode) -> None:
|
||||
if self.button_frame_counts[ButtonType.gapAdjustCruise] >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
|
||||
self._experimental_mode = not experimental_mode
|
||||
self.params.put_bool_nonblocking("ExperimentalMode", self._experimental_mode)
|
||||
events.add(EventNameSP.experimentalModeSwitched)
|
||||
self.experimental_mode_switched = True
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.car.button_hold_tracker import ButtonHoldTracker, ButtonType, EventName
|
||||
|
||||
DISTANCE_LONG_PRESS = 50
|
||||
|
||||
|
||||
class ExperimentalSwitcher:
|
||||
def __init__(self, params, button_type=ButtonType.gapAdjustCruise):
|
||||
self.params = params
|
||||
self.button_type = button_type
|
||||
self._button_tracker = ButtonHoldTracker()
|
||||
self.experimental_mode_switched = False # Meant to be toggled off by this class's children.
|
||||
|
||||
def update(self, CS, events, experimental_mode):
|
||||
self._button_tracker.update(CS)
|
||||
if CS.cruiseState.available:
|
||||
self.update_mode(events, experimental_mode)
|
||||
|
||||
def update_mode(self, events, experimental_mode) -> None:
|
||||
if self._button_tracker.get_hold_duration(self.button_type) >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
|
||||
experimental_mode = not experimental_mode
|
||||
self.params.put_bool_nonblocking("ExperimentalMode", experimental_mode)
|
||||
events.add(EventName.experimentalModeSwitched)
|
||||
self.experimental_mode_switched = True
|
||||
@@ -22,21 +22,20 @@ def log_fingerprint(CP: structs.CarParams) -> None:
|
||||
sentry.capture_fingerprint(CP.carFingerprint, CP.carName)
|
||||
|
||||
|
||||
def setup_car_interface_sp(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params):
|
||||
def setup_car_interface_sp(CP: structs.CarParams, params):
|
||||
if CP.carName == 'hyundai':
|
||||
if CP.flags & HyundaiFlags.MANDO_RADAR and CP.radarUnavailable:
|
||||
# Having this automatic without a toggle causes a weird process replay diff because
|
||||
# somehow it sees fewer logs than intended
|
||||
if params.get_bool("HyundaiRadarTracksToggle"):
|
||||
CP_SP.flags |= HyundaiFlagsSP.ENABLE_RADAR_TRACKS.value
|
||||
CP.sunnypilotFlags |= HyundaiFlagsSP.ENABLE_RADAR_TRACKS.value
|
||||
if params.get_bool("HyundaiRadarTracks"):
|
||||
CP.radarUnavailable = False
|
||||
|
||||
|
||||
def initialize_car_interface_sp(CP: structs.CarParams, CP_SP: structs.CarParamsSP, params, can_recv: CanRecvCallable,
|
||||
can_send: CanSendCallable):
|
||||
def initialize_car_interface_sp(CP: structs.CarParams, params, can_recv: CanRecvCallable, can_send: CanSendCallable):
|
||||
if CP.carName == 'hyundai':
|
||||
if CP_SP.flags & HyundaiFlagsSP.ENABLE_RADAR_TRACKS:
|
||||
if CP.sunnypilotFlags & HyundaiFlagsSP.ENABLE_RADAR_TRACKS:
|
||||
can_recv()
|
||||
_, fingerprint = can_fingerprint(can_recv)
|
||||
radar_unavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in HYUNDAI_DBC[CP.carFingerprint]
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from cereal import car
|
||||
from sunnypilot.selfdrive.car.button_hold_tracker import ButtonHoldTracker, ButtonType
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def setup_button_tracker():
|
||||
return ButtonHoldTracker()
|
||||
|
||||
|
||||
class TestButtonHoldTracker:
|
||||
@pytest.mark.parametrize(
|
||||
"button_type, button_events, initial_timer, expected_timer",
|
||||
[
|
||||
# Basic button press scenarios
|
||||
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)], 0, 1),
|
||||
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)], 1, 0),
|
||||
|
||||
# Auto-increment when already held
|
||||
(ButtonType.gapAdjustCruise, [], 5, 6),
|
||||
(ButtonType.cancel, [], 10, 11),
|
||||
(ButtonType.leftBlinker, [], 1, 2),
|
||||
|
||||
# Multiple button events in same frame
|
||||
(ButtonType.gapAdjustCruise,
|
||||
[
|
||||
car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True),
|
||||
car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)
|
||||
], 0, 0),
|
||||
|
||||
# Events for different buttons shouldn't affect each other
|
||||
(ButtonType.gapAdjustCruise, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True)], 5, 6),
|
||||
|
||||
# Press while already held (like if it was pulsing the event for some reason)
|
||||
(ButtonType.cancel, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True)], 5, 6),
|
||||
|
||||
# Edge cases
|
||||
(ButtonType.leftBlinker, [], 0, 0),
|
||||
(ButtonType.cancel, [car.CarState.ButtonEvent(type=ButtonType.cancel, pressed=False)], 0, 0),
|
||||
],
|
||||
ids=[
|
||||
"initial_button_press",
|
||||
"button_release",
|
||||
"increment_held_gap_adjust",
|
||||
"increment_held_cancel",
|
||||
"increment_held_blinker",
|
||||
"multiple_events_same_frame",
|
||||
"different_button_no_effect",
|
||||
"press_while_held",
|
||||
"zero_state_no_events",
|
||||
"release_when_not_held"
|
||||
]
|
||||
)
|
||||
def test_update_button_timers(self, mocker, setup_button_tracker, button_type, button_events, initial_timer, expected_timer):
|
||||
tracker = setup_button_tracker
|
||||
mock_CS = mocker.Mock(buttonEvents=button_events, cruiseState=mocker.Mock(available=True))
|
||||
|
||||
if initial_timer > 0:
|
||||
tracker.button_frame_counts[button_type] = initial_timer
|
||||
|
||||
tracker.update(mock_CS)
|
||||
timer_value = tracker.get_hold_duration(button_type)
|
||||
assert timer_value == expected_timer, f"Expected timer for {button_type} to be {expected_timer}, but got {timer_value}"
|
||||
|
||||
def test_cruise_state_unavailable(self, mocker, setup_button_tracker):
|
||||
tracker = setup_button_tracker
|
||||
mock_CS = mocker.Mock(
|
||||
buttonEvents=[car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)],
|
||||
cruiseState=mocker.Mock(available=False)
|
||||
)
|
||||
|
||||
tracker.update(mock_CS)
|
||||
assert tracker.get_hold_duration(ButtonType.gapAdjustCruise) == 0
|
||||
@@ -1,66 +0,0 @@
|
||||
from parameterized import parameterized_class
|
||||
from cereal import car
|
||||
from openpilot.selfdrive.selfdrived.events import Events
|
||||
from openpilot.sunnypilot.selfdrive.car.cruise_helpers import CruiseHelper, DISTANCE_LONG_PRESS
|
||||
|
||||
ButtonEvent = car.CarState.ButtonEvent
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
|
||||
|
||||
@parameterized_class(('openpilot_longitudinal',), [(True,)])
|
||||
class TestCruiseHelper:
|
||||
def setup_method(self):
|
||||
self.CP = car.CarParams(openpilotLongitudinalControl=self.openpilot_longitudinal)
|
||||
self.cruise_helper = CruiseHelper(self.CP)
|
||||
self.cruise_helper.experimental_mode_switched = False
|
||||
self.events = Events()
|
||||
|
||||
def reset(self):
|
||||
for _ in range(2):
|
||||
CS = car.CarState(cruiseState={"available": False})
|
||||
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=False)]
|
||||
self.cruise_helper._experimental_mode = False
|
||||
self.cruise_helper.experimental_mode_switched = False
|
||||
self.cruise_helper.update(CS, self.events, False)
|
||||
|
||||
|
||||
def test_gap_adjust_cruise_long_press_toggle_mode(self) -> None:
|
||||
for pressed in (True, False):
|
||||
for experimental_mode in (True, False):
|
||||
self.reset()
|
||||
self.cruise_helper._experimental_mode = experimental_mode
|
||||
toggled_mode = not experimental_mode if pressed else experimental_mode
|
||||
|
||||
for i in range(DISTANCE_LONG_PRESS):
|
||||
CS = car.CarState(cruiseState={"available": True})
|
||||
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)] if i == 0 else []
|
||||
self.cruise_helper.update(CS, self.events, experimental_mode)
|
||||
|
||||
# mode should be toggled
|
||||
assert self.cruise_helper._experimental_mode == toggled_mode
|
||||
assert self.cruise_helper.experimental_mode_switched is pressed
|
||||
|
||||
# keep holding button after switching mode
|
||||
for _ in range(DISTANCE_LONG_PRESS):
|
||||
CS = car.CarState(cruiseState={"available": True})
|
||||
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)]
|
||||
self.cruise_helper.update(CS, self.events, toggled_mode)
|
||||
|
||||
# mode should not be toggled
|
||||
assert self.cruise_helper._experimental_mode == toggled_mode
|
||||
assert self.cruise_helper.experimental_mode_switched is pressed
|
||||
|
||||
def test_gap_adjust_cruise_short_press_toggle_mode(self) -> None:
|
||||
for pressed in (True, False):
|
||||
for experimental_mode in (True, False):
|
||||
self.reset()
|
||||
self.cruise_helper._experimental_mode = experimental_mode
|
||||
|
||||
for i in range(DISTANCE_LONG_PRESS - 1):
|
||||
CS = car.CarState(cruiseState={"available": True})
|
||||
CS.buttonEvents = [ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=pressed)] if i == 0 else []
|
||||
self.cruise_helper.update(CS, self.events, experimental_mode)
|
||||
|
||||
# mode should not be toggled
|
||||
assert self.cruise_helper._experimental_mode == experimental_mode
|
||||
assert self.cruise_helper.experimental_mode_switched is False
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from cereal import car
|
||||
from sunnypilot.selfdrive.car.experimental_switcher import ExperimentalSwitcher, ButtonType, EventName, DISTANCE_LONG_PRESS
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def setup_switcher(mocker):
|
||||
mock_params = mocker.Mock()
|
||||
return ExperimentalSwitcher(mock_params), mock_params
|
||||
|
||||
|
||||
class TestExperimentalSwitcher:
|
||||
@pytest.mark.parametrize(
|
||||
"use_experimental_mode, long_press, expected_mode, expected_experimental_mode",
|
||||
[
|
||||
(False, True, True, True), # Normal -> Experimental via long press
|
||||
(True, True, False, True), # Experimental -> Normal via long press
|
||||
(False, False, False, False) # No change without long press
|
||||
],
|
||||
ids=[
|
||||
"enable_experimental_mode",
|
||||
"disable_experimental_mode",
|
||||
"no_mode_change_without_long_press"
|
||||
]
|
||||
)
|
||||
def test_update_mode_switches(self, mocker, setup_switcher, use_experimental_mode, long_press, expected_mode, expected_experimental_mode):
|
||||
switcher, params = setup_switcher
|
||||
mock_events = mocker.Mock()
|
||||
mock_CS = mocker.Mock(
|
||||
buttonEvents=[car.CarState.ButtonEvent(type=ButtonType.gapAdjustCruise, pressed=True)],
|
||||
cruiseState=mocker.Mock(available=True)
|
||||
)
|
||||
|
||||
if long_press:
|
||||
for _ in range(DISTANCE_LONG_PRESS + 1):
|
||||
switcher.update(mock_CS, mock_events, use_experimental_mode)
|
||||
|
||||
switcher.update_mode(mock_events, use_experimental_mode)
|
||||
|
||||
if expected_experimental_mode:
|
||||
params.put_bool_nonblocking.assert_called_once_with("ExperimentalMode", expected_mode)
|
||||
mock_events.add.assert_called_once_with(EventName.experimentalModeSwitched)
|
||||
assert switcher.experimental_mode_switched is True
|
||||
else:
|
||||
params.put_bool_nonblocking.assert_not_called()
|
||||
mock_events.add.assert_not_called()
|
||||
assert switcher.experimental_mode_switched is False
|
||||
@@ -1,133 +0,0 @@
|
||||
from cereal import log, car, custom
|
||||
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
|
||||
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType
|
||||
|
||||
|
||||
AlertSize = log.SelfdriveState.AlertSize
|
||||
AlertStatus = log.SelfdriveState.AlertStatus
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
EventNameSP = custom.OnroadEventSP.EventName
|
||||
|
||||
|
||||
# get event name from enum
|
||||
EVENT_NAME_SP = {v: k for k, v in EventNameSP.schema.enumerants.items()}
|
||||
|
||||
|
||||
class EventsSP(EventsBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.event_counters = dict.fromkeys(EVENTS_SP.keys(), 0)
|
||||
|
||||
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
|
||||
return EVENTS_SP
|
||||
|
||||
def get_event_name(self, event: int):
|
||||
return EVENT_NAME_SP[event]
|
||||
|
||||
def get_event_msg_type(self):
|
||||
return custom.OnroadEventSP
|
||||
|
||||
|
||||
EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
# sunnypilot
|
||||
EventNameSP.lkasEnable: {
|
||||
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
|
||||
},
|
||||
|
||||
EventNameSP.lkasDisable: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
|
||||
},
|
||||
|
||||
EventNameSP.manualSteeringRequired: {
|
||||
ET.USER_DISABLE: Alert(
|
||||
"Automatic Lane Centering is OFF",
|
||||
"Manual Steering Required",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.disengage, 1.),
|
||||
},
|
||||
|
||||
EventNameSP.manualLongitudinalRequired: {
|
||||
ET.WARNING: Alert(
|
||||
"Smart/Adaptive Cruise Control: OFF",
|
||||
"Manual Speed Control Required",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 1.),
|
||||
},
|
||||
|
||||
EventNameSP.silentLkasEnable: {
|
||||
ET.ENABLE: EngagementAlert(AudibleAlert.none),
|
||||
},
|
||||
|
||||
EventNameSP.silentLkasDisable: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
|
||||
},
|
||||
|
||||
EventNameSP.silentBrakeHold: {
|
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.none),
|
||||
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
|
||||
},
|
||||
|
||||
EventNameSP.silentWrongGear: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: Alert(
|
||||
"Gear not D",
|
||||
"openpilot Unavailable",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
},
|
||||
|
||||
EventNameSP.silentReverseGear: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Reverse\nGear",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.full,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
|
||||
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
|
||||
},
|
||||
|
||||
EventNameSP.silentDoorOpen: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Door Open"),
|
||||
},
|
||||
|
||||
EventNameSP.silentSeatbeltNotLatched: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
|
||||
},
|
||||
|
||||
EventNameSP.silentParkBrake: {
|
||||
ET.WARNING: Alert(
|
||||
"",
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.),
|
||||
ET.NO_ENTRY: NoEntryAlert("Parking Brake Engaged"),
|
||||
},
|
||||
|
||||
EventNameSP.controlsMismatchLateral: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch: Lateral"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Controls Mismatch: Lateral"),
|
||||
},
|
||||
|
||||
EventNameSP.hyundaiRadarTracksConfirmed: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Radar tracks available. Restart the car to initialize")
|
||||
},
|
||||
|
||||
EventNameSP.experimentalModeSwitched: {
|
||||
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
import bisect
|
||||
from enum import IntEnum
|
||||
from abc import abstractmethod
|
||||
from collections.abc import Callable
|
||||
|
||||
from cereal import log, car
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
AlertSize = log.SelfdriveState.AlertSize
|
||||
AlertStatus = log.SelfdriveState.AlertStatus
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
|
||||
|
||||
# Alert priorities
|
||||
class Priority(IntEnum):
|
||||
LOWEST = 0
|
||||
LOWER = 1
|
||||
LOW = 2
|
||||
MID = 3
|
||||
HIGH = 4
|
||||
HIGHEST = 5
|
||||
|
||||
|
||||
# Event types
|
||||
class ET:
|
||||
ENABLE = 'enable'
|
||||
PRE_ENABLE = 'preEnable'
|
||||
OVERRIDE_LATERAL = 'overrideLateral'
|
||||
OVERRIDE_LONGITUDINAL = 'overrideLongitudinal'
|
||||
NO_ENTRY = 'noEntry'
|
||||
WARNING = 'warning'
|
||||
USER_DISABLE = 'userDisable'
|
||||
SOFT_DISABLE = 'softDisable'
|
||||
IMMEDIATE_DISABLE = 'immediateDisable'
|
||||
PERMANENT = 'permanent'
|
||||
|
||||
|
||||
class Alert:
|
||||
def __init__(self,
|
||||
alert_text_1: str,
|
||||
alert_text_2: str,
|
||||
alert_status: log.SelfdriveState.AlertStatus,
|
||||
alert_size: log.SelfdriveState.AlertSize,
|
||||
priority: Priority,
|
||||
visual_alert: car.CarControl.HUDControl.VisualAlert,
|
||||
audible_alert: car.CarControl.HUDControl.AudibleAlert,
|
||||
duration: float,
|
||||
creation_delay: float = 0.):
|
||||
|
||||
self.alert_text_1 = alert_text_1
|
||||
self.alert_text_2 = alert_text_2
|
||||
self.alert_status = alert_status
|
||||
self.alert_size = alert_size
|
||||
self.priority = priority
|
||||
self.visual_alert = visual_alert
|
||||
self.audible_alert = audible_alert
|
||||
|
||||
self.duration = int(duration / DT_CTRL)
|
||||
|
||||
self.creation_delay = creation_delay
|
||||
|
||||
self.alert_type = ""
|
||||
self.event_type: str | None = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.alert_text_1}/{self.alert_text_2} {self.priority} {self.visual_alert} {self.audible_alert}"
|
||||
|
||||
def __gt__(self, alert2) -> bool:
|
||||
if not isinstance(alert2, Alert):
|
||||
return False
|
||||
return self.priority > alert2.priority
|
||||
|
||||
class AlertBase(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str, alert_status: log.SelfdriveState.AlertStatus,
|
||||
alert_size: log.SelfdriveState.AlertSize, priority: Priority,
|
||||
visual_alert: car.CarControl.HUDControl.VisualAlert,
|
||||
audible_alert: car.CarControl.HUDControl.AudibleAlert, duration: float):
|
||||
super().__init__(alert_text_1, alert_text_2, alert_status, alert_size, priority, visual_alert, audible_alert, duration)
|
||||
|
||||
|
||||
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], Alert]
|
||||
|
||||
|
||||
class EventsBase:
|
||||
def __init__(self):
|
||||
self.events: list[int] = []
|
||||
self.static_events: list[int] = []
|
||||
self.event_counters = {}
|
||||
|
||||
@property
|
||||
def names(self) -> list[int]:
|
||||
return self.events
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.events)
|
||||
|
||||
def add(self, event_name: int, static: bool = False) -> None:
|
||||
if static:
|
||||
bisect.insort(self.static_events, event_name)
|
||||
bisect.insort(self.events, event_name)
|
||||
|
||||
def clear(self) -> None:
|
||||
self.event_counters = {k: (v + 1 if k in self.events else 0) for k, v in self.event_counters.items()}
|
||||
self.events = self.static_events.copy()
|
||||
|
||||
def contains(self, event_type: str) -> bool:
|
||||
return any(event_type in self.get_events_mapping().get(e, {}) for e in self.events)
|
||||
|
||||
def create_alerts(self, event_types: list[str], callback_args=None):
|
||||
if callback_args is None:
|
||||
callback_args = []
|
||||
|
||||
ret = []
|
||||
for e in self.events:
|
||||
types = self.get_events_mapping()[e].keys()
|
||||
for et in event_types:
|
||||
if et in types:
|
||||
alert = self.get_events_mapping()[e][et]
|
||||
if not isinstance(alert, Alert):
|
||||
alert = alert(*callback_args)
|
||||
|
||||
if DT_CTRL * (self.event_counters[e] + 1) >= alert.creation_delay:
|
||||
alert.alert_type = f"{self.get_event_name(e)}/{et}"
|
||||
alert.event_type = et
|
||||
ret.append(alert)
|
||||
return ret
|
||||
|
||||
def add_from_msg(self, events):
|
||||
for e in events:
|
||||
bisect.insort(self.events, e.name.raw)
|
||||
|
||||
def to_msg(self):
|
||||
ret = []
|
||||
for event_name in self.events:
|
||||
event = self.get_event_msg_type().new_message()
|
||||
event.name = event_name
|
||||
for event_type in self.get_events_mapping().get(event_name, {}):
|
||||
setattr(event, event_type, True)
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
||||
def has(self, event_name: int) -> bool:
|
||||
return event_name in self.events
|
||||
|
||||
def contains_in_list(self, events_list: list[int]) -> bool:
|
||||
return any(event_name in self.events for event_name in events_list)
|
||||
|
||||
def remove(self, event_name: int, static: bool = False) -> None:
|
||||
if static and event_name in self.static_events:
|
||||
self.static_events.remove(event_name)
|
||||
|
||||
if event_name in self.events:
|
||||
self.event_counters[event_name] = self.event_counters[event_name] + 1
|
||||
self.events.remove(event_name)
|
||||
|
||||
@abstractmethod
|
||||
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_event_name(self, event: int) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_event_msg_type(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
EmptyAlert = Alert("" , "", AlertStatus.normal, AlertSize.none, Priority.LOWEST,
|
||||
VisualAlert.none, AudibleAlert.none, 0)
|
||||
|
||||
class NoEntryAlert(Alert):
|
||||
def __init__(self, alert_text_2: str,
|
||||
alert_text_1: str = "openpilot Unavailable",
|
||||
visual_alert: car.CarControl.HUDControl.VisualAlert=VisualAlert.none):
|
||||
super().__init__(alert_text_1, alert_text_2, AlertStatus.normal,
|
||||
AlertSize.mid, Priority.LOW, visual_alert,
|
||||
AudibleAlert.refuse, 3.)
|
||||
|
||||
|
||||
class SoftDisableAlert(Alert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
|
||||
AlertStatus.userPrompt, AlertSize.full,
|
||||
Priority.MID, VisualAlert.steerRequired,
|
||||
AudibleAlert.warningSoft, 2.),
|
||||
|
||||
|
||||
# less harsh version of SoftDisable, where the condition is user-triggered
|
||||
class UserSoftDisableAlert(SoftDisableAlert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__(alert_text_2),
|
||||
self.alert_text_1 = "openpilot will disengage"
|
||||
|
||||
|
||||
class ImmediateDisableAlert(Alert):
|
||||
def __init__(self, alert_text_2: str):
|
||||
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
|
||||
AlertStatus.critical, AlertSize.full,
|
||||
Priority.HIGHEST, VisualAlert.steerRequired,
|
||||
AudibleAlert.warningImmediate, 4.),
|
||||
|
||||
|
||||
class EngagementAlert(Alert):
|
||||
def __init__(self, audible_alert: car.CarControl.HUDControl.AudibleAlert):
|
||||
super().__init__("", "",
|
||||
AlertStatus.normal, AlertSize.none,
|
||||
Priority.MID, VisualAlert.none,
|
||||
audible_alert, .2),
|
||||
|
||||
|
||||
class NormalPermanentAlert(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str = "", duration: float = 0.2, priority: Priority = Priority.LOWER, creation_delay: float = 0.):
|
||||
super().__init__(alert_text_1, alert_text_2,
|
||||
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
|
||||
priority, VisualAlert.none, AudibleAlert.none, duration, creation_delay=creation_delay),
|
||||
|
||||
|
||||
class StartupAlert(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str = "Always keep hands on wheel and eyes on road", alert_status=AlertStatus.normal):
|
||||
super().__init__(alert_text_1, alert_text_2,
|
||||
alert_status, AlertSize.mid,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
float fl_pix = 0;
|
||||
|
||||
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, true /*config.stream_type == VISION_STREAM_ROAD*/) {};
|
||||
CameraState(SpectraMaster *master, const CameraConfig &config) : camera(master, config, config.stream_type == VISION_STREAM_ROAD) {};
|
||||
~CameraState();
|
||||
void init(VisionIpcServer *v, cl_device_id device_id, cl_context ctx);
|
||||
void update_exposure_score(float desired_ev, int exp_t, int exp_g_idx, float exp_gain);
|
||||
@@ -97,7 +97,7 @@ void CameraState::set_exposure_rect() {
|
||||
};
|
||||
int h_ref = 1208;
|
||||
/*
|
||||
exposure target intrinsics is
|
||||
exposure target intrinics is
|
||||
[
|
||||
[F, 0, 0.5*ae_xywh[2]]
|
||||
[0, F, 0.5*H-ae_xywh[1]]
|
||||
@@ -127,8 +127,6 @@ void CameraState::update_exposure_score(float desired_ev, int exp_t, int exp_g_i
|
||||
|
||||
void CameraState::set_camera_exposure(float grey_frac) {
|
||||
if (!camera.enabled) return;
|
||||
std::vector<double> target_grey_minimums = {0.1, 0.1, 0.125}; // wide, road, driver
|
||||
|
||||
const float dt = 0.05;
|
||||
|
||||
const float ts_grey = 10.0;
|
||||
@@ -145,8 +143,8 @@ void CameraState::set_camera_exposure(float grey_frac) {
|
||||
const auto &sensor = camera.sensor;
|
||||
const float cur_ev_ = cur_ev[camera.buf.cur_frame_data.frame_id % 3] * sensor->ev_scale;
|
||||
|
||||
// Scale target grey between min and 0.4 depending on lighting conditions
|
||||
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + sensor->target_grey_factor*cur_ev_) / log2(6000.0), target_grey_minimums[camera.cc.camera_num], 0.4);
|
||||
// Scale target grey between 0.1 and 0.4 depending on lighting conditions
|
||||
float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + sensor->target_grey_factor*cur_ev_) / log2(6000.0), 0.1, 0.4);
|
||||
float target_grey = (1.0 - k_grey) * target_grey_fraction + k_grey * new_target_grey;
|
||||
|
||||
float desired_ev = std::clamp(cur_ev_ / sensor->ev_scale * target_grey / grey_frac, sensor->min_ev, sensor->max_ev);
|
||||
|
||||
@@ -258,10 +258,6 @@ int SpectraCamera::clear_req_queue() {
|
||||
req_mgr_flush_request.flush_type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
|
||||
int ret = do_cam_control(m->video0_fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
|
||||
// LOGD("flushed all req: %d", ret);
|
||||
|
||||
for (int i = 0; i < MAX_IFE_BUFS; ++i) {
|
||||
destroySyncObjectAt(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -693,7 +689,16 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
|
||||
buf.queue(i);
|
||||
}
|
||||
|
||||
destroySyncObjectAt(i);
|
||||
// destroy old output fence
|
||||
for (auto so : {sync_objs, sync_objs_bps_out}) {
|
||||
if (so[i] == 0) continue;
|
||||
struct cam_sync_info sync_destroy = {0};
|
||||
sync_destroy.sync_obj = so[i];
|
||||
ret = do_sync_control(m->cam_sync_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
|
||||
if (ret != 0) {
|
||||
LOGE("failed to destroy sync object: %d %d", ret, sync_destroy.sync_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create output fences
|
||||
@@ -731,23 +736,6 @@ void SpectraCamera::enqueue_buffer(int i, bool dp) {
|
||||
config_bps(i, request_id);
|
||||
}
|
||||
|
||||
void SpectraCamera::destroySyncObjectAt(int index) {
|
||||
auto destroy_sync_obj = [](int cam_sync_fd, int32_t &sync_obj) {
|
||||
if (sync_obj == 0) return;
|
||||
|
||||
struct cam_sync_info sync_destroy = {.sync_obj = sync_obj};
|
||||
int ret = do_sync_control(cam_sync_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
|
||||
if (ret != 0) {
|
||||
LOGE("Failed to destroy sync object: %d, sync_obj: %d", ret, sync_destroy.sync_obj);
|
||||
}
|
||||
|
||||
sync_obj = 0; // Reset the sync object to 0
|
||||
};
|
||||
|
||||
destroy_sync_obj(m->cam_sync_fd, sync_objs[index]);
|
||||
destroy_sync_obj(m->cam_sync_fd, sync_objs_bps_out[index]);
|
||||
}
|
||||
|
||||
void SpectraCamera::camera_map_bufs() {
|
||||
int ret;
|
||||
for (int i = 0; i < ife_buf_depth; i++) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -73,21 +72,10 @@ public:
|
||||
|
||||
class SpectraBuf {
|
||||
public:
|
||||
SpectraBuf() = default;
|
||||
|
||||
~SpectraBuf() {
|
||||
if (video_fd >= 0 && ptr) {
|
||||
munmap(ptr, mmap_size);
|
||||
release(video_fd, handle);
|
||||
}
|
||||
}
|
||||
|
||||
void init(SpectraMaster *m, int s, int a, int flags, int mmu_hdl = 0, int mmu_hdl2 = 0, int count=1) {
|
||||
video_fd = m->video0_fd;
|
||||
size = s;
|
||||
alignment = a;
|
||||
mmap_size = aligned_size() * count;
|
||||
void *p = alloc_w_mmu_hdl(video_fd, mmap_size, (uint32_t*)&handle, alignment, flags, mmu_hdl, mmu_hdl2);
|
||||
void *p = alloc_w_mmu_hdl(m->video0_fd, ALIGNED_SIZE(size, alignment)*count, (uint32_t*)&handle, alignment, flags, mmu_hdl, mmu_hdl2);
|
||||
ptr = (unsigned char*)p;
|
||||
assert(ptr != NULL);
|
||||
};
|
||||
@@ -96,9 +84,8 @@ public:
|
||||
return ALIGNED_SIZE(size, alignment);
|
||||
};
|
||||
|
||||
int video_fd = -1;
|
||||
unsigned char *ptr = nullptr;
|
||||
int size = 0, alignment = 0, handle = 0, mmap_size = 0;
|
||||
unsigned char *ptr;
|
||||
int size, alignment, handle;
|
||||
};
|
||||
|
||||
class SpectraCamera {
|
||||
@@ -127,7 +114,6 @@ public:
|
||||
void configICP();
|
||||
void configCSIPHY();
|
||||
void linkDevices();
|
||||
void destroySyncObjectAt(int index);
|
||||
|
||||
// *** state ***
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user