|
|
|
#!/usr/bin/env python3
|
|
|
|
import os
|
|
|
|
import argparse
|
|
|
|
import time
|
|
|
|
import capnp
|
|
|
|
|
|
|
|
from typing import Union, Iterable, Optional, List, Any, Dict, Tuple
|
|
|
|
|
|
|
|
from selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, replay_process, get_process_config, check_openpilot_enabled, get_custom_params_from_lr
|
|
|
|
from selfdrive.test.update_ci_routes import upload_route
|
|
|
|
from tools.lib.route import Route
|
|
|
|
from tools.lib.framereader import FrameReader
|
|
|
|
from tools.lib.logreader import LogReader
|
|
|
|
from tools.lib.helpers import save_log
|
|
|
|
|
|
|
|
|
|
|
|
def regen_segment(
|
|
|
|
lr: Union[LogReader, List[capnp._DynamicStructReader]], frs: Optional[Dict[str, Any]] = None,
|
|
|
|
daemons: Union[str, Iterable[str]] = "all", disable_tqdm: bool = False
|
|
|
|
) -> List[capnp._DynamicStructReader]:
|
|
|
|
if not isinstance(daemons, str) and not hasattr(daemons, "__iter__"):
|
|
|
|
raise ValueError("whitelist_proc must be a string or iterable")
|
|
|
|
|
|
|
|
all_msgs = sorted(lr, key=lambda m: m.logMonoTime)
|
|
|
|
custom_params = get_custom_params_from_lr(all_msgs)
|
|
|
|
|
|
|
|
if daemons != "all":
|
|
|
|
if isinstance(daemons, str):
|
|
|
|
raise ValueError(f"Invalid value for daemons: {daemons}")
|
|
|
|
|
|
|
|
replayed_processes = []
|
|
|
|
for d in daemons:
|
|
|
|
cfg = get_process_config(d)
|
|
|
|
replayed_processes.append(cfg)
|
|
|
|
else:
|
|
|
|
replayed_processes = CONFIGS
|
|
|
|
|
|
|
|
print("Replayed processes:", [p.proc_name for p in replayed_processes])
|
|
|
|
print("\n\n", "*"*30, "\n\n", sep="")
|
|
|
|
|
|
|
|
output_logs = replay_process(replayed_processes, all_msgs, frs, return_all_logs=True, custom_params=custom_params, disable_progress=disable_tqdm)
|
|
|
|
|
|
|
|
return output_logs
|
|
|
|
|
|
|
|
|
|
|
|
def setup_data_readers(route: str, sidx: int, use_route_meta: bool) -> Tuple[LogReader, Dict[str, Any]]:
|
|
|
|
if use_route_meta:
|
Live torque (#25456)
* wip torqued
* add basic logic
* setup in manager
* check sanity and publish msg
* add first order filter to outputs
* wire up controlsd, and update gains
* rename intercept to offset
* add cloudlog, live values are not updated
* fix bugs, do not reset points for now
* fix crashes
* rename to main
* fix bugs, works offline
* fix float in cereal bug
* add latacc filter
* randomly choose points, approx for iid
* add variable decay
* local param to capnp instead of dict
* verify works in replay
* use torqued output in controlsd
* use in controlsd; use points from past routes
* controlsd bugfix
* filter before updating gains, needs to be replaced
* save all points to ensure smooth transition across routes, revert friction factor to 1.5
* add filters to prevent noisy low-speed data points; improve fit sanity
* add engaged buffer
* revert lat_acc thresh
* use paramsd realtime process config
* make latacc-to-torque generic, and overrideable
* move freq to 4Hz, avoid storing in np.array, don't publish points in the message
* float instead of np
* remove constant while storing pts
* rename slope, offset to lat_accet_factor, offset
* resolve issues
* use camelcase in all capnp params
* use camelcase everywhere
* reduce latacc threshold or sanity, add car_sane todo, save points properly
* add and check tag
* write param to disk at end of route
* remove args
* rebase op, cereal
* save on exit
* restore default handler
* cpu usage check
* add to process replay
* handle reset better, reduce unnecessary computation
* always publish raw values - useful for debug
* regen routes
* update refs
* checks on cache restore
* check tuning vals too
* clean that up
* reduce cpu usage
* reduce cpu usage by 75%
* cleanup
* optimize further
* handle reset condition better, don't put points in init, use only in corolla
* bump cereal after rebasing
* update refs
* Update common/params.cc
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
* remove unnecessary checks
* Update RELEASES.md
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
3 years ago
|
|
|
r = Route(route)
|
|
|
|
lr = LogReader(r.log_paths()[sidx])
|
|
|
|
frs = {}
|
|
|
|
if len(r.camera_paths()) > sidx and r.camera_paths()[sidx] is not None:
|
|
|
|
frs['roadCameraState'] = FrameReader(r.camera_paths()[sidx])
|
|
|
|
if len(r.ecamera_paths()) > sidx and r.ecamera_paths()[sidx] is not None:
|
|
|
|
frs['wideCameraState'] = FrameReader(r.ecamera_paths()[sidx])
|
|
|
|
if len(r.dcamera_paths()) > sidx and r.dcamera_paths()[sidx] is not None:
|
|
|
|
frs['driverCameraState'] = FrameReader(r.dcamera_paths()[sidx])
|
|
|
|
else:
|
|
|
|
lr = LogReader(f"cd:/{route.replace('|', '/')}/{sidx}/rlog.bz2")
|
|
|
|
frs = {
|
|
|
|
'roadCameraState': FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/fcamera.hevc"),
|
|
|
|
'driverCameraState': FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/dcamera.hevc"),
|
|
|
|
}
|
|
|
|
if next((True for m in lr if m.which() == "wideRoadCameraState"), False):
|
|
|
|
frs['wideRoadCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/ecamera.hevc")
|
|
|
|
|
|
|
|
return lr, frs
|
|
|
|
|
|
|
|
|
|
|
|
def regen_and_save(
|
|
|
|
route: str, sidx: int, daemons: Union[str, Iterable[str]] = "all", outdir: str = FAKEDATA,
|
|
|
|
upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False
|
|
|
|
) -> str:
|
|
|
|
lr, frs = setup_data_readers(route, sidx, use_route_meta)
|
|
|
|
output_logs = regen_segment(lr, frs, daemons, disable_tqdm=disable_tqdm)
|
|
|
|
|
|
|
|
log_dir = os.path.join(outdir, time.strftime("%Y-%m-%d--%H-%M-%S--0", time.gmtime()))
|
|
|
|
rel_log_dir = os.path.relpath(log_dir)
|
|
|
|
rpath = os.path.join(log_dir, "rlog.bz2")
|
|
|
|
|
|
|
|
os.makedirs(log_dir)
|
|
|
|
save_log(rpath, output_logs, compress=True)
|
|
|
|
|
|
|
|
print("\n\n", "*"*30, "\n\n", sep="")
|
|
|
|
print("New route:", rel_log_dir, "\n")
|
|
|
|
|
|
|
|
if not check_openpilot_enabled(output_logs):
|
|
|
|
raise Exception("Route did not engage for long enough")
|
|
|
|
|
|
|
|
if upload:
|
|
|
|
upload_route(rel_log_dir)
|
|
|
|
|
|
|
|
return rel_log_dir
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
def comma_separated_list(string):
|
|
|
|
if string == "all":
|
|
|
|
return string
|
|
|
|
return string.split(",")
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description="Generate new segments from old ones")
|
|
|
|
parser.add_argument("--upload", action="store_true", help="Upload the new segment to the CI bucket")
|
|
|
|
parser.add_argument("--outdir", help="log output dir", default=FAKEDATA)
|
|
|
|
parser.add_argument("--whitelist-procs", type=comma_separated_list, default="all",
|
|
|
|
help="Comma-separated whitelist of processes to regen (e.g. controlsd). Pass 'all' to whitelist all processes.")
|
|
|
|
parser.add_argument("route", type=str, help="The source route")
|
|
|
|
parser.add_argument("seg", type=int, help="Segment in source route")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
regen_and_save(args.route, args.seg, daemons=args.whitelist_procs, upload=args.upload, outdir=args.outdir)
|