openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
4.2 KiB

#!/usr/bin/env python3
import os
import sys
import multiprocessing
import subprocess
import argparse
from tempfile import NamedTemporaryFile
from common.basedir import BASEDIR
from selfdrive.test.process_replay.compare_logs import save_log
from tools.lib.api import CommaApi
from tools.lib.auth_config import get_token
from tools.lib.robust_logreader import RobustLogReader
from tools.lib.route import Route
from urllib.parse import urlparse, parse_qs
juggle_dir = os.path.dirname(os.path.realpath(__file__))
def load_segment(segment_name):
print(f"Loading {segment_name}")
if segment_name is None:
return []
try:
return list(RobustLogReader(segment_name))
except ValueError as e:
print(f"Error parsing {segment_name}: {e}")
return []
def start_juggler(fn=None, dbc=None, layout=None):
env = os.environ.copy()
env["BASEDIR"] = BASEDIR
pj = os.getenv("PLOTJUGGLER_PATH", os.path.join(juggle_dir, "bin/plotjuggler"))
if dbc:
env["DBC_NAME"] = dbc
extra_args = []
if fn is not None:
extra_args.append(f'-d {fn}')
if layout is not None:
extra_args.append(f'-l {layout}')
extra_args = " ".join(extra_args)
subprocess.call(f'{pj} --plugin_folders {os.path.join(juggle_dir, "bin")} {extra_args}', shell=True, env=env, cwd=juggle_dir)
def juggle_route(route_name, segment_number, segment_count, qlog, can, layout):
if 'cabana' in route_name:
query = parse_qs(urlparse(route_name).query)
api = CommaApi(get_token())
logs = api.get(f'v1/route/{query["route"][0]}/log_urls?sig={query["sig"][0]}&exp={query["exp"][0]}')
elif route_name.startswith("http://") or route_name.startswith("https://") or os.path.isfile(route_name):
logs = [route_name]
else:
r = Route(route_name)
logs = r.qlog_paths() if qlog else r.log_paths()
if segment_number is not None:
logs = logs[segment_number:segment_number+segment_count]
if None in logs:
fallback_answer = input("At least one of the rlogs in this segment does not exist, would you like to use the qlogs? (y/n) : ")
if fallback_answer == 'y':
logs = r.qlog_paths()
if segment_number is not None:
logs = logs[segment_number:segment_number+segment_count]
else:
print(f"Please try a different {'segment' if segment_number is not None else 'route'}")
return
all_data = []
with multiprocessing.Pool(24) as pool:
for d in pool.map(load_segment, logs):
all_data += d
if not can:
all_data = [d for d in all_data if d.which() not in ['can', 'sendcan']]
# Infer DBC name from logs
dbc = None
for cp in [m for m in all_data if m.which() == 'carParams']:
try:
DBC = __import__(f"selfdrive.car.{cp.carParams.carName}.values", fromlist=['DBC']).DBC
dbc = DBC[cp.carParams.carFingerprint]['pt']
except (ImportError, KeyError, AttributeError):
pass
break
tempfile = NamedTemporaryFile(suffix='.rlog', dir=juggle_dir)
save_log(tempfile.name, all_data, compress=False)
del all_data
start_juggler(tempfile.name, dbc, layout)
def get_arg_parser():
parser = argparse.ArgumentParser(description="PlotJuggler plugin for reading openpilot logs",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--qlog", action="store_true", help="Use qlogs")
parser.add_argument("--can", action="store_true", help="Parse CAN data")
parser.add_argument("--stream", action="store_true", help="Start PlotJuggler without a route to stream data using Cereal")
parser.add_argument("--layout", nargs='?', help="Run PlotJuggler with a pre-defined layout")
parser.add_argument("route_name", nargs='?', help="The route name to plot (cabana share URL accepted)")
parser.add_argument("segment_number", type=int, nargs='?', help="The index of the segment to plot")
parser.add_argument("segment_count", type=int, nargs='?', help="The number of segments to plot", default=1)
return parser
if __name__ == "__main__":
arg_parser = get_arg_parser()
if len(sys.argv) == 1:
arg_parser.print_help()
sys.exit()
args = arg_parser.parse_args(sys.argv[1:])
if args.stream:
start_juggler(layout=args.layout)
else:
juggle_route(args.route_name.strip(), args.segment_number, args.segment_count, args.qlog, args.can, args.layout)