mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-06-11 11:44:47 +08:00
Compare commits
115 Commits
tn-next
...
nav-events
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
692a4587db | ||
|
|
80a6f39a79 | ||
|
|
997ab25057 | ||
|
|
05da45a1bf | ||
|
|
864c811ef6 | ||
|
|
906e9d7a80 | ||
|
|
cfb8f3ae24 | ||
|
|
0cc5e56192 | ||
|
|
1a62ae821e | ||
|
|
8caa57feeb | ||
|
|
2858a068f0 | ||
|
|
7d15afe5bc | ||
|
|
b6dd2d14db | ||
|
|
7d4e5bedaf | ||
|
|
1063114408 | ||
|
|
958b4df69f | ||
|
|
f5953c5d8c | ||
|
|
72998034e6 | ||
|
|
cefb344183 | ||
|
|
c0da31abb6 | ||
|
|
bd759a56cf | ||
|
|
befc73c53e | ||
|
|
8dbfc267ac | ||
|
|
d17e80ad94 | ||
|
|
c2b7087723 | ||
|
|
81b37712f1 | ||
|
|
68270a13a3 | ||
|
|
18cd3633e5 | ||
|
|
9c6a4d4a57 | ||
|
|
1a4c48249b | ||
|
|
95d887a417 | ||
|
|
e297b4c03f | ||
|
|
1132377837 | ||
|
|
35f03ae001 | ||
|
|
1c0b54a447 | ||
|
|
8f0cdd514e | ||
|
|
3681caa717 | ||
|
|
7446c43f69 | ||
|
|
5f5e3668eb | ||
|
|
8c07958f6f | ||
|
|
ca1ce9bcc9 | ||
|
|
34a0819bc5 | ||
|
|
c68ea82a5d | ||
|
|
3157054100 | ||
|
|
2486ef1825 | ||
|
|
29f15dc8ed | ||
|
|
31a5a3b3c0 | ||
|
|
d8fa3cfd04 | ||
|
|
2a4b348497 | ||
|
|
3ef3aceb4b | ||
|
|
3d8763b3ce | ||
|
|
b2427a5f20 | ||
|
|
7ddafe62cd | ||
|
|
ff4cc96a81 | ||
|
|
3b1ada64be | ||
|
|
6a08186434 | ||
|
|
cf2b033c79 | ||
|
|
9fbef36c6b | ||
|
|
f5a38aa613 | ||
|
|
25f5058430 | ||
|
|
7b28c2f59a | ||
|
|
99d954de10 | ||
|
|
b28f33481c | ||
|
|
589e33f665 | ||
|
|
39342d7b5e | ||
|
|
fe70650f73 | ||
|
|
e3f9fe892a | ||
|
|
f4373fa244 | ||
|
|
2376802589 | ||
|
|
c3b51d7335 | ||
|
|
d3d8802402 | ||
|
|
d866500c92 | ||
|
|
23879836d9 | ||
|
|
06add21971 | ||
|
|
66fd3d1a01 | ||
|
|
71f7754f51 | ||
|
|
b5591cbd62 | ||
|
|
7430c450c2 | ||
|
|
e54a39cf43 | ||
|
|
3afe0bcdb3 | ||
|
|
b763f7aac1 | ||
|
|
450fcd4d55 | ||
|
|
551b4dea31 | ||
|
|
bd269defb3 | ||
|
|
8998f63a28 | ||
|
|
399ed08926 | ||
|
|
90f02040fe | ||
|
|
8423ecedb1 | ||
|
|
34d1514e11 | ||
|
|
c50d511616 | ||
|
|
dd1479ed82 | ||
|
|
87ec262e39 | ||
|
|
f82845ff42 | ||
|
|
efcc5ccd15 | ||
|
|
6aac50ab56 | ||
|
|
da0920cb60 | ||
|
|
091bce4a3a | ||
|
|
088f6aa407 | ||
|
|
211c8adcce | ||
|
|
fe5366e5b2 | ||
|
|
1ecb0b0f66 | ||
|
|
51e455db79 | ||
|
|
dc6672fa80 | ||
|
|
07b8e7783d | ||
|
|
f17b0f200c | ||
|
|
ad9bde8b1f | ||
|
|
8cf9f9fe23 | ||
|
|
713985d823 | ||
|
|
088f9d0b59 | ||
|
|
53bf5b0d41 | ||
|
|
8c33592628 | ||
|
|
3bbb33f6bd | ||
|
|
5bd9549bd1 | ||
|
|
3481702715 | ||
|
|
c9781ee31d |
@@ -74,7 +74,7 @@ jobs:
|
||||
env:
|
||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||
run: |
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
||||
cd gitlab_docs
|
||||
git checkout main
|
||||
git sparse-checkout set --no-cone models/
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||
run: |
|
||||
echo "Cloning GitLab"
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
||||
cd gitlab_docs
|
||||
echo "checkout models/${RECOMPILED_DIR}"
|
||||
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
||||
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
GIT_SSH_COMMAND: 'ssh -o UserKnownHostsFile=~/.ssh/known_hosts'
|
||||
run: |
|
||||
echo "Cloning GitLab"
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/${{ vars.MODELS_GITLAB }} gitlab_docs
|
||||
git clone --depth 1 --filter=tree:0 --sparse git@gitlab.com:sunnypilot/public/docs.sunnypilot.ai2.git gitlab_docs
|
||||
cd gitlab_docs
|
||||
echo "checkout models/${RECOMPILED_DIR}"
|
||||
git sparse-checkout set --no-cone models/${RECOMPILED_DIR}
|
||||
|
||||
@@ -156,8 +156,6 @@ jobs:
|
||||
with:
|
||||
name: models-${{ env.REF }}${{ inputs.artifact_suffix }}
|
||||
path: ${{ github.workspace }}/selfdrive/modeld/models
|
||||
- run: |
|
||||
rm -f ${{ github.workspace }}/selfdrive/modeld/models/{dmonitoring_model,big_driving_policy,big_driving_vision}.onnx
|
||||
|
||||
- name: Build Model
|
||||
run: |
|
||||
|
||||
1
.gitmodules
vendored
1
.gitmodules
vendored
@@ -4,7 +4,6 @@
|
||||
[submodule "opendbc"]
|
||||
path = opendbc_repo
|
||||
url = https://github.com/sunnypilot/opendbc.git
|
||||
branch = tn
|
||||
[submodule "msgq"]
|
||||
path = msgq_repo
|
||||
url = https://github.com/sunnypilot/msgq.git
|
||||
|
||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -1,30 +1,6 @@
|
||||
sunnypilot Version 2025.003.000 (20xx-xx-xx)
|
||||
sunnypilot Version 2025.002.000 (2025-xx-xx)
|
||||
========================
|
||||
|
||||
sunnypilot Version 2025.002.000 (2025-11-06)
|
||||
========================
|
||||
* What's Changed (sunnypilot/sunnypilot)
|
||||
* models: bump model json to v8 by @Discountchubbs
|
||||
* Bug: Model UI Crash Fix by @nayan8teen
|
||||
* controlsd: add `CP_SP` to `get_pid_accel_limits` by @THERoenPR
|
||||
* sunnylink: update uploader button logic to support novice tier and above by @devtekve
|
||||
* Tesla: Coop Steering by @AmyJeanes
|
||||
* ui: update discord references and add forum widget by @devtekve
|
||||
* ui: Fix spacing in sunnylink panel by @devtekve
|
||||
* docs: Update README installation branches and discord links by @mpurnell1 in
|
||||
* stats: sunnylink integration by @devtekve
|
||||
* bug: Fix initial registration for sunnylink by @devtekve
|
||||
* What's Changed (sunnypilot/opendbc)
|
||||
* Honda: add brake hold messages for Clarity by @mvl-boston
|
||||
* interface: add `CP_SP` to `get_pid_accel_limits` method signature by @roenthomas
|
||||
* Honda: use fixed accel min/max constants for Gas Interceptor by @roenthomas
|
||||
* Tesla: Coop Steering by @AmyJeanes
|
||||
* New Contributors (sunnypilot/sunnypilot)
|
||||
* @THERoenPR made their first contribution in "controlsd: add `CP_SP` to `get_pid_accel_limits`"
|
||||
* @AmyJeanes made their first contribution in "Tesla: Coop Steering"
|
||||
* @mpurnell1 made their first contribution in "docs: Update README installation branches and discord links"
|
||||
* Full Changelog: https://github.com/sunnypilot/sunnypilot/compare/v2025.001.000...v2025.002.000
|
||||
|
||||
sunnypilot Version 2025.001.000 (2025-10-25)
|
||||
========================
|
||||
* 🛠️ Major rewrite
|
||||
|
||||
36
README.md
36
README.md
@@ -3,9 +3,11 @@
|
||||
## 🌞 What is sunnypilot?
|
||||
[sunnypilot](https://github.com/sunnyhaibin/sunnypilot) is a fork of comma.ai's openpilot, an open source driver assistance system. sunnypilot offers the user a unique driving experience for over 300+ supported car makes and models with modified behaviors of driving assist engagements. sunnypilot complies with comma.ai's safety rules as accurately as possible.
|
||||
|
||||
## 💭 Join our Community Forum
|
||||
Join the official sunnypilot community forum to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
||||
* https://community.sunnypilot.ai/
|
||||
## 💭 Join our Discord
|
||||
Join the official sunnypilot Discord server to stay up to date with all the latest features and be a part of shaping the future of sunnypilot!
|
||||
* https://discord.gg/sunnypilot
|
||||
|
||||
 
|
||||
|
||||
## Documentation
|
||||
https://docs.sunnypilot.ai/ is your one stop shop for everything from features to installation to FAQ about the sunnypilot
|
||||
@@ -14,13 +16,13 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
|
||||
* A supported device to run this software
|
||||
* a [comma three](https://comma.ai/shop/products/three) or a [C3X](https://comma.ai/shop/comma-3x)
|
||||
* This software
|
||||
* One of [the 325+ supported cars](https://github.com/sunnypilot/sunnypilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
||||
* One of [the 300+ supported cars](https://github.com/commaai/openpilot/blob/master/docs/CARS.md). We support Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford and more. If your car is not supported but has adaptive cruise control and lane-keeping assist, it's likely able to run sunnypilot.
|
||||
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
|
||||
|
||||
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
|
||||
|
||||
## Installation
|
||||
Please refer to [Recommended Branches](#recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging` branch.
|
||||
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-c3-new` branch.
|
||||
|
||||
### If you want to use our newest branches (our rewrite)
|
||||
> [!TIP]
|
||||
@@ -29,28 +31,28 @@ Please refer to [Recommended Branches](#recommended-branches) to find your prefe
|
||||
* sunnypilot not installed or you installed a version before 0.8.17?
|
||||
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
|
||||
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
|
||||
3. Input the installation URL per [Recommended Branches](#recommended-branches). Example: ```https://staging.sunnypilot.ai```.
|
||||
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.sunnypilot.ai```.
|
||||
4. Complete the rest of the installation following the onscreen instructions.
|
||||
|
||||
* sunnypilot already installed and you installed a version after 0.8.17?
|
||||
1. On the comma three/3X, go to `Settings` ▶️ `Software`.
|
||||
1. On the comma three, go to `Settings` ▶️ `Software`.
|
||||
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
|
||||
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
|
||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging`
|
||||
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
|
||||
|
||||
### Recommended Branches
|
||||
| Branch | Installation URL |
|
||||
|:---------------:|:---------------------------------------------:|
|
||||
| `release` | `https://release.sunnypilot.ai` |
|
||||
| `staging` | `https://staging.sunnypilot.ai` |
|
||||
| `dev` | `https://dev.sunnypilot.ai` |
|
||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||
|
||||
| Branch | Installation URL |
|
||||
|:----------------:|:---------------------------------------------:|
|
||||
| `staging-c3-new` | `https://staging-c3-new.sunnypilot.ai` |
|
||||
| `dev-c3-new` | `https://dev-c3-new.sunnypilot.ai` |
|
||||
| `custom-branch` | `https://install.sunnypilot.ai/{branch_name}` |
|
||||
| `release-c3-new` | **Not yet available**. |
|
||||
|
||||
> [!TIP]
|
||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging'.
|
||||
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
|
||||
|
||||
> [!NOTE]
|
||||
> Do you require further assistance with software installation? Join the [sunnypilot community forum](https://community.sunnypilot.ai/new-topic?category=general/qa) and create a topic in the General/Q&A Category channel.
|
||||
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
|
||||
|
||||
|
||||
<details>
|
||||
|
||||
@@ -192,7 +192,6 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
aTarget @5 :Float32;
|
||||
events @6 :List(OnroadEventSP.Event);
|
||||
e2eAlerts @7 :E2eAlerts;
|
||||
accelPersonality @8 :AccelerationPersonality;
|
||||
|
||||
struct DynamicExperimentalControl {
|
||||
state @0 :DynamicExperimentalControlState;
|
||||
@@ -204,11 +203,7 @@ struct LongitudinalPlanSP @0xf35cc4560bbf6ec2 {
|
||||
blended @1;
|
||||
}
|
||||
}
|
||||
enum AccelerationPersonality {
|
||||
sport @0;
|
||||
normal @1;
|
||||
eco @2;
|
||||
}
|
||||
|
||||
struct SmartCruiseControl {
|
||||
vision @0 :Vision;
|
||||
map @1 :Map;
|
||||
@@ -345,7 +340,7 @@ struct OnroadEventSP @0xda96579883444c35 {
|
||||
speedLimitChanged @21;
|
||||
speedLimitPending @22;
|
||||
e2eChime @23;
|
||||
laneChangeRoadEdge @24;
|
||||
navigationBanner @24;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,8 +447,6 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
|
||||
|
||||
struct ModelDataV2SP @0xa1680744031fdb2d {
|
||||
laneTurnDirection @0 :TurnDirection;
|
||||
leftLaneChangeEdgeBlock @1 :Bool;
|
||||
rightLaneChangeEdgeBlock @2 :Bool;
|
||||
|
||||
enum TurnDirection {
|
||||
none @0;
|
||||
@@ -496,84 +489,11 @@ struct CustomReserved15 @0xbd443b539493bc68 {
|
||||
struct CustomReserved16 @0xfc6241ed8877b611 {
|
||||
}
|
||||
|
||||
enum MapdExtendedOutType {
|
||||
paths @0;
|
||||
settings @1;
|
||||
struct CustomReserved17 @0xa30662f84033036c {
|
||||
}
|
||||
|
||||
struct MapdExtendedOut @0xa30662f84033036c {
|
||||
type @0 :MapdExtendedOutType;
|
||||
json @1 :Text;
|
||||
struct CustomReserved18 @0xc86a3d38d13eb3ef {
|
||||
}
|
||||
|
||||
enum MapdInputType {
|
||||
download @0;
|
||||
setTargetLateralAccel @1;
|
||||
setSpeedLimitOffset @2;
|
||||
setSpeedLimitControl @3;
|
||||
setCurveSpeedControl @4;
|
||||
setVisionCurveSpeedControl @5;
|
||||
setLogLevel @6;
|
||||
setVisionCurveTargetLatA @7;
|
||||
setVisionCurveMinTargetV @8;
|
||||
reloadSettings @9;
|
||||
saveSettings @10;
|
||||
setEnableSpeed @11;
|
||||
setVisionCurveUseEnableSpeed @12;
|
||||
setCurveUseEnableSpeed @13;
|
||||
setSpeedLimitUseEnableSpeed @14;
|
||||
setHoldLastSeenSpeedLimit @15;
|
||||
setCurveTargetJerk @16;
|
||||
setCurveTargetAccel @17;
|
||||
setCurveTargetOffset @18;
|
||||
setDefaultLaneWidth @19;
|
||||
setCurveTargetLatA @20;
|
||||
loadDefaultSettings @21;
|
||||
loadRecommendedSettings @22;
|
||||
setSlowDownForNextSpeedLimit @23;
|
||||
setSpeedUpForNextSpeedLimit @24;
|
||||
setHoldSpeedLimitWhileChangingSetSpeed @25;
|
||||
}
|
||||
|
||||
enum SpeedLimitOffsetType {
|
||||
static @0;
|
||||
percent @1;
|
||||
}
|
||||
|
||||
struct MapdIn @0xc86a3d38d13eb3ef {
|
||||
type @0 :MapdInputType;
|
||||
float @1 :Float32;
|
||||
str @2 :Text;
|
||||
bool @3 :Bool;
|
||||
}
|
||||
|
||||
enum RoadContext {
|
||||
freeway @0;
|
||||
city @1;
|
||||
unknown @2;
|
||||
}
|
||||
|
||||
struct MapdOut @0xa4f1eb3323f5f582 {
|
||||
wayName @0 :Text;
|
||||
wayRef @1 :Text;
|
||||
roadName @2 :Text;
|
||||
speedLimit @3 :Float32;
|
||||
nextSpeedLimit @4 :Float32;
|
||||
nextSpeedLimitDistance @5 :Float32;
|
||||
hazard @6 :Text;
|
||||
nextHazard @7 :Text;
|
||||
nextHazardDistance @8 :Float32;
|
||||
advisorySpeed @9 :Float32;
|
||||
nextAdvisorySpeed @10 :Float32;
|
||||
nextAdvisorySpeedDistance @11 :Float32;
|
||||
oneWay @12 :Bool;
|
||||
lanes @13 :UInt8;
|
||||
tileLoaded @14 :Bool;
|
||||
speedLimitOffset @15 :Float32;
|
||||
suggestedSpeed @16 :Float32;
|
||||
estimatedRoadWidth @17 :Float32;
|
||||
roadContext @18 :RoadContext;
|
||||
distanceFromWayCenter @19 :Float32;
|
||||
visionCurveSpeed @20 :Float32;
|
||||
curveSpeed @21 :Float32;
|
||||
struct CustomReserved19 @0xa4f1eb3323f5f582 {
|
||||
}
|
||||
|
||||
@@ -2639,9 +2639,9 @@ struct Event {
|
||||
customReserved14 @140 :Custom.CustomReserved14;
|
||||
customReserved15 @141 :Custom.CustomReserved15;
|
||||
customReserved16 @142 :Custom.CustomReserved16;
|
||||
mapdExtendedOut @143 :Custom.MapdExtendedOut;
|
||||
mapdIn @144 :Custom.MapdIn;
|
||||
mapdOut @145 :Custom.MapdOut;
|
||||
customReserved17 @143 :Custom.CustomReserved17;
|
||||
customReserved18 @144 :Custom.CustomReserved18;
|
||||
customReserved19 @145 :Custom.CustomReserved19;
|
||||
|
||||
# *********** legacy + deprecated ***********
|
||||
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
|
||||
|
||||
@@ -91,7 +91,6 @@ _services: dict[str, tuple] = {
|
||||
"modelDataV2SP": (True, 20.),
|
||||
"navigationd": (True, 3.),
|
||||
"liveLocationKalman": (True, 20.),
|
||||
"mapdOut": (True, 20., 20),
|
||||
|
||||
# debug
|
||||
"uiDebug": (True, 0., 1),
|
||||
|
||||
@@ -130,8 +130,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"Version", {PERSISTENT, STRING}},
|
||||
|
||||
// --- sunnypilot params --- //
|
||||
{"AccelPersonality", {PERSISTENT | BACKUP, INT, std::to_string(static_cast<int>(cereal::LongitudinalPlanSP::AccelerationPersonality::NORMAL))}},
|
||||
{"AccelPersonalityEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ApiCache_DriveStats", {PERSISTENT, JSON}},
|
||||
{"AutoLaneChangeBsmDelay", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"AutoLaneChangeTimer", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
@@ -148,7 +146,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
|
||||
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"DevUIInfo", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"DynamicFollow", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"GreenLightAlert", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
@@ -171,19 +168,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"RoadEdgeLaneChangeEnabled", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
// toyota specific params
|
||||
{"ToyotaAutoHold", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaEnhancedBsm", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaTSS2Long", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaStockLongitudinal", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaDriveMode", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
// MADS params
|
||||
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||
{"MadsMainCruiseAllowed", {PERSISTENT | BACKUP, BOOL, "1"}},
|
||||
@@ -205,6 +194,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"MapboxRoute", {PERSISTENT, STRING}},
|
||||
{"MapboxRecompute", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"NavDesiresAllowed", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"NavEvents", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
// Neural Network Lateral Control
|
||||
{"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
@@ -227,7 +217,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
@@ -239,9 +228,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"LaneTurnDesire", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"LaneTurnValue", {PERSISTENT | BACKUP, FLOAT, "19.0"}},
|
||||
|
||||
|
||||
// mapd v020
|
||||
{"MapdSettings", {PERSISTENT | BACKUP, JSON}},
|
||||
// mapd
|
||||
{"MapAdvisorySpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT}},
|
||||
{"MapdVersion", {PERSISTENT, STRING}},
|
||||
|
||||
Submodule opendbc_repo updated: 2bcc263692...e0e1626820
@@ -10,7 +10,7 @@ from cereal import car, log, custom
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper
|
||||
from openpilot.common.swaglog import cloudlog, ForwardingHandler
|
||||
from opendbc.safety import ALTERNATIVE_EXPERIENCE
|
||||
|
||||
from opendbc.car import DT_CTRL, structs
|
||||
from opendbc.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
|
||||
from opendbc.car.carlog import carlog
|
||||
@@ -123,13 +123,7 @@ class Car:
|
||||
self.CI, self.CP, self.CP_SP = CI, CI.CP, CI.CP_SP
|
||||
self.RI = RI
|
||||
|
||||
# set alternative experiences from parameters
|
||||
sp_toyota_auto_brake_hold = self.params.get_bool("ToyotaAutoHold")
|
||||
self.CP.alternativeExperience = 0
|
||||
if sp_toyota_auto_brake_hold:
|
||||
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALLOW_AEB
|
||||
|
||||
|
||||
# mads
|
||||
set_alternative_experience(self.CP, self.CP_SP, self.params)
|
||||
set_car_specific_params(self.CP, self.CP_SP, self.params)
|
||||
|
||||
@@ -58,7 +58,7 @@ class DesireHelper:
|
||||
def get_lane_change_direction(CS):
|
||||
return LaneChangeDirection.left if CS.leftBlinker else LaneChangeDirection.right
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob, left_edge_detected, right_edge_detected):
|
||||
def update(self, carstate, lateral_active, lane_change_prob):
|
||||
self.alc.update_params()
|
||||
self.lane_turn_controller.update_params()
|
||||
v_ego = carstate.vEgo
|
||||
@@ -90,8 +90,8 @@ class DesireHelper:
|
||||
((carstate.steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or
|
||||
(carstate.steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right))
|
||||
|
||||
blindspot_detected = (((carstate.leftBlindspot or left_edge_detected) and self.lane_change_direction == LaneChangeDirection.left) or
|
||||
((carstate.rightBlindspot or right_edge_detected) and self.lane_change_direction == LaneChangeDirection.right))
|
||||
blindspot_detected = ((carstate.leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or
|
||||
(carstate.rightBlindspot and self.lane_change_direction == LaneChangeDirection.right))
|
||||
|
||||
self.alc.update_lane_change(blindspot_detected, carstate.brakePressed)
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.selfdrive.modeld.constants import index_function
|
||||
from openpilot.selfdrive.controls.radard import _LEAD_ACCEL_TAU
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.accel_personality.accel_controller import AccelPersonalityController
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.dynamic_personality.dynamic_follow import FollowDistanceController
|
||||
if __name__ == '__main__': # generating code
|
||||
from openpilot.third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
|
||||
else:
|
||||
@@ -230,8 +228,6 @@ class LongitudinalMpc:
|
||||
self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
|
||||
self.reset()
|
||||
self.source = SOURCES[2]
|
||||
self.accel_controller = AccelPersonalityController()
|
||||
self.dynamic_follow = FollowDistanceController()
|
||||
|
||||
def reset(self):
|
||||
# self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
|
||||
@@ -332,27 +328,10 @@ class LongitudinalMpc:
|
||||
return lead_xv
|
||||
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, personality=log.LongitudinalPersonality.standard):
|
||||
t_follow = get_T_FOLLOW(personality)
|
||||
v_ego = self.x0[1]
|
||||
|
||||
if self.dynamic_follow.is_enabled():
|
||||
t_follow = self.dynamic_follow.get_follow_distance_multiplier(v_ego)
|
||||
#print(f"DEBUG: dynamic_follow enabled, t_follow={t_follow:.3f}, v_ego={v_ego:.2f}, v_cruise={v_cruise:.2f}")
|
||||
else:
|
||||
t_follow = get_T_FOLLOW(personality)
|
||||
#print(f"DEBUG: dynamic_follow disabled, using personality t_follow={t_follow:.3f}, personality={personality}")
|
||||
|
||||
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
|
||||
|
||||
# Get acceleration limits
|
||||
if self.accel_controller.is_enabled():
|
||||
min_accel = self.accel_controller.get_min_accel(v_ego)
|
||||
#print(f"DEBUG: accel_enabled=True, min_accel={min_accel:.3f}")
|
||||
else:
|
||||
min_accel = CRUISE_MIN_ACCEL
|
||||
#print(f"DEBUG: accel_enabled=False, using stock min_accel={min_accel}")
|
||||
|
||||
a_cruise_min = min_accel
|
||||
|
||||
lead_xv_0 = self.process_lead(radarstate.leadOne)
|
||||
lead_xv_1 = self.process_lead(radarstate.leadTwo)
|
||||
|
||||
@@ -371,7 +350,7 @@ class LongitudinalMpc:
|
||||
|
||||
# Fake an obstacle for cruise, this ensures smooth acceleration to set speed
|
||||
# when the leads are no factor.
|
||||
v_lower = v_ego + (T_IDXS * a_cruise_min * 1.05)
|
||||
v_lower = v_ego + (T_IDXS * CRUISE_MIN_ACCEL * 1.05)
|
||||
# TODO does this make sense when max_a is negative?
|
||||
v_upper = v_ego + (T_IDXS * CRUISE_MAX_ACCEL * 1.05)
|
||||
v_cruise_clipped = np.clip(v_cruise * np.ones(N+1),
|
||||
|
||||
@@ -124,13 +124,7 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
||||
prev_accel_constraint = not (reset_state or sm['carState'].standstill)
|
||||
|
||||
if mode == 'acc':
|
||||
if self.accel_controller.is_enabled():
|
||||
max_accel = self.accel_controller.get_max_accel(v_ego)
|
||||
#print(f"Vibe personality active - max accel: {max_accel:.3f}")
|
||||
accel_clip = [ACCEL_MIN, max_accel]
|
||||
else:
|
||||
accel_clip = [ACCEL_MIN, get_max_accel(v_ego)]
|
||||
|
||||
accel_clip = [ACCEL_MIN, get_max_accel(v_ego)]
|
||||
steer_angle_without_offset = sm['carState'].steeringAngleDeg - sm['liveParameters'].angleOffsetDeg
|
||||
accel_clip = limit_accel_in_turns(v_ego, steer_angle_without_offset, accel_clip, self.CP)
|
||||
else:
|
||||
@@ -155,10 +149,6 @@ class LongitudinalPlanner(LongitudinalPlannerSP):
|
||||
# Get new v_cruise and a_desired from Smart Cruise Control and Speed Limit Assist
|
||||
v_cruise, self.a_desired = LongitudinalPlannerSP.update_targets(self, sm, self.v_desired_filter.x, self.a_desired, v_cruise)
|
||||
|
||||
if sm.valid['mapdOut']:
|
||||
if sm['mapdOut'].suggestedSpeed > 0 and v_cruise > sm['mapdOut'].suggestedSpeed:
|
||||
v_cruise = sm['mapdOut'].suggestedSpeed
|
||||
|
||||
if force_slow_decel:
|
||||
v_cruise = 0.0
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@ def main():
|
||||
longitudinal_planner = LongitudinalPlanner(CP, CP_SP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'driverAssistance', 'longitudinalPlanSP'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState',
|
||||
'liveMapDataSP', 'carStateSP', 'mapdOut', gps_location_service],
|
||||
'liveMapDataSP', 'navigationd', 'carStateSP', gps_location_service],
|
||||
poll='carState')
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
#longitudinal_planner.sla.update_car_state(sm['carState'])
|
||||
longitudinal_planner.sla.update_car_state(sm['carState'])
|
||||
if sm.updated['modelV2']:
|
||||
longitudinal_planner.update(sm)
|
||||
longitudinal_planner.publish(sm, pm)
|
||||
|
||||
BIN
selfdrive/mapd
BIN
selfdrive/mapd
Binary file not shown.
@@ -51,8 +51,8 @@ def tg_compile(flags, model_name):
|
||||
for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']:
|
||||
flags = {
|
||||
'larch64': 'DEV=QCOM',
|
||||
'Darwin': f'DEV=CPU HOME={os.path.expanduser("~")} IMAGE=0', # tinygrad calls brew which needs a $HOME in the env
|
||||
}.get(arch, 'DEV=CPU CPU_LLVM=1 IMAGE=0')
|
||||
'Darwin': 'DEV=CPU IMAGE=0',
|
||||
}.get(arch, 'DEV=LLVM IMAGE=0')
|
||||
tg_compile(flags, model_name)
|
||||
|
||||
# Compile BIG model if USB GPU is available
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
from openpilot.system.hardware import TICI
|
||||
os.environ['DEV'] = 'QCOM' if TICI else 'CPU'
|
||||
os.environ['DEV'] = 'QCOM' if TICI else 'LLVM'
|
||||
from tinygrad.tensor import Tensor
|
||||
from tinygrad.dtype import dtypes
|
||||
import math
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
from openpilot.system.hardware import TICI
|
||||
os.environ['DEV'] = 'QCOM' if TICI else 'CPU'
|
||||
os.environ['DEV'] = 'QCOM' if TICI else 'LLVM'
|
||||
USBGPU = "USBGPU" in os.environ
|
||||
if USBGPU:
|
||||
os.environ['DEV'] = 'AMD'
|
||||
@@ -33,7 +33,7 @@ from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from
|
||||
|
||||
from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
||||
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.relc import RoadEdgeLaneChangeController
|
||||
|
||||
|
||||
PROCESS_NAME = "selfdrive.modeld.modeld"
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
@@ -298,7 +298,6 @@ def main(demo=False):
|
||||
prev_action = log.ModelDataV2.Action()
|
||||
|
||||
DH = DesireHelper()
|
||||
RELC = RoadEdgeLaneChangeController(params.get_bool("RoadEdgeLaneChangeEnabled"))
|
||||
|
||||
while True:
|
||||
# Keep receiving frames until we are at least 1 frame ahead of previous extra frame
|
||||
@@ -396,10 +395,7 @@ def main(demo=False):
|
||||
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
|
||||
r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
|
||||
lane_change_prob = l_lane_change_prob + r_lane_change_prob
|
||||
RELC.update(modelv2_send.modelV2.roadEdgeStds, modelv2_send.modelV2.laneLineProbs)
|
||||
mdv2sp_send.modelDataV2SP.leftLaneChangeEdgeBlock = RELC.left_edge_detected
|
||||
mdv2sp_send.modelDataV2SP.rightLaneChangeEdgeBlock = RELC.right_edge_detected
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, RELC.left_edge_detected, RELC.right_edge_detected)
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
|
||||
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
|
||||
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
|
||||
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
|
||||
|
||||
@@ -99,7 +99,7 @@ class SelfdriveD(CruiseHelper):
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback',
|
||||
'modelDataV2SP', 'longitudinalPlanSP', 'navigationd'] + \
|
||||
self.camera_packets + self.sensor_packets + self.gps_packets,
|
||||
self.camera_packets + self.sensor_packets + self.gps_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore,
|
||||
ignore_valid=ignore, frequency=int(1/DT_CTRL))
|
||||
|
||||
@@ -230,8 +230,8 @@ class SelfdriveD(CruiseHelper):
|
||||
|
||||
# Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0
|
||||
if (CS.gasPressed and not self.CS_prev.gasPressed and self.disengage_on_accelerator) or \
|
||||
(CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or \
|
||||
(CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)):
|
||||
(CS.brakePressed and (not self.CS_prev.brakePressed or not CS.standstill)) or \
|
||||
(CS.regenBraking and (not self.CS_prev.regenBraking or not CS.standstill)):
|
||||
self.events.add(EventName.pedalPressed)
|
||||
|
||||
# Create events for temperature, disk space, and memory
|
||||
@@ -292,22 +292,16 @@ class SelfdriveD(CruiseHelper):
|
||||
# Handle lane change
|
||||
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
|
||||
direction = self.sm['modelV2'].meta.laneChangeDirection
|
||||
mdv2sp = self.sm['modelDataV2SP']
|
||||
|
||||
if (CS.leftBlindspot and direction == LaneChangeDirection.left) or \
|
||||
(CS.rightBlindspot and direction == LaneChangeDirection.right):
|
||||
(CS.rightBlindspot and direction == LaneChangeDirection.right):
|
||||
self.events.add(EventName.laneChangeBlocked)
|
||||
|
||||
elif mdv2sp.leftLaneChangeEdgeBlock or mdv2sp.rightLaneChangeEdgeBlock:
|
||||
self.events_sp.add(custom.OnroadEventSP.EventName.laneChangeRoadEdge)
|
||||
|
||||
else:
|
||||
if direction == LaneChangeDirection.left:
|
||||
self.events.add(EventName.preLaneChangeLeft)
|
||||
else:
|
||||
self.events.add(EventName.preLaneChangeRight)
|
||||
elif self.sm['modelV2'].meta.laneChangeState in (LaneChangeState.laneChangeStarting,
|
||||
LaneChangeState.laneChangeFinishing):
|
||||
LaneChangeState.laneChangeFinishing):
|
||||
self.events.add(EventName.laneChange)
|
||||
|
||||
# Handle lane turn
|
||||
@@ -502,7 +496,7 @@ class SelfdriveD(CruiseHelper):
|
||||
|
||||
# All pandas not in silent mode must have controlsAllowed when openpilot is enabled
|
||||
if self.enabled and any(not ps.controlsAllowed for ps in self.sm['pandaStates']
|
||||
if ps.safetyModel not in IGNORED_SAFETY_MODES):
|
||||
if ps.safetyModel not in IGNORED_SAFETY_MODES):
|
||||
self.mismatch_counter += 1
|
||||
|
||||
return CS
|
||||
|
||||
@@ -71,6 +71,7 @@ class Plant:
|
||||
model = messaging.new_message('modelV2')
|
||||
car_state_sp = messaging.new_message('carStateSP')
|
||||
live_map_data_sp = messaging.new_message('liveMapDataSP')
|
||||
navigationd = messaging.new_message('navigationd')
|
||||
gps_data = messaging.new_message('gpsLocation')
|
||||
a_lead = (v_lead - self.v_lead_prev)/self.ts
|
||||
self.v_lead_prev = v_lead
|
||||
@@ -141,6 +142,7 @@ class Plant:
|
||||
'modelV2': model.modelV2,
|
||||
'carStateSP': car_state_sp.carStateSP,
|
||||
'liveMapDataSP': live_map_data_sp.liveMapDataSP,
|
||||
'navigationd': navigationd.navigationd,
|
||||
'gpsLocation': gps_data.gpsLocation}
|
||||
self.planner.update(sm)
|
||||
self.acceleration = self.planner.output_a_target
|
||||
|
||||
@@ -33,42 +33,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
"../assets/icons/experimental_white.svg",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ToyotaDriveMode",
|
||||
tr("Enable drive mode btn link"),
|
||||
tr("Links cars drive mode btn with accel personalities based on personality (i.e., relaxed, standard, sport)"),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ToyotaAutoHold",
|
||||
tr("Toyota: Auto Brake Hold FOR TSS2 HYBRID CARS"),
|
||||
tr("As you may auto brake hold currently supported by openpilot, this feature will allow sunnypilot to automatically hold the vehicle at a stop when the lead car is stopped. (TSS2 Hybird only)"),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ToyotaEnhancedBsm",
|
||||
tr("Toyota: Prius TSS2 BSM and some tssp"),
|
||||
tr("Add support for BSM."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ToyotaTSS2Long",
|
||||
tr("Toyota: custom tune"),
|
||||
tr("idk something gas and brake"),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ToyotaStockLongitudinal",
|
||||
tr("Toyota: Stock Toyota Longitudinal"),
|
||||
tr("This feature will allow sunnypilot to use the stock Toyota longitudinal control instead of the sunnypilot longitudinal control. "
|
||||
""),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"DisengageOnAccelerator",
|
||||
tr("Disengage on Accelerator Pedal"),
|
||||
@@ -121,15 +85,7 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
"your steering wheel distance button."),
|
||||
"../assets/icons/speed_limit.png",
|
||||
longi_button_texts);
|
||||
// accel controller
|
||||
std::vector<QString> accel_personality_texts{tr("Sport"), tr("Normal"), tr("Eco")};
|
||||
accel_personality_setting = new ButtonParamControlSP("AccelPersonality", tr("Acceleration Personality"),
|
||||
tr("Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. "
|
||||
"In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these "
|
||||
"acceleration personality within Onroad Settings on the driving screen."),
|
||||
"",
|
||||
accel_personality_texts);
|
||||
accel_personality_setting->showDescription();
|
||||
|
||||
// set up uiState update for personality setting
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &TogglesPanel::updateState);
|
||||
|
||||
@@ -157,7 +113,6 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) {
|
||||
// insert longitudinal personality after NDOG toggle
|
||||
if (param == "DisengageOnAccelerator") {
|
||||
addItem(long_personality_setting);
|
||||
addItem(accel_personality_setting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,13 +133,6 @@ void TogglesPanel::updateState(const UIState &s) {
|
||||
}
|
||||
uiState()->scene.personality = personality;
|
||||
}
|
||||
if (sm.updated("longitudinalPlanSP")) {
|
||||
auto accel_personality = sm["longitudinalPlanSP"].getLongitudinalPlanSP().getAccelPersonality();
|
||||
if (accel_personality != s.scene.accel_personality && s.scene.started && isVisible()) {
|
||||
accel_personality_setting->setCheckedButton(static_cast<int>(accel_personality));
|
||||
}
|
||||
uiState()->scene.accel_personality = accel_personality;
|
||||
}
|
||||
}
|
||||
|
||||
void TogglesPanel::expandToggleDescription(const QString ¶m) {
|
||||
@@ -231,12 +179,10 @@ void TogglesPanel::updateToggles() {
|
||||
experimental_mode_toggle->setEnabled(true);
|
||||
experimental_mode_toggle->setDescription(e2e_description);
|
||||
long_personality_setting->setEnabled(true);
|
||||
accel_personality_setting->setEnabled(true);
|
||||
} else {
|
||||
// no long for now
|
||||
experimental_mode_toggle->setEnabled(false);
|
||||
long_personality_setting->setEnabled(false);
|
||||
accel_personality_setting->setEnabled(true);
|
||||
params.remove("ExperimentalMode");
|
||||
|
||||
const QString unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.");
|
||||
|
||||
@@ -88,7 +88,6 @@ protected:
|
||||
Params params;
|
||||
std::map<std::string, ParamControl*> toggles;
|
||||
ButtonParamControl *long_personality_setting;
|
||||
ButtonParamControl *accel_personality_setting;
|
||||
|
||||
virtual void updateToggles();
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) {
|
||||
|
||||
update_model(model, lead_one);
|
||||
drawLaneLines(painter);
|
||||
drawPath(painter, model, surface_rect.height(), surface_rect.width());
|
||||
drawPath(painter, model, surface_rect.height());
|
||||
|
||||
if (longitudinal_control && sm.alive("radarState")) {
|
||||
update_leads(radar_state, model.getPosition());
|
||||
@@ -92,7 +92,7 @@ void ModelRenderer::drawLaneLines(QPainter &painter) {
|
||||
}
|
||||
}
|
||||
|
||||
void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height, int width) {
|
||||
void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height) {
|
||||
QLinearGradient bg(0, height, 0, 0);
|
||||
if (experimental_mode) {
|
||||
// The first half of track_vertices are the points for the right side of the path
|
||||
@@ -127,9 +127,6 @@ void ModelRenderer::drawPath(QPainter &painter, const cereal::ModelDataV2::Reade
|
||||
|
||||
painter.setBrush(bg);
|
||||
painter.drawPolygon(track_vertices);
|
||||
|
||||
//LongFuel(painter,height, width);
|
||||
//LateralFuel(painter, height, width);
|
||||
}
|
||||
|
||||
void ModelRenderer::updatePathGradient(QLinearGradient &bg) {
|
||||
@@ -176,195 +173,6 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float
|
||||
(1 - t) * start.alphaF() + t * end.alphaF());
|
||||
}
|
||||
|
||||
void ModelRenderer::drawGaugeBackground(QPainter &painter, qreal centerX, qreal centerY) {
|
||||
const qreal backgroundSize = GAUGE_SIZE * BACKGROUND_SIZE_MULTIPLIER;
|
||||
|
||||
// Draw circular background
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(BACKGROUND_COLOR);
|
||||
painter.drawEllipse(QPointF(centerX, centerY), backgroundSize / 2, backgroundSize / 2);
|
||||
|
||||
// Draw border
|
||||
QPen borderPen(BORDER_COLOR);
|
||||
borderPen.setWidth(BORDER_PEN_WIDTH);
|
||||
painter.setPen(borderPen);
|
||||
painter.drawEllipse(QPointF(centerX, centerY), backgroundSize / 2 + 1, backgroundSize / 2 + 1);
|
||||
|
||||
// Draw background semicircle
|
||||
QPen semicirclePen(GAUGE_BACKGROUND_COLOR);
|
||||
semicirclePen.setWidth(GAUGE_PEN_WIDTH);
|
||||
semicirclePen.setCapStyle(Qt::RoundCap);
|
||||
painter.setPen(semicirclePen);
|
||||
painter.drawArc(QRectF(centerX - GAUGE_SIZE / 2, centerY - GAUGE_SIZE / 2,
|
||||
GAUGE_SIZE, GAUGE_SIZE), 0, SEMICIRCLE_SPAN);
|
||||
}
|
||||
|
||||
QColor ModelRenderer::getIndicatorColor(float absoluteValue, float lowThreshold, float highThreshold) {
|
||||
if (absoluteValue < lowThreshold) {
|
||||
return LOW_INDICATOR_COLOR;
|
||||
} else if (absoluteValue < highThreshold) {
|
||||
return MODERATE_INDICATOR_COLOR;
|
||||
} else {
|
||||
return HIGH_INDICATOR_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
int ModelRenderer::calculateSpanAngle(float absoluteValue, float maxValue) {
|
||||
const int spanAngle = static_cast<int>(QUARTER_CIRCLE_SPAN * (absoluteValue / maxValue));
|
||||
return std::clamp(spanAngle, 0, QUARTER_CIRCLE_SPAN);
|
||||
}
|
||||
|
||||
void ModelRenderer::drawGaugeArc(QPainter &painter, qreal centerX, qreal centerY,
|
||||
float value, bool isPositive, const QString &label) {
|
||||
const float absoluteValue = std::abs(value);
|
||||
|
||||
if (absoluteValue <= MIN_THRESHOLD) {
|
||||
return; // Skip drawing if value is too small
|
||||
}
|
||||
|
||||
// Set up the arc rectangle
|
||||
const QRectF arcRect(centerX - GAUGE_SIZE / 2, centerY - GAUGE_SIZE / 2,
|
||||
GAUGE_SIZE, GAUGE_SIZE);
|
||||
|
||||
// Configure pen for the indicator arc
|
||||
QPen indicatorPen;
|
||||
indicatorPen.setWidth(GAUGE_PEN_WIDTH);
|
||||
indicatorPen.setCapStyle(Qt::RoundCap);
|
||||
painter.setPen(indicatorPen);
|
||||
|
||||
// Draw the arc based on direction
|
||||
const int spanAngle = calculateSpanAngle(absoluteValue, 1.0f); // Adjust max value as needed
|
||||
if (isPositive) {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, spanAngle);
|
||||
} else {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, -spanAngle);
|
||||
}
|
||||
|
||||
// Draw center label
|
||||
painter.setPen(Qt::white);
|
||||
QFont font = painter.font();
|
||||
font.setPixelSize(20);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
painter.drawText(QRectF(centerX - 50, centerY + 10, 100, 20), Qt::AlignCenter, label);
|
||||
}
|
||||
|
||||
void ModelRenderer::LongFuel(QPainter &painter, int height, int width) {
|
||||
const qreal rectWidth = static_cast<qreal>(width);
|
||||
const qreal rectHeight = static_cast<qreal>(height);
|
||||
|
||||
UIState *s = uiState();
|
||||
if (!s || !s->sm) {
|
||||
return; // Safety check
|
||||
}
|
||||
|
||||
// Get current acceleration
|
||||
const float currentAcceleration = (*s->sm)["carControl"].getCarControl().getActuators().getAccel();
|
||||
const float absoluteAcceleration = std::abs(currentAcceleration);
|
||||
|
||||
// Calculate gauge position
|
||||
const qreal centerX = rectWidth / 17;
|
||||
const qreal centerY = rectHeight / 2 + 120;
|
||||
|
||||
// Draw gauge background
|
||||
drawGaugeBackground(painter, centerX, centerY);
|
||||
|
||||
// Skip drawing arc if acceleration is too small
|
||||
if (absoluteAcceleration <= MIN_THRESHOLD) {
|
||||
drawGaugeArc(painter, centerX, centerY, 0.0f, true, "LONG");
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine indicator color based on acceleration magnitude
|
||||
const QColor indicatorColor = getIndicatorColor(absoluteAcceleration, 0.3f, 0.6f);
|
||||
|
||||
// Calculate span angle (scale for better visibility)
|
||||
const int spanAngle = static_cast<int>(QUARTER_CIRCLE_SPAN * absoluteAcceleration);
|
||||
const int clampedSpanAngle = std::clamp(spanAngle, 0, QUARTER_CIRCLE_SPAN);
|
||||
|
||||
// Draw the acceleration arc
|
||||
QPen indicatorPen(indicatorColor);
|
||||
indicatorPen.setWidth(GAUGE_PEN_WIDTH);
|
||||
indicatorPen.setCapStyle(Qt::RoundCap);
|
||||
painter.setPen(indicatorPen);
|
||||
|
||||
const QRectF arcRect(centerX - GAUGE_SIZE / 2, centerY - GAUGE_SIZE / 2,
|
||||
GAUGE_SIZE, GAUGE_SIZE);
|
||||
|
||||
// Draw arc based on acceleration direction
|
||||
if (currentAcceleration > 0) {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, -clampedSpanAngle); // Left side for positive
|
||||
} else {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, clampedSpanAngle); // Right side for negative
|
||||
}
|
||||
|
||||
// Draw center label
|
||||
painter.setPen(Qt::white);
|
||||
QFont font = painter.font();
|
||||
font.setPixelSize(20);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
painter.drawText(QRectF(centerX - 50, centerY + 10, 100, 20), Qt::AlignCenter, "LONG");
|
||||
}
|
||||
|
||||
void ModelRenderer::LateralFuel(QPainter &painter, int height, int width) {
|
||||
const qreal rectWidth = static_cast<qreal>(width);
|
||||
const qreal rectHeight = static_cast<qreal>(height);
|
||||
|
||||
UIState *s = uiState();
|
||||
if (!s || !s->sm) {
|
||||
return; // Safety check
|
||||
}
|
||||
|
||||
// Get current steering angle
|
||||
const float currentLateral = (*s->sm)["carState"].getCarState().getSteeringAngleDeg();
|
||||
const float absoluteLateral = std::abs(currentLateral);
|
||||
|
||||
// Calculate gauge position
|
||||
const qreal centerX = rectWidth / 17;
|
||||
const qreal centerY = rectHeight / 2 - 120;
|
||||
|
||||
// Draw gauge background
|
||||
drawGaugeBackground(painter, centerX, centerY);
|
||||
|
||||
// Skip drawing arc if lateral force is too small
|
||||
if (absoluteLateral <= 0.1f) {
|
||||
drawGaugeArc(painter, centerX, centerY, 0.0f, true, "LAT");
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine indicator color based on lateral force magnitude
|
||||
const QColor indicatorColor = getIndicatorColor(absoluteLateral, 5.0f, 15.0f);
|
||||
|
||||
// Calculate span angle (normalized to max expected steering angle)
|
||||
const float maxSteeringAngle = 15.0f; // Adjust based on your vehicle's characteristics
|
||||
const int spanAngle = static_cast<int>(QUARTER_CIRCLE_SPAN * (absoluteLateral / maxSteeringAngle));
|
||||
const int clampedSpanAngle = std::clamp(spanAngle, 0, QUARTER_CIRCLE_SPAN);
|
||||
|
||||
// Draw the lateral arc
|
||||
QPen indicatorPen(indicatorColor);
|
||||
indicatorPen.setWidth(GAUGE_PEN_WIDTH);
|
||||
indicatorPen.setCapStyle(Qt::RoundCap);
|
||||
painter.setPen(indicatorPen);
|
||||
|
||||
const QRectF arcRect(centerX - GAUGE_SIZE / 2, centerY - GAUGE_SIZE / 2,
|
||||
GAUGE_SIZE, GAUGE_SIZE);
|
||||
|
||||
// Draw arc based on steering direction
|
||||
if (currentLateral < 0) {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, -clampedSpanAngle); // Left turn
|
||||
} else {
|
||||
painter.drawArc(arcRect, STARTING_ANGLE, clampedSpanAngle); // Right turn
|
||||
}
|
||||
|
||||
// Draw center label
|
||||
painter.setPen(Qt::white);
|
||||
QFont font = painter.font();
|
||||
font.setPixelSize(20);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
painter.drawText(QRectF(centerX - 50, centerY + 10, 100, 20), Qt::AlignCenter, "LAT");
|
||||
}
|
||||
void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
|
||||
const QPointF &vd, const QRect &surface_rect) {
|
||||
const float speedBuff = 10.;
|
||||
|
||||
@@ -29,8 +29,6 @@ public:
|
||||
ModelRenderer() {}
|
||||
void setTransform(const Eigen::Matrix3f &transform) { car_space_transform = transform; }
|
||||
void draw(QPainter &painter, const QRect &surface_rect);
|
||||
void LongFuel(QPainter &p, int height, int width);
|
||||
void LateralFuel(QPainter &p, int height, int width);
|
||||
|
||||
protected:
|
||||
bool mapToScreen(float in_x, float in_y, float in_z, QPointF *out);
|
||||
@@ -40,16 +38,7 @@ protected:
|
||||
void update_leads(const cereal::RadarState::Reader &radar_state, const cereal::XYZTData::Reader &line);
|
||||
virtual void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead);
|
||||
void drawLaneLines(QPainter &painter);
|
||||
void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height, int width);
|
||||
|
||||
// Gauge helper methods
|
||||
void drawGaugeBackground(QPainter &painter, qreal centerX, qreal centerY);
|
||||
void drawGaugeArc(QPainter &painter, qreal centerX, qreal centerY,
|
||||
float value, bool isPositive, const QString &label);
|
||||
QColor getIndicatorColor(float absoluteValue, float lowThreshold, float highThreshold);
|
||||
int calculateSpanAngle(float absoluteValue, float maxValue);
|
||||
|
||||
|
||||
void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, int height);
|
||||
void updatePathGradient(QLinearGradient &bg);
|
||||
QColor blendColors(const QColor &start, const QColor &end, float t);
|
||||
|
||||
@@ -66,22 +55,4 @@ protected:
|
||||
QPointF lead_vertices[2] = {};
|
||||
Eigen::Matrix3f car_space_transform = Eigen::Matrix3f::Zero();
|
||||
QRectF clip_region;
|
||||
|
||||
// Gauge configuration constants
|
||||
static constexpr qreal GAUGE_SIZE = 140.0;
|
||||
static constexpr qreal BACKGROUND_SIZE_MULTIPLIER = 1.4;
|
||||
static constexpr qreal GAUGE_PEN_WIDTH = 30.0;
|
||||
static constexpr qreal BORDER_PEN_WIDTH = 2.0;
|
||||
static constexpr int SEMICIRCLE_SPAN = 180 * 16;
|
||||
static constexpr int QUARTER_CIRCLE_SPAN = 90 * 16;
|
||||
static constexpr int STARTING_ANGLE = 90 * 16;
|
||||
static constexpr qreal MIN_THRESHOLD = 0.01;
|
||||
|
||||
// Color constants - Note: QColor cannot be constexpr, use inline static const instead
|
||||
inline static const QColor BACKGROUND_COLOR = QColor(0, 0, 0, 80);
|
||||
inline static const QColor BORDER_COLOR = QColor(0, 0, 0, 100);
|
||||
inline static const QColor GAUGE_BACKGROUND_COLOR = QColor(50, 50, 50);
|
||||
inline static const QColor LOW_INDICATOR_COLOR = QColor(23, 241, 66, 200);
|
||||
inline static const QColor MODERATE_INDICATOR_COLOR = QColor(255, 166, 0, 200);
|
||||
inline static const QColor HIGH_INDICATOR_COLOR = QColor(245, 0, 0, 200);
|
||||
};
|
||||
|
||||
@@ -11,18 +11,17 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) {
|
||||
main_layout->setContentsMargins(56, 40, 56, 40);
|
||||
main_layout->setSpacing(42);
|
||||
|
||||
community_popup = new SunnylinkCommunityPopup(this);
|
||||
QLabel *title = new QLabel(tr("sunnypilot Community"));
|
||||
title->setStyleSheet("font-size: 56px; font-weight: 500;");
|
||||
QLabel *title = new QLabel(tr("<span style='font-family: \"Noto Color Emoji\";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span>"));
|
||||
title->setStyleSheet("font-size: 64px; font-weight: 500;");
|
||||
main_layout->addWidget(title);
|
||||
|
||||
QLabel *desc = new QLabel(tr("Need help or have ideas?<br><b>Join</b> our community now!"));
|
||||
QLabel *desc = new QLabel(tr("Maximize your training data uploads to improve openpilot's driving models."));
|
||||
desc->setStyleSheet("font-size: 40px; font-weight: 400;");
|
||||
desc->setWordWrap(true);
|
||||
main_layout->addWidget(desc);
|
||||
|
||||
QPushButton *settings_btn = new QPushButton(tr("Learn More"));
|
||||
connect(settings_btn, &QPushButton::clicked, [=]() { community_popup->exec(); });
|
||||
QPushButton *settings_btn = new QPushButton(tr("Open"));
|
||||
connect(settings_btn, &QPushButton::clicked, [=]() { emit openSettings(1, "FirehosePanel"); });
|
||||
settings_btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
font-size: 48px;
|
||||
|
||||
@@ -3,17 +3,12 @@
|
||||
#include <QFrame>
|
||||
#include <QWidget>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h"
|
||||
|
||||
class WiFiPromptWidget : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WiFiPromptWidget(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
SunnylinkCommunityPopup *community_popup;
|
||||
|
||||
signals:
|
||||
void openSettings(int index = 0, const QString ¶m = "");
|
||||
};
|
||||
|
||||
@@ -30,13 +30,11 @@ qt_src = [
|
||||
"sunnypilot/qt/offroad/settings/max_time_offroad.cc",
|
||||
"sunnypilot/qt/offroad/settings/brightness.cc",
|
||||
"sunnypilot/qt/offroad/settings/models_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/navigation_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/osm_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/settings.cc",
|
||||
"sunnypilot/qt/offroad/settings/software_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/sunnylink_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/sunnylink/sponsor_widget.cc",
|
||||
"sunnypilot/qt/offroad/settings/sunnylink/community_widget.cc",
|
||||
"sunnypilot/qt/offroad/settings/trips_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/vehicle_panel.cc",
|
||||
"sunnypilot/qt/offroad/settings/visuals_panel.cc",
|
||||
|
||||
@@ -33,12 +33,6 @@ LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) {
|
||||
tr("Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
},
|
||||
{
|
||||
"RoadEdgeLaneChangeEnabled",
|
||||
tr("Block Lane Change: Road Edge Detection"),
|
||||
tr("Enable this toggle to block lane change when road edge is detected on the stalk actuated side."),
|
||||
"../assets/offroad/icon_blank.png",
|
||||
}
|
||||
};
|
||||
|
||||
// Controls: Auto Lane Change Timer
|
||||
|
||||
@@ -75,22 +75,6 @@ LongitudinalPanel::LongitudinalPanel(QWidget *parent) : QWidget(parent) {
|
||||
|
||||
QObject::connect(uiState(), &UIState::offroadTransition, this, &LongitudinalPanel::refresh);
|
||||
|
||||
// Acceleration Personality
|
||||
AccelPersonalityControl = new ParamControlSP("AccelPersonalityEnabled",
|
||||
tr("Acceleration Personality"),
|
||||
tr("Controls acceleration behavior: Eco (efficient), Normal (balanced), Sport (responsive). "
|
||||
"Adjust how aggressively the vehicle accelerates while maintaining smooth operation."),
|
||||
"../assets/offroad/icon_shell.png");
|
||||
list->addItem(AccelPersonalityControl);
|
||||
|
||||
// Dynamic Personality
|
||||
DynamicPersonalityControl = new ParamControlSP("DynamicFollow",
|
||||
tr("Following Distance Personality"),
|
||||
tr("Controls following distance and braking behavior: Relaxed (longer distance, gentler braking), Standard (balanced), Aggressive (shorter distance, firmer braking). "
|
||||
"Fine-tune your comfort level in traffic situations."),
|
||||
"../assets/offroad/icon_shell.png");
|
||||
list->addItem(DynamicPersonalityControl);
|
||||
|
||||
speedLimitSettings = new PushButtonSP(tr("Speed Limit"), 750, this);
|
||||
connect(speedLimitSettings, &QPushButton::clicked, [&]() {
|
||||
cruisePanelScroller->setLastScrollPosition();
|
||||
@@ -180,10 +164,6 @@ void LongitudinalPanel::refresh(bool _offroad) {
|
||||
dynamicExperimentalControl->refresh();
|
||||
SmartCruiseControlVision->refresh();
|
||||
SmartCruiseControlMap->refresh();
|
||||
AccelPersonalityControl->setEnabled(true);
|
||||
DynamicPersonalityControl->setEnabled(true);
|
||||
AccelPersonalityControl->refresh();
|
||||
DynamicPersonalityControl->refresh();
|
||||
} else {
|
||||
has_longitudinal_control = false;
|
||||
is_pcm_cruise = false;
|
||||
|
||||
@@ -36,9 +36,6 @@ private:
|
||||
ParamControl *SmartCruiseControlMap;
|
||||
ParamControl *intelligentCruiseButtonManagement = nullptr;
|
||||
ParamControl *dynamicExperimentalControl = nullptr;
|
||||
|
||||
ParamControlSP *AccelPersonalityControl;
|
||||
ParamControlSP *DynamicPersonalityControl;
|
||||
SpeedLimitSettings *speedLimitScreen;
|
||||
PushButtonSP *speedLimitSettings;
|
||||
};
|
||||
|
||||
@@ -1,79 +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.
|
||||
*/
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/navigation_panel.h"
|
||||
|
||||
NavigationPanel::NavigationPanel(QWidget* parent) : QWidget(parent) {
|
||||
QVBoxLayout* main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(50, 25, 50, 25);
|
||||
|
||||
list = new ListWidget(this, false);
|
||||
scroller = new ScrollViewSP(list, this);
|
||||
main_layout->addWidget(scroller);
|
||||
|
||||
// Mapbox Token
|
||||
mapbox_token = new ButtonControl(tr("Mapbox Token"), tr("Edit"), tr("Enter your Mapbox API token"));
|
||||
QObject::connect(mapbox_token, &ButtonControl::clicked, [=]() {
|
||||
QString current = QString::fromStdString(params.get("MapboxToken"));
|
||||
QString token = InputDialog::getText(tr("Enter Mapbox Token"), this, "", false, -1, current);
|
||||
if (!token.isEmpty()) {
|
||||
params.put("MapboxToken", token.toStdString());
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
list->addItem(mapbox_token);
|
||||
|
||||
// Mapbox Route
|
||||
mapbox_route = new ButtonControl(tr("Mapbox Route"), tr("Edit"), tr("Enter Mapbox route data"));
|
||||
QObject::connect(mapbox_route, &ButtonControl::clicked, [=]() {
|
||||
QString current = QString::fromStdString(params.get("MapboxRoute"));
|
||||
QString route = InputDialog::getText(tr("Enter Mapbox Route"), this, "", false, -1, current);
|
||||
if (!route.isEmpty()) {
|
||||
params.put("MapboxRoute", route.toStdString());
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
list->addItem(mapbox_route);
|
||||
|
||||
// Allow Navigation
|
||||
allow_navigation = new ParamControlSP("AllowNavigation", tr("Allow Navigation"), tr("Enable navigation features and start navigationd"), "", this);
|
||||
QObject::connect(allow_navigation, &ParamControlSP::toggleFlipped, this, &NavigationPanel::updateNavigationVisibility);
|
||||
list->addItem(allow_navigation);
|
||||
|
||||
// Mapbox Recompute
|
||||
mapbox_recompute = new ParamControlSP("MapboxRecompute", tr("Mapbox Recompute"), tr("Enable automatic route recomputation"), "", this);
|
||||
list->addItem(mapbox_recompute);
|
||||
|
||||
// Nav Allowed
|
||||
nav_allowed = new ParamControlSP("NavDesiresAllowed", tr("Navigation Allowed"), tr("Allow navigation to automatically take turns"), "", this);
|
||||
list->addItem(nav_allowed);
|
||||
}
|
||||
|
||||
void NavigationPanel::updateNavigationVisibility(bool state) {
|
||||
mapbox_recompute->setVisible(state);
|
||||
nav_allowed->setVisible(state);
|
||||
}
|
||||
|
||||
void NavigationPanel::showEvent(QShowEvent *event) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void NavigationPanel::refresh() {
|
||||
allow_navigation->refresh();
|
||||
|
||||
bool nav_enabled = allow_navigation->isToggled();
|
||||
updateNavigationVisibility(nav_enabled);
|
||||
|
||||
QString token = QString::fromStdString(params.get("MapboxToken"));
|
||||
mapbox_token->setValue(token.isEmpty() ? tr("Not set") : token);
|
||||
|
||||
QString route = QString::fromStdString(params.get("MapboxRoute"));
|
||||
mapbox_route->setValue(route.isEmpty() ? tr("Not set") : route);
|
||||
|
||||
mapbox_recompute->refresh();
|
||||
nav_allowed->refresh();
|
||||
}
|
||||
@@ -1,38 +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/offroad/settings.h"
|
||||
#include "selfdrive/ui/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
|
||||
|
||||
class NavigationPanel : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NavigationPanel(QWidget* parent = nullptr);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void refresh();
|
||||
|
||||
public slots:
|
||||
void updateNavigationVisibility(bool state);
|
||||
|
||||
private:
|
||||
Params params;
|
||||
ListWidget* list;
|
||||
ScrollViewSP* scroller;
|
||||
ParamControlSP* allow_navigation;
|
||||
ButtonControl* mapbox_token;
|
||||
ButtonControl* mapbox_route;
|
||||
ParamControlSP* mapbox_recompute;
|
||||
ParamControlSP* nav_allowed;
|
||||
};
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/display_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/navigation_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/software_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink_panel.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/lateral_panel.h"
|
||||
@@ -86,7 +85,6 @@ SettingsWindowSP::SettingsWindowSP(QWidget *parent) : SettingsWindow(parent) {
|
||||
PanelInfo(" " + tr("Toggles"), toggles, "../../sunnypilot/selfdrive/assets/offroad/icon_toggle.png"),
|
||||
PanelInfo(" " + tr("Software"), new SoftwarePanelSP(this), "../../sunnypilot/selfdrive/assets/offroad/icon_software.png"),
|
||||
PanelInfo(" " + tr("Models"), new ModelsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_models.png"),
|
||||
PanelInfo(" " + tr("Navigation"), new NavigationPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_map.png"),
|
||||
PanelInfo(" " + tr("Steering"), new LateralPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_lateral.png"),
|
||||
PanelInfo(" " + tr("Cruise"), new LongitudinalPanel(this), "../assets/icons/speed_limit.png"),
|
||||
PanelInfo(" " + tr("Visuals"), new VisualsPanel(this), "../../sunnypilot/selfdrive/assets/offroad/icon_visuals.png"),
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025-, sunnypilot 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.
|
||||
*/
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/sunnylink/community_widget.h"
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/util.h"
|
||||
|
||||
using qrcodegen::QrCode;
|
||||
|
||||
// --- SunnylinkCommunityQRWidget ---
|
||||
|
||||
SunnylinkCommunityQRWidget::SunnylinkCommunityQRWidget(QWidget* parent)
|
||||
: QWidget(parent) {}
|
||||
|
||||
void SunnylinkCommunityQRWidget::showEvent(QShowEvent *event) {
|
||||
updateQrCode(SUNNYLINK_COMMUNITY_URL);
|
||||
update();
|
||||
}
|
||||
|
||||
void SunnylinkCommunityQRWidget::updateQrCode(const QString &text) {
|
||||
QrCode qr = QrCode::encodeText(text.toUtf8().data(), QrCode::Ecc::LOW);
|
||||
qint32 sz = qr.getSize();
|
||||
QImage im(sz, sz, QImage::Format_RGB32);
|
||||
|
||||
QRgb black = qRgb(0, 0, 0);
|
||||
QRgb white = qRgb(255, 255, 255);
|
||||
for (int y = 0; y < sz; y++) {
|
||||
for (int x = 0; x < sz; x++) {
|
||||
im.setPixel(x, y, qr.getModule(x, y) ? black : white);
|
||||
}
|
||||
}
|
||||
|
||||
int final_sz = ((width() / sz) - 1) * sz;
|
||||
img = QPixmap::fromImage(im.scaled(final_sz, final_sz, Qt::KeepAspectRatio), Qt::MonoOnly);
|
||||
}
|
||||
|
||||
void SunnylinkCommunityQRWidget::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), Qt::white);
|
||||
|
||||
if (!img.isNull()) {
|
||||
QSize s = (size() - img.size()) / 2;
|
||||
p.drawPixmap(s.width(), s.height(), img);
|
||||
}
|
||||
}
|
||||
|
||||
// --- SunnylinkCommunityPopup ---
|
||||
|
||||
QStringList SunnylinkCommunityPopup::getInstructions() {
|
||||
QStringList instructions;
|
||||
instructions << tr("Scan the QR code and join us!");
|
||||
return instructions;
|
||||
}
|
||||
|
||||
SunnylinkCommunityPopup::SunnylinkCommunityPopup(QWidget* parent)
|
||||
: DialogBase(parent) {
|
||||
auto *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
// Solarized Light base3 background
|
||||
setStyleSheet("SunnylinkCommunityPopup { background-color: #FDF6E3; }");
|
||||
|
||||
// Header spanning full width
|
||||
auto headerWidget = new QWidget(this);
|
||||
auto headerLayout = new QHBoxLayout(headerWidget);
|
||||
headerLayout->setContentsMargins(85, 50, 85, 30);
|
||||
headerLayout->setSpacing(30);
|
||||
|
||||
auto close = new QPushButton(QIcon(":/icons/close.svg"), "", this);
|
||||
close->setIconSize(QSize(80, 80));
|
||||
close->setStyleSheet("border: none;");
|
||||
connect(close, &QPushButton::clicked, this, &QDialog::reject);
|
||||
headerLayout->addWidget(close, 0, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
||||
const auto title = new QLabel(tr("Join the sunnypilot Community Forum"), this);
|
||||
// Solarized base02 for text
|
||||
title->setStyleSheet("font-size: 65px; color: #073642;");
|
||||
title->setWordWrap(false);
|
||||
title->setAlignment(Qt::AlignCenter);
|
||||
headerLayout->addWidget(title, 1);
|
||||
|
||||
// Spacer to balance the close button on the right
|
||||
auto spacer = new QWidget(this);
|
||||
spacer->setFixedSize(80, 80);
|
||||
headerLayout->addWidget(spacer, 0);
|
||||
|
||||
mainLayout->addWidget(headerWidget);
|
||||
|
||||
// Two-column content layout
|
||||
auto contentLayout = new QHBoxLayout();
|
||||
contentLayout->setContentsMargins(0, 0, 0, 0);
|
||||
contentLayout->setSpacing(0);
|
||||
mainLayout->addLayout(contentLayout, 66);
|
||||
|
||||
// Left side: description
|
||||
auto leftLayout = new QVBoxLayout();
|
||||
leftLayout->setContentsMargins(85, 40, 50, 70);
|
||||
leftLayout->setSpacing(35);
|
||||
contentLayout->addLayout(leftLayout, 40);
|
||||
|
||||
// Hype / intro paragraph
|
||||
const auto desc = new QLabel(tr(
|
||||
"We're excited to announce our <b>sunnypilot Community Forum</b><br><br>"
|
||||
"Over the years, Discord just hasn't scaled well for our growing community.<br>"
|
||||
"It's noisy, unsearchable, and great discussions disappear too easily.<br>"
|
||||
"Our new community forum aims to fix that by making it easier to <b>find answers, share ideas, track feedback, report bugs, help newcomers</b> and more!<br><br>"
|
||||
"<b>Here's what's waiting for you:</b><br>"
|
||||
"• Fully <b>indexable</b> and discoverable through search engines 🔎<br>"
|
||||
"• <b>AI-powered</b>🤖 topic and chat summaries, spam detection, and more<br>"
|
||||
"• A <b>trust-level system</b>✅ that rewards meaningful contributions<br>"
|
||||
"• Designed to work <b>on your own time</b>.🧘<br><br>"
|
||||
"Scan the QR code on the right and join the discussion!"
|
||||
), this);
|
||||
// Solarized base01 for body text
|
||||
desc->setStyleSheet("font-size: 40px; color: #586E75;");
|
||||
desc->setWordWrap(true);
|
||||
leftLayout->addWidget(desc);
|
||||
|
||||
leftLayout->addStretch();
|
||||
|
||||
// Right side: QR code and instructions
|
||||
auto rightLayout = new QVBoxLayout();
|
||||
rightLayout->setContentsMargins(50, 40, 85, 70);
|
||||
rightLayout->setSpacing(40);
|
||||
contentLayout->addLayout(rightLayout, 1);
|
||||
|
||||
// QR code (smaller, fixed size)
|
||||
auto *qr = new SunnylinkCommunityQRWidget(this);
|
||||
qr->setFixedSize(500, 500);
|
||||
rightLayout->addStretch();
|
||||
rightLayout->addWidget(qr, 0, Qt::AlignCenter);
|
||||
rightLayout->addStretch();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025-, sunnypilot 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 <QrCode.hpp>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
|
||||
#include "common/util.h"
|
||||
#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h"
|
||||
|
||||
const QString SUNNYLINK_COMMUNITY_URL = "https://community.sunnypilot.ai/sp-qr";
|
||||
|
||||
class SunnylinkCommunityQRWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SunnylinkCommunityQRWidget(QWidget* parent = nullptr);
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
|
||||
private:
|
||||
QPixmap img;
|
||||
void updateQrCode(const QString &text);
|
||||
void showEvent(QShowEvent *event) override;
|
||||
};
|
||||
|
||||
// Popup widget
|
||||
class SunnylinkCommunityPopup : public DialogBase {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SunnylinkCommunityPopup(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
static QStringList getInstructions();
|
||||
};
|
||||
@@ -79,11 +79,11 @@ QStringList SunnylinkSponsorPopup::getInstructions(bool sponsor_pair) {
|
||||
instructions << tr("Scan the QR code to login to your GitHub account")
|
||||
<< tr("Follow the prompts to complete the pairing process")
|
||||
<< tr("Re-enter the \"sunnylink\" panel to verify sponsorship status")
|
||||
<< tr("If sponsorship status was not updated, please contact a moderator on our forum at https://community.sunnypilot.ai");
|
||||
<< tr("If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot");
|
||||
} else {
|
||||
instructions << tr("Scan the QR code to visit sunnyhaibin's GitHub Sponsors page")
|
||||
<< tr("Choose your sponsorship tier and confirm your support")
|
||||
<< tr("Join our Community Forum at https://community.sunnypilot.ai and reach out to a moderator if you have issues");
|
||||
<< tr("Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status");
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ SunnylinkPanel::SunnylinkPanel(QWidget *parent) : QFrame(parent) {
|
||||
QString sunnylinkUploaderDesc = tr("Enable sunnylink uploader to allow sunnypilot to upload your driving data to sunnypilot servers. (only for highest tiers, and does NOT bring ANY benefit to you. We are just testing data volume.)");
|
||||
sunnylinkUploaderEnabledBtn = new ParamControlSP(
|
||||
"EnableSunnylinkUploader",
|
||||
tr("Enable sunnylink uploader (infrastructure test)"),
|
||||
tr("Enable sunnylink uploader (just for testing infrastructure)"),
|
||||
sunnylinkUploaderDesc,
|
||||
"", nullptr, true);
|
||||
list->addItem(sunnylinkUploaderEnabledBtn);
|
||||
|
||||
@@ -8,41 +8,7 @@
|
||||
#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/tesla_settings.h"
|
||||
|
||||
TeslaSettings::TeslaSettings(QWidget *parent) : BrandSettingsInterface(parent) {
|
||||
constexpr int coopSteeringMinKmh = 23; // minimum speed for cooperative steering (enforced by Tesla firmware)
|
||||
constexpr int oemSteeringMinKmh = 48; // minimum speed for OEM lane departure avoidance (enforced by Tesla firmware)
|
||||
bool is_metric = params.getBool("IsMetric");
|
||||
QString unit = is_metric ? "km/h" : "mph";
|
||||
int display_value_coop;
|
||||
int display_value_oem;
|
||||
if (is_metric) {
|
||||
display_value_coop = coopSteeringMinKmh;
|
||||
display_value_oem = oemSteeringMinKmh;
|
||||
} else {
|
||||
display_value_coop = static_cast<int>(std::round(coopSteeringMinKmh * KM_TO_MILE));
|
||||
display_value_oem = static_cast<int>(std::round(oemSteeringMinKmh * KM_TO_MILE));
|
||||
}
|
||||
const QString coop_desc = QString("<b>%1</b><br><br>"
|
||||
"%2<br>"
|
||||
"%3<br>")
|
||||
.arg(tr("Warning: May experience steering oscillations below %5 %6 during turns, recommend disabling this feature if you experience these."))
|
||||
.arg(tr("Allows the driver to provide limited steering input while openpilot is engaged."))
|
||||
.arg(tr("Only works above %4 %6."))
|
||||
.arg(display_value_coop)
|
||||
.arg(display_value_oem)
|
||||
.arg(unit);
|
||||
|
||||
coopSteeringToggle = new ParamControlSP(
|
||||
"TeslaCoopSteering",
|
||||
tr("Cooperative Steering (Beta)"),
|
||||
coop_desc,
|
||||
"",
|
||||
this
|
||||
);
|
||||
list->addItem(coopSteeringToggle);
|
||||
coopSteeringToggle->showDescription();
|
||||
coopSteeringToggle->setConfirmation(true, false);
|
||||
}
|
||||
|
||||
void TeslaSettings::updateSettings() {
|
||||
coopSteeringToggle->setEnabled(offroad);
|
||||
}
|
||||
|
||||
@@ -22,5 +22,5 @@ public:
|
||||
void updateSettings() override;
|
||||
|
||||
private:
|
||||
ParamControlSP *coopSteeringToggle = nullptr;
|
||||
bool offroad = false;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* See the LICENSE.md file in the root directory for more details.
|
||||
*/
|
||||
#include <QPainterPath>
|
||||
#include <cmath>
|
||||
|
||||
#include "selfdrive/ui/sunnypilot/qt/onroad/hud.h"
|
||||
|
||||
@@ -44,6 +43,8 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
const auto car_params = sm["carParams"].getCarParams();
|
||||
const auto car_params_sp = sm["carParamsSP"].getCarParamsSP();
|
||||
const auto lp_sp = sm["longitudinalPlanSP"].getLongitudinalPlanSP();
|
||||
const auto lmd = sm["liveMapDataSP"].getLiveMapDataSP();
|
||||
|
||||
if (sm.updated("carParams")) {
|
||||
steerControlType = car_params.getSteerControlType();
|
||||
}
|
||||
@@ -52,80 +53,37 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
pcmCruiseSpeed = car_params_sp.getPcmCruiseSpeed();
|
||||
}
|
||||
|
||||
if (sm.alive("mapdOut") && sm.rcv_frame("mapdOut") > 0) {
|
||||
const auto mapd = sm["mapdOut"].getMapdOut();
|
||||
|
||||
// Road name can come from wayName, wayRef, or roadName
|
||||
wayName = QString::fromStdString(mapd.getWayName());
|
||||
wayRef = QString::fromStdString(mapd.getWayRef());
|
||||
QString mapdRoadName = QString::fromStdString(mapd.getRoadName());
|
||||
|
||||
if (!mapdRoadName.isEmpty()) {
|
||||
roadNameStr = mapdRoadName;
|
||||
} else if (!wayRef.isEmpty() && !wayName.isEmpty()) {
|
||||
roadNameStr = wayRef + " - " + wayName;
|
||||
} else if (!wayName.isEmpty()) {
|
||||
roadNameStr = wayName;
|
||||
} else if (!wayRef.isEmpty()) {
|
||||
roadNameStr = wayRef;
|
||||
} else {
|
||||
roadNameStr = "";
|
||||
}
|
||||
|
||||
if (sm.updated("longitudinalPlanSP")) {
|
||||
speedLimit = lp_sp.getSpeedLimit().getResolver().getSpeedLimit() * speedConv;
|
||||
speedLimitLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLast() * speedConv;
|
||||
speedLimitOffset = lp_sp.getSpeedLimit().getResolver().getSpeedLimitOffset() * speedConv;
|
||||
speedLimitValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitValid();
|
||||
speedLimitLastValid = lp_sp.getSpeedLimit().getResolver().getSpeedLimitLastValid();
|
||||
speedLimitFinalLast = lp_sp.getSpeedLimit().getResolver().getSpeedLimitFinalLast() * speedConv;
|
||||
speedLimitSource = lp_sp.getSpeedLimit().getResolver().getSource();
|
||||
speedLimitAssistState = lp_sp.getSpeedLimit().getAssist().getState();
|
||||
speedLimitAssistActive = lp_sp.getSpeedLimit().getAssist().getActive();
|
||||
smartCruiseControlVisionEnabled = lp_sp.getSmartCruiseControl().getVision().getEnabled();
|
||||
smartCruiseControlVisionActive = lp_sp.getSmartCruiseControl().getVision().getActive();
|
||||
smartCruiseControlMapEnabled = lp_sp.getSmartCruiseControl().getMap().getEnabled();
|
||||
smartCruiseControlMapActive = lp_sp.getSmartCruiseControl().getMap().getActive();
|
||||
}
|
||||
greenLightAlert = lp_sp.getE2eAlerts().getGreenLightAlert();
|
||||
leadDepartAlert = lp_sp.getE2eAlerts().getLeadDepartAlert();
|
||||
|
||||
tileLoaded = mapd.getTileLoaded();
|
||||
|
||||
float mapdSpeedLimitRaw = mapd.getSpeedLimit();
|
||||
float mapdOffsetRaw = mapd.getSpeedLimitOffset();
|
||||
|
||||
|
||||
mapdSpeedLimit = mapdSpeedLimitRaw * speedConv;
|
||||
speedLimit = mapdSpeedLimit;
|
||||
speedLimitLast = mapdSpeedLimit;
|
||||
speedLimitOffset = mapdOffsetRaw * speedConv;
|
||||
speedLimitValid = tileLoaded && mapdSpeedLimitRaw > 0;
|
||||
speedLimitLastValid = speedLimitValid;
|
||||
speedLimitFinalLast = mapdSpeedLimit + speedLimitOffset;
|
||||
|
||||
if (tileLoaded) {
|
||||
speedLimitSource = 1; // MAP
|
||||
} else {
|
||||
speedLimitSource = 0; // NONE
|
||||
}
|
||||
|
||||
float nextSpeedLimitRaw = mapd.getNextSpeedLimit();
|
||||
speedLimitAheadValid = nextSpeedLimitRaw > 0 && tileLoaded;
|
||||
speedLimitAhead = nextSpeedLimitRaw * speedConv;
|
||||
speedLimitAheadDistance = mapd.getNextSpeedLimitDistance();
|
||||
|
||||
if (sm.updated("liveMapDataSP")) {
|
||||
roadNameStr = QString::fromStdString(lmd.getRoadName());
|
||||
speedLimitAheadValid = lmd.getSpeedLimitAheadValid();
|
||||
speedLimitAhead = lmd.getSpeedLimitAhead() * speedConv;
|
||||
speedLimitAheadDistance = lmd.getSpeedLimitAheadDistance();
|
||||
if (speedLimitAheadDistance < speedLimitAheadDistancePrev && speedLimitAheadValidFrame < SPEED_LIMIT_AHEAD_VALID_FRAME_THRESHOLD) {
|
||||
speedLimitAheadValidFrame++;
|
||||
} else if (speedLimitAheadDistance > speedLimitAheadDistancePrev && speedLimitAheadValidFrame > 0) {
|
||||
speedLimitAheadValidFrame--;
|
||||
}
|
||||
|
||||
// SCC data from mapd
|
||||
suggestedSpeed = mapd.getSuggestedSpeed() * speedConv;
|
||||
visionCurveSpeed = mapd.getVisionCurveSpeed() * speedConv;
|
||||
curveSpeed = mapd.getCurveSpeed() * speedConv;
|
||||
|
||||
smartCruiseControlVisionEnabled = visionCurveSpeed > 0;
|
||||
smartCruiseControlVisionActive = visionCurveSpeed > 0 && visionCurveSpeed < speedLimit;
|
||||
|
||||
smartCruiseControlMapEnabled = curveSpeed > 0;
|
||||
smartCruiseControlMapActive = curveSpeed > 0 && curveSpeed < speedLimit;
|
||||
|
||||
advisorySpeed = mapd.getAdvisorySpeed() * speedConv;
|
||||
nextAdvisorySpeed = mapd.getNextAdvisorySpeed() * speedConv;
|
||||
nextAdvisorySpeedDistance = mapd.getNextAdvisorySpeedDistance();
|
||||
}
|
||||
speedLimitAheadDistancePrev = speedLimitAheadDistance;
|
||||
|
||||
speedLimitAssistState = 0;
|
||||
speedLimitAssistActive = false;
|
||||
|
||||
static int reverse_delay = 0;
|
||||
bool reverse_allowed = false;
|
||||
if (car_state.getGearShifter() != cereal::CarState::GearShifter::REVERSE) {
|
||||
@@ -149,7 +107,7 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
}
|
||||
|
||||
if (sm.updated(gps_source)) {
|
||||
gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0;
|
||||
gpsAccuracy = is_gps_location_external ? gpsLocation.getHorizontalAccuracy() : 1.0; // External reports accuracy, internal does not.
|
||||
altitude = gpsLocation.getAltitude();
|
||||
bearingAccuracyDeg = gpsLocation.getBearingAccuracyDeg();
|
||||
bearingDeg = gpsLocation.getBearingDeg();
|
||||
@@ -196,63 +154,6 @@ void HudRendererSP::updateState(const UIState &s) {
|
||||
|
||||
allow_e2e_alerts = sm["selfdriveState"].getSelfdriveState().getAlertSize() == cereal::SelfdriveState::AlertSize::NONE &&
|
||||
sm.rcv_frame("driverStateV2") > s.scene.started_frame && !reversing;
|
||||
|
||||
// Navigationd
|
||||
if (sm.updated("navigationd")) {
|
||||
auto nav = sm["navigationd"].getNavigationd();
|
||||
navigationValid = nav.getValid();
|
||||
if (navigationValid && nav.getAllManeuvers().size() > 0) {
|
||||
int currManeuverIdx = nav.getAllManeuvers().size() > 1 ? 1 : 0;
|
||||
auto maneuver = nav.getAllManeuvers()[currManeuverIdx];
|
||||
navigationModifier = QString::fromStdString(maneuver.getModifier());
|
||||
navigationManeuverType = QString::fromStdString(maneuver.getType());
|
||||
|
||||
float dist = maneuver.getDistance();
|
||||
if (is_metric) {
|
||||
if (dist < 1000) {
|
||||
if (dist < 500) {
|
||||
navigationDistance = QString::number(std::round(dist / 25.0) * 25) + " m";
|
||||
}
|
||||
else {
|
||||
navigationDistance = QString::number(std::round(dist / 50.0) * 50) + " m";
|
||||
}
|
||||
} else {
|
||||
navigationDistance = QString::number(dist / 1000, 'f', 1) + " km";
|
||||
}
|
||||
} else {
|
||||
float dist_ft = dist * 3.28084f;
|
||||
if (dist_ft < 1000) {
|
||||
if (dist_ft <= 100){
|
||||
navigationDistance = QString::number((std::round(dist_ft / 10.0) * 10)) + " ft";
|
||||
}
|
||||
else {
|
||||
navigationDistance = QString::number((std::round(dist_ft / 50.0) * 50)) + " ft";
|
||||
}
|
||||
} else {
|
||||
navigationDistance = QString::number(dist_ft / 5280, 'f', 1) + " mi";
|
||||
}
|
||||
}
|
||||
|
||||
QString instruction = QString::fromStdString(maneuver.getInstruction());
|
||||
QStringList parts = instruction.split(" onto ");
|
||||
if (parts.size() > 1) {
|
||||
navigationStreet = parts[1].trimmed();
|
||||
} else {
|
||||
navigationStreet = instruction;
|
||||
}
|
||||
navigationStreet = navigationStreet.replace(".", "");
|
||||
|
||||
// Get next maneuver if available
|
||||
if (nav.getAllManeuvers().size() > 2) {
|
||||
auto nextManeuver = nav.getAllManeuvers()[2];
|
||||
navigationNextModifier = QString::fromStdString(nextManeuver.getModifier());
|
||||
navigationNextManeuverType = QString::fromStdString(nextManeuver.getType());
|
||||
navigationHasNext = true;
|
||||
} else {
|
||||
navigationHasNext = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
@@ -323,7 +224,7 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
const int sign_height = 204;
|
||||
QRect sign_rect(sign_x, sign_y, sign_width, sign_height);
|
||||
|
||||
if (speedLimitAssistState == 1) {
|
||||
if (speedLimitAssistState == cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) {
|
||||
speedLimitAssistFrame++;
|
||||
showSpeedLimit = speed_limit_assist_pre_active_pulse;
|
||||
drawSpeedLimitPreActiveArrow(p, sign_rect);
|
||||
@@ -336,7 +237,7 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
drawSpeedLimitSigns(p, sign_rect);
|
||||
|
||||
// do not show during SLA's preActive state
|
||||
if (speedLimitAssistState != 1) {
|
||||
if (speedLimitAssistState != cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) {
|
||||
drawUpcomingSpeedLimit(p);
|
||||
}
|
||||
}
|
||||
@@ -386,8 +287,6 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) {
|
||||
}
|
||||
}
|
||||
|
||||
drawNavigationHUD(p, surface_rect);
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
@@ -407,14 +306,9 @@ bool HudRendererSP::pulseElement(int frame) {
|
||||
}
|
||||
|
||||
void HudRendererSP::drawSmartCruiseControlOnroadIcon(QPainter &p, const QRect &surface_rect, int x_offset, int y_offset, std::string name) {
|
||||
int base_x = surface_rect.center().x();
|
||||
int x = surface_rect.center().x();
|
||||
int y = surface_rect.height() / 4;
|
||||
|
||||
if (navigationValid) {
|
||||
base_x = 618;
|
||||
y = 420;
|
||||
}
|
||||
|
||||
QString text = QString::fromStdString(name);
|
||||
QFont font = InterFont(36, QFont::Bold);
|
||||
p.setFont(font);
|
||||
@@ -425,7 +319,7 @@ void HudRendererSP::drawSmartCruiseControlOnroadIcon(QPainter &p, const QRect &s
|
||||
int box_width = 160;
|
||||
int box_height = fm.height() + padding_v * 2;
|
||||
|
||||
QRectF bg_rect(base_x - (box_width / 2) + x_offset,
|
||||
QRectF bg_rect(x - (box_width / 2) + x_offset,
|
||||
y - (box_height / 2) + y_offset,
|
||||
box_width, box_height);
|
||||
|
||||
@@ -676,7 +570,7 @@ void HudRendererSP::drawSpeedLimitSigns(QPainter &p, QRect &sign_rect) {
|
||||
|
||||
void HudRendererSP::drawUpcomingSpeedLimit(QPainter &p) {
|
||||
bool speed_limit_ahead = speedLimitAheadValid && speedLimitAhead > 0 && speedLimitAhead != speedLimit && speedLimitAheadValidFrame > 0 &&
|
||||
tileLoaded;
|
||||
speedLimitSource == cereal::LongitudinalPlanSP::SpeedLimit::Source::MAP;
|
||||
if (!speed_limit_ahead) {
|
||||
return;
|
||||
}
|
||||
@@ -790,16 +684,15 @@ void HudRendererSP::drawSpeedLimitPreActiveArrow(QPainter &p, QRect &sign_rect)
|
||||
}
|
||||
|
||||
void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
// ICBM counter logic
|
||||
if (!pcmCruiseSpeed && carControlEnabled) {
|
||||
if (std::nearbyint(set_speed) != std::nearbyint(speedCluster)) {
|
||||
icbm_active_counter = 3 * UI_FREQ;
|
||||
} else if (icbm_active_counter > 0) {
|
||||
icbm_active_counter--;
|
||||
}
|
||||
} else {
|
||||
icbm_active_counter = 0;
|
||||
}
|
||||
// Draw outer box + border to contain set speed
|
||||
const QSize default_size = {172, 204};
|
||||
QSize set_speed_size = is_metric ? QSize(200, 204) : default_size;
|
||||
QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size);
|
||||
|
||||
// Draw set speed box
|
||||
p.setPen(QPen(QColor(255, 255, 255, 75), 6));
|
||||
p.setBrush(QColor(0, 0, 0, 166));
|
||||
p.drawRoundedRect(set_speed_rect, 32, 32);
|
||||
|
||||
// Colors based on status
|
||||
QColor max_color = QColor(0xa6, 0xa6, 0xa6, 0xff);
|
||||
@@ -820,62 +713,29 @@ void HudRendererSP::drawSetSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
}
|
||||
}
|
||||
|
||||
QString max_str = (icbm_active_counter != 0) ? QString::number(std::nearbyint(speedCluster)) : tr("MAX");
|
||||
QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–";
|
||||
|
||||
if (!navigationValid) {
|
||||
// Original positions when navigation is not valid
|
||||
const QSize default_size = {172, 204};
|
||||
QSize set_speed_size = is_metric ? QSize(200, 204) : default_size;
|
||||
QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size);
|
||||
|
||||
// Draw set speed box
|
||||
p.setPen(QPen(QColor(255, 255, 255, 75), 6));
|
||||
p.setBrush(QColor(0, 0, 0, 166));
|
||||
p.drawRoundedRect(set_speed_rect, 32, 32);
|
||||
|
||||
// Draw "MAX" or carState.cruiseState.speedCluster (when ICBM is active) text
|
||||
int max_str_size = (icbm_active_counter != 0) ? 60 : 40;
|
||||
int max_str_y = (icbm_active_counter != 0) ? 15 : 27;
|
||||
|
||||
p.setFont(InterFont(max_str_size, QFont::DemiBold));
|
||||
p.setPen(max_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, max_str_y, 0, 0), Qt::AlignTop | Qt::AlignHCenter, max_str);
|
||||
|
||||
// Draw set speed
|
||||
p.setFont(InterFont(90, QFont::Bold));
|
||||
p.setPen(set_speed_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr);
|
||||
// Draw "MAX" or carState.cruiseState.speedCluster (when ICBM is active) text
|
||||
if (!pcmCruiseSpeed && carControlEnabled) {
|
||||
if (std::nearbyint(set_speed) != std::nearbyint(speedCluster)) {
|
||||
icbm_active_counter = 3 * UI_FREQ;
|
||||
} else if (icbm_active_counter > 0) {
|
||||
icbm_active_counter--;
|
||||
}
|
||||
} else {
|
||||
// Modified positions when navigation is valid
|
||||
const int container_width = 200;
|
||||
const int container_height = 320;
|
||||
const int container_x = 40;
|
||||
const int container_y = 45;
|
||||
|
||||
QRect speed_container(container_x, container_y, container_width, container_height);
|
||||
|
||||
// Draw outer rounded rectangle container
|
||||
p.setPen(QPen(QColor(255, 255, 255, 75), 6));
|
||||
p.setBrush(QColor(0, 0, 0, 166));
|
||||
p.drawRoundedRect(speed_container, 24, 24);
|
||||
|
||||
int divider_y = container_y + 190;
|
||||
p.setPen(QPen(QColor(255, 255, 255, 50), 2));
|
||||
p.drawLine(container_x + 20, divider_y, container_x + container_width - 20, divider_y);
|
||||
|
||||
// max label
|
||||
QRect max_label_rect(container_x, container_y + 200, container_width, 35);
|
||||
p.setFont(InterFont(32, QFont::Normal));
|
||||
p.setPen(max_color);
|
||||
p.drawText(max_label_rect, Qt::AlignCenter, max_str);
|
||||
|
||||
// Set speed value
|
||||
QRect set_speed_rect(container_x, container_y + 240, container_width, 70);
|
||||
p.setFont(InterFont(68, QFont::Bold));
|
||||
p.setPen(set_speed_color);
|
||||
p.drawText(set_speed_rect, Qt::AlignCenter, setSpeedStr);
|
||||
icbm_active_counter = 0;
|
||||
}
|
||||
int max_str_size = (icbm_active_counter != 0) ? 60 : 40;
|
||||
int max_str_y = (icbm_active_counter != 0) ? 15 : 27;
|
||||
QString max_str = (icbm_active_counter != 0) ? QString::number(std::nearbyint(speedCluster)) : tr("MAX");
|
||||
|
||||
p.setFont(InterFont(max_str_size, QFont::DemiBold));
|
||||
p.setPen(max_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, max_str_y, 0, 0), Qt::AlignTop | Qt::AlignHCenter, max_str);
|
||||
|
||||
// Draw set speed
|
||||
QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–";
|
||||
p.setFont(InterFont(90, QFont::Bold));
|
||||
p.setPen(set_speed_color);
|
||||
p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text) {
|
||||
@@ -934,40 +794,12 @@ void HudRendererSP::drawE2eAlert(QPainter &p, const QRect &surface_rect, const Q
|
||||
|
||||
void HudRendererSP::drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect) {
|
||||
QString speedStr = QString::number(std::nearbyint(speed));
|
||||
QString unit = is_metric ? tr("km/h") : tr("mph");
|
||||
|
||||
int speed_x = surface_rect.center().x();
|
||||
int speed_y = 210;
|
||||
int unit_y = 290;
|
||||
QFont speed_font = InterFont(176, QFont::Bold);
|
||||
QFont unit_font = InterFont(66);
|
||||
p.setFont(InterFont(176, QFont::Bold));
|
||||
HudRenderer::drawText(p, surface_rect.center().x(), 210, speedStr);
|
||||
|
||||
if (navigationValid) {
|
||||
speed_y = 75;
|
||||
unit_y = 175;
|
||||
speed_font = InterFont(100, QFont::Bold);
|
||||
unit_font = InterFont(35, QFont::Normal);
|
||||
}
|
||||
|
||||
// Draw speed
|
||||
p.setFont(speed_font);
|
||||
if (!navigationValid) {
|
||||
HudRenderer::drawText(p, speed_x, speed_y, speedStr);
|
||||
} else {
|
||||
QRect current_speed_rect(40, speed_y, 200, 100);
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(current_speed_rect, Qt::AlignCenter, speedStr);
|
||||
}
|
||||
|
||||
// Draw unit
|
||||
p.setFont(unit_font);
|
||||
if (!navigationValid) {
|
||||
HudRenderer::drawText(p, speed_x, unit_y, unit, 200);
|
||||
} else {
|
||||
QRect unit_rect(40, unit_y, 200, 40);
|
||||
p.setPen(QColor(180, 180, 180, 255));
|
||||
p.drawText(unit_rect, Qt::AlignCenter, unit);
|
||||
}
|
||||
p.setFont(InterFont(66));
|
||||
HudRenderer::drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200);
|
||||
}
|
||||
|
||||
void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) {
|
||||
@@ -995,7 +827,7 @@ void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) {
|
||||
const int circleRadius = 60;
|
||||
const int arrowLength = 60;
|
||||
const int x_gap = 160;
|
||||
const int y_offset = navigationValid ? 352 : 300;
|
||||
const int y_offset = 272;
|
||||
|
||||
const int centerX = surface_rect.center().x();
|
||||
|
||||
@@ -1053,181 +885,3 @@ void HudRendererSP::drawBlinker(QPainter &p, const QRect &surface_rect) {
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
QString HudRendererSP::getNavigationIconName(const QString &type, const QString &mod) {
|
||||
static QMap<QString, QString> icon_map;
|
||||
if (icon_map.isEmpty()) {
|
||||
icon_map["turn|uturn"] = "direction_uturn.png";
|
||||
icon_map["turn|sharp right"] = "direction_turn_sharp_right.png";
|
||||
icon_map["turn|right"] = "direction_turn_right.png";
|
||||
icon_map["turn|slight right"] = "direction_turn_slight_right.png";
|
||||
icon_map["turn|straight"] = "direction_turn_straight.png";
|
||||
icon_map["turn|slight left"] = "direction_turn_slight_left.png";
|
||||
icon_map["turn|left"] = "direction_turn_left.png";
|
||||
icon_map["turn|sharp left"] = "direction_turn_sharp_left.png";
|
||||
|
||||
icon_map["arrive|right"] = "direction_arrive_right.png";
|
||||
icon_map["arrive|straight"] = "direction_arrive_straight.png";
|
||||
icon_map["arrive|left"] = "direction_arrive_left.png";
|
||||
icon_map["arrive|"] = "direction_arrive.png";
|
||||
|
||||
icon_map["merge|slight right"] = "direction_merge_slight_right.png";
|
||||
icon_map["merge|right"] = "direction_merge_right.png";
|
||||
icon_map["merge|straight"] = "direction_merge_straight.png";
|
||||
icon_map["merge|slight left"] = "direction_merge_slight_left.png";
|
||||
icon_map["merge|left"] = "direction_merge_left.png";
|
||||
|
||||
icon_map["on ramp|sharp right"] = "direction_on_ramp_sharp_right.png";
|
||||
icon_map["on ramp|right"] = "direction_on_ramp_right.png";
|
||||
icon_map["on ramp|slight right"] = "direction_on_ramp_slight_right.png";
|
||||
icon_map["on ramp|straight"] = "direction_on_ramp_straight.png";
|
||||
icon_map["on ramp|slight left"] = "direction_on_ramp_slight_left.png";
|
||||
icon_map["on ramp|left"] = "direction_on_ramp_left.png";
|
||||
icon_map["on ramp|sharp left"] = "direction_on_ramp_sharp_left.png";
|
||||
|
||||
icon_map["off ramp|slight right"] = "direction_off_ramp_slight_right.png";
|
||||
icon_map["off ramp|right"] = "direction_off_ramp_right.png";
|
||||
icon_map["off ramp|slight left"] = "direction_off_ramp_slight_left.png";
|
||||
icon_map["off ramp|left"] = "direction_off_ramp_left.png";
|
||||
|
||||
icon_map["roundabout|sharp right"] = "direction_roundabout_sharp_right.png";
|
||||
icon_map["roundabout|right"] = "direction_roundabout_right.png";
|
||||
icon_map["roundabout|slight right"] = "direction_roundabout_slight_right.png";
|
||||
icon_map["roundabout|straight"] = "direction_roundabout_straight.png";
|
||||
icon_map["roundabout|slight left"] = "direction_roundabout_slight_left.png";
|
||||
icon_map["roundabout|left"] = "direction_roundabout_left.png";
|
||||
icon_map["roundabout|sharp left"] = "direction_roundabout_sharp_left.png";
|
||||
icon_map["roundabout|"] = "direction_roundabout.png";
|
||||
}
|
||||
|
||||
QString normalized_type = type;
|
||||
if (normalized_type == "rotary") {
|
||||
normalized_type = "roundabout";
|
||||
} else if (normalized_type == "new name") {
|
||||
normalized_type = "turn";
|
||||
} else if (normalized_type == "continue") {
|
||||
normalized_type = "turn";
|
||||
}
|
||||
|
||||
QString icon_name;
|
||||
QStringList keys = {normalized_type + "|" + mod, normalized_type + "|", "turn|" + mod};
|
||||
for (const QString &key : keys) {
|
||||
icon_name = icon_map.value(key);
|
||||
if (!icon_name.isEmpty()) break;
|
||||
}
|
||||
if (icon_name.isEmpty()) {
|
||||
icon_name = "direction_turn_straight.png";
|
||||
}
|
||||
return icon_name;
|
||||
}
|
||||
|
||||
void HudRendererSP::drawNavigationHUD(QPainter &p, const QRect &surface_rect) {
|
||||
if (!navigationValid) return;
|
||||
p.save();
|
||||
|
||||
const int container_width = 1080;
|
||||
const int container_height = 225;
|
||||
const int container_x = (surface_rect.width() - container_width) / 2;
|
||||
const int container_y = 62;
|
||||
const int border_radius = 42;
|
||||
|
||||
QRect container_rect(container_x, container_y, container_width, container_height);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(QColor(0, 0, 0, 180));
|
||||
p.drawRoundedRect(container_rect, border_radius, border_radius);
|
||||
|
||||
// Navigation icon
|
||||
const int icon_size = 150;
|
||||
const int icon_padding = 30;
|
||||
const int icon_x = container_x + icon_padding;
|
||||
const int icon_y = container_y;
|
||||
|
||||
QString icon_name = getNavigationIconName(navigationManeuverType, navigationModifier);
|
||||
QPixmap nav_icon = loadPixmap("../../sunnypilot/selfdrive/assets/navigation/" + icon_name, {icon_size, icon_size});
|
||||
|
||||
if (!nav_icon.isNull()) {
|
||||
p.drawPixmap(icon_x, icon_y, nav_icon);
|
||||
}
|
||||
|
||||
// Distance
|
||||
p.setFont(InterFont(48, QFont::Bold));
|
||||
p.setPen(Qt::white);
|
||||
QRect distance_rect(icon_x, icon_y + icon_size, icon_size, 38);
|
||||
p.drawText(distance_rect, Qt::AlignCenter, navigationDistance);
|
||||
|
||||
const int then_section_width = 180;
|
||||
const int text_x = icon_x + icon_size + 53;
|
||||
const int text_area_width = container_width - (text_x - container_x) - icon_padding - then_section_width;
|
||||
|
||||
// Street name
|
||||
p.setFont(InterFont(75, QFont::Bold));
|
||||
p.setPen(Qt::white);
|
||||
QFontMetrics fm(p.font());
|
||||
|
||||
QString street_line1, street_line2;
|
||||
QStringList words = navigationStreet.split(' ');
|
||||
QString currentLine;
|
||||
|
||||
for (int i = 0; i < words.size(); ++i) {
|
||||
QString testLine = currentLine.isEmpty() ? words[i] : currentLine + " " + words[i];
|
||||
if (fm.horizontalAdvance(testLine) <= text_area_width) {
|
||||
currentLine = testLine;
|
||||
} else {
|
||||
if (street_line1.isEmpty()) {
|
||||
street_line1 = currentLine;
|
||||
currentLine = words[i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (street_line1.isEmpty()) {
|
||||
street_line1 = currentLine;
|
||||
} else if (!currentLine.isEmpty()) {
|
||||
street_line2 = currentLine;
|
||||
if (words.size() > words.indexOf(currentLine.split(' ').last()) + 1) {
|
||||
street_line2 = fm.elidedText(street_line2, Qt::ElideRight, text_area_width);
|
||||
}
|
||||
}
|
||||
|
||||
if (street_line2.isEmpty()) {
|
||||
QRect street_rect(text_x, container_y + (container_height - fm.height()) / 2, text_area_width, fm.height());
|
||||
p.drawText(street_rect, Qt::AlignLeft | Qt::AlignVCenter, street_line1);
|
||||
} else {
|
||||
QRect street_rect1(text_x, container_y + 23, text_area_width, fm.height());
|
||||
p.drawText(street_rect1, Qt::AlignLeft | Qt::AlignVCenter, street_line1);
|
||||
|
||||
QRect street_rect2(text_x, container_y + 23 + fm.height(), text_area_width, fm.height());
|
||||
p.drawText(street_rect2, Qt::AlignLeft | Qt::AlignVCenter, street_line2);
|
||||
}
|
||||
|
||||
// Next Maneuver
|
||||
if (navigationHasNext) {
|
||||
const int divider_x = container_x + container_width - then_section_width - 8;
|
||||
p.setPen(QPen(QColor(255, 255, 255, 50), 2));
|
||||
p.drawLine(divider_x, container_y + 23, divider_x, container_y + container_height - 23);
|
||||
|
||||
const int then_x = divider_x + 15;
|
||||
const int then_icon_size = 105;
|
||||
|
||||
QRect then_label_rect(then_x, container_y + 30, then_section_width - 23, 38);
|
||||
p.setFont(InterFont(53, QFont::Medium));
|
||||
p.setPen(Qt::white);
|
||||
p.drawText(then_label_rect, Qt::AlignCenter, tr("Then"));
|
||||
|
||||
// Next maneuver icon
|
||||
const int then_icon_x = then_x + (then_section_width - 23 - then_icon_size) / 2;
|
||||
const int then_icon_y = container_y + 75;
|
||||
|
||||
QString next_icon_name = getNavigationIconName(navigationNextManeuverType, navigationNextModifier);
|
||||
QPixmap next_nav_icon = loadPixmap("../../sunnypilot/selfdrive/assets/navigation/" + next_icon_name, {then_icon_size, then_icon_size});
|
||||
|
||||
if (!next_nav_icon.isNull()) {
|
||||
p.drawPixmap(then_icon_x, then_icon_y, next_nav_icon);
|
||||
}
|
||||
}
|
||||
|
||||
p.restore();
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ private:
|
||||
void drawE2eAlert(QPainter &p, const QRect &surface_rect, const QString &alert_alt_text = "");
|
||||
void drawCurrentSpeedSP(QPainter &p, const QRect &surface_rect);
|
||||
void drawBlinker(QPainter &p, const QRect &surface_rect);
|
||||
void drawNavigationHUD(QPainter &p, const QRect &surface_rect);
|
||||
QString getNavigationIconName(const QString &type, const QString &mod);
|
||||
|
||||
bool lead_status;
|
||||
float lead_d_rel;
|
||||
@@ -85,7 +83,7 @@ private:
|
||||
bool speedLimitValid;
|
||||
bool speedLimitLastValid;
|
||||
float speedLimitFinalLast;
|
||||
int speedLimitSource; // 0=NONE, 1=MAP
|
||||
cereal::LongitudinalPlanSP::SpeedLimit::Source speedLimitSource;
|
||||
bool speedLimitAheadValid;
|
||||
float speedLimitAhead;
|
||||
float speedLimitAheadDistance;
|
||||
@@ -94,7 +92,7 @@ private:
|
||||
SpeedLimitMode speedLimitMode = SpeedLimitMode::OFF;
|
||||
bool roadName;
|
||||
QString roadNameStr;
|
||||
int speedLimitAssistState; // 0=NONE, 1=PRE_ACTIVE, etc.
|
||||
cereal::LongitudinalPlanSP::SpeedLimit::AssistState speedLimitAssistState;
|
||||
bool speedLimitAssistActive;
|
||||
int speedLimitAssistFrame;
|
||||
QPixmap plus_arrow_up_img;
|
||||
@@ -122,24 +120,4 @@ private:
|
||||
float speedCluster = 0;
|
||||
int icbm_active_counter = 0;
|
||||
bool pcmCruiseSpeed = true;
|
||||
|
||||
bool navigationValid;
|
||||
QString navigationStreet;
|
||||
QString navigationDistance;
|
||||
QString navigationModifier;
|
||||
QString navigationManeuverType;
|
||||
QString navigationNextModifier;
|
||||
QString navigationNextManeuverType;
|
||||
bool navigationHasNext;
|
||||
|
||||
QString wayName;
|
||||
QString wayRef;
|
||||
float mapdSpeedLimit;
|
||||
float advisorySpeed;
|
||||
float nextAdvisorySpeed;
|
||||
float nextAdvisorySpeedDistance;
|
||||
float suggestedSpeed;
|
||||
float visionCurveSpeed;
|
||||
float curveSpeed;
|
||||
bool tileLoaded;
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ void ModelRendererSP::draw(QPainter &painter, const QRect &surface_rect) {
|
||||
if (s->scene.rainbow_mode) {
|
||||
drawRainbowPath(painter, surface_rect);
|
||||
} else {
|
||||
ModelRenderer::drawPath(painter, model, surface_rect.height(), surface_rect.width());
|
||||
ModelRenderer::drawPath(painter, model, surface_rect.height());
|
||||
}
|
||||
|
||||
if (longitudinal_control && sm.alive("radarState")) {
|
||||
|
||||
@@ -29,8 +29,7 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
|
||||
"wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan",
|
||||
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP",
|
||||
"carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters",
|
||||
"carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP", "navigationd",
|
||||
"mapdOut"
|
||||
"carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP"
|
||||
});
|
||||
|
||||
// update timer
|
||||
|
||||
@@ -60,7 +60,6 @@ typedef struct UIScene {
|
||||
cereal::PandaState::PandaType pandaType;
|
||||
|
||||
cereal::LongitudinalPersonality personality;
|
||||
cereal::LongitudinalPlanSP::AccelerationPersonality accel_personality;
|
||||
|
||||
float light_sensor = -1;
|
||||
bool started, ignition, is_metric, recording_audio;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define SUNNYPILOT_VERSION "2025.003.000"
|
||||
#define SUNNYPILOT_VERSION "2025.002.000"
|
||||
|
||||
@@ -28,7 +28,6 @@ from openpilot.sunnypilot.modeld.constants import ModelConstants, Plan
|
||||
from openpilot.sunnypilot.models.helpers import get_active_bundle, get_model_path, load_metadata, prepare_inputs, load_meta_constants
|
||||
from openpilot.sunnypilot.modeld.models.commonmodel_pyx import ModelFrame, CLContext
|
||||
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.relc import RoadEdgeLaneChangeController
|
||||
|
||||
|
||||
PROCESS_NAME = "selfdrive.modeld.modeld_snpe"
|
||||
@@ -210,7 +209,6 @@ def main(demo=False):
|
||||
prev_action = log.ModelDataV2.Action()
|
||||
|
||||
DH = DesireHelper()
|
||||
RELC = RoadEdgeLaneChangeController(params.get_bool("RoadEdgeLaneChangeEnabled"))
|
||||
|
||||
while True:
|
||||
# Keep receiving frames until we are at least 1 frame ahead of previous extra frame
|
||||
@@ -316,10 +314,7 @@ def main(demo=False):
|
||||
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
|
||||
r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
|
||||
lane_change_prob = l_lane_change_prob + r_lane_change_prob
|
||||
RELC.update(modelv2_send.modelV2.roadEdgeStds, modelv2_send.modelV2.laneLineProbs)
|
||||
mdv2sp_send.modelDataV2SP.leftLaneChangeEdgeBlock = RELC.left_edge_detected
|
||||
mdv2sp_send.modelDataV2SP.rightLaneChangeEdgeBlock = RELC.right_edge_detected
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, RELC.left_edge_detected, RELC.right_edge_detected)
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
|
||||
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
|
||||
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
|
||||
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
|
||||
|
||||
@@ -26,7 +26,6 @@ from openpilot.sunnypilot.livedelay.helpers import get_lat_delay
|
||||
from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase
|
||||
from openpilot.sunnypilot.models.helpers import get_active_bundle
|
||||
from openpilot.sunnypilot.models.runners.helpers import get_model_runner
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.relc import RoadEdgeLaneChangeController
|
||||
|
||||
PROCESS_NAME = "selfdrive.modeld.modeld_tinygrad"
|
||||
|
||||
@@ -240,9 +239,6 @@ def main(demo=False):
|
||||
prev_action = log.ModelDataV2.Action()
|
||||
|
||||
DH = DesireHelper()
|
||||
RELC = RoadEdgeLaneChangeController(params.get_bool("RoadEdgeLaneChangeEnabled"))
|
||||
|
||||
|
||||
|
||||
while True:
|
||||
# Keep receiving frames until we are at least 1 frame ahead of previous extra frame
|
||||
@@ -344,10 +340,7 @@ def main(demo=False):
|
||||
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
|
||||
r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
|
||||
lane_change_prob = l_lane_change_prob + r_lane_change_prob
|
||||
RELC.update(modelv2_send.modelV2.roadEdgeStds, modelv2_send.modelV2.laneLineProbs)
|
||||
mdv2sp_send.modelDataV2SP.leftLaneChangeEdgeBlock = RELC.left_edge_detected
|
||||
mdv2sp_send.modelDataV2SP.rightLaneChangeEdgeBlock = RELC.right_edge_detected
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob, RELC.left_edge_detected, RELC.right_edge_detected)
|
||||
DH.update(sm['carState'], sm['carControl'].latActive, lane_change_prob)
|
||||
modelv2_send.modelV2.meta.laneChangeState = DH.lane_change_state
|
||||
modelv2_send.modelV2.meta.laneChangeDirection = DH.lane_change_direction
|
||||
mdv2sp_send.modelDataV2SP.laneTurnDirection = DH.lane_turn_direction
|
||||
|
||||
@@ -116,7 +116,7 @@ class ModelCache:
|
||||
|
||||
class ModelFetcher:
|
||||
"""Handles fetching and caching of model data from remote source"""
|
||||
MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-docs/refs/heads/gh-pages/docs/driving_models_v9.json"
|
||||
MODEL_URL = "https://docs.sunnypilot.ai/driving_models_v8.json"
|
||||
|
||||
def __init__(self, params: Params):
|
||||
self.params = params
|
||||
|
||||
@@ -19,8 +19,8 @@ from openpilot.system.hardware.hw import Paths
|
||||
from pathlib import Path
|
||||
|
||||
# see the README.md for more details on the model selector versioning
|
||||
CURRENT_SELECTOR_VERSION = 11
|
||||
REQUIRED_MIN_SELECTOR_VERSION = 11
|
||||
CURRENT_SELECTOR_VERSION = 10
|
||||
REQUIRED_MIN_SELECTOR_VERSION = 9
|
||||
|
||||
USE_ONNX = os.getenv('USE_ONNX', PC)
|
||||
|
||||
|
||||
@@ -14,10 +14,13 @@ CUSTOM_MODEL_PATH = Paths.model_root()
|
||||
# Set QCOM environment variable for TICI devices, potentially enabling hardware acceleration
|
||||
USBGPU = "USBGPU" in os.environ
|
||||
if USBGPU:
|
||||
os.environ['DEV'] = 'AMD'
|
||||
os.environ['AMD'] = '1'
|
||||
os.environ['AMD_IFACE'] = 'USB'
|
||||
elif TICI:
|
||||
os.environ['QCOM'] = '1'
|
||||
else:
|
||||
os.environ['DEV'] = 'QCOM' if TICI else 'CPU'
|
||||
os.environ['LLVM'] = '1'
|
||||
os.environ['JIT'] = '2' # TODO: This may cause issues
|
||||
|
||||
|
||||
class ModelData:
|
||||
|
||||
83
sunnypilot/navd/event_builder.py
Normal file
83
sunnypilot/navd/event_builder.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Copyright (c) 2021-, James Vecellio, 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 custom, messaging
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
|
||||
from sunnypilot.navd.constants import NAV_CV
|
||||
|
||||
|
||||
class EventBuilder:
|
||||
def __init__(self):
|
||||
self._counter: int = -1
|
||||
self._enabled: bool = False
|
||||
self._params = Params()
|
||||
|
||||
@staticmethod
|
||||
def _build_banner_message(metric: bool, nav_msg):
|
||||
m = nav_msg.allManeuvers[1] if len(nav_msg.allManeuvers) > 1 else nav_msg.allManeuvers[0]
|
||||
banner = m.instruction
|
||||
|
||||
if metric:
|
||||
dist = f'{m.distance / NAV_CV.METERS_TO_KILO:.1f} km,'
|
||||
if m.distance < NAV_CV.SHORT_DISTANCE_METERS:
|
||||
dist = f'{int(m.distance)}m,'
|
||||
else:
|
||||
dist = f'{m.distance / NAV_CV.METERS_TO_MILE:.1f} mi,'
|
||||
if m.distance < NAV_CV.QUARTER_MILE:
|
||||
dist = f'{round((m.distance * NAV_CV.METERS_TO_FEET) / 50) * 50}ft,'
|
||||
|
||||
if m.type == 'arrive' or m.type == 'depart' or 'Your destination' in banner:
|
||||
base_msg = banner
|
||||
elif banner.startswith(('Continue', 'Drive', 'Head')):
|
||||
base_msg = f'For {dist} {banner}'
|
||||
elif 'Turn' in banner or 'Take' in banner or 'Make' in banner:
|
||||
base_msg = f'In {dist} {banner}'
|
||||
else:
|
||||
base_msg = f'For {dist} Continue on {banner}'
|
||||
|
||||
return base_msg
|
||||
|
||||
@staticmethod
|
||||
def _get_turning_message(upcoming_turn):
|
||||
turn_messages = {
|
||||
'left': 'Turning Left, Make sure to nudge the wheel',
|
||||
'right': 'Turning Right, Make sure to nudge the wheel',
|
||||
'slightLeft': 'Keeping Left',
|
||||
'slightRight': 'Keeping Right',
|
||||
'sharpLeft': 'Sharp Left Turn',
|
||||
'sharpRight': 'Sharp Right Turn',
|
||||
'straight': 'Continuing Straight',
|
||||
'uturn': 'U-Turn Ahead',
|
||||
}
|
||||
return turn_messages.get(upcoming_turn, f"Upcoming {upcoming_turn.replace('_', ' ').title()}")
|
||||
|
||||
@staticmethod
|
||||
def build_navigation_events(sm: messaging.SubMaster, metric=True) -> list:
|
||||
nav_msg = sm['navigationd']
|
||||
if not nav_msg.valid:
|
||||
return []
|
||||
|
||||
banner_message = EventBuilder._build_banner_message(metric, nav_msg)
|
||||
|
||||
if nav_msg.upcomingTurn != 'none':
|
||||
banner_message = EventBuilder._get_turning_message(nav_msg.upcomingTurn)
|
||||
|
||||
return [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': banner_message,
|
||||
}]
|
||||
|
||||
def update(self, sm: messaging.SubMaster) -> list:
|
||||
self._counter += 1
|
||||
if self._counter % int(3.0 / DT_MDL) == 0:
|
||||
self._enabled = self._params.get("NavEvents", return_default=True)
|
||||
|
||||
if self._enabled:
|
||||
return self.build_navigation_events(sm)
|
||||
else:
|
||||
return []
|
||||
@@ -114,7 +114,7 @@ class NavigationInstructions:
|
||||
self.coord.latitude = current_lat
|
||||
self.coord.longitude = current_lon
|
||||
distance = self.coord.distance_to(progress['next_turn']['location'])
|
||||
if distance <= 30.0:
|
||||
if distance <= 100:
|
||||
modifier = progress['next_turn']['modifier']
|
||||
return str(modifier)
|
||||
return 'none'
|
||||
|
||||
@@ -61,7 +61,7 @@ class TestMapbox:
|
||||
if self.route['steps']:
|
||||
turn_lat = self.route['steps'][1]['location'].latitude
|
||||
turn_lon = self.route['steps'][1]['location'].longitude
|
||||
close_lat = turn_lat - 0.00025 # slightly before the turn
|
||||
close_lat = turn_lat - 0.0008 # 80 ish meters before the turn
|
||||
if self.progress and self.progress.get('next_turn'):
|
||||
expected_turn = self.progress['next_turn']['modifier']
|
||||
upcoming_close = self.nav.get_upcoming_turn_from_progress(self.progress, close_lat, turn_lon)
|
||||
|
||||
92
sunnypilot/navd/tests/test_event_builder.py
Normal file
92
sunnypilot/navd/tests/test_event_builder.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
Copyright (c) 2021-, James Vecellio, 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 custom
|
||||
from openpilot.common.params import Params
|
||||
|
||||
from openpilot.sunnypilot.navd.event_builder import EventBuilder
|
||||
|
||||
|
||||
class MockSM(dict):
|
||||
def __init__(self, nav_msg):
|
||||
super().__init__()
|
||||
self['navigationd'] = nav_msg
|
||||
|
||||
|
||||
class TestEventBuilder:
|
||||
def setup_method(self):
|
||||
self.params = Params()
|
||||
self.event_builder = EventBuilder()
|
||||
|
||||
def create_nav_msg(self, upcoming_turn='none', valid=True):
|
||||
nav_msg = custom.Navigationd.new_message()
|
||||
nav_msg.valid = valid
|
||||
nav_msg.upcomingTurn = upcoming_turn
|
||||
nav_msg.allManeuvers = [
|
||||
custom.Navigationd.Maneuver.new_message(distance=192.84873284, type='turn', modifier='left', instruction='West Esplanade Drive'),
|
||||
custom.Navigationd.Maneuver.new_message(distance=192.84809314, type='turn', modifier='right', instruction='West Esplanade Drive'),
|
||||
]
|
||||
return nav_msg
|
||||
|
||||
def test_validity(self):
|
||||
nav_msg = self.create_nav_msg(valid=False)
|
||||
events = EventBuilder.build_navigation_events(MockSM(nav_msg))
|
||||
assert events == []
|
||||
|
||||
def test_enabled(self):
|
||||
self.params.put("NavEvents", True)
|
||||
nav_msg = self.create_nav_msg()
|
||||
events = self.event_builder.update(MockSM(nav_msg))
|
||||
expected = [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': 'For 192m, Continue on West Esplanade Drive'
|
||||
}]
|
||||
assert events == expected
|
||||
|
||||
self.params.put("NavEvents", False)
|
||||
self.event_builder._counter = 59
|
||||
events = self.event_builder.update(MockSM(nav_msg))
|
||||
assert events == []
|
||||
|
||||
|
||||
def test_build_navigation_events(self):
|
||||
nav_msg = self.create_nav_msg()
|
||||
events = EventBuilder.build_navigation_events(MockSM(nav_msg), False)
|
||||
expected = [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': 'For 650ft, Continue on West Esplanade Drive',
|
||||
}]
|
||||
assert events == expected
|
||||
|
||||
def test_distance_condition_imperial(self):
|
||||
nav_msg = self.create_nav_msg()
|
||||
nav_msg.allManeuvers[1] = custom.Navigationd.Maneuver.new_message(distance=160.0, type='continue', modifier='straight', instruction='1234 Apple Way')
|
||||
events = EventBuilder.build_navigation_events(MockSM(nav_msg), False)
|
||||
expected = [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': 'For 500ft, Continue on 1234 Apple Way',
|
||||
}]
|
||||
assert events == expected
|
||||
|
||||
def test_upcoming_turn_override(self):
|
||||
nav_msg = self.create_nav_msg(upcoming_turn='left')
|
||||
events = EventBuilder.build_navigation_events(MockSM(nav_msg))
|
||||
expected = [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': 'Turning Left, Make sure to nudge the wheel',
|
||||
}]
|
||||
assert events == expected
|
||||
|
||||
def test_straight(self):
|
||||
nav_msg = self.create_nav_msg()
|
||||
nav_msg.allManeuvers[1] = custom.Navigationd.Maneuver.new_message(distance=80.0, type='continue', modifier='straight', instruction='1234 Apple Way')
|
||||
|
||||
events = EventBuilder.build_navigation_events(MockSM(nav_msg))
|
||||
expected = [{
|
||||
'name': custom.OnroadEventSP.EventName.navigationBanner,
|
||||
'message': 'For 80m, Continue on 1234 Apple Way'
|
||||
}]
|
||||
assert events == expected
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user