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
+1
View File
@@ -340,6 +340,7 @@ struct OnroadEventSP @0xda96579883444c35 {
speedLimitChanged @21;
speedLimitPending @22;
e2eChime @23;
navigationBanner @24;
}
}
+1
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"}},
+1 -1
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:
+2 -2
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))
@@ -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
+83
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 []
@@ -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
@@ -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')
+13
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,
},
}