diff --git a/tools/longitudinal_maneuvers/generate_report.py b/tools/longitudinal_maneuvers/generate_report.py old mode 100644 new mode 100755 index 354d3bab34..9873a899b1 --- a/tools/longitudinal_maneuvers/generate_report.py +++ b/tools/longitudinal_maneuvers/generate_report.py @@ -1,48 +1,60 @@ +#!/usr/bin/env python3 +import argparse +import base64 import io import os +import json 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 +import matplotlib.pyplot as plt +from openpilot.tools.lib.logreader import LogReader -def report(args, logs, fp): + +# TODO any import for this? +REALDATA = Path('/home/batman/.comma/media/0/realdata') + + +def report(platform, maneuvers): 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_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("

Longitudinal maneuver report

\n") - f.write(f"

{fp}

\n") - if args.desc: - f.write(f"

{args.desc}

") - for description, runs in logs.items(): + f.write(f"

{platform}

\n") + # if args.desc: + # f.write(f"

{args.desc}

") + for description, runs in maneuvers: + print('using description:', description) f.write("
\n") f.write(f"

{description}

\n") - for run, log in runs.items(): + for run, msgs in enumerate(runs): + t_carControl, carControl = zip(*[(m.logMonoTime, m.carControl) for m in msgs if m.which() == 'carControl']) + t_carState, carState = zip(*[(m.logMonoTime, m.carState) for m in msgs if m.which() == 'carState']) + t_longitudinalPlan, longitudinalPlan = zip(*[(m.logMonoTime, m.longitudinalPlan) for m in msgs if m.which() == 'longitudinalPlan']) + f.write(f"

Run #{int(run)+1}

\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].plot(t_carControl, [m.actuators.accel for m in carControl], label='accel command', linewidth=6) + ax[0].plot(t_longitudinalPlan, [m.aTarget for m in longitudinalPlan], label='accel target', linewidth=6) + ax[0].plot(t_carState, [m.aEgo for m in carState], 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].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(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) + ax[2].plot(t_carControl, [m.enabled for m in carControl], label='enabled', linewidth=6) + ax[3].plot(t_carState, [m.gasPressed for m in carState], label='gasPressed', linewidth=6) + ax[3].plot(t_carState, [m.brakePressed for m in carState], label='brakePressed', linewidth=6) for i in (2, 3): ax[i].set_yticks([0, 1], minor=False) ax[i].set_ylim(-1, 2) @@ -56,6 +68,51 @@ def report(args, logs, fp): buffer.seek(0) f.write(f"\n") - import json - f.write(f"

{json.dumps(logs)}

") + # f.write(f"

{json.dumps(logs)}

") 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() + + logs = defaultdict(dict) + + segs = [] + for seg in os.listdir(REALDATA): + if args.route == seg[:20]: + print(seg) + segs.append(seg) + + lr = LogReader([str(REALDATA / seg / 'rlog') for seg in segs]) + + CP = lr.first('carParams') + platform = CP.carFingerprint + print('got platform', 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 + # print((msg.alertDebug.alertText1, msg.alertDebug.alertText2)) + + if active_prev: + maneuvers[-1][1][-1].append(msg) + + # print(len(list(lr))) + for desc, msgs in maneuvers: + print(desc, len(msgs)) + + report(platform, maneuvers) diff --git a/tools/sim/launch_openpilot.sh b/tools/sim/launch_openpilot.sh index fa5ac731bd..ecbf1509eb 100755 --- a/tools/sim/launch_openpilot.sh +++ b/tools/sim/launch_openpilot.sh @@ -6,7 +6,7 @@ export SIMULATION="1" export SKIP_FW_QUERY="1" export FINGERPRINT="HONDA_CIVIC_2022" -export BLOCK="${BLOCK},camerad,loggerd,encoderd,micd,logmessaged" +export BLOCK="${BLOCK},camerad,encoderd,micd,logmessaged" if [[ "$CI" ]]; then # TODO: offscreen UI should work export BLOCK="${BLOCK},ui"