#!/usr/bin/env python3 import sys import argparse import multiprocessing import rerun as rr import rerun.blueprint as rrb from functools import partial from openpilot.tools.lib.logreader import LogReader from cereal.services import SERVICE_LIST NUM_CPUS = multiprocessing.cpu_count() DEMO_ROUTE = "a2a0ccea32023010|2023-07-27--13-01-19" def log_msg(msg, parent_key=''): stack = [(msg, parent_key)] while stack: current_msg, current_parent_key = stack.pop() if isinstance(current_msg, list): for index, item in enumerate(current_msg): new_key = f"{current_parent_key}/{index}" if isinstance(item, (int, float)): rr.log(str(new_key), rr.Scalar(item)) elif isinstance(item, dict): stack.append((item, new_key)) elif isinstance(current_msg, dict): for key, value in current_msg.items(): new_key = f"{current_parent_key}/{key}" if isinstance(value, (int, float)): rr.log(str(new_key), rr.Scalar(value)) elif isinstance(value, dict): stack.append((value, new_key)) elif isinstance(value, list): for index, item in enumerate(value): if isinstance(item, (int, float)): rr.log(f"{new_key}/{index}", rr.Scalar(item)) else: pass # Not a plottable value def createBlueprint(): blueprint = None timeSeriesViews = [] for topic in sorted(SERVICE_LIST.keys()): timeSeriesViews.append(rrb.TimeSeriesView(name=topic, origin=f"/{topic}/", visible=False)) rr.log(topic, rr.SeriesLine(name=topic), timeless=True) blueprint = rrb.Blueprint(rrb.Grid(rrb.Vertical(*timeSeriesViews,rrb.SelectionPanel(expanded=False),rrb.TimePanel(expanded=False)), rrb.Spatial2DView(name="thumbnail", origin="/thumbnail"))) return blueprint def log_thumbnail(thumbnailMsg): bytesImgData = thumbnailMsg.get('thumbnail') rr.log("/thumbnail", rr.ImageEncoded(contents=bytesImgData)) @rr.shutdown_at_exit def process(blueprint, lr): rr.init("rerun_test") rr.connect(default_blueprint=blueprint) ret = [] for msg in lr: ret.append(msg) rr.set_time_nanos("TIMELINE", msg.logMonoTime) if msg.which() != "thumbnail": log_msg(msg.to_dict()[msg.which()], msg.which()) else: log_thumbnail(msg.to_dict()[msg.which()]) return ret if __name__ == '__main__': parser = argparse.ArgumentParser(description="A helper to run rerun on openpilot routes", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--demo", action="store_true", help="Use the demo route instead of providing one") parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot") if len(sys.argv) == 1: parser.print_help() sys.exit() args = parser.parse_args() blueprint = createBlueprint() rr.init("rerun_test") rr.spawn(connect=False) # child processes stream data to Viewer route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() print("Getting route log paths") lr = LogReader(route_or_segment_name) lr.run_across_segments(NUM_CPUS, partial(process, blueprint))