rerun.io proof of concept (#32416)
* Adding demo version for acceleration only
* Adding, plot any event
* Adding dynamic blueprint creation and menu to choose what to plot
* Adding, pool of processes for faster data visualization
* Adding, install rerun if not present
* Adding. thumbnail support
* Refactoring, minor cleanup
* -Use rerun pre-release
-Remove json as a middle format
-Replace recursion with stack-based approach
* Refactoring, using services from cereal instead of hardcoding them
* Use of lr.run_across_segments instead of pool,
Use of python dict instead of capnp objs - better performance
Use LogReader syntax
* Enable logging of liveTracks, pandaStates
* Use of plotjuggler user experience
* Fixing bug in log_msg function
* cleanup
---------
Co-authored-by: savojovic <jovo.savic00@gmail.com>
Co-authored-by: savojovic <74861870+savojovic@users.noreply.github.com>
old-commit-hash: 1c481c5ad3
pull/32199/head
parent
4c7c4272d0
commit
6e0d84d829
1 changed files with 104 additions and 0 deletions
@ -0,0 +1,104 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
import subprocess |
||||||
|
import sys |
||||||
|
import argparse |
||||||
|
import multiprocessing |
||||||
|
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" |
||||||
|
WHEEL_URL = "https://build.rerun.io/commit/660463d/wheels" |
||||||
|
|
||||||
|
|
||||||
|
def install(): |
||||||
|
# currently requires a preview release build |
||||||
|
subprocess.run([sys.executable, "-m", "pip", "install", "--pre", "-f", WHEEL_URL, "--upgrade", "rerun-sdk"], check=True) |
||||||
|
print("Rerun installed") |
||||||
|
|
||||||
|
|
||||||
|
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(): |
||||||
|
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)) |
||||||
|
|
||||||
|
|
||||||
|
def process(blueprint, lr): |
||||||
|
ret = [] |
||||||
|
rr.init("rerun_test", spawn=True, default_blueprint=blueprint) |
||||||
|
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("--install", action="store_true", help="Install or update rerun") |
||||||
|
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() |
||||||
|
if args.install: |
||||||
|
install() |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
try: |
||||||
|
import rerun as rr |
||||||
|
import rerun.blueprint as rrb |
||||||
|
except ImportError: |
||||||
|
print("Rerun is not installed, run with --install first") |
||||||
|
sys.exit() |
||||||
|
|
||||||
|
route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip() |
||||||
|
blueprint = createBlueprint() |
||||||
|
print("Getting route log paths") |
||||||
|
lr = LogReader(route_or_segment_name) |
||||||
|
lr.run_across_segments(NUM_CPUS, partial(process, blueprint)) |
Loading…
Reference in new issue