#!/usr/bin/env python3
import os
import argparse
import time
import capnp
import numpy as np
from typing import Any
from collections . abc import Iterable
from openpilot . selfdrive . test . process_replay . process_replay import CONFIGS , FAKEDATA , ProcessConfig , replay_process , get_process_config , \
check_openpilot_enabled , get_custom_params_from_lr
from openpilot . selfdrive . test . process_replay . vision_meta import DRIVER_FRAME_SIZES
from openpilot . selfdrive . test . update_ci_routes import upload_route
from openpilot . tools . lib . route import Route
from openpilot . tools . lib . framereader import FrameReader , BaseFrameReader , FrameType
from openpilot . tools . lib . logreader import LogReader , LogIterable
from openpilot . tools . lib . helpers import save_log
class DummyFrameReader ( BaseFrameReader ) :
def __init__ ( self , w : int , h : int , frame_count : int , pix_val : int ) :
self . pix_val = pix_val
self . w , self . h = w , h
self . frame_count = frame_count
self . frame_type = FrameType . raw
def get ( self , idx , count = 1 , pix_fmt = " yuv420p " ) :
if pix_fmt == " rgb24 " :
shape = ( self . h , self . w , 3 )
elif pix_fmt == " nv12 " or pix_fmt == " yuv420p " :
shape = ( int ( ( self . h * self . w ) * 3 / 2 ) , )
else :
raise NotImplementedError
return [ np . full ( shape , self . pix_val , dtype = np . uint8 ) for _ in range ( count ) ]
@staticmethod
def zero_dcamera ( ) :
return DummyFrameReader ( * DRIVER_FRAME_SIZES [ " tici " ] , 1200 , 0 )
def regen_segment (
lr : LogIterable , frs : dict [ str , Any ] | None = None ,
processes : Iterable [ ProcessConfig ] = CONFIGS , disable_tqdm : bool = False
) - > list [ capnp . _DynamicStructReader ] :
all_msgs = sorted ( lr , key = lambda m : m . logMonoTime )
custom_params = get_custom_params_from_lr ( all_msgs )
print ( " Replayed processes: " , [ p . proc_name for p in processes ] )
print ( " \n \n " , " * " * 30 , " \n \n " , sep = " " )
output_logs = replay_process ( 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 ,
needs_driver_cam : bool = True , needs_road_cam : bool = True , dummy_driver_cam : bool = False
) - > 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 needs_road_cam and len ( r . camera_paths ( ) ) > sidx and r . camera_paths ( ) [ sidx ] is not None :
frs [ ' roadCameraState ' ] = FrameReader ( r . camera_paths ( ) [ sidx ] )
if needs_road_cam and len ( r . ecamera_paths ( ) ) > sidx and r . ecamera_paths ( ) [ sidx ] is not None :
frs [ ' wideRoadCameraState ' ] = FrameReader ( r . ecamera_paths ( ) [ sidx ] )
if needs_driver_cam :
if dummy_driver_cam :
frs [ ' driverCameraState ' ] = DummyFrameReader . zero_dcamera ( )
elif len ( r . dcamera_paths ( ) ) > sidx and r . dcamera_paths ( ) [ sidx ] is not None :
device_type = next ( str ( msg . initData . deviceType ) for msg in lr if msg . which ( ) == " initData " )
assert device_type != " neo " , " Driver camera not supported on neo segments. Use dummy dcamera. "
frs [ ' driverCameraState ' ] = FrameReader ( r . dcamera_paths ( ) [ sidx ] )
else :
lr = LogReader ( f " cd:/ { route . replace ( ' | ' , ' / ' ) } / { sidx } /rlog.bz2 " )
frs = { }
if needs_road_cam :
frs [ ' roadCameraState ' ] = FrameReader ( f " cd:/ { route . replace ( ' | ' , ' / ' ) } / { sidx } /fcamera.hevc " )
if next ( ( True for m in lr if m . which ( ) == " wideRoadCameraState " ) , False ) :
frs [ ' wideRoadCameraState ' ] = FrameReader ( f " cd:/ { route . replace ( ' | ' , ' / ' ) } / { sidx } /ecamera.hevc " )
if needs_driver_cam :
if dummy_driver_cam :
frs [ ' driverCameraState ' ] = DummyFrameReader . zero_dcamera ( )
else :
device_type = next ( str ( msg . initData . deviceType ) for msg in lr if msg . which ( ) == " initData " )
assert device_type != " neo " , " Driver camera not supported on neo segments. Use dummy dcamera. "
frs [ ' driverCameraState ' ] = FrameReader ( f " cd:/ { route . replace ( ' | ' , ' / ' ) } / { sidx } /dcamera.hevc " )
return lr , frs
def regen_and_save (
route : str , sidx : int , processes : str | Iterable [ str ] = " all " , outdir : str = FAKEDATA ,
upload : bool = False , use_route_meta : bool = False , disable_tqdm : bool = False , dummy_driver_cam : bool = False
) - > str :
if not isinstance ( processes , str ) and not hasattr ( processes , " __iter__ " ) :
raise ValueError ( " whitelist_proc must be a string or iterable " )
if processes != " all " :
if isinstance ( processes , str ) :
raise ValueError ( f " Invalid value for processes: { processes } " )
replayed_processes = [ ]
for d in processes :
cfg = get_process_config ( d )
replayed_processes . append ( cfg )
else :
replayed_processes = CONFIGS
all_vision_pubs = { pub for cfg in replayed_processes for pub in cfg . vision_pubs }
lr , frs = setup_data_readers ( route , sidx , use_route_meta ,
needs_driver_cam = " driverCameraState " in all_vision_pubs ,
needs_road_cam = " roadCameraState " in all_vision_pubs or " wideRoadCameraState " in all_vision_pubs ,
dummy_driver_cam = dummy_driver_cam )
output_logs = regen_segment ( lr , frs , replayed_processes , 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 ) :
return string . split ( " , " )
all_procs = [ p . proc_name for p in CONFIGS ]
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 ( " --dummy-dcamera " , action = ' store_true ' , help = " Use dummy blank driver camera " )
parser . add_argument ( " --whitelist-procs " , type = comma_separated_list , default = all_procs ,
help = " Comma-separated whitelist of processes to regen (e.g. controlsd,radard) " )
parser . add_argument ( " --blacklist-procs " , type = comma_separated_list , default = [ ] ,
help = " Comma-separated blacklist of processes to regen (e.g. controlsd,radard) " )
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 ( )
blacklist_set = set ( args . blacklist_procs )
processes = [ p for p in args . whitelist_procs if p not in blacklist_set ]
regen_and_save ( args . route , args . seg , processes = processes , upload = args . upload , outdir = args . outdir , dummy_driver_cam = args . dummy_dcamera )