Compare commits

..

12 Commits

Author SHA1 Message Date
royjr
672053db65 Update display_panel.cc 2025-11-08 09:57:57 -08:00
royjr
774710e95e Squashed commit of the following:
commit 669f3b7945
Author: royjr <royjr96@gmail.com>
Date:   Fri Nov 7 21:51:35 2025 -0500

    fix

commit 63122e1a33
Merge: c9b1afb15 c1d3ae427
Author: royjr <royjr96@gmail.com>
Date:   Fri Nov 7 21:25:46 2025 -0500

    Merge branch 'master' into visual-style

commit c9b1afb154
Merge: 6e3bd3fbe 9b92cdd2c
Author: royjr <royjr96@gmail.com>
Date:   Fri Oct 10 00:06:55 2025 -0400

    Merge branch 'master' into visual-style

commit 6e3bd3fbed
Author: royjr <royjr96@gmail.com>
Date:   Thu Oct 9 23:56:37 2025 -0400

    explicit radius

commit 42592dd550
Author: royjr <royjr96@gmail.com>
Date:   Thu Oct 9 23:54:34 2025 -0400

    match what we currently send

commit b2f7d72a33
Author: royjr <royjr96@gmail.com>
Date:   Thu Oct 9 23:53:07 2025 -0400

    no need

commit 2e0ce18c84
Author: royjr <royjr96@gmail.com>
Date:   Thu Oct 9 23:52:51 2025 -0400

    group

commit 2a9a4a9263
Merge: e63fb10fd d6317ffd2
Author: royjr <royjr96@gmail.com>
Date:   Thu Oct 9 23:51:18 2025 -0400

    Merge branch 'master' into visual-style

commit e63fb10fdb
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:35:23 2025 -0400

    Revert "metric threshold"

    This reverts commit b54941928d.

commit b54941928d
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:35:15 2025 -0400

    metric threshold

commit b85b8ffacf
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:28:10 2025 -0400

    better VisualStyleOverheadThreshold

commit 3ff2e9b26a
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:25:37 2025 -0400

    reorder

commit 4b3ffc722a
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:24:52 2025 -0400

    show visual_radar_tracks_delay_settings on VisualRadarTracks

commit 5f49066829
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:18:51 2025 -0400

    more

commit ab2eb218d5
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:16:06 2025 -0400

    clean

commit 6212b174e9
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 21:12:08 2025 -0400

    descs

commit a8a6e5708a
Merge: 54b060f17 ae21d40a1
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:47:03 2025 -0400

    Merge branch 'master' into visual-style

commit 54b060f178
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:45:17 2025 -0400

    move with

commit 8266386cd0
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:44:06 2025 -0400

    better

commit 8bbe87ee22
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:40:23 2025 -0400

    simple

commit d35ac0c145
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:34:26 2025 -0400

    a bit better

commit a134ae1e29
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:25:55 2025 -0400

    combine

commit 6a69759b9e
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 20:24:51 2025 -0400

    hide options based on options

commit b9063e2966
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:55:40 2025 -0400

    cleanup

commit 4397a4387a
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:49:14 2025 -0400

    mooooore fps

commit 32dc384524
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:47:08 2025 -0400

    not needed for now

commit 68fa239b97
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:45:37 2025 -0400

    unused

commit c8367fbc25
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:44:45 2025 -0400

    more fps remove

commit 76fc4514e1
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:43:32 2025 -0400

    reorder

commit 073ce2b4df
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 19:35:37 2025 -0400

    remove VisualFPS

commit 5d516ba89f
Merge: e819a0dcb 014baf8e9
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 12:26:38 2025 -0400

    Merge branch 'master' into visual-style

commit e819a0dcb1
Merge: ba4b583e6 8050c56a4
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 02:14:22 2025 -0400

    Merge branch 'master' into visual-style

commit ba4b583e6e
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:55:38 2025 -0400

    fix visual_style_overhead_zoom

commit 5954354356
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:48:06 2025 -0400

    fix visual_style_overhead

commit 23ff232333
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:40:10 2025 -0400

    fix visual_style_overhead_settings

commit 0bb47fcfa9
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:29:15 2025 -0400

    fix visual_style_overhead_threshold_settings

commit 99a5682371
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:09:08 2025 -0400

    todo

commit 22ca343050
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:07:53 2025 -0400

    fix visual_style_overhead_threshold_settings

commit 0049d20151
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 01:05:17 2025 -0400

    VisualStyleZoom fix

commit b9f8f4e8ac
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 00:55:20 2025 -0400

    visual style better

commit 26564dd42f
Author: royjr <royjr96@gmail.com>
Date:   Wed Oct 8 00:07:31 2025 -0400

    better VisualWideCam

commit ec440e4568
Merge: 69817f887 408d52d72
Author: royjr <royjr96@gmail.com>
Date:   Tue Oct 7 22:38:57 2025 -0400

    Merge branch 'master' into visual-style

commit 69817f887b
Merge: df21208b7 0f4828df8
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 30 15:01:21 2025 -0400

    Merge branch 'master' into visual-style

commit df21208b7c
Merge: 660c994c5 082ea8119
Author: royjr <royjr96@gmail.com>
Date:   Thu Sep 25 02:08:38 2025 -0400

    Merge branch 'master' into visual-style

commit 660c994c5e
Author: royjr <royjr96@gmail.com>
Date:   Thu Sep 25 02:08:28 2025 -0400

    visual_style_blend  vs visual_style_overhead_blend

commit 904cc796b0
Author: royjr <royjr96@gmail.com>
Date:   Thu Sep 25 01:44:06 2025 -0400

    prevent jitter

commit 1a9a1e1b8a
Merge: 2ae7078c0 1465e38c7
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 23:00:46 2025 -0400

    Merge branch 'master' into visual-style

commit 2ae7078c0f
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 14:37:21 2025 -0400

    use ParamWatcher

commit 0fde830a30
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 10:35:46 2025 -0400

    fix params

commit 7c744a42e5
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 08:18:51 2025 -0400

    safe font

commit 90cc169dec
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 08:17:59 2025 -0400

    VisualRadarTracksDelay

commit 36c1e11a9e
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 07:47:16 2025 -0400

    add FPS toggle

commit 5e26a99337
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 07:40:59 2025 -0400

    better fps

commit 53683cf90b
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 07:25:00 2025 -0400

    constant track size

commit 95dcc23887
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 07:21:57 2025 -0400

    better tracks for overhead

commit cef3163c7c
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 06:54:46 2025 -0400

    more more more cached params

commit cbc34dd1f6
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 06:49:41 2025 -0400

    more cached params

commit fbd1f6bad1
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 06:42:14 2025 -0400

    cached params

commit f2ddf9abba
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 04:04:52 2025 -0400

    debug ui lag

commit 8a5eaf5ba6
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 03:35:06 2025 -0400

    prepare for lag compensation

commit ddb377ac5b
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 03:24:15 2025 -0400

    radar lag compensate

commit 512a01d28c
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 01:33:50 2025 -0400

    VisualWideCam toggle (untested)

commit b30e275169
Merge: ee9fe5c9e ecee67dd6
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 01:15:18 2025 -0400

    Merge branch 'master' into visual-style

commit ee9fe5c9ed
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 01:10:44 2025 -0400

    VisualRadarTracks toggle

commit e672a352d3
Author: royjr <royjr96@gmail.com>
Date:   Tue Sep 23 00:24:38 2025 -0400

    bigger points

commit 361d107040
Author: royjr <royjr96@gmail.com>
Date:   Mon Sep 22 23:55:55 2025 -0400

    basic radar

commit 36eb047cd3
Merge: 218c6172e d5a873ed8
Author: royjr <royjr96@gmail.com>
Date:   Mon Sep 22 00:10:31 2025 -0400

    Merge branch 'master' into visual-style

commit 218c6172e6
Author: royjr <royjr96@gmail.com>
Date:   Mon Sep 22 00:03:29 2025 -0400

    darker fills

commit 8f35e4fc3c
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 23:02:48 2025 -0400

    Revert "smooooth"

    This reverts commit c965df39d6.

commit c965df39d6
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 22:10:35 2025 -0400

    smooooth

commit 53ef69f3c3
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 21:55:23 2025 -0400

    hide horizon if no data

commit ea9ca18c8b
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 21:49:01 2025 -0400

    horizon at end

commit 225858261e
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 21:34:14 2025 -0400

    better horizon

commit 43de43b34a
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 21:25:39 2025 -0400

    better lines

commit 96ddbe35a1
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 15:37:54 2025 -0400

    dynamically adjust background

commit 7d547ad533
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 15:30:13 2025 -0400

    fix default

commit 13de58b845
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 15:30:06 2025 -0400

    add more speeds

commit 3d8c563a4b
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 15:19:57 2025 -0400

    dynamic zoom

commit bc75199d5a
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 14:34:38 2025 -0400

    overhead

commit ba6e18ed91
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 14:32:30 2025 -0400

    only for vision

commit 74dbcd699b
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 14:31:58 2025 -0400

    add road edges to vision

commit 35c6af0190
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 13:55:56 2025 -0400

    theme

commit 827de88c8b
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 13:03:37 2025 -0400

    stump top down

commit 54ca4b537d
Author: royjr <royjr96@gmail.com>
Date:   Sun Sep 21 12:48:32 2025 -0400

    VisualStyleBlendThreshold

commit c61f327076
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 13:04:07 2025 -0400

    allow always overhead view

commit d569913e5a
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 12:57:17 2025 -0400

    VisualStyleBlend

commit 418c93be06
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 12:16:49 2025 -0400

    animate overhead

commit 5acc040a89
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 11:24:24 2025 -0400

    overhead

commit e45b17c230
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 03:00:00 2025 -0400

    better

commit b14b6246d7
Author: royjr <royjr96@gmail.com>
Date:   Sat Sep 20 00:31:07 2025 -0400

    visual style init
2025-11-07 22:11:17 -05:00
royjr
8cdc236585 Merge branch 'master' into nav-commacon-visual-style 2025-11-07 22:10:20 -05:00
Jason Wen
c1d3ae427b version: bump to 2025.003.000 2025-11-06 23:12:41 -05:00
Jason Wen
2ab45b552d Update CHANGELOG.md 2025-11-06 23:10:03 -05:00
github-actions[bot]
8c1d59fecd [bot] Update Python packages (#1434)
Update Python packages

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-06 22:47:55 -05:00
DevTekVE
cde88fd8ed bug: Fix initial registration for sunnylink (#1457)
refactor(sunnylink): defer `SunnylinkApi` initialization to function scope

- Moved `SunnylinkApi` object creation into individual functions as needed.
- Prevents unnecessary initialization when the object isn't used.
2025-11-06 12:13:15 +01:00
DevTekVE
4b5de0eddb stats: sunnylink integration (#1454)
* sunnylink: add statsd process and related telemetry logging infrastructure

- Introduced `statsd_sp` process for handling Sunnylink-specific stats.
- Enhanced metrics logging with improved directory structure and data handling.

* sunnylink: re-enable and refine stat_handler for telemetry processing

- Reactivated `stat_handler` thread with improved path handling.
- Made `stat_handler` more flexible by allowing directory injection.

* statsd: fix formatting issue in telemetry string generation

- Corrected missing comma between `sunnylink_dongle_id` and `comma_dongle_id`.

* update statsd_sp process configuration for enhanced readiness logic

- Modified `statsd_sp` initialization to include `always_run` alongside `sunnylink_ready_shim`.
- Ensures robust process activation conditions.

* refactor(statsd): enhance and unify StatLogSP implementation

- Replaced custom `StatLogSP` in sunnylink with centralized implementation from `system.statsd`.
- Ensures consistent logic for StatLogSP handling across modules.

* fix

* refactor(statsd): add intercept parameter to StatLogSP for configurable logging

- Introduced optional `intercept` parameter to `StatLogSP` to manage `comma_statlog` initialization.
- Updated usage in `sunnylink` to disable interception where unnecessary.

* Dont complain

* feat(statsd): add raw metric type and SunnyPilot-specific stats collection

- Introduced `METRIC_TYPE.RAW` for base64-encoded raw data metrics.
- Added `sp_stats` thread to export SunnyPilot params as raw metrics.
- Enhanced telemetry handling with decoding and serialization updates.

* refactor(statsd): improve `sp_stats` error handling and param processing

- Enhanced exception handling for `params.get` to prevent crashes.
- Added support for nested dict values to be included in stats.

* refactor(statsd): adjust imports and minor code formatting updates

- Updated `Ratekeeper` import path for consistency with the `openpilot` module structure.
- Fixed minor formatting for improved readability.

* refactor(statsd): update typings and remove unused NoReturn annotation

- Removed unnecessary `NoReturn` typing for `stats_main` to simplify function definition.
- Adjusted `get_influxdb_line_raw` to refine typing for `value` parameter.

* cleanup

* init

* init

* slightly more

* staticmethod

* handle them all

* get them models

* log with route

* more

* car

* Revert "car"

This reverts commit fe1c90cf4d.

* handle capnp

* Revert "handle capnp"

This reverts commit c5aea68803.

* 1 more time

* Revert "1 more time"

This reverts commit a364474fa5.

* Cleaning to expose wider

* feat(interfaces, statsd): log car params to stats system

- Added `STATSLOGSP` import and logging to capture `carFingerprint` in metrics.
- Improved error handling in `get_influxdb_line_raw` for robust metric generation.

* refactor(interfaces): streamline car params logging to stats

- Simplified logging by directly converting `CP` to a dictionary.
- Removed legacy stats aggregation for clarity.

* feat(sunnylink): enable compression for stats in SunnyLink

- Added optional compression for stats payload to support large data.
- Updated `stat_handler` to handle compression and base64 encoding.

* fix(statsd): filter complex types in `get_influxdb_line_raw`

- Skips unsupported types (dict, list, bytes) to prevent formatting errors.
- Simplifies type annotation for `value` parameter.

* fix(statsd): use `json.dumps` for string conversion in `get_influxdb_line_raw`

- Ensures proper handling of special characters in values.
- Prevents potential formatting issues with raw `str()` conversion.

* refactor(interfaces, statsd): update parameter keys for stats logging

- Renamed logged keys for better clarity (`sunnypilot_params` → `sunnypilot.car_params`, `device_params`).
- Ensures consistency across data logs.

* bet

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-11-04 16:53:31 -05:00
Matt Purnell
071147baaf docs: Update README installation branches and discord links (#1453)
* Use sunnypilot CARS.md, update number of supported cars, add comma

* Update device reference

* Update discord links to forum links

* Update references to -c3-new branches and release

* Update broken link to branches table

* Update README.md

---------

Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-11-03 06:52:17 +01:00
DevTekVE
18af4d6ad6 ui: Fix spacing in sunnylink panel (#1450)
Fix spacing
2025-11-02 20:26:17 +01:00
DevTekVE
b81d5bca3c ui: update discord references and add forum widget (#1440)
* sunnylink: introduce community popup with QR code embedding

- Added `SunnylinkCommunityPopup` widget to promote the sunnypilot Community Forum.
- Integrated a QR code generator and display for quick access.
- Updated `WiFiPromptWidget` to include a "Learn More" button triggering the community popup.

* sunnylink: adjust community popup styling for better layout

- Reduced font size of description text slightly for consistency.
- Decreased QR code dimensions to improve visual balance.

* Making more space out of thin air

* sunnylink: update community references to use forum links

- Replaced Discord links with Community Forum URLs for better alignment.
- Improved clarity in sponsorship instructions.
2025-11-02 06:50:41 +01:00
Amy Jeanes
682d738ffa Tesla: Coop Steering (#1283)
* Tesla: Coop Steering

* bump

* bump

* sync with opendbc/master

* resolve comment

* add oscillation warning and add confirmation

* styling desc

* beta

---------

Co-authored-by: Jason Wen <haibin.wen3@gmail.com>
2025-11-01 22:47:30 -04:00
26 changed files with 577 additions and 154 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: |

View File

@@ -369,7 +369,6 @@ struct CarControlSP @0xa5cd762cd951a455 {
leadOne @2 :LeadData;
leadTwo @3 :LeadData;
intelligentCruiseButtonManagement @4 :IntelligentCruiseButtonManagement;
speed @5 :Float32;
struct Param {
key @0 :Text;
@@ -457,14 +456,14 @@ struct ModelDataV2SP @0xa1680744031fdb2d {
struct Navigationd @0xcb9fd56c7057593a {
upcomingTurn @0 :Text;
currentSpeedLimit @1 :UInt16;
currentSpeedLimit @1 :UInt64;
bannerInstructions @2 :Text;
distanceFromRoute @3 :Float32;
distanceFromRoute @3 :Float64;
allManeuvers @4 :List(Maneuver);
valid @5 :Bool;
struct Maneuver {
distance @0 :Float32;
distance @0 :Float64;
type @1 :Text;
modifier @2 :Text;
instruction @3 :Text;

View File

@@ -172,6 +172,14 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}},
{"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}},
{"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualRadarTracks", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualRadarTracksDelay", {PERSISTENT | BACKUP, FLOAT, "0.0"}},
{"VisualWideCam", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualStyle", {PERSISTENT | BACKUP, INT, "0"}},
{"VisualStyleZoom", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualStyleOverhead", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualStyleOverheadZoom", {PERSISTENT | BACKUP, BOOL, "0"}},
{"VisualStyleOverheadThreshold", {PERSISTENT | BACKUP, INT, "20"}},
// MADS params
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},

View File

@@ -88,7 +88,7 @@ class SelfdriveD(CruiseHelper):
# TODO: de-couple selfdrived with card/conflate on carState without introducing controls mismatches
self.car_state_sock = messaging.sub_sock('carState', timeout=20)
ignore = self.sensor_packets + self.gps_packets + ['alertDebug'] + ['modelDataV2SP']
ignore = self.sensor_packets + self.gps_packets + ['alertDebug'] + ['modelDataV2SP'] + ['navigationd']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
if REPLAY:
@@ -98,7 +98,7 @@ class SelfdriveD(CruiseHelper):
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose', 'liveDelay',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'controlsState', 'carControl', 'driverAssistance', 'alertDebug', 'userBookmark', 'audioFeedback',
'modelDataV2SP', 'longitudinalPlanSP'] + \
'modelDataV2SP', 'longitudinalPlanSP', 'navigationd'] + \
self.camera_packets + self.sensor_packets + self.gps_packets,
ignore_alive=ignore, ignore_avg_freq=ignore,
ignore_valid=ignore, frequency=int(1/DT_CTRL))

View File

@@ -25,6 +25,11 @@ void AnnotatedCameraWidget::updateState(const UIState &s) {
// update engageability/experimental mode button
experimental_btn->updateState(s);
dmon.updateState(s);
if (s.scene.visual_style == 0) {
setBackgroundColor(bg_colors[STATUS_DISENGAGED]);
} else {
setBackgroundColor(QColor(0, 0, 0));
}
}
void AnnotatedCameraWidget::initializeGL() {
@@ -35,7 +40,12 @@ void AnnotatedCameraWidget::initializeGL() {
qInfo() << "OpenGL language version:" << QString((const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
prev_draw_t = millis_since_boot();
setBackgroundColor(bg_colors[STATUS_DISENGAGED]);
auto *s = uiState();
if (s->scene.visual_style == 0) {
setBackgroundColor(bg_colors[STATUS_DISENGAGED]);
} else {
setBackgroundColor(QColor(0, 0, 0));
}
}
mat4 AnnotatedCameraWidget::calcFrameMatrix() {
@@ -118,7 +128,13 @@ void AnnotatedCameraWidget::paintGL() {
} else if (v_ego > 15) {
wide_cam_requested = false;
}
wide_cam_requested = wide_cam_requested && sm["selfdriveState"].getSelfdriveState().getExperimentalMode();
if (s->scene.visual_wide_cam == 1) {
wide_cam_requested = true;
} else if (s->scene.visual_wide_cam == 2) {
wide_cam_requested = false;
} else {
wide_cam_requested = wide_cam_requested && sm["selfdriveState"].getSelfdriveState().getExperimentalMode();
}
}
CameraWidget::setStreamType(wide_cam_requested ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD);
CameraWidget::setFrameId(sm["modelV2"].getModelV2().getFrameId());

View File

@@ -1,4 +1,5 @@
#include "selfdrive/ui/qt/onroad/model.h"
#include <algorithm>
void ModelRenderer::draw(QPainter &painter, const QRect &surface_rect) {
auto *s = uiState();
@@ -49,8 +50,14 @@ void ModelRenderer::update_leads(const cereal::RadarState::Reader &radar_state,
}
void ModelRenderer::update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) {
auto *s = uiState();
const auto &model_position = model.getPosition();
float max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
float max_distance;
if (s->scene.visual_style == 0) {
max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
} else {
max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
}
// update lane lines
const auto &lane_lines = model.getLaneLines();
@@ -58,7 +65,11 @@ void ModelRenderer::update_model(const cereal::ModelDataV2::Reader &model, const
int max_idx = get_path_length_idx(lane_lines[0], max_distance);
for (int i = 0; i < std::size(lane_line_vertices); i++) {
lane_line_probs[i] = line_probs[i];
mapLineToPolygon(lane_lines[i], 0.025 * lane_line_probs[i], 0, &lane_line_vertices[i], max_idx);
if (s->scene.visual_style == 2) {
mapLineToPolygon(lane_lines[i], 0.075 * lane_line_probs[i], 0, &lane_line_vertices[i], max_idx);
} else {
mapLineToPolygon(lane_lines[i], 0.025 * lane_line_probs[i], 0, &lane_line_vertices[i], max_idx);
}
}
// update road edges
@@ -66,7 +77,11 @@ void ModelRenderer::update_model(const cereal::ModelDataV2::Reader &model, const
const auto &edge_stds = model.getRoadEdgeStds();
for (int i = 0; i < std::size(road_edge_vertices); i++) {
road_edge_stds[i] = edge_stds[i];
mapLineToPolygon(road_edges[i], 0.025, 0, &road_edge_vertices[i], max_idx);
if (s->scene.visual_style == 2) {
mapLineToPolygon(road_edges[i], 0.1, 0, &road_edge_vertices[i], max_idx);
} else {
mapLineToPolygon(road_edges[i], 0.025, 0, &road_edge_vertices[i], max_idx);
}
}
// update path
@@ -79,16 +94,112 @@ void ModelRenderer::update_model(const cereal::ModelDataV2::Reader &model, const
}
void ModelRenderer::drawLaneLines(QPainter &painter) {
// lanelines
for (int i = 0; i < std::size(lane_line_vertices); ++i) {
painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp<float>(lane_line_probs[i], 0.0, 0.7)));
painter.drawPolygon(lane_line_vertices[i]);
}
auto *s = uiState();
if (s->scene.visual_style == 2) {
QRectF r = clip_region;
// road edges
for (int i = 0; i < std::size(road_edge_vertices); ++i) {
painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp<float>(1.0 - road_edge_stds[i], 0.0, 1.0)));
painter.drawPolygon(road_edge_vertices[i]);
qreal horizonY = r.bottom();
if (!road_edge_vertices[0].isEmpty() || !road_edge_vertices[1].isEmpty()) {
qreal leftH = r.top();
qreal rightH = r.top();
if (!road_edge_vertices[0].isEmpty()) {
leftH = std::numeric_limits<qreal>::max();
for (const QPointF &pt : road_edge_vertices[0]) {
if (pt.y() < leftH) leftH = pt.y();
}
}
if (!road_edge_vertices[1].isEmpty()) {
rightH = std::numeric_limits<qreal>::max();
for (const QPointF &pt : road_edge_vertices[1]) {
if (pt.y() < rightH) rightH = pt.y();
}
}
horizonY = std::max(leftH, rightH);
}
painter.fillRect(QRectF(r.left(), horizonY + 0, r.width(), r.bottom() - (horizonY + 0)), QColor("#111111"));
auto buildFill = [&](const QPolygonF &edgeRibbon, bool isLeftSide) -> QPolygonF {
if (edgeRibbon.isEmpty()) return {};
QMap<int, QPointF> byY;
for (const QPointF &pt : edgeRibbon) {
int yi = int(std::round(pt.y()));
if (!byY.contains(yi)) {
byY[yi] = pt;
} else {
if (isLeftSide) {
if (pt.x() > byY[yi].x()) byY[yi] = pt;
} else {
if (pt.x() < byY[yi].x()) byY[yi] = pt;
}
}
}
if (byY.isEmpty()) return {};
QPolygonF curve;
for (auto it = byY.cbegin(); it != byY.cend(); ++it) {
curve << it.value();
}
if (curve.size() < 2) return {};
const qreal topY = curve.first().y();
QPolygonF fill;
if (isLeftSide) {
fill << QPointF(r.left(), topY);
for (const QPointF &pt : curve) fill << pt;
fill << QPointF(r.left(), r.bottom());
} else {
fill << QPointF(r.right(), topY);
for (const QPointF &pt : curve) fill << pt;
fill << QPointF(r.right(), r.bottom());
}
return fill;
};
QPolygonF leftFill = buildFill(road_edge_vertices[0], true);
QPolygonF rightFill = buildFill(road_edge_vertices[1], false);
if (!leftFill.isEmpty()) {
painter.setBrush(QColor("#222222"));
painter.drawPolygon(leftFill);
}
if (!rightFill.isEmpty()) {
painter.setBrush(QColor("#222222"));
painter.drawPolygon(rightFill);
}
for (int i = 0; i < std::size(lane_line_vertices); ++i) {
painter.setBrush(QColor::fromRgbF(0.902, 0.902, 0.902, std::clamp<float>(lane_line_probs[i], 0.0, 0.7)));
painter.drawPolygon(lane_line_vertices[i]);
}
for (int i = 0; i < std::size(road_edge_vertices); ++i) {
painter.setBrush(QColor(0x55, 0x55, 0x55, 255));
painter.drawPolygon(road_edge_vertices[i]);
}
QLinearGradient bgGrad(r.left(), horizonY - 100, r.left(), horizonY + 100);
bgGrad.setColorAt(0.0, QColor("#000000"));
bgGrad.setColorAt(0.5, QColor("#111111"));
bgGrad.setColorAt(1.0, QColor("#111111"));
painter.fillRect(QRectF(r.left(), horizonY - 200, r.width(), 200), bgGrad);
} else {
// lanelines
for (int i = 0; i < std::size(lane_line_vertices); ++i) {
painter.setBrush(QColor::fromRgbF(1.0, 1.0, 1.0, std::clamp<float>(lane_line_probs[i], 0.0, 0.7)));
painter.drawPolygon(lane_line_vertices[i]);
}
// road edges
for (int i = 0; i < std::size(road_edge_vertices); ++i) {
painter.setBrush(QColor::fromRgbF(1.0, 0, 0, std::clamp<float>(1.0 - road_edge_stds[i], 0.0, 1.0)));
painter.drawPolygon(road_edge_vertices[i]);
}
}
}
@@ -175,6 +286,7 @@ QColor ModelRenderer::blendColors(const QColor &start, const QColor &end, float
void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data,
const QPointF &vd, const QRect &surface_rect) {
auto *s = uiState();
const float speedBuff = 10.;
const float leadBuff = 40.;
const float d_rel = lead_data.getDRel();
@@ -197,20 +309,133 @@ void ModelRenderer::drawLead(QPainter &painter, const cereal::RadarState::LeadDa
float g_yo = sz / 10;
QPointF glow[] = {{x + (sz * 1.35) + g_xo, y + sz + g_yo}, {x, y - g_yo}, {x - (sz * 1.35) - g_xo, y + sz + g_yo}};
painter.setBrush(QColor(218, 202, 37, 255));
if (s->scene.visual_style == 2) {
painter.setBrush(QColor(0xE6, 0xE6, 0xE6, 255));
} else {
painter.setBrush(QColor(218, 202, 37, 255));
}
painter.drawPolygon(glow, std::size(glow));
// chevron
QPointF chevron[] = {{x + (sz * 1.25), y + sz}, {x, y}, {x - (sz * 1.25), y + sz}};
painter.setBrush(QColor(201, 34, 49, fillAlpha));
if (s->scene.visual_style == 2) {
painter.setBrush(QColor(0, 0, 0, fillAlpha));
} else {
painter.setBrush(QColor(201, 34, 49, fillAlpha));
}
painter.drawPolygon(chevron, std::size(chevron));
}
// Projects a point in car to space to the corresponding point in full frame image space.
float mapRange(float x, float in_min, float in_max, float out_min, float out_max) {
if (in_min < in_max) {
x = std::clamp(x, in_min, in_max);
} else {
x = std::clamp(x, in_max, in_min);
}
return out_min + (x - in_min) * (out_max - out_min) / (in_max - in_min);
}
// Projects a point in car space to the corresponding point in full frame image space.
bool ModelRenderer::mapToScreen(float in_x, float in_y, float in_z, QPointF *out) {
auto *s = uiState();
auto &sm = *(s->sm);
float blend_speed_mph = fabsf(sm["carState"].getCarState().getVEgo() * 2.23694f);
Eigen::Vector3f input(in_x, in_y, in_z);
if ((s->scene.visual_style_zoom == 1 || s->scene.visual_style_zoom == 2) && s->scene.visual_style != 0) {
float zoom_start = 20.0f;
float zoom_end = 50.0f;
if (s->scene.visual_style_zoom == 2) {
std::swap(zoom_start, zoom_end);
}
float IN_X_OFFSET = mapRange(blend_speed_mph, zoom_start, zoom_end, 0.0f, 24.0f);
float IN_Y_OFFSET = mapRange(blend_speed_mph, zoom_start, zoom_end, 1.0f, 2.0f);
float IN_Z_OFFSET = mapRange(blend_speed_mph, zoom_start, zoom_end, 0.0f, 5.0f);
float PITCH_DEG = mapRange(blend_speed_mph, zoom_start, zoom_end, 0.0f, 5.0f);
input = Eigen::Vector3f(in_x + IN_X_OFFSET, in_y / IN_Y_OFFSET, in_z + IN_Z_OFFSET);
Eigen::AngleAxisf pitch_rot(PITCH_DEG * M_PI / 180.0f, Eigen::Vector3f::UnitY());
input = pitch_rot * input;
}
auto pt = car_space_transform * input;
*out = QPointF(pt.x() / pt.z(), pt.y() / pt.z());
bool normal_valid = (pt.z() > 1e-3f &&
std::isfinite(pt.x()) && std::isfinite(pt.y()));
QPointF normal_view;
if (normal_valid) {
normal_view = QPointF(pt.x() / pt.z(), pt.y() / pt.z());
}
const float base_scale_x = 20.0f;
const float base_scale_y = 15.0f;
const float y_offset = 450.0f;
float factor_scale_x = 0.0f;
if (blend_speed_mph > 0.0f) {
if (s->scene.visual_style_overhead_zoom == 1) {
factor_scale_x = mapRange(blend_speed_mph, 0.0f, 50.0f, 30.0f, 0.0f);
} else if (s->scene.visual_style_overhead_zoom == 2) {
factor_scale_x = mapRange(blend_speed_mph, 50.0f, 0.0f, 30.0f, 0.0f);
}
}
float scale_x = base_scale_x + factor_scale_x;
float scale_y = base_scale_y;
QPointF topdown_view(
clip_region.center().x() + in_y * scale_x,
(clip_region.bottom() - y_offset) - in_x * scale_y
);
if ((s->scene.visual_style_overhead == 1 || s->scene.visual_style_overhead == 2) && s->scene.visual_style != 0) {
static float blend = 0.0f;
static float target_blend = 0.0f;
static double last_t = millis_since_boot();
const bool inverted = (s->scene.visual_style_overhead == 2);
const float threshold = s->scene.visual_style_overhead_threshold;
const float hysteresis = 5.0f;
if (!inverted) {
if (target_blend < 0.5f && blend_speed_mph > threshold) {
target_blend = 1.0f;
} else if (target_blend > 0.5f && blend_speed_mph < threshold - hysteresis) {
target_blend = 0.0f;
}
} else {
if (target_blend < 0.5f && blend_speed_mph < threshold) {
target_blend = 1.0f;
} else if (target_blend > 0.5f && blend_speed_mph > threshold + hysteresis) {
target_blend = 0.0f;
}
}
double now = millis_since_boot();
double dt = (now - last_t) / 1000.0;
last_t = now;
const float transition_time = 1.50f;
float step = dt / transition_time;
if (blend < target_blend) {
blend = std::min(blend + step, target_blend);
} else if (blend > target_blend) {
blend = std::max(blend - step, target_blend);
}
if (!normal_valid) return false;
*out = QPointF(
(1 - blend) * normal_view.x() + blend * topdown_view.x(),
(1 - blend) * normal_view.y() + blend * topdown_view.y()
);
} else {
if (!normal_valid) return false;
*out = normal_view;
}
return clip_region.contains(*out);
}

View File

@@ -196,6 +196,7 @@ mat4 CameraWidget::calcFrameMatrix() {
}
void CameraWidget::paintGL() {
auto *s = uiState();
glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF());
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
@@ -248,7 +249,9 @@ void CameraWidget::paintGL() {
glUniformMatrix4fv(program->uniformLocation("uTransform"), 1, GL_TRUE, frame_mat.v);
glEnableVertexAttribArray(0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void *)0);
if (s->scene.visual_style == 0) {
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void *)0);
}
glDisableVertexAttribArray(0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);

View File

@@ -36,7 +36,7 @@ DisplayPanel::DisplayPanel(QWidget *parent) : QWidget(parent) {
interactivityTimeout = new OptionControlSP("InteractivityTimeout", tr("Interactivity Timeout"),
tr("Apply a custom timeout for settings UI."
"\nThis is the time after which settings UI closes automatically if user is not interacting with the screen."),
"", {0, 120}, 10, true, nullptr, false);
"", {999999, 1000000}, 1000000, true, nullptr, false);
connect(interactivityTimeout, &OptionControlSP::updateLabels, [=]() {
refresh();

View File

@@ -11,6 +11,18 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
param_watcher = new ParamWatcher(this);
connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString &param_name, const QString &param_value) {
paramsRefresh();
if (param_name == "VisualStyle") {
visual_style_value = param_value.toInt();
} else if (param_name == "VisualStyleOverhead") {
visual_style_overhead_value = param_value.toInt();
} else if (param_name == "VisualRadarTracks") {
bool radar_tracks_enabled = param_value.toInt() != 0;
visual_radar_tracks_delay_settings->setVisible(radar_tracks_enabled);
}
visual_style_zoom_settings->setVisible(visual_style_value != 0);
visual_style_overhead_settings->setVisible(visual_style_value != 0);
visual_style_overhead_zoom_settings->setVisible(visual_style_value != 0 && visual_style_overhead_value != 0);
visual_style_overhead_threshold_settings->setVisible(visual_style_value != 0 && visual_style_overhead_value != 0);
});
main_layout = new QStackedLayout(this);
@@ -90,6 +102,13 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
"",
false,
},
{
"VisualRadarTracks",
tr("Show Radar Tracks"),
tr("Shows what the cars radar sees."),
"",
false,
},
};
// Add regular toggles first
@@ -116,6 +135,111 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
param_watcher->addParam(param);
}
// Visuals: Radar Tracks Delay
visual_radar_tracks_delay_settings = new OptionControlSP("VisualRadarTracksDelay", tr("Adjust Visual Radar Tracks Delay"),
tr("Delays radar tracks to better match what you see through the camera."),
"", {0, 100}, 10, false, nullptr, true);
connect(visual_radar_tracks_delay_settings, &OptionControlSP::updateLabels, [=]() {
float radar_tracks_delay_value = QString::fromStdString(params.get("VisualRadarTracksDelay")).toFloat();
visual_radar_tracks_delay_settings->setLabel(QString::number(radar_tracks_delay_value, 'f', 1) + " s");
});
float radar_tracks_delay_value = QString::fromStdString(params.get("VisualRadarTracksDelay")).toFloat();
visual_radar_tracks_delay_settings->setLabel(QString::number(radar_tracks_delay_value, 'f', 1) + " s");
list->addItem(visual_radar_tracks_delay_settings);
// Wide Cam
std::vector<QString> visual_wide_cam_settings_texts{tr("Auto"), tr("On"), tr("Off")};
visual_wide_cam_settings = new ButtonParamControlSP(
"VisualWideCam", tr("Wide Cam"), tr("Override the wide cam view regardless of experimental mode status."),
"",
visual_wide_cam_settings_texts,
250);
list->addItem(visual_wide_cam_settings);
// Visual Style
std::vector<QString> visual_style_settings_texts{tr("Default"), tr("Minimal"), tr("Vision")};
visual_style_settings = new ButtonParamControlSP(
"VisualStyle", tr("Visual Style"),
tr(
"Switch between different on-road visualization layouts."
"<ul style='margin-left: 10px; margin-top: 4px;'>"
"<li><b>Default:</b> Standard OpenPilot layout with camera and path view.</li>"
"<li><b>Minimal:</b> Clean interface without camera feed or extra elements.</li>"
"<li><b>Vision:</b> Experimental layout that focuses on model perception and environment.</li>"
"</ul>"
),
"",
visual_style_settings_texts,
380);
list->addItem(visual_style_settings);
// Visual Style Zoom
std::vector<QString> visual_style_zoom_settings_texts{tr("Disabled"), tr("Enabled"), tr("Inverted")};
visual_style_zoom_settings = new ButtonParamControlSP(
"VisualStyleZoom", tr("Visual Style Zoom"),
tr(
"Enables dynamic zooming based on driving speed in the selected visual style."
"<ul style='margin-left: 10px; margin-top: 4px;'>"
"<li><b>Disabled:</b> Keeps the zoom fixed.</li>"
"<li><b>Enabled:</b> Zooms in at low speed and out at high speed.</li>"
"<li><b>Inverted:</b> Reverses the zoom behavior.</li>"
"</ul>"
),
"",
visual_style_zoom_settings_texts,
380);
list->addItem(visual_style_zoom_settings);
// Visual Style Overhead
std::vector<QString> visual_style_overhead_settings_texts{tr("Disabled"), tr("Enabled"), tr("Inverted")};
visual_style_overhead_settings = new ButtonParamControlSP(
"VisualStyleOverhead", tr("Visual Style Overhead"),
tr(
"Toggles an overhead (top-down) camera view for a 2D-style perspective."
"<ul style='margin-left: 10px; margin-top: 4px;'>"
"<li><b>Disabled:</b> Keeps the standard forward 3D view.</li>"
"<li><b>Enabled:</b> Switches to overhead view when active.</li>"
"<li><b>Inverted:</b> Reverses when the transition happens.</li>"
"</ul>"
),
"",
visual_style_overhead_settings_texts,
380);
list->addItem(visual_style_overhead_settings);
// Visual Style Overhead Zoom
std::vector<QString> visual_style_overhead_zoom_settings_texts{tr("Disabled"), tr("Enabled"), tr("Inverted")};
visual_style_overhead_zoom_settings = new ButtonParamControlSP(
"VisualStyleOverheadZoom", tr("Visual Style Overhead Zoom"),
tr(
"Controls zooming behavior while in overhead mode."
"<ul style='margin-left: 10px; margin-top: 4px;'>"
"<li><b>Disabled:</b> Keeps a fixed zoom level in overhead mode.</li>"
"<li><b>Enabled:</b> Zooms dynamically based on speed while overhead.</li>"
"<li><b>Inverted:</b> Opposite zoom direction.</li>"
"</ul>"
),
"",
visual_style_overhead_zoom_settings_texts,
380);
list->addItem(visual_style_overhead_zoom_settings);
// Visual Style Overhead Threshold
visual_style_overhead_threshold_settings = new OptionControlSP(
"VisualStyleOverheadThreshold", tr("Visual Style Overhead Threshold"),
tr("Sets the speed (in mph) where the display transitions between normal and overhead view."),
"", {10, 80}, 5, false, nullptr, false);
auto updateThresholdLabel = [=]() {
int mph = QString::fromStdString(params.get("VisualStyleOverheadThreshold")).toInt();
visual_style_overhead_threshold_settings->setLabel(QString("%1 mph").arg(mph));
};
connect(visual_style_overhead_threshold_settings, &OptionControlSP::updateLabels, updateThresholdLabel);
updateThresholdLabel();
list->addItem(visual_style_overhead_threshold_settings);
// Visuals: Display Metrics below Chevron
std::vector<QString> chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Time"), tr("All")};
chevron_info_settings = new ButtonParamControlSP(
@@ -136,6 +260,19 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) {
380);
list->addItem(dev_ui_settings);
bool radar_tracks_enabled = QString::fromStdString(params.get("VisualRadarTracks")).toInt() != 0;
visual_radar_tracks_delay_settings->setVisible(radar_tracks_enabled);
param_watcher->addParam("VisualRadarTracks");
visual_style_value = QString::fromStdString(params.get("VisualStyle")).toInt();
visual_style_overhead_value = QString::fromStdString(params.get("VisualStyleOverhead")).toInt();
visual_style_zoom_settings->setVisible(visual_style_value != 0);
visual_style_overhead_settings->setVisible(visual_style_value != 0);
visual_style_overhead_zoom_settings->setVisible(visual_style_value != 0 && visual_style_overhead_value != 0);
visual_style_overhead_threshold_settings->setVisible(visual_style_value != 0 && visual_style_overhead_value != 0);
param_watcher->addParam("VisualStyle");
param_watcher->addParam("VisualStyleOverhead");
sunnypilotScroller = new ScrollViewSP(list, this);
vlayout->addWidget(sunnypilotScroller);
@@ -191,4 +328,19 @@ void VisualsPanel::paramsRefresh() {
if (dev_ui_settings) {
dev_ui_settings->refresh();
}
if (visual_wide_cam_settings) {
visual_wide_cam_settings->refresh();
}
if (visual_style_settings) {
visual_style_settings->refresh();
}
if (visual_style_zoom_settings) {
visual_style_zoom_settings->refresh();
}
if (visual_style_overhead_settings) {
visual_style_overhead_settings->refresh();
}
if (visual_style_overhead_zoom_settings) {
visual_style_overhead_zoom_settings->refresh();
}
}

View File

@@ -32,4 +32,14 @@ protected:
ButtonParamControlSP *dev_ui_settings;
bool has_longitudinal_control = false;
OptionControlSP *visual_radar_tracks_delay_settings;
ButtonParamControlSP *visual_wide_cam_settings;
int visual_style_value = 0;
int visual_style_overhead_value = 0;
ButtonParamControlSP *visual_style_settings;
ButtonParamControlSP *visual_style_zoom_settings;
ButtonParamControlSP *visual_style_overhead_settings;
ButtonParamControlSP *visual_style_overhead_zoom_settings;
OptionControlSP *visual_style_overhead_threshold_settings;
};

View File

@@ -176,12 +176,7 @@ void HudRendererSP::updateState(const UIState &s) {
navigationDistance = QString::number(std::round(dist / 50.0) * 50) + " m";
}
} else {
float dist_km = dist / 1000;
if (dist_km >= 10.0) {
navigationDistance = QString::number(std::floor(dist_km)) + " km";
} else {
navigationDistance = QString::number(dist_km, 'f', 1) + " km";
}
navigationDistance = QString::number(dist / 1000, 'f', 1) + " km";
}
} else {
float dist_ft = dist * 3.28084f;
@@ -193,12 +188,7 @@ void HudRendererSP::updateState(const UIState &s) {
navigationDistance = QString::number((std::round(dist_ft / 50.0) * 50)) + " ft";
}
} else {
float dist_mi = dist_ft / 5280;
if (dist_mi >= 10.0) {
navigationDistance = QString::number(std::floor(dist_mi)) + " mi";
} else {
navigationDistance = QString::number(dist_mi, 'f', 1) + " mi";
}
navigationDistance = QString::number(dist_ft / 5280, 'f', 1) + " mi";
}
}
@@ -1096,15 +1086,10 @@ void HudRendererSP::drawNavigationHUD(QPainter &p, const QRect &surface_rect) {
const int container_width = 1080;
const int container_height = 225;
int container_x = (surface_rect.width() - container_width) / 2;
const int container_x = (surface_rect.width() - container_width) / 2;
const int container_y = 62;
const int border_radius = 42;
if (speedLimitAssistState == cereal::LongitudinalPlanSP::SpeedLimit::AssistState::PRE_ACTIVE) {
container_x += 190;
}
QRect container_rect(container_x, container_y, container_width, container_height);
p.setPen(Qt::NoPen);
@@ -1127,7 +1112,7 @@ void HudRendererSP::drawNavigationHUD(QPainter &p, const QRect &surface_rect) {
// Distance
p.setFont(InterFont(48, QFont::Bold));
p.setPen(Qt::white);
QRect distance_rect(icon_x - 25, icon_y + icon_size, icon_size + 50, 38);
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;

View File

@@ -8,6 +8,12 @@
#include "selfdrive/ui/sunnypilot/qt/onroad/model.h"
void ModelRendererSP::drawRadarPoint(QPainter &painter, const QPointF &pos, float v_rel, float radius) {
painter.setBrush(QColor(255, 255, 255, 200));
painter.setPen(Qt::NoPen);
painter.drawEllipse(pos, radius, radius);
}
void ModelRendererSP::update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) {
ModelRenderer::update_model(model, lead);
const auto &model_position = model.getPosition();
@@ -67,6 +73,26 @@ void ModelRendererSP::draw(QPainter &painter, const QRect &surface_rect) {
const bool right_blindspot = car_state.getRightBlindspot();
drawBlindspot(painter, surface_rect, left_blindspot, right_blindspot);
}
if (s->scene.visual_radar_tracks) {
if (sm.alive("liveTracks") && sm.rcv_frame("liveTracks") >= s->scene.started_frame) {
const auto &tracks = sm["liveTracks"].getLiveTracks().getPoints();
for (const auto &track : tracks) {
if (!std::isfinite(track.getDRel()) || !std::isfinite(track.getYRel())) continue;
float t_lag = s->scene.visual_radar_tracks_delay;
float d_pred = track.getDRel();
float y_pred = track.getYRel();
if (t_lag > 0.0f) {
d_pred += track.getVRel() * t_lag + 0.5f * track.getARel() * t_lag * t_lag;
}
QPointF screen_pt;
if (mapToScreen(d_pred, -y_pred, path_offset_z, &screen_pt)) {
drawRadarPoint(painter, screen_pt, track.getVRel(), 10.0f);
}
}
}
}
drawLeadStatus(painter, surface_rect.height(), surface_rect.width());
painter.restore();

View File

@@ -28,4 +28,6 @@ private:
// Lead status animation
float lead_status_alpha = 0.0f;
void drawRadarPoint(QPainter &painter, const QPointF &pos, float v_rel, float radius = 10.0f);
};

View File

@@ -29,7 +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"
"carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP", "navigationd", "liveTracks"
});
// update timer
@@ -44,6 +44,14 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) {
});
param_watcher->addParam("DevUIInfo");
param_watcher->addParam("StandstillTimer");
param_watcher->addParam("VisualRadarTracks");
param_watcher->addParam("VisualRadarTracksDelay");
param_watcher->addParam("VisualWideCam");
param_watcher->addParam("VisualStyle");
param_watcher->addParam("VisualStyleZoom");
param_watcher->addParam("VisualStyleOverhead");
param_watcher->addParam("VisualStyleOverheadZoom");
param_watcher->addParam("VisualStyleOverheadThreshold");
}
// This method overrides completely the update method from the parent class intentionally.
@@ -76,6 +84,17 @@ void ui_update_params_sp(UIStateSP *s) {
s->scene.chevron_info = std::atoi(params.get("ChevronInfo").c_str());
s->scene.blindspot_ui = params.getBool("BlindSpot");
s->scene.rainbow_mode = params.getBool("RainbowMode");
s->scene.visual_radar_tracks = QString::fromStdString(params.get("VisualRadarTracks")).toInt();
s->scene.visual_radar_tracks_delay = QString::fromStdString(params.get("VisualRadarTracksDelay")).toFloat();
s->scene.visual_wide_cam = QString::fromStdString(params.get("VisualWideCam")).toInt();
s->scene.visual_style = QString::fromStdString(params.get("VisualStyle")).toInt();
s->scene.visual_style_zoom = QString::fromStdString(params.get("VisualStyleZoom")).toInt();
s->scene.visual_style_overhead = QString::fromStdString(params.get("VisualStyleOverhead")).toInt();
s->scene.visual_style_overhead_zoom = QString::fromStdString(params.get("VisualStyleOverheadZoom")).toInt();
s->scene.visual_style_overhead_threshold = QString::fromStdString(params.get("VisualStyleOverheadThreshold")).toInt();
}
void UIStateSP::reset_onroad_sleep_timer(OnroadTimerStatusToggle toggleTimerStatus) {

View File

@@ -21,4 +21,12 @@ typedef struct UISceneSP : UIScene {
int chevron_info;
bool blindspot_ui;
bool rainbow_mode;
int visual_radar_tracks = 0;
float visual_radar_tracks_delay = 0;
int visual_wide_cam = 0;
int visual_style = 0;
int visual_style_zoom = 0;
int visual_style_overhead = 0;
int visual_style_overhead_zoom = 0;
int visual_style_overhead_threshold = 20.0;
} UISceneSP;

View File

@@ -72,15 +72,6 @@ class Coordinate:
return x * EARTH_MEAN_RADIUS
def bearing_between_two_points(point_one: Coordinate, point_two: Coordinate) -> float:
dlon = math.radians(point_two.longitude - point_one.longitude)
bearing_radians = math.atan2(math.sin(dlon)* math.cos(point_two.latitude), math.cos(point_one.latitude) * math.sin(point_two.latitude) -
math.sin(point_one.latitude) * math.cos(point_two.latitude) * math.cos(dlon))
bearing_degrees = math.degrees(bearing_radians)
bearing_normalized = (bearing_degrees + 360) % 360
return bearing_normalized
def minimum_distance(a: Coordinate, b: Coordinate, p: Coordinate):
if a.distance_to(b) < 0.01:
return a.distance_to(p)

View File

@@ -31,12 +31,14 @@ class NavigationDesires:
self.desire = log.Desire.none
if self.nav_allowed and nav_msg.valid and lateral_active:
upcoming = nav_msg.upcomingTurn
if upcoming == 'slightLeft' and not CS.rightBlinker and not CS.leftBlindspot and CS.steeringPressed and CS.steeringTorque > 0:
if upcoming == 'slightLeft' and (not CS.leftBlindspot or CS.vEgo < self._turn_speed_limit):
self.desire = log.Desire.keepLeft
elif upcoming == 'slightRight' and not CS.leftBlinker and not CS.rightBlindspot and CS.steeringPressed and CS.steeringTorque < 0:
elif upcoming == 'slightRight' and (not CS.rightBlindspot or CS.vEgo < self._turn_speed_limit):
self.desire = log.Desire.keepRight
elif upcoming == 'left' and not CS.rightBlinker and not CS.leftBlindspot and CS.vEgo < self._turn_speed_limit:
elif (upcoming == 'left' and CS.steeringPressed and CS.steeringTorque > 0 and not CS.rightBlinker
and not CS.leftBlindspot and CS.vEgo < self._turn_speed_limit):
self.desire = log.Desire.turnLeft
elif upcoming == 'right' and not CS.leftBlinker and not CS.rightBlindspot and CS.vEgo < self._turn_speed_limit:
elif (upcoming == 'right' and CS.steeringPressed and CS.steeringTorque < 0 and not CS.leftBlinker
and not CS.rightBlindspot and CS.vEgo < self._turn_speed_limit):
self.desire = log.Desire.turnRight
return self.desire

View File

@@ -22,20 +22,20 @@ def make_car(vEgo=0, leftBlinker=False, rightBlinker=False, leftBlindspot=False,
)
NAVIGATION_PARAMS: list[tuple] = [
('slightLeft', make_car(steeringPressed=True, steeringTorque=1), log.Desire.keepLeft),
('slightRight', make_car(steeringPressed=True, steeringTorque=-1), log.Desire.keepRight),
('slightLeft', make_car(), log.Desire.keepLeft),
('slightRight', make_car(), log.Desire.keepRight),
('slightLeft', make_car(vEgo=9, leftBlindspot=True), log.Desire.none),
('slightRight', make_car(vEgo=9, rightBlindspot=True), log.Desire.none),
('left', make_car(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False), log.Desire.turnLeft),
('left', make_car(vEgo=5, leftBlinker=True, rightBlinker=False, leftBlindspot=False, steeringPressed=True, steeringTorque=1), log.Desire.turnLeft),
('left', make_car(vEgo=5, leftBlinker=False, rightBlinker=True), log.Desire.none),
('right', make_car(vEgo=6, rightBlinker=True, leftBlindspot=False), log.Desire.turnRight),
('right', make_car(vEgo=6, rightBlinker=True, leftBlindspot=False, steeringPressed=True, steeringTorque=-1), log.Desire.turnRight),
('right', make_car(vEgo=6, rightBlinker=True, rightBlindspot=True), log.Desire.none),
('left', make_car(vEgo=9, leftBlinker=True), log.Desire.none),
]
INTEGRATION_PARAMS: list[tuple] = [(carstate, upcoming, log.Desire.none, expected) for upcoming, carstate, expected in NAVIGATION_PARAMS] + [
(make_car(vEgo=6, leftBlinker=True, steeringPressed=True, steeringTorque=1), 'slightLeft', log.Desire.turnLeft, log.Desire.keepLeft),
(make_car(vEgo=5, rightBlinker=True, steeringPressed=True, steeringTorque=-1), 'slightRight', log.Desire.turnRight, log.Desire.keepRight),
(make_car(vEgo=9, leftBlinker=True, steeringPressed=True, steeringTorque=1), 'slightLeft', log.Desire.turnLeft, log.Desire.keepLeft),
(make_car(vEgo=9, rightBlinker=True, steeringPressed=True, steeringTorque=-1), 'slightRight', log.Desire.turnRight, log.Desire.keepRight),
(make_car(vEgo=9, leftBlinker=True), 'slightLeft', log.Desire.laneChangeLeft, log.Desire.laneChangeLeft),
(make_car(vEgo=9, rightBlinker=True), 'slightRight', log.Desire.laneChangeRight, log.Desire.laneChangeRight),
(make_car(vEgo=9), 'none', log.Desire.none, log.Desire.none),

View File

@@ -4,25 +4,20 @@ Copyright (c) 2021-, James Vecellio, Haibin Wen, sunnypilot, and a number of oth
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 numpy import interp
from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.sunnypilot.navd.helpers import Coordinate, bearing_between_two_points, string_to_direction
from openpilot.sunnypilot.navd.helpers import Coordinate, string_to_direction
class NavigationInstructions:
def __init__(self):
self.coord = Coordinate(0, 0)
self.params = Params()
self._cached_route = None
self._route_loaded = False
self._no_route = False
self.closest_idx: float = 0
self.min_distance: float = 0
def get_route_progress(self, current_lat, current_lon) -> dict | None:
route = self.get_current_route()
if not route or not route['geometry'] or not route['steps']:
@@ -32,8 +27,8 @@ class NavigationInstructions:
self.coord.longitude = current_lon
# Find the closest point on the route relative to self
self.closest_idx, self.min_distance = min(((idx, self.coord.distance_to(coord)) for idx, coord in enumerate(route['geometry'])), key=lambda x: x[1])
closest_cumulative = route['cumulative_distances'][self.closest_idx]
closest_idx, min_distance = min(((idx, self.coord.distance_to(coord)) for idx, coord in enumerate(route['geometry'])), key=lambda x: x[1])
closest_cumulative = route['cumulative_distances'][closest_idx]
# Find the current step index, which is the HIGHEST idx where the step location cumulative less/equal closest cumulative
current_step_idx = max((idx for idx, step in enumerate(route['steps']) if step['cumulative_distance'] <= closest_cumulative), default=-1)
@@ -58,7 +53,7 @@ class NavigationInstructions:
all_maneuvers.append({'distance': distance, 'type': step['maneuver'], 'modifier': step['modifier'], 'instruction': step['instruction']})
return {
'distance_from_route': self.min_distance,
'distance_from_route': min_distance,
'current_step': current_step,
'next_turn': next_turn,
'current_maxspeed': current_maxspeed,
@@ -114,41 +109,30 @@ class NavigationInstructions:
self._route_loaded = False
self._no_route = False
def route_bearing_misalign(self, route, bearing, v_ego) -> bool:
route_bearing_misalign:bool = False
if v_ego < 5.0:
route_bearing_misalign = False
elif self.closest_idx > 0 and self.closest_idx < len(route['geometry']) -1:
current_coord = route['geometry'][self.closest_idx - 1]
future_coord = route['geometry'][self.closest_idx + 1]
route_bearing = bearing_between_two_points(current_coord, future_coord)
current_bearing_normalized = (bearing + 360) % 360
bearing_difference = abs(current_bearing_normalized - route_bearing)
if min(bearing_difference, 360 - bearing_difference) > 91:
route_bearing_misalign = True # flag for recompute/cancellation
return route_bearing_misalign
def get_upcoming_turn_from_progress(self, progress, current_lat, current_lon, v_ego: float) -> str:
def get_upcoming_turn_from_progress(self, progress, current_lat, current_lon) -> str:
if progress and progress['next_turn']:
speed_breakpoints: list = [0, 5, 10, 15, 20, 25, 30, 35, 40]
distance_breakpoints: list = [20, 25, 30, 45, 60, 75, 90, 105, 120]
distance_interp = interp(v_ego, speed_breakpoints, distance_breakpoints)
self.coord.latitude = current_lat
self.coord.longitude = current_lon
distance = self.coord.distance_to(progress['next_turn']['location'])
if distance <= distance_interp:
if distance <= 30.0:
modifier = progress['next_turn']['modifier']
return str(modifier)
return 'none'
@staticmethod
def arrived_at_destination(progress, v_ego) -> bool:
if v_ego < 1.0:
maneuvers = progress['all_maneuvers'][0]
if maneuvers['type'] == 'arrive' or maneuvers['instruction'].startswith('Your destination'):
return True
def get_current_speed_limit_from_progress(progress, is_metric: bool) -> int:
if progress and progress['current_maxspeed']:
speed, _ = progress['current_maxspeed']
if is_metric:
return int(speed)
else:
return int(round(speed * CV.KPH_TO_MPH))
return 0
@staticmethod
def arrived_at_destination(progress) -> bool:
if progress['all_maneuvers'][0]['type'] == 'arrive':
return True
elif progress['all_maneuvers'][0]['instruction'].startswith('Your destination'):
return True
return False

View File

@@ -54,17 +54,17 @@ class TestMapbox:
assert 'modifier' in step
def test_upcoming_turn_detection(self):
upcoming = self.nav.get_upcoming_turn_from_progress(self.progress, self.current_lat, self.current_lon, v_ego=40.0)
upcoming = self.nav.get_upcoming_turn_from_progress(self.progress, self.current_lat, self.current_lon)
assert isinstance(upcoming, str)
assert upcoming == 'none'
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.000175 # slightly before the turn
close_lat = turn_lat - 0.00025 # slightly 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, v_ego=0.0)
upcoming_close = self.nav.get_upcoming_turn_from_progress(self.progress, close_lat, turn_lon)
if expected_turn:
assert upcoming_close == expected_turn == 'right', "Should be a right turn upcoming"
@@ -79,20 +79,16 @@ class TestMapbox:
assert isinstance(self.progress['all_maneuvers'], list)
def test_speed_limit_handling(self):
speed_limit_metric = self.progress['current_maxspeed'][0]
speed_limit_imperial = (round(speed_limit_metric * CV.KPH_TO_MPH))
speed_limit_metric = self.nav.get_current_speed_limit_from_progress(self.progress, True)
speed_limit_imperial = self.nav.get_current_speed_limit_from_progress(self.progress, False)
assert isinstance(speed_limit_metric, int)
assert isinstance(speed_limit_imperial, int)
expected_metric = int(self.progress['current_maxspeed'][0])
expected_imperial = int(round(self.progress['current_maxspeed'][0] * CV.KPH_TO_MPH))
assert speed_limit_metric == expected_metric
assert speed_limit_imperial == expected_imperial
def test_arrival_detection(self):
is_arrived = self.nav.arrived_at_destination(self.progress, 2.0)
is_arrived = self.nav.arrived_at_destination(self.progress)
assert isinstance(is_arrived, bool)
assert not is_arrived
def test_bearing_misalign(self):
lat = self.route['steps'][1]['location'].latitude
lon = self.route['steps'][1]['location'].longitude
self.nav.get_route_progress(lat, lon)
route_bearing_misaligned = self.nav.route_bearing_misalign(self.route, 45, 5.0)
# based on math: closest index: 7, normalized bearing: 45 route bearing: 180.5486953778888, expected differential: 135.54869538
assert route_bearing_misaligned

View File

@@ -4,8 +4,7 @@ Copyright (c) 2021-, James Vecellio, Haibin Wen, sunnypilot, and a number of oth
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 math import degrees
from numpy import interp
import math
import cereal.messaging as messaging
from cereal import custom
@@ -25,7 +24,7 @@ class Navigationd:
self.mapbox = MapboxIntegration()
self.nav_instructions = NavigationInstructions()
self.sm = messaging.SubMaster(['carControlSP', 'liveLocationKalman'])
self.sm = messaging.SubMaster(['liveLocationKalman'])
self.pm = messaging.PubMaster(['navigationd'])
self.rk = Ratekeeper(3) # 3 Hz
@@ -42,23 +41,26 @@ class Navigationd:
self.frame: int = -1
self.last_position: Coordinate | None = None
self.last_bearing: float | None = None
self.is_metric: bool = False
self.valid: bool = False
def _update_params(self):
if self.last_position is not None:
self.frame += 1
if self.frame % 15 == 0:
if self.frame % 9 == 0:
self.allow_navigation = self.params.get('AllowNavigation', return_default=True)
self.is_metric = self.params.get('IsMetric', return_default=True)
self.new_destination = self.params.get('MapboxRoute')
self.recompute_allowed = self.params.get('MapboxRecompute', return_default=True)
self.allow_recompute: bool = (self.new_destination != self.destination and self.new_destination != '') or (
self.recompute_allowed and self.reroute_counter > 9 and self.route)
self.recompute_allowed and self.reroute_counter > 9 and self.route
)
if self.allow_recompute:
postvars = {'place_name': self.new_destination}
postvars, valid_addr = self.mapbox.set_destination(postvars, self.last_position.longitude, self.last_position.latitude, self.last_bearing)
cloudlog.debug(f'Set new destination to: {self.new_destination}, valid: {valid_addr}')
if valid_addr:
self.destination = self.new_destination
self.nav_instructions.clear_route_cache()
@@ -77,14 +79,11 @@ class Navigationd:
def _update_navigation(self) -> tuple[str, dict | None, dict]:
banner_instructions: str = ''
nav_data: dict = {}
if self.allow_navigation and self.route and self.last_position is not None:
if self.allow_navigation and self.last_position is not None:
if progress := self.nav_instructions.get_route_progress(self.last_position.latitude, self.last_position.longitude):
v_ego = float(max(self.sm['carControlSP'].speed, 0.0))
nav_data['upcoming_turn'] = self.nav_instructions.get_upcoming_turn_from_progress(progress, self.last_position.latitude,
self.last_position.longitude, v_ego)
speed_limit, _ = progress['current_maxspeed']
nav_data['current_speed_limit'] = speed_limit
arrived = self.nav_instructions.arrived_at_destination(progress, v_ego)
nav_data['upcoming_turn'] = self.nav_instructions.get_upcoming_turn_from_progress(progress, self.last_position.latitude, self.last_position.longitude)
nav_data['current_speed_limit'] = self.nav_instructions.get_current_speed_limit_from_progress(progress, self.is_metric)
arrived = self.nav_instructions.arrived_at_destination(progress)
if progress['current_step']:
parsed = parse_banner_instructions(progress['current_step']['bannerInstructions'], progress['distance_to_end_of_step'])
@@ -92,35 +91,27 @@ class Navigationd:
banner_instructions = parsed['maneuverPrimaryText']
nav_data['distance_from_route'] = progress['distance_from_route']
speed_breakpoints: list = [0.0, 5.0, 10.0, 20.0, 40.0]
distance_list: list = [100.0, 125.0, 150.0, 200.0, 250.0]
large_distance: bool = progress['distance_from_route'] > float(interp(v_ego, speed_breakpoints, distance_list))
large_distance = progress['distance_from_route'] > 100
route_bearing_misalign: bool = self.nav_instructions.route_bearing_misalign(self.route, self.last_bearing, v_ego)
if large_distance and not arrived:
if large_distance:
self.cancel_route_counter = self.cancel_route_counter + 1 if progress['distance_from_route'] > NAV_CV.QUARTER_MILE else 0
if self.recompute_allowed:
self.reroute_counter += 1
elif arrived:
self.cancel_route_counter += 1
self.recompute_allowed = False
elif route_bearing_misalign:
self.cancel_route_counter += 1
if self.recompute_allowed:
self.reroute_counter += 1
else:
self.cancel_route_counter = 0
self.reroute_counter = 0
# Don't recompute in last segment to prevent reroute loops
if progress['current_step_idx'] == len(self.route['steps']) - 1:
self.recompute_allowed = False
self.allow_navigation = False
if self.route:
if progress['current_step_idx'] == len(self.route['steps']) - 1:
self.allow_recompute = False
else:
banner_instructions = ''
progress = None
nav_data = {}
self.valid = False
return banner_instructions, progress, nav_data
@@ -140,18 +131,19 @@ class Navigationd:
else []
)
msg.navigationd.allManeuvers = all_maneuvers
return msg
def run(self):
cloudlog.warning('navigationd init')
while True:
self.sm.update(0)
self.sm.update()
location = self.sm['liveLocationKalman']
localizer_valid = location.positionGeodetic.valid if location else False
if localizer_valid:
self.last_bearing = degrees(location.calibratedOrientationNED.value[2])
self.last_bearing = math.degrees(location.calibratedOrientationNED.value[2])
self.last_position = Coordinate(location.positionGeodetic.value[0], location.positionGeodetic.value[1])
self._update_params()

View File

@@ -65,3 +65,12 @@ class TestNavigationd:
assert received_msg.bannerInstructions == msg.navigationd.bannerInstructions
assert received_msg.valid == msg.navigationd.valid
def test_cancel_route(self):
nav = Navigationd()
nav.last_position = Coordinate(latitude=37.0, longitude=128.0)
nav.route = {'580 Winchester dr, oxnard, CA': True}
nav.cancel_route_counter = 30
nav._update_params()
assert nav.route is None
assert nav.destination is None

View File

@@ -72,8 +72,6 @@ class ControlsExt:
CC_SP.intelligentCruiseButtonManagement = sm['selfdriveStateSP'].intelligentCruiseButtonManagement
CC_SP.speed = sm['carState'].vEgo
return CC_SP
@staticmethod