pull/33527/head
Shane Smiskol 1 year ago
parent 40a1201f05
commit 85761980b7
  1. 2
      common/params.cc
  2. 2
      system/manager/process_config.py
  3. 61
      tools/longitudinal_maneuvers/generate_report.py
  4. 104
      tools/longitudinal_maneuvers/maneuversd.py

@ -158,7 +158,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"LiveParameters", PERSISTENT}, {"LiveParameters", PERSISTENT},
{"LiveTorqueParameters", PERSISTENT | DONT_LOG}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG},
{"LocationFilterInitialState", PERSISTENT}, {"LocationFilterInitialState", PERSISTENT},
{"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, {"LongitudinalManeuverMode", PERSISTENT},
{"LongitudinalPersonality", PERSISTENT}, {"LongitudinalPersonality", PERSISTENT},
{"NetworkMetered", PERSISTENT}, {"NetworkMetered", PERSISTENT},
{"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION},

@ -77,7 +77,7 @@ procs = [
PythonProcess("torqued", "selfdrive.locationd.torqued", only_onroad), PythonProcess("torqued", "selfdrive.locationd.torqued", only_onroad),
PythonProcess("controlsd", "selfdrive.controls.controlsd", not_joystick), PythonProcess("controlsd", "selfdrive.controls.controlsd", not_joystick),
PythonProcess("joystickd", "tools.joystick.joystickd", joystick), PythonProcess("joystickd", "tools.joystick.joystickd", joystick),
PythonProcess("longitudinal_profilesd", "examples.longitudinal_profiles", long_maneuver), PythonProcess("maneuversd", "examples.maneuversd", long_maneuver),
PythonProcess("selfdrived", "selfdrive.selfdrived.selfdrived", only_onroad), PythonProcess("selfdrived", "selfdrive.selfdrived.selfdrived", only_onroad),
PythonProcess("card", "selfdrive.car.card", only_onroad), PythonProcess("card", "selfdrive.car.card", only_onroad),
PythonProcess("deleter", "system.loggerd.deleter", always_run), PythonProcess("deleter", "system.loggerd.deleter", always_run),

@ -0,0 +1,61 @@
import io
import os
import time
import base64
import argparse
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict
from dataclasses import dataclass, asdict
from pathlib import Path
def report(args, logs, fp):
output_path = Path(__file__).resolve().parent / "longitudinal_reports"
output_fn = args.output or output_path / f"{fp}_{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>{fp}</h3>\n")
if args.desc:
f.write(f"<h3>{args.desc}</h3>")
for description, runs in logs.items():
f.write("<div style='border-top: 1px solid #000; margin: 20px 0;'></div>\n")
f.write(f"<h2>{description}</h2>\n")
for run, log in runs.items():
f.write(f"<h3>Run #{int(run)+1}</h3>\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(log["t"], log["carControl.actuators.accel"], label='accel command', linewidth=6)
ax[0].plot(log["t"], log["carState.aEgo"], label='aEgo', linewidth=6)
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(log["t"], log["carState.vEgo"], 'g', label='vEgo', linewidth=6)
ax[1].set_ylabel('Velocity (m/s)')
ax[1].legend()
ax[2].plot(log["t"], log["carControl.enabled"], label='enabled', linewidth=6)
ax[3].plot(log["t"], log["carState.gasPressed"], label='gasPressed', linewidth=6)
ax[3].plot(log["t"], log["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")
import json
f.write(f"<p style='display: none'>{json.dumps(logs)}</p>")
print(f"\nReport written to {output_fn}\n")

@ -1,27 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import io from dataclasses import dataclass
import os
import time
import base64
import argparse
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict
from dataclasses import dataclass, asdict
from pathlib import Path
from cereal import messaging, car from cereal import messaging, car
from opendbc.car.structs import CarControl
from opendbc.car.common.conversions import Conversions from opendbc.car.common.conversions import Conversions
from openpilot.common.realtime import DT_CTRL, DT_MDL, Ratekeeper from openpilot.common.realtime import DT_MDL
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
from openpilot.selfdrive.controls.lib.longitudinal_planner import get_accel_from_plan
# TODOs
# - support lateral maneuvers
# - setup: show countdown?
@dataclass @dataclass
@ -63,7 +47,7 @@ class Maneuver:
# next action # next action
if self._action_index < len(self.actions) - 1: if self._action_index < len(self.actions) - 1:
self._action_index += 1 self._action_index += 1
self._action_frames = 0 # TODO rename action frames? self._action_frames = 0
# repeat maneuver # repeat maneuver
elif self._repeated < self.repeat: elif self._repeated < self.repeat:
self._repeated += 1 self._repeated += 1
@ -123,57 +107,6 @@ MANEUVERS = [
] ]
def report(args, logs, fp):
output_path = Path(__file__).resolve().parent / "longitudinal_reports"
output_fn = args.output or output_path / f"{fp}_{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>{fp}</h3>\n")
if args.desc:
f.write(f"<h3>{args.desc}</h3>")
for description, runs in logs.items():
f.write("<div style='border-top: 1px solid #000; margin: 20px 0;'></div>\n")
f.write(f"<h2>{description}</h2>\n")
for run, log in runs.items():
f.write(f"<h3>Run #{int(run)+1}</h3>\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(log["t"], log["carControl.actuators.accel"], label='accel command', linewidth=6)
ax[0].plot(log["t"], log["carState.aEgo"], label='aEgo', linewidth=6)
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(log["t"], log["carState.vEgo"], 'g', label='vEgo', linewidth=6)
ax[1].set_ylabel('Velocity (m/s)')
ax[1].legend()
ax[2].plot(log["t"], log["carControl.enabled"], label='enabled', linewidth=6)
ax[3].plot(log["t"], log["carState.gasPressed"], label='gasPressed', linewidth=6)
ax[3].plot(log["t"], log["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")
import json
f.write(f"<p style='display: none'>{json.dumps(logs)}</p>")
print(f"\nReport written to {output_fn}\n")
def main(): def main():
params = Params() params = Params()
cloudlog.info("joystickd is waiting for CarParams") cloudlog.info("joystickd is waiting for CarParams")
@ -226,34 +159,9 @@ def main():
assistance_send.valid = True assistance_send.valid = True
pm.send('driverAssistance', assistance_send) pm.send('driverAssistance', assistance_send)
print('finished?', maneuver is not None and maneuver.finished) # print('finished?', maneuver is not None and maneuver.finished)
print('aTarget:', longitudinalPlan.aTarget) # print('aTarget:', longitudinalPlan.aTarget)
print('shouldStop:', longitudinalPlan.shouldStop) # print('shouldStop:', longitudinalPlan.shouldStop)
if maneuver is not None and maneuver.finished: if maneuver is not None and maneuver.finished:
maneuver = None maneuver = None
if __name__ == "__main__":
main()
exit()
maneuver_help = "\n".join([f"{i+1}. {m.description}" for i, m in enumerate(MANEUVERS)])
parser = argparse.ArgumentParser(description="A tool for longitudinal control testing.",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--desc', help="Extra description to include in report.")
parser.add_argument('--output', help="Write out report to this file.", default=None)
parser.add_argument('maneuvers', nargs='*', type=int, default=None, help=f'Deafult is all.\n{maneuver_help}')
args = parser.parse_args()
print(args)
if "REPORT_TEST" in os.environ:
with open(os.environ["REPORT_TEST"]) as f:
import json
logs = json.loads(f.read().split("none'>")[1].split('</p>')[0])
report(args, logs, "testing")
exit()
assert args.output is None or args.output.endswith(".html"), "Output filename must end with '.html'"
main(args)
Loading…
Cancel
Save