Compare commits

..

115 Commits

Author SHA1 Message Date
discountchubbs
692a4587db gap 2025-11-05 19:21:59 -08:00
James Vecellio-Grant
80a6f39a79 Merge branch 'nav-desires' into nav-events 2025-11-05 19:20:54 -08:00
discountchubbs
997ab25057 adjust list builder to accomodate the 3 indices 2025-11-05 19:18:45 -08:00
discountchubbs
05da45a1bf # Conflicts:
#	common/params_keys.h
#	sunnypilot/navd/constants.py
2025-11-05 19:07:02 -08:00
discountchubbs
864c811ef6 small clean 2025-11-05 19:05:29 -08:00
James Vecellio-Grant
906e9d7a80 Merge branch 'navigationd-service' into nav-desires 2025-11-05 18:51:41 -08:00
discountchubbs
cfb8f3ae24 main entry point for navigation updates 2025-11-05 18:49:32 -08:00
James Vecellio-Grant
0cc5e56192 Merge branch 'navigationd-init' into navigationd-service 2025-11-05 18:03:19 -08:00
discountchubbs
1a62ae821e green means good 2025-11-05 18:02:38 -08:00
discountchubbs
8caa57feeb Revert "tcpv3 and uhhh i forgot the other model"
This reverts commit 2c922afa12.
2025-11-04 16:05:03 -08:00
James Vecellio
2858a068f0 tcpv3 and uhhh i forgot the other model
model_checkpoint: merged with 0.875w from (model1: 'fd9a6816-8758-466b-bbde-3c1413b98f0a/400') and (model2: '0e620593-e85f-40c2-9adf-1e945651ed13/400')
2025-11-04 16:04:37 -08:00
James Vecellio-Grant
7d15afe5bc Merge branch 'nav-desires' into nav-events 2025-11-01 08:02:31 -07:00
James Vecellio-Grant
b6dd2d14db Merge branch 'navigationd-service' into nav-desires 2025-11-01 08:02:18 -07:00
James Vecellio-Grant
7d4e5bedaf Merge branch 'navigationd-init' into navigationd-service 2025-11-01 08:02:08 -07:00
James Vecellio-Grant
1063114408 Merge branch 'master' into navigationd-init 2025-11-01 08:01:57 -07:00
discountchubbs
958b4df69f give slightly more leniancy for offline routing 2025-11-01 08:01:30 -07:00
discountchubbs
f5953c5d8c Quarter mile is what apple maps uses 2025-11-01 07:57:55 -07:00
discountchubbs
72998034e6 copyright 2025-10-30 06:26:01 -07:00
discountchubbs
cefb344183 copyright 2025-10-30 06:22:34 -07:00
discountchubbs
c0da31abb6 mild clean 2025-10-30 06:18:47 -07:00
discountchubbs
bd759a56cf ehh no, 50 ft increments is better 2025-10-29 20:05:16 -07:00
discountchubbs
befc73c53e more 2025-10-29 20:03:19 -07:00
discountchubbs
8dbfc267ac Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-29 19:41:51 -07:00
discountchubbs
d17e80ad94 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-29 19:41:29 -07:00
discountchubbs
c2b7087723 Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-29 19:40:19 -07:00
James Vecellio-Grant
81b37712f1 Merge branch 'master' into navigationd-init 2025-10-29 19:39:41 -07:00
discountchubbs
68270a13a3 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-29 19:38:20 -07:00
discountchubbs
18cd3633e5 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-29 19:37:41 -07:00
discountchubbs
9c6a4d4a57 Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-29 19:37:10 -07:00
discountchubbs
1a4c48249b fix: handle empty maxspeed list in nav_instructions 2025-10-29 19:36:39 -07:00
James Vecellio-Grant
95d887a417 Update event_builder.py 2025-10-29 18:11:22 -07:00
James Vecellio-Grant
e297b4c03f Update event_builder.py 2025-10-29 18:06:28 -07:00
discountchubbs
1132377837 refactor event_builder into class with staticmethod for events.py call 2025-10-29 15:42:23 -07:00
discountchubbs
35f03ae001 Well im conflicted 2025-10-28 11:52:32 -07:00
discountchubbs
1c0b54a447 more 2025-10-28 06:55:28 -07:00
discountchubbs
8f0cdd514e weird 2025-10-28 06:54:50 -07:00
discountchubbs
3681caa717 Add nudge notif to event builder 2025-10-28 06:46:39 -07:00
discountchubbs
7446c43f69 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-28 06:44:01 -07:00
discountchubbs
5f5e3668eb Add steering pressed and torque to desire for non blindspot cars, and a note! 2025-10-28 06:43:00 -07:00
discountchubbs
8c07958f6f Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-28 06:28:33 -07:00
discountchubbs
ca1ce9bcc9 Clear route cache more gracefully to allow we based route connection to happen quick ish 2025-10-28 06:27:51 -07:00
discountchubbs
34a0819bc5 Read the description:
It's ideal that we should always use the next instruction ahead instead of our current instruction that we are driving on. Sure, current instruction is great for grepping maxspeed tags, but for upcoming instructions we want to use index 1.

I updated the test to reflect the two indexes.
2025-10-28 06:23:40 -07:00
James Vecellio-Grant
c68ea82a5d hahaha it’ll fail the test but that’s a later problem 2025-10-27 19:27:37 -07:00
discountchubbs
3157054100 a bit more readible 2025-10-26 13:02:09 -07:00
discountchubbs
2486ef1825 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-26 11:07:49 -07:00
discountchubbs
29f15dc8ed Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-26 11:07:16 -07:00
discountchubbs
31a5a3b3c0 assertion comparison operators 2025-10-26 11:06:00 -07:00
discountchubbs
d8fa3cfd04 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-26 08:45:24 -07:00
discountchubbs
2a4b348497 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-26 08:44:38 -07:00
discountchubbs
3ef3aceb4b Apply auto cancel route after 10 seconds off route. 2025-10-26 08:44:03 -07:00
James Vecellio-Grant
3d8763b3ce Merge branch 'master' into navigationd-init 2025-10-25 21:14:39 -07:00
James Vecellio-Grant
b2427a5f20 Merge branch 'master' into navigationd-init 2025-10-25 16:27:44 -07:00
discountchubbs
7ddafe62cd Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-23 19:21:25 -07:00
discountchubbs
ff4cc96a81 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-23 19:21:04 -07:00
discountchubbs
3b1ada64be sync 2025-10-23 19:20:15 -07:00
discountchubbs
6a08186434 Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-23 19:17:49 -07:00
discountchubbs
cf2b033c79 clean 2025-10-23 19:15:54 -07:00
discountchubbs
9fbef36c6b desire handling 2025-10-23 19:12:34 -07:00
discountchubbs
f5a38aa613 Add instruction field to maneuvers and update banner message logic 2025-10-23 19:08:52 -07:00
discountchubbs
25f5058430 Merge remote-tracking branch 'origin/nav-desires' into nav-events
# Conflicts:
#	sunnypilot/navd/navigation_helpers/nav_instructions.py
#	sunnypilot/navd/navigationd.py
2025-10-23 17:26:23 -07:00
discountchubbs
7b28c2f59a Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-23 17:24:16 -07:00
discountchubbs
99d954de10 sync 2025-10-23 17:23:47 -07:00
discountchubbs
b28f33481c Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-23 17:21:56 -07:00
discountchubbs
589e33f665 sum red diff 2025-10-23 17:20:23 -07:00
discountchubbs
39342d7b5e diff is red so == good? 2025-10-23 17:16:29 -07:00
discountchubbs
fe70650f73 100 meters 2025-10-23 16:56:58 -07:00
discountchubbs
e3f9fe892a more 2025-10-23 12:21:04 -07:00
discountchubbs
f4373fa244 Revert "dead"
This reverts commit 2376802589.
2025-10-23 12:20:52 -07:00
James Vecellio
2376802589 dead 2025-10-23 09:44:28 -07:00
James Vecellio
c3b51d7335 long maneuvers fix 2025-10-23 09:35:43 -07:00
discountchubbs
d3d8802402 no mid, yet 2025-10-22 19:34:24 -07:00
discountchubbs
d866500c92 daughter wants to take a bath 2025-10-22 19:27:59 -07:00
discountchubbs
23879836d9 return validity 2025-10-22 14:26:15 -07:00
discountchubbs
06add21971 sm shenanigans 2025-10-22 13:47:03 -07:00
discountchubbs
66fd3d1a01 smh 2025-10-22 09:51:33 -07:00
James Vecellio-Grant
71f7754f51 Didn’t like it 2025-10-22 07:45:44 -07:00
James Vecellio-Grant
b5591cbd62 Update plannerd.py 2025-10-22 07:36:56 -07:00
discountchubbs
7430c450c2 longitudinal maneuvers no subscribey 2025-10-22 06:15:52 -07:00
discountchubbs
e54a39cf43 publish dem events 👀 2025-10-21 21:13:33 -07:00
discountchubbs
3afe0bcdb3 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-21 16:27:46 -07:00
discountchubbs
b763f7aac1 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-21 16:27:02 -07:00
discountchubbs
450fcd4d55 oopsie part two lol 2025-10-21 16:25:30 -07:00
James Vecellio
551b4dea31 oopsie 2025-10-21 16:20:20 -07:00
James Vecellio
bd269defb3 oopsie 2025-10-21 16:19:49 -07:00
James Vecellio
8998f63a28 oopsie 2025-10-21 16:18:27 -07:00
James Vecellio-Grant
399ed08926 Merge branch 'master' into navigationd-init 2025-10-21 15:29:45 -07:00
James Vecellio-Grant
90f02040fe Merge branch 'master' into navigationd-service 2025-10-21 15:29:42 -07:00
James Vecellio-Grant
8423ecedb1 Merge branch 'master' into nav-desires 2025-10-21 15:29:39 -07:00
James Vecellio-Grant
34d1514e11 Merge branch 'master' into nav-events 2025-10-21 15:29:35 -07:00
discountchubbs
c50d511616 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-21 15:27:41 -07:00
discountchubbs
dd1479ed82 More macOS crap 🤠 2025-10-21 15:25:15 -07:00
discountchubbs
87ec262e39 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-21 12:06:07 -07:00
discountchubbs
f82845ff42 Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-21 12:05:13 -07:00
discountchubbs
efcc5ccd15 Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-21 12:03:44 -07:00
James Vecellio-Grant
6aac50ab56 Merge branch 'master' into navigationd-init 2025-10-21 12:03:05 -07:00
discountchubbs
da0920cb60 feat: navigationd onroad events 2025-10-21 11:59:13 -07:00
discountchubbs
091bce4a3a Merge remote-tracking branch 'origin/navigationd-service' into nav-desires 2025-10-21 05:54:42 -07:00
discountchubbs
088f6aa407 sync 2025-10-21 05:53:12 -07:00
James Vecellio-Grant
211c8adcce Merge branch 'master' into navigationd-init 2025-10-21 05:52:06 -07:00
discountchubbs
fe5366e5b2 rm unused import 2025-10-19 20:34:11 -07:00
discountchubbs
1ecb0b0f66 dumb 2025-10-19 20:16:36 -07:00
discountchubbs
51e455db79 stupid msgq always breaking macOS 2025-10-19 20:15:14 -07:00
discountchubbs
dc6672fa80 Merge remote-tracking branch 'origin/navigationd-init' into navigationd-service 2025-10-19 20:02:36 -07:00
discountchubbs
07b8e7783d Do i really need a readme 2025-10-19 19:47:21 -07:00
discountchubbs
f17b0f200c non blocking polling
SOME attribute protection. kids crying, so need to stop for now!
2025-10-19 17:20:13 -07:00
discountchubbs
ad9bde8b1f non blocking polling
SOME attribute protection. kids crying, so need to stop for now!
2025-10-19 17:17:37 -07:00
discountchubbs
8cf9f9fe23 params!
maybe these should be protected attributes, but thats a tomorrow problem
2025-10-19 17:03:04 -07:00
discountchubbs
713985d823 feat: navigationd desire loop
Notes: Maybe I should add a param for this, so its not automatic when a route is set.
2025-10-19 09:38:29 -07:00
James Vecellio-Grant
088f9d0b59 Merge branch 'master' into navigationd-service 2025-10-18 18:22:34 -07:00
James Vecellio-Grant
53bf5b0d41 Merge branch 'master' into navigationd-init 2025-10-18 18:22:27 -07:00
discountchubbs
8c33592628 Revert "feat: navigationd" bc it was supposed to be a branch lol
This reverts commit 3bbb33f6bd.
2025-10-18 18:18:28 -07:00
James Vecellio
3bbb33f6bd feat: navigationd
I changed the reroute counter to 9 updates, which is every 3 seconds.  compared to 3, which is one second.
2025-10-18 18:15:22 -07:00
discountchubbs
5bd9549bd1 some clean up for production 2025-10-16 15:43:34 -07:00
discountchubbs
3481702715 some suggestions applied 2025-10-16 06:55:15 -07:00
discountchubbs
c9781ee31d feat: mapbox navigation helpers 2025-10-16 06:43:48 -07:00
163 changed files with 432 additions and 3057 deletions

View File

@@ -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}

View File

@@ -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}

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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
![](https://dcbadge.vercel.app/api/server/wRW3meAgtx?style=flat) ![Discord Shield](https://discordapp.com/api/guilds/880416502577266699/widget.png?style=shield)
## 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>

View File

@@ -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 {
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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}},

View File

@@ -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)

View File

@@ -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)

View File

@@ -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),

View File

@@ -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

View File

@@ -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)

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 &param) {
@@ -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.");

View File

@@ -88,7 +88,6 @@ protected:
Params params;
std::map<std::string, ParamControl*> toggles;
ButtonParamControl *long_personality_setting;
ButtonParamControl *accel_personality_setting;
virtual void updateToggles();
};

View File

@@ -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.;

View File

@@ -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);
};

View File

@@ -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;

View File

@@ -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 &param = "");
};

View File

@@ -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",

View File

@@ -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

View File

@@ -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;

View File

@@ -36,9 +36,6 @@ private:
ParamControl *SmartCruiseControlMap;
ParamControl *intelligentCruiseButtonManagement = nullptr;
ParamControl *dynamicExperimentalControl = nullptr;
ParamControlSP *AccelPersonalityControl;
ParamControlSP *DynamicPersonalityControl;
SpeedLimitSettings *speedLimitScreen;
PushButtonSP *speedLimitSettings;
};

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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"),

View File

@@ -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();
}

View File

@@ -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();
};

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -22,5 +22,5 @@ public:
void updateSettings() override;
private:
ParamControlSP *coopSteeringToggle = nullptr;
bool offroad = false;
};

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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")) {

View File

@@ -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

View File

@@ -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;

View File

@@ -1 +1 @@
#define SUNNYPILOT_VERSION "2025.003.000"
#define SUNNYPILOT_VERSION "2025.002.000"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View 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 []

View File

@@ -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'

View File

@@ -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)

View 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

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