|
|
|
@ -8,7 +8,7 @@ import capnp |
|
|
|
|
from cereal import messaging, log, car |
|
|
|
|
from common.numpy_fast import interp |
|
|
|
|
from common.params import Params |
|
|
|
|
from common.realtime import Ratekeeper, Priority, config_realtime_process, DT_MDL |
|
|
|
|
from common.realtime import Ratekeeper, Priority, config_realtime_process |
|
|
|
|
from system.swaglog import cloudlog |
|
|
|
|
|
|
|
|
|
from common.kalman.simple_kalman import KF1D |
|
|
|
@ -50,8 +50,7 @@ class KalmanParams: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Track: |
|
|
|
|
def __init__(self, identifier: int, v_lead: float, kalman_params: KalmanParams): |
|
|
|
|
self.identifier = identifier |
|
|
|
|
def __init__(self, v_lead: float, kalman_params: KalmanParams): |
|
|
|
|
self.cnt = 0 |
|
|
|
|
self.aLeadTau = _LEAD_ACCEL_TAU |
|
|
|
|
self.K_A = kalman_params.A |
|
|
|
@ -64,12 +63,8 @@ class Track: |
|
|
|
|
self.dRel = d_rel # LONG_DIST |
|
|
|
|
self.yRel = y_rel # -LAT_DIST |
|
|
|
|
self.vRel = v_rel # REL_SPEED |
|
|
|
|
self.measured = measured # measured or estimate |
|
|
|
|
|
|
|
|
|
self.update_vlead(v_lead) |
|
|
|
|
|
|
|
|
|
def update_vlead(self, v_lead: float): |
|
|
|
|
self.vLead = v_lead |
|
|
|
|
self.measured = measured # measured or estimate |
|
|
|
|
|
|
|
|
|
# computed velocity and accelerations |
|
|
|
|
if self.cnt > 0: |
|
|
|
@ -103,12 +98,11 @@ class Track: |
|
|
|
|
"vLead": float(self.vLead), |
|
|
|
|
"vLeadK": float(self.vLeadK), |
|
|
|
|
"aLeadK": float(self.aLeadK), |
|
|
|
|
"aLeadTau": float(self.aLeadTau), |
|
|
|
|
"status": True, |
|
|
|
|
"fcw": self.is_potential_fcw(model_prob), |
|
|
|
|
"modelProb": model_prob, |
|
|
|
|
"radar": True, |
|
|
|
|
"radarTrackId": self.identifier, |
|
|
|
|
"aLeadTau": float(self.aLeadTau) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
def potential_low_speed_lead(self, v_ego: float): |
|
|
|
@ -164,16 +158,14 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa |
|
|
|
|
"aLeadTau": 0.3, |
|
|
|
|
"fcw": False, |
|
|
|
|
"modelProb": float(lead_msg.prob), |
|
|
|
|
"status": True, |
|
|
|
|
"radar": False, |
|
|
|
|
"radarTrackId": -1, |
|
|
|
|
"status": True |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_lead(v_ego: float, ready: bool, tracks: Dict[int, Track], lead_msg: capnp._DynamicStructReader, model_v_ego: float, low_speed_override: bool = True) -> Dict[str, Any]: |
|
|
|
|
# Determine leads, this is where the essential logic happens |
|
|
|
|
lead_msg_empty = any([len(c) == 0 for c in [lead_msg.x, lead_msg.y, lead_msg.v]]) |
|
|
|
|
if len(tracks) > 0 and ready and not lead_msg_empty and lead_msg.prob > .5: |
|
|
|
|
if len(tracks) > 0 and ready and lead_msg.prob > .5: |
|
|
|
|
track = match_vision_to_track(v_ego, lead_msg, tracks) |
|
|
|
|
else: |
|
|
|
|
track = None |
|
|
|
@ -181,7 +173,7 @@ def get_lead(v_ego: float, ready: bool, tracks: Dict[int, Track], lead_msg: capn |
|
|
|
|
lead_dict = {'status': False} |
|
|
|
|
if track is not None: |
|
|
|
|
lead_dict = track.get_RadarState(lead_msg.prob) |
|
|
|
|
elif track is None and ready and not lead_msg_empty and lead_msg.prob > .5: |
|
|
|
|
elif (track is None) and ready and (lead_msg.prob > .5): |
|
|
|
|
lead_dict = get_RadarState_from_vision(lead_msg, v_ego, model_v_ego) |
|
|
|
|
|
|
|
|
|
if low_speed_override: |
|
|
|
@ -211,14 +203,14 @@ class RadarD: |
|
|
|
|
|
|
|
|
|
self.ready = False |
|
|
|
|
|
|
|
|
|
def update(self, sm: messaging.SubMaster, radar_data: Optional[car.RadarData]): |
|
|
|
|
def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]): |
|
|
|
|
self.current_time = 1e-9*max(sm.logMonoTime.values()) |
|
|
|
|
|
|
|
|
|
radar_points = [] |
|
|
|
|
radar_errors = [] |
|
|
|
|
if radar_data is not None: |
|
|
|
|
radar_points = radar_data.points |
|
|
|
|
radar_errors = radar_data.errors |
|
|
|
|
if rr is not None: |
|
|
|
|
radar_points = rr.points |
|
|
|
|
radar_errors = rr.errors |
|
|
|
|
|
|
|
|
|
if sm.updated['carState']: |
|
|
|
|
self.v_ego = sm['carState'].vEgo |
|
|
|
@ -226,32 +218,26 @@ class RadarD: |
|
|
|
|
if sm.updated['modelV2']: |
|
|
|
|
self.ready = True |
|
|
|
|
|
|
|
|
|
if radar_data is not None: |
|
|
|
|
ar_pts = {} |
|
|
|
|
for pt in radar_points: |
|
|
|
|
ar_pts[pt.trackId] = [pt.dRel, pt.yRel, pt.vRel, pt.measured] |
|
|
|
|
ar_pts = {} |
|
|
|
|
for pt in radar_points: |
|
|
|
|
ar_pts[pt.trackId] = [pt.dRel, pt.yRel, pt.vRel, pt.measured] |
|
|
|
|
|
|
|
|
|
# *** remove missing points from meta data *** |
|
|
|
|
for ids in list(self.tracks.keys()): |
|
|
|
|
if ids not in ar_pts: |
|
|
|
|
self.tracks.pop(ids, None) |
|
|
|
|
# *** remove missing points from meta data *** |
|
|
|
|
for ids in list(self.tracks.keys()): |
|
|
|
|
if ids not in ar_pts: |
|
|
|
|
self.tracks.pop(ids, None) |
|
|
|
|
|
|
|
|
|
# *** compute the tracks *** |
|
|
|
|
for ids in ar_pts: |
|
|
|
|
rpt = ar_pts[ids] |
|
|
|
|
# *** compute the tracks *** |
|
|
|
|
for ids in ar_pts: |
|
|
|
|
rpt = ar_pts[ids] |
|
|
|
|
|
|
|
|
|
# align v_ego by a fixed time to align it with the radar measurement |
|
|
|
|
v_lead = rpt[2] + self.v_ego_hist[0] |
|
|
|
|
# align v_ego by a fixed time to align it with the radar measurement |
|
|
|
|
v_lead = rpt[2] + self.v_ego_hist[0] |
|
|
|
|
|
|
|
|
|
# create the track if it doesn't exist or it's a new track |
|
|
|
|
if ids not in self.tracks: |
|
|
|
|
self.tracks[ids] = Track(ids, v_lead, self.kalman_params) |
|
|
|
|
self.tracks[ids].update(rpt[0], rpt[1], rpt[2], v_lead, rpt[3]) |
|
|
|
|
else: |
|
|
|
|
# *** no radar points, keep existing tracks, update v_lead |
|
|
|
|
for track in self.tracks.values(): |
|
|
|
|
v_lead = track.vRel + self.v_ego_hist[0] |
|
|
|
|
track.update_vlead(v_lead) |
|
|
|
|
# create the track if it doesn't exist or it's a new track |
|
|
|
|
if ids not in self.tracks: |
|
|
|
|
self.tracks[ids] = Track(v_lead, self.kalman_params) |
|
|
|
|
self.tracks[ids].update(rpt[0], rpt[1], rpt[2], v_lead, rpt[3]) |
|
|
|
|
|
|
|
|
|
# *** publish radarState *** |
|
|
|
|
self.radar_state_valid = sm.all_checks() and len(radar_errors) == 0 |
|
|
|
@ -304,30 +290,32 @@ def radard_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[messagi |
|
|
|
|
cloudlog.info("radard is importing %s", CP.carName) |
|
|
|
|
RadarInterface = importlib.import_module(f'selfdrive.car.{CP.carName}.radar_interface').RadarInterface |
|
|
|
|
|
|
|
|
|
# setup messaging |
|
|
|
|
# *** setup messaging |
|
|
|
|
if can_sock is None: |
|
|
|
|
can_sock = messaging.sub_sock('can') |
|
|
|
|
if sm is None: |
|
|
|
|
sm = messaging.SubMaster(['modelV2', 'carState'], poll=["modelV2"]) |
|
|
|
|
sm = messaging.SubMaster(['modelV2', 'carState'], ignore_avg_freq=['modelV2', 'carState']) # Can't check average frequency, since radar determines timing |
|
|
|
|
if pm is None: |
|
|
|
|
pm = messaging.PubMaster(['radarState', 'liveTracks']) |
|
|
|
|
|
|
|
|
|
interface = RadarInterface(CP) |
|
|
|
|
RI = RadarInterface(CP) |
|
|
|
|
|
|
|
|
|
rk = Ratekeeper(1 / DT_MDL, print_delay_threshold=None) |
|
|
|
|
radar = RadarD(DT_MDL, interface.delay) |
|
|
|
|
rk = Ratekeeper(1.0 / CP.radarTimeStep, print_delay_threshold=None) |
|
|
|
|
RD = RadarD(CP.radarTimeStep, RI.delay) |
|
|
|
|
|
|
|
|
|
while True: |
|
|
|
|
sm.update() |
|
|
|
|
while 1: |
|
|
|
|
can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True) |
|
|
|
|
rr = RI.update(can_strings) |
|
|
|
|
|
|
|
|
|
if sm.updated['modelV2']: |
|
|
|
|
can_strings = messaging.drain_sock_raw(can_sock) |
|
|
|
|
radar_data = interface.update(can_strings) |
|
|
|
|
if rr is None: |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
sm.update(0) |
|
|
|
|
|
|
|
|
|
radar.update(sm, radar_data) |
|
|
|
|
radar.publish(pm, -rk.remaining*1000.0) |
|
|
|
|
RD.update(sm, rr) |
|
|
|
|
RD.publish(pm, -rk.remaining*1000.0) |
|
|
|
|
|
|
|
|
|
rk.monitor_time() |
|
|
|
|
rk.monitor_time() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(sm: Optional[messaging.SubMaster] = None, pm: Optional[messaging.PubMaster] = None, can_sock: messaging.SubSocket = None): |
|
|
|
|