Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add longitudinal maneuvers #33527

Merged
merged 36 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3de57b1
add longitudinal profiles
sshane Sep 9, 2024
5e17e6c
stash
sshane Sep 9, 2024
c1a99d4
unfortunately even longitudinalPlan causes circle
sshane Sep 9, 2024
fdc0cc1
add to process config
sshane Sep 11, 2024
b5e7f45
reach target speed smoothly
sshane Sep 11, 2024
388f1c9
stash
sshane Sep 11, 2024
d74e708
works
sshane Sep 11, 2024
a55ea3f
clean up
sshane Sep 11, 2024
40a1201
debug alert
sshane Sep 11, 2024
8576198
rename
sshane Sep 11, 2024
7ea0406
fix
sshane Sep 11, 2024
8e7786d
better text
sshane Sep 11, 2024
dde59cc
toggle via exp button
sshane Sep 11, 2024
37e73a4
try coming to a stop better, smoother target reaching
sshane Sep 11, 2024
2c9272d
closer to target
sshane Sep 11, 2024
8d414c2
Merge remote-tracking branch 'upstream/master' into long-man
sshane Sep 11, 2024
557c3dd
revert controlsd migration
sshane Sep 11, 2024
17e0fa8
add description to alert
sshane Sep 11, 2024
0f9db4f
generate report from local logs
sshane Sep 11, 2024
d4521ce
hide bad maneuvers
sshane Sep 11, 2024
6d4af1b
pdflike
sshane Sep 11, 2024
3a06ef5
Revert "pdflike"
sshane Sep 11, 2024
e79ff84
try this
sshane Sep 11, 2024
da484a6
use alert manager
sshane Sep 12, 2024
1f2c38f
fix that check
sshane Sep 12, 2024
93d0d27
wat
sshane Sep 12, 2024
6e1414d
Revert "wat"
sshane Sep 12, 2024
0bda3b1
some clean up
sshane Sep 12, 2024
0b9eb4c
rm
sshane Sep 12, 2024
cd86941
cleanup
sshane Sep 12, 2024
afbac32
move
sshane Sep 12, 2024
4eb47eb
fix test
sshane Sep 12, 2024
9173df2
more fix
sshane Sep 12, 2024
a48796a
clean up
sshane Sep 12, 2024
ffaf1b3
fix that
sshane Sep 12, 2024
ca01032
Merge remote-tracking branch 'upstream/master' into long-man
sshane Sep 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cereal/car.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct OnroadEvent @0x9b1657f34caf3ad3 {
manualRestart @30;
lowSpeedLockout @31;
joystickDebug @34;
longitudinalManeuver @124;
steerTempUnavailableSilent @35;
resumeRequired @36;
preDriverDistracted @37;
Expand Down
6 changes: 6 additions & 0 deletions cereal/log.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,11 @@ struct EncodeData {
height @5 :UInt32;
}

struct DebugAlert {
alertText1 @0 :Text;
alertText2 @1 :Text;
}

struct UserFlag {
}

Expand Down Expand Up @@ -2411,6 +2416,7 @@ struct Event {
driverEncodeData @87 :EncodeData;
wideRoadEncodeData @88 :EncodeData;
qRoadEncodeData @89 :EncodeData;
alertDebug @133 :DebugAlert;

livestreamRoadEncodeData @120 :EncodeData;
livestreamWideRoadEncodeData @121 :EncodeData;
Expand Down
1 change: 1 addition & 0 deletions cereal/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(self, should_log: bool, frequency: float, decimation: Optional[int]

# debug
"uiDebug": (True, 0., 1),
"alertDebug": (True, 0.),
"roadEncodeData": (False, 20.),
"driverEncodeData": (False, 20.),
"wideRoadEncodeData": (False, 20.),
Expand Down
1 change: 1 addition & 0 deletions common/params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LiveParameters", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LocationFilterInitialState", PERSISTENT},
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION},
{"LongitudinalPersonality", PERSISTENT},
{"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},
Expand Down
1 change: 1 addition & 0 deletions release/release_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"tools/lib/",
"tools/bodyteleop/",
"tools/joystick/",
"tools/longitudinal_maneuvers/",

"tinygrad_repo/openpilot/compile2.py",
"tinygrad_repo/extra/onnx.py",
Expand Down
16 changes: 16 additions & 0 deletions selfdrive/selfdrived/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,17 @@ def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster,
vals = f"Gas: {round(gb * 100.)}%, Steer: {round(steer * 100.)}%"
return NormalPermanentAlert("Joystick Mode", vals)


def longitudinal_maneuver_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
ad = sm['alertDebug']
audible_alert = AudibleAlert.prompt if 'Active' in ad.alertText1 else AudibleAlert.none
alert_status = AlertStatus.userPrompt if 'Active' in ad.alertText1 else AlertStatus.normal
alert_size = AlertSize.mid if ad.alertText2 else AlertSize.small
return Alert(ad.alertText1, ad.alertText2,
alert_status, alert_size,
Priority.LOW, VisualAlert.none, audible_alert, 0.2)


def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int, personality) -> Alert:
personality = str(personality).title()
return NormalPermanentAlert(f"Driving Personality: {personality}", duration=1.5)
Expand All @@ -344,6 +355,11 @@ def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging
ET.PERMANENT: NormalPermanentAlert("Joystick Mode"),
},

EventName.longitudinalManeuver: {
ET.WARNING: longitudinal_maneuver_alert,
ET.PERMANENT: NormalPermanentAlert("Longitudinal Maneuver Mode"),
},

EventName.selfdriveInitializing: {
ET.NO_ENTRY: NoEntryAlert("System Initializing"),
},
Expand Down
8 changes: 6 additions & 2 deletions selfdrive/selfdrived/selfdrived.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self):
# 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
ignore = self.sensor_packets + self.gps_packets + ['alertDebug']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
if REPLAY:
Expand All @@ -70,7 +70,7 @@ def __init__(self):
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'carOutput', 'driverMonitoringState', 'longitudinalPlan', 'livePose',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'controlsState', 'carControl', 'driverAssistance'] + \
'controlsState', 'carControl', 'driverAssistance', 'alertDebug'] + \
self.camera_packets + self.sensor_packets + self.gps_packets,
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState',],
ignore_valid=ignore, frequency=int(1/DT_CTRL))
Expand Down Expand Up @@ -135,6 +135,10 @@ def update_events(self, CS):
self.events.add(EventName.joystickDebug)
self.startup_event = None

if self.sm.recv_frame['alertDebug'] > 0:
self.events.add(EventName.longitudinalManeuver)
self.startup_event = None

# Add startup event
if self.startup_event is not None:
self.events.add(self.startup_event)
Expand Down
9 changes: 8 additions & 1 deletion system/manager/process_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ def joystick(started: bool, params, CP: car.CarParams) -> bool:
def not_joystick(started: bool, params, CP: car.CarParams) -> bool:
return started and not params.get_bool("JoystickDebugMode")

def long_maneuver(started: bool, params, CP: car.CarParams) -> bool:
return started and params.get_bool("LongitudinalManeuverMode")

def not_long_maneuver(started: bool, params, CP: car.CarParams) -> bool:
return started and not params.get_bool("LongitudinalManeuverMode")

def qcomgps(started, params, CP: car.CarParams) -> bool:
return started and not ublox_available()

Expand Down Expand Up @@ -81,7 +87,8 @@ def only_offroad(started, params, CP: car.CarParams) -> bool:
PythonProcess("paramsd", "selfdrive.locationd.paramsd", only_onroad),
NativeProcess("ubloxd", "system/ubloxd", ["./ubloxd"], ublox, enabled=TICI),
PythonProcess("pigeond", "system.ubloxd.pigeond", ublox, enabled=TICI),
PythonProcess("plannerd", "selfdrive.controls.plannerd", only_onroad),
PythonProcess("plannerd", "selfdrive.controls.plannerd", not_long_maneuver),
PythonProcess("maneuversd", "tools.longitudinal_maneuvers.maneuversd", long_maneuver),
PythonProcess("radard", "selfdrive.controls.radard", only_onroad),
PythonProcess("hardwared", "system.hardware.hardwared", always_run),
PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC),
Expand Down
115 changes: 115 additions & 0 deletions tools/longitudinal_maneuvers/generate_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python3
import argparse
import base64
import io
import os
import time
from pathlib import Path
import matplotlib.pyplot as plt

from openpilot.tools.lib.logreader import LogReader
from openpilot.system.hardware.hw import Paths


def report(platform, maneuvers):
output_path = Path(__file__).resolve().parent / "longitudinal_reports"
output_fn = output_path / f"{platform}_{time.strftime('%Y%m%d-%H_%M_%S')}.html"
output_path.mkdir(exist_ok=True)
with open(output_fn, "w") as f:
f.write("<h1>Longitudinal maneuver report</h1>\n")
f.write(f"<h3>{platform}</h3>\n")
for description, runs in maneuvers:
print('plotting maneuver:', description, 'runs:', len(runs))
f.write("<div style='border-top: 1px solid #000; margin: 20px 0;'></div>\n")
f.write(f"<h2>{description}</h2>\n")
for run, msgs in enumerate(runs):
t_carControl, carControl = zip(*[(m.logMonoTime, m.carControl) for m in msgs if m.which() == 'carControl'], strict=True)
t_carOutput, carOutput = zip(*[(m.logMonoTime, m.carOutput) for m in msgs if m.which() == 'carOutput'], strict=True)
t_carState, carState = zip(*[(m.logMonoTime, m.carState) for m in msgs if m.which() == 'carState'], strict=True)
t_longitudinalPlan, longitudinalPlan = zip(*[(m.logMonoTime, m.longitudinalPlan) for m in msgs if m.which() == 'longitudinalPlan'], strict=True)

longActive = [m.longActive for m in carControl]
gasPressed = [m.gasPressed for m in carState]
brakePressed = [m.brakePressed for m in carState]

maneuver_valid = all(longActive) and not (any(gasPressed) or any(brakePressed))

_open = 'open' if maneuver_valid else ''
title = f'Run #{int(run)+1}' + (' <span style="color: red">(invalid maneuver!)</span>' if not maneuver_valid else '')

f.write(f"<details {_open}><summary><h3 style='display: inline-block;'>{title}</h3></summary>\n")

plt.rcParams['font.size'] = 40
fig = plt.figure(figsize=(30, 25))
ax = fig.subplots(4, 1, sharex=True, gridspec_kw={'hspace': 0, 'height_ratios': [5, 3, 1, 1]})

ax[0].grid(linewidth=4)
ax[0].plot(t_carControl, [m.actuators.accel for m in carControl], label='carControl.actuators.accel', linewidth=6)
ax[0].plot(t_carOutput, [m.actuatorsOutput.accel for m in carOutput], label='carOutput.actuatorsOutput.accel', linewidth=6)
ax[0].plot(t_longitudinalPlan, [m.aTarget for m in longitudinalPlan], label='longitudinalPlan.aTarget', linewidth=6)
ax[0].plot(t_carState, [m.aEgo for m in carState], label='carState.aEgo', linewidth=6)
# TODO localizer accel
ax[0].set_ylabel('Acceleration (m/s^2)')
#ax[0].set_ylim(-6.5, 6.5)
ax[0].legend()

ax[1].grid(linewidth=4)
ax[1].plot(t_carState, [m.vEgo for m in carState], 'g', label='vEgo', linewidth=6)
ax[1].set_ylabel('Velocity (m/s)')
ax[1].legend()

ax[2].plot(t_carControl, longActive, label='longActive', linewidth=6)
ax[3].plot(t_carState, gasPressed, label='gasPressed', linewidth=6)
ax[3].plot(t_carState, brakePressed, label='brakePressed', linewidth=6)
for i in (2, 3):
ax[i].set_yticks([0, 1], minor=False)
ax[i].set_ylim(-1, 2)
ax[i].legend()

ax[-1].set_xlabel("Time (s)")
fig.tight_layout()

buffer = io.BytesIO()
fig.savefig(buffer, format='png')
buffer.seek(0)
f.write(f"<img src='data:image/png;base64,{base64.b64encode(buffer.getvalue()).decode()}' style='width:100%; max-width:800px;'>\n")
f.write("</details>\n")

print(f"\nReport written to {output_fn}\n")


if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Generate longitudinal maneuver report from route')
parser.add_argument('route', type=str, help='Route name (e.g. 00000000--5f742174be)')

args = parser.parse_args()

if '/' in args.route or '|' in args.route:
lr = LogReader(args.route)
else:
segs = [seg for seg in os.listdir(Paths.log_root()) if args.route in seg]
lr = LogReader([os.path.join(Paths.log_root(), seg, 'rlog') for seg in segs])

CP = lr.first('carParams')
platform = CP.carFingerprint
print('processing report for', platform)

maneuvers: list[tuple[str, list[list]]] = []
active_prev = False
description_prev = None

for msg in lr:
if msg.which() == 'alertDebug':
active = 'Maneuver Active' in msg.alertDebug.alertText1
if active and not active_prev:
if msg.alertDebug.alertText2 == description_prev:
maneuvers[-1][1].append([])
else:
maneuvers.append((msg.alertDebug.alertText2, [[]]))
description_prev = maneuvers[-1][0]
active_prev = active

if active_prev:
maneuvers[-1][1][-1].append(msg)

report(platform, maneuvers)
Loading
Loading