Compare commits

...

49 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
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
discountchubbs
f5953c5d8c Quarter mile is what apple maps uses 2025-11-01 07:57:55 -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
68270a13a3 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-29 19:38:20 -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
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
d8fa3cfd04 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-26 08:45:24 -07:00
discountchubbs
7ddafe62cd Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-23 19:21:25 -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
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
James Vecellio
8998f63a28 oopsie 2025-10-21 16:18:27 -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
87ec262e39 Merge remote-tracking branch 'origin/nav-desires' into nav-events 2025-10-21 12:06:07 -07:00
discountchubbs
da0920cb60 feat: navigationd onroad events 2025-10-21 11:59:13 -07:00
9 changed files with 203 additions and 3 deletions

View File

@@ -340,6 +340,7 @@ struct OnroadEventSP @0xda96579883444c35 {
speedLimitChanged @21;
speedLimitPending @22;
e2eChime @23;
navigationBanner @24;
}
}

View File

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

View File

@@ -27,7 +27,7 @@ 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', gps_location_service],
'liveMapDataSP', 'navigationd', 'carStateSP', gps_location_service],
poll='carState')
while True:

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

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

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

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

View File

@@ -16,6 +16,7 @@ from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.speed_limit_assist
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.speed_limit_resolver import SpeedLimitResolver
from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
from openpilot.sunnypilot.models.helpers import get_active_bundle
from openpilot.sunnypilot.navd.event_builder import EventBuilder
DecState = custom.LongitudinalPlanSP.DynamicExperimentalControl.DynamicExperimentalControlState
LongitudinalPlanSource = custom.LongitudinalPlanSP.LongitudinalPlanSource
@@ -32,6 +33,7 @@ class LongitudinalPlannerSP:
self.generation = int(model_bundle.generation) if (model_bundle := get_active_bundle()) else None
self.source = LongitudinalPlanSource.cruise
self.e2e_alerts_helper = E2EAlertsHelper()
self.event_builder = EventBuilder()
self.output_v_target = 0.
self.output_a_target = 0.
@@ -77,10 +79,16 @@ class LongitudinalPlannerSP:
self.output_v_target, self.output_a_target = targets[self.source]
return self.output_v_target, self.output_a_target
def update_navigation_events(self, sm: messaging.SubMaster) -> None:
nav_events = self.event_builder.update(sm)
for event in nav_events:
self.events_sp.add(event['name'])
def update(self, sm: messaging.SubMaster) -> None:
self.events_sp.clear()
self.dec.update(sm)
self.e2e_alerts_helper.update(sm, self.events_sp)
self.update_navigation_events(sm)
def publish_longitudinal_plan_sp(self, sm: messaging.SubMaster, pm: messaging.PubMaster) -> None:
plan_sp_send = messaging.new_message('longitudinalPlanSP')

View File

@@ -4,6 +4,7 @@ from openpilot.common.constants import CV
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType, wrong_car_mode_alert
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import PCM_LONG_REQUIRED_MAX_SET_SPEED, CONFIRM_SPEED_THRESHOLD
from openpilot.sunnypilot.navd.event_builder import EventBuilder
AlertSize = log.SelfdriveState.AlertSize
@@ -55,6 +56,14 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleLow, .1)
def navigation_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
events = EventBuilder.build_navigation_events(sm, metric)
if not events:
return Alert("", "", AlertStatus.normal, AlertSize.none, Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0.)
return Alert(events[0]['message'], "", AlertStatus.normal, AlertSize.small, Priority.LOW, VisualAlert.none, AudibleAlert.none, 2.)
class EventsSP(EventsBase):
def __init__(self):
super().__init__()
@@ -226,4 +235,8 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
AlertStatus.normal, AlertSize.none,
Priority.MID, VisualAlert.none, AudibleAlert.prompt, 3.),
},
EventNameSP.navigationBanner: {
ET.WARNING: navigation_alert,
},
}