parent
eb89041a6a
commit
02cedeadd9
95 changed files with 1755 additions and 626 deletions
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:3bf24d5dd606d364e339c8823a5b71b0a5271716b551a187ca8a8ea457a275d0 |
||||
size 17042107 |
||||
oid sha256:9eba15d8e77847b242a83fbd43dd67a5bd5d0c6d76f4f11f6fd6820621f69771 |
||||
size 17096653 |
||||
|
@ -1,7 +1,7 @@ |
||||
{ |
||||
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f.zip", |
||||
"ota_hash": "c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f", |
||||
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a.img", |
||||
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11.zip", |
||||
"ota_hash": "4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11", |
||||
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662.img", |
||||
"recovery_len": 15136044, |
||||
"recovery_hash": "af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a" |
||||
"recovery_hash": "31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662" |
||||
} |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:743ba86c3b4d643272c11eba28e2b0a8824c542caa613a94ff6a2f01c37e54a7 |
||||
size 2501656 |
||||
oid sha256:da43154c2563cfda1af50018a412a6105338c4fafc021f8b3c7442fcec514d44 |
||||
size 2464536 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:32aef4d710c994e0c8a019b64eb2bd495f493be0dc0daa9f312f7dfeeb7f1568 |
||||
size 14761531 |
||||
oid sha256:f5fb0036eaaa6136b8b605c24ab255de45b14ce827af538e15c47a04a6b200af |
||||
size 14438998 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:eb047afc34b4b5b9888dc1dfc796d4f83fc695734decac5f6a6057a70e468623 |
||||
size 544528 |
||||
oid sha256:9fdd514ad8a38876468adf9fa106f511150c077223c13eb1cc3ae939bc414564 |
||||
size 601956 |
||||
|
@ -1,3 +0,0 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:ef2ab0e402d5cb9de893e263a2c44e57f57fec3974b0d981bfe84dec3dae83a1 |
||||
size 162464 |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:c898025ae57cbc55d29af9381fe65fd2db4704beb46c606411c4522d059bfe0b |
||||
size 428188 |
||||
oid sha256:f888f84627b4b69395cdf3f8bedf7a6a50c13253b30b7ddc2eda010c8be16b66 |
||||
size 40662 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:bd26959d1a73071764378885fbb1a2941cfd4a15650361a5b6fbeccf81900def |
||||
size 159998 |
||||
oid sha256:113afc45a281e491a771bdd749f1375b96b174e9c74a8dff5ab1cd83f3cad406 |
||||
size 40654 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:6c0cf1b6fcdb5489146b2973aed01c4deb2bed34d9610e39b8dc3596d6e1e9af |
||||
size 71030 |
||||
oid sha256:301eef864fa7b306527828bb9e8295208c08c24382026391a9206b19aca58a4e |
||||
size 40650 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:d39d45560063a9b3f0b2c473cda5ea1e052b38ee3fd7dcbd4465043b37f661ed |
||||
size 128798 |
||||
oid sha256:9cffe1d8cd2dec399fb3fce5ce2833e0405bd44191d3a24d6085592cd8d31dd5 |
||||
size 21468 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:8249c685cab9896799290f28a53cc3751dd3fbf31c300e03fd039cd129e6c03c |
||||
size 119446 |
||||
oid sha256:62580fd60d5784505f4f7697e5a5011cf0ae1f3c92ed1104700159bfbcd7de3e |
||||
size 52800 |
||||
|
@ -1 +1 @@ |
||||
#define COMMA_VERSION "0.6.2-release" |
||||
#define COMMA_VERSION "0.6.3-release" |
||||
|
@ -0,0 +1,74 @@ |
||||
from common.numpy_fast import interp |
||||
import numpy as np |
||||
from selfdrive.controls.lib.latcontrol_helpers import model_polyfit, compute_path_pinv |
||||
|
||||
CAMERA_OFFSET = 0.06 # m from center car to camera |
||||
|
||||
|
||||
def calc_d_poly(l_poly, r_poly, p_poly, l_prob, r_prob, lane_width): |
||||
# This will improve behaviour when lanes suddenly widen |
||||
lane_width = min(4.0, lane_width) |
||||
l_prob = l_prob * interp(abs(l_poly[3]), [2, 2.5], [1.0, 0.0]) |
||||
r_prob = r_prob * interp(abs(r_poly[3]), [2, 2.5], [1.0, 0.0]) |
||||
|
||||
path_from_left_lane = l_poly.copy() |
||||
path_from_left_lane[3] -= lane_width / 2.0 |
||||
path_from_right_lane = r_poly.copy() |
||||
path_from_right_lane[3] += lane_width / 2.0 |
||||
|
||||
lr_prob = l_prob + r_prob - l_prob * r_prob |
||||
|
||||
d_poly_lane = (l_prob * path_from_left_lane + r_prob * path_from_right_lane) / (l_prob + r_prob + 0.0001) |
||||
return lr_prob * d_poly_lane + (1.0 - lr_prob) * p_poly |
||||
|
||||
|
||||
class LanePlanner(object): |
||||
def __init__(self): |
||||
self.l_poly = [0., 0., 0., 0.] |
||||
self.r_poly = [0., 0., 0., 0.] |
||||
self.p_poly = [0., 0., 0., 0.] |
||||
self.d_poly = [0., 0., 0., 0.] |
||||
|
||||
self.lane_width_estimate = 3.7 |
||||
self.lane_width_certainty = 1.0 |
||||
self.lane_width = 3.7 |
||||
|
||||
self.l_prob = 0. |
||||
self.r_prob = 0. |
||||
self.lr_prob = 0. |
||||
|
||||
self._path_pinv = compute_path_pinv() |
||||
self.x_points = np.arange(50) |
||||
|
||||
def parse_model(self, md): |
||||
if len(md.leftLane.poly): |
||||
self.l_poly = np.array(md.leftLane.poly) |
||||
self.r_poly = np.array(md.rightLane.poly) |
||||
self.p_poly = np.array(md.path.poly) |
||||
else: |
||||
self.l_poly = model_polyfit(md.leftLane.points, self._path_pinv) # left line |
||||
self.r_poly = model_polyfit(md.rightLane.points, self._path_pinv) # right line |
||||
self.p_poly = model_polyfit(md.path.points, self._path_pinv) # predicted path |
||||
self.l_prob = md.leftLane.prob # left line prob |
||||
self.r_prob = md.rightLane.prob # right line prob |
||||
|
||||
def update_lane(self, v_ego): |
||||
# only offset left and right lane lines; offsetting p_poly does not make sense |
||||
self.l_poly[3] += CAMERA_OFFSET |
||||
self.r_poly[3] += CAMERA_OFFSET |
||||
|
||||
self.lr_prob = self.l_prob + self.r_prob - self.l_prob * self.r_prob |
||||
|
||||
# Find current lanewidth |
||||
self.lane_width_certainty += 0.05 * (self.l_prob * self.r_prob - self.lane_width_certainty) |
||||
current_lane_width = abs(self.l_poly[3] - self.r_poly[3]) |
||||
self.lane_width_estimate += 0.005 * (current_lane_width - self.lane_width_estimate) |
||||
speed_lane_width = interp(v_ego, [0., 31.], [2.8, 3.5]) |
||||
self.lane_width = self.lane_width_certainty * self.lane_width_estimate + \ |
||||
(1 - self.lane_width_certainty) * speed_lane_width |
||||
|
||||
self.d_poly = calc_d_poly(self.l_poly, self.r_poly, self.p_poly, self.l_prob, self.r_prob, self.lane_width) |
||||
|
||||
def update(self, v_ego, md): |
||||
self.parse_model(md) |
||||
self.update_lane(v_ego) |
@ -0,0 +1,72 @@ |
||||
import numpy as np |
||||
from selfdrive.controls.lib.drive_helpers import get_steer_max |
||||
from common.numpy_fast import clip |
||||
from cereal import log |
||||
|
||||
|
||||
class LatControlLQR(object): |
||||
def __init__(self, CP, rate=100): |
||||
self.sat_flag = False |
||||
self.scale = CP.lateralTuning.lqr.scale |
||||
self.ki = CP.lateralTuning.lqr.ki |
||||
|
||||
|
||||
self.A = np.array(CP.lateralTuning.lqr.a).reshape((2,2)) |
||||
self.B = np.array(CP.lateralTuning.lqr.b).reshape((2,1)) |
||||
self.C = np.array(CP.lateralTuning.lqr.c).reshape((1,2)) |
||||
self.K = np.array(CP.lateralTuning.lqr.k).reshape((1,2)) |
||||
self.L = np.array(CP.lateralTuning.lqr.l).reshape((2,1)) |
||||
self.dc_gain = CP.lateralTuning.lqr.dcGain |
||||
|
||||
self.x_hat = np.array([[0], [0]]) |
||||
self.i_unwind_rate = 0.3 / rate |
||||
self.i_rate = 1.0 / rate |
||||
|
||||
self.reset() |
||||
|
||||
def reset(self): |
||||
self.i_lqr = 0.0 |
||||
self.output_steer = 0.0 |
||||
|
||||
def update(self, active, v_ego, angle_steers, angle_steers_rate, eps_torque, steer_override, CP, VM, path_plan): |
||||
lqr_log = log.ControlsState.LateralLQRState.new_message() |
||||
|
||||
torque_scale = (0.45 + v_ego / 60.0)**2 # Scale actuator model with speed |
||||
|
||||
# Subtract offset. Zero angle should correspond to zero torque |
||||
self.angle_steers_des = path_plan.angleSteers - path_plan.angleOffset |
||||
angle_steers -= path_plan.angleOffset |
||||
|
||||
# Update Kalman filter |
||||
angle_steers_k = float(self.C.dot(self.x_hat)) |
||||
e = angle_steers - angle_steers_k |
||||
self.x_hat = self.A.dot(self.x_hat) + self.B.dot(eps_torque / torque_scale) + self.L.dot(e) |
||||
|
||||
if v_ego < 0.3 or not active: |
||||
lqr_log.active = False |
||||
self.reset() |
||||
else: |
||||
lqr_log.active = True |
||||
|
||||
# LQR |
||||
u_lqr = float(self.angle_steers_des / self.dc_gain - self.K.dot(self.x_hat)) |
||||
|
||||
# Integrator |
||||
if steer_override: |
||||
self.i_lqr -= self.i_unwind_rate * float(np.sign(self.i_lqr)) |
||||
else: |
||||
self.i_lqr += self.ki * self.i_rate * (self.angle_steers_des - angle_steers_k) |
||||
|
||||
lqr_output = torque_scale * u_lqr / self.scale |
||||
self.i_lqr = clip(self.i_lqr, -1.0 - lqr_output, 1.0 - lqr_output) # (LQR + I) has to be between -1 and 1 |
||||
|
||||
self.output_steer = lqr_output + self.i_lqr |
||||
|
||||
# Clip output |
||||
steers_max = get_steer_max(CP, v_ego) |
||||
self.output_steer = clip(self.output_steer, -steers_max, steers_max) |
||||
|
||||
lqr_log.steerAngle = angle_steers_k + path_plan.angleOffset |
||||
lqr_log.i = self.i_lqr |
||||
lqr_log.output = self.output_steer |
||||
return self.output_steer, float(self.angle_steers_des), lqr_log |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f1d93e7b412f1573e2b6b22b11587bbed076d59a1c1c6d8f6d69eddc3998518c |
||||
oid sha256:b175a66de26ad7bd788086a2d6a7ef6243eb2a0aac1ddcff39b00554a8960d97 |
||||
size 8823 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5cf12c96cffb69f1e659a20760c9ad3ab74ecce3d88aba1e50af359ab14c88da |
||||
size 18662 |
||||
oid sha256:5848ec6e7975d6fee93187e0f41d6cba57cc0ebee6edf63ebddf3c7ad6f8f52c |
||||
size 18622 |
||||
|
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:269cf8ba0c80202e59352e7474d5aa768fa1ffc8268e051496d28629fa8cb144 |
||||
size 400285 |
||||
oid sha256:a2c030dd09379475b0247609d8a02f161f3e468e85480740d4abcf9c80868de0 |
||||
size 390405 |
||||
|
@ -1,66 +0,0 @@ |
||||
from common.numpy_fast import interp |
||||
import numpy as np |
||||
from selfdrive.controls.lib.latcontrol_helpers import model_polyfit, calc_desired_path, compute_path_pinv |
||||
|
||||
CAMERA_OFFSET = 0.06 # m from center car to camera |
||||
|
||||
|
||||
class ModelParser(object): |
||||
def __init__(self): |
||||
self.d_poly = [0., 0., 0., 0.] |
||||
self.c_poly = [0., 0., 0., 0.] |
||||
self.c_prob = 0. |
||||
self.last_model = 0. |
||||
self.lead_dist, self.lead_prob, self.lead_var = 0, 0, 1 |
||||
self._path_pinv = compute_path_pinv() |
||||
|
||||
self.lane_width_estimate = 3.7 |
||||
self.lane_width_certainty = 1.0 |
||||
self.lane_width = 3.7 |
||||
self.l_prob = 0. |
||||
self.r_prob = 0. |
||||
self.x_points = np.arange(50) |
||||
|
||||
def update(self, v_ego, md): |
||||
if len(md.leftLane.poly): |
||||
l_poly = np.array(md.leftLane.poly) |
||||
r_poly = np.array(md.rightLane.poly) |
||||
p_poly = np.array(md.path.poly) |
||||
else: |
||||
l_poly = model_polyfit(md.leftLane.points, self._path_pinv) # left line |
||||
r_poly = model_polyfit(md.rightLane.points, self._path_pinv) # right line |
||||
p_poly = model_polyfit(md.path.points, self._path_pinv) # predicted path |
||||
|
||||
# only offset left and right lane lines; offsetting p_poly does not make sense |
||||
l_poly[3] += CAMERA_OFFSET |
||||
r_poly[3] += CAMERA_OFFSET |
||||
|
||||
p_prob = 1. # model does not tell this probability yet, so set to 1 for now |
||||
l_prob = md.leftLane.prob # left line prob |
||||
r_prob = md.rightLane.prob # right line prob |
||||
|
||||
# Find current lanewidth |
||||
lr_prob = l_prob * r_prob |
||||
self.lane_width_certainty += 0.05 * (lr_prob - self.lane_width_certainty) |
||||
current_lane_width = abs(l_poly[3] - r_poly[3]) |
||||
self.lane_width_estimate += 0.005 * (current_lane_width - self.lane_width_estimate) |
||||
speed_lane_width = interp(v_ego, [0., 31.], [2.8, 3.5]) |
||||
self.lane_width = self.lane_width_certainty * self.lane_width_estimate + \ |
||||
(1 - self.lane_width_certainty) * speed_lane_width |
||||
|
||||
self.lead_dist = md.lead.dist |
||||
self.lead_prob = md.lead.prob |
||||
self.lead_var = md.lead.std**2 |
||||
|
||||
# compute target path |
||||
self.d_poly, self.c_poly, self.c_prob = calc_desired_path( |
||||
l_poly, r_poly, p_poly, l_prob, r_prob, p_prob, v_ego, self.lane_width) |
||||
|
||||
self.r_poly = r_poly |
||||
self.r_prob = r_prob |
||||
|
||||
self.l_poly = l_poly |
||||
self.l_prob = l_prob |
||||
|
||||
self.p_poly = p_poly |
||||
self.p_prob = p_prob |
@ -0,0 +1,22 @@ |
||||
#!/usr/bin/env python2 |
||||
import os |
||||
import sys |
||||
import subprocess |
||||
from azure.storage.blob import BlockBlobService |
||||
|
||||
def upload_file(path, name): |
||||
sas_token = os.getenv("TOKEN", None) |
||||
if sas_token is not None: |
||||
service = BlockBlobService(account_name="commadataci", sas_token=sas_token) |
||||
else: |
||||
account_key = subprocess.check_output("az storage account keys list --account-name commadataci --output tsv --query '[0].value'", shell=True) |
||||
service = BlockBlobService(account_name="commadataci", account_key=account_key) |
||||
service.create_blob_from_path("openpilotci", name, path) |
||||
return "https://commadataci.blob.core.windows.net/openpilotci/" + name |
||||
|
||||
if __name__ == "__main__": |
||||
for f in sys.argv[1:]: |
||||
name = os.path.basename(f) |
||||
url = upload_file(f, name) |
||||
print url |
||||
|
@ -0,0 +1,494 @@ |
||||
#!/usr/bin/env python2 |
||||
import shutil |
||||
import time |
||||
import zmq |
||||
import os |
||||
import sys |
||||
import signal |
||||
import subprocess |
||||
import requests |
||||
from cereal import car |
||||
|
||||
import selfdrive.manager as manager |
||||
from selfdrive.services import service_list |
||||
import selfdrive.messaging as messaging |
||||
from common.params import Params |
||||
from common.basedir import BASEDIR |
||||
from selfdrive.car.honda.values import CAR as HONDA |
||||
from selfdrive.car.toyota.values import CAR as TOYOTA |
||||
from selfdrive.car.gm.values import CAR as GM |
||||
from selfdrive.car.ford.values import CAR as FORD |
||||
from selfdrive.car.hyundai.values import CAR as HYUNDAI |
||||
from selfdrive.car.chrysler.values import CAR as CHRYSLER |
||||
from selfdrive.car.subaru.values import CAR as SUBARU |
||||
from selfdrive.car.mock.values import CAR as MOCK |
||||
|
||||
|
||||
os.environ['NOCRASH'] = '1' |
||||
|
||||
|
||||
def wait_for_socket(name, timeout=10.0): |
||||
socket = messaging.sub_sock(service_list[name].port) |
||||
cur_time = time.time() |
||||
|
||||
r = None |
||||
while time.time() - cur_time < timeout: |
||||
print("waiting for %s" % name) |
||||
try: |
||||
r = socket.recv(zmq.NOBLOCK) |
||||
break |
||||
except zmq.error.Again: |
||||
pass |
||||
time.sleep(0.5) |
||||
return r |
||||
|
||||
def get_route_logs(route_name): |
||||
for log_f in ["rlog.bz2", "fcamera.hevc"]: |
||||
log_path = os.path.join("/tmp", "%s--0--%s" % (route_name.replace("|", "_"), log_f)) |
||||
|
||||
if not os.path.isfile(log_path): |
||||
log_url = "https://commadataci.blob.core.windows.net/openpilotci/%s/0/%s" % (route_name.replace("|", "/"), log_f) |
||||
r = requests.get(log_url) |
||||
|
||||
if r.status_code == 200: |
||||
with open(log_path, "w") as f: |
||||
f.write(r.content) |
||||
else: |
||||
sys.exit(-1) |
||||
|
||||
routes = { |
||||
|
||||
"975b26878285314d|2018-12-25--14-42-13": { |
||||
'carFingerprint': CHRYSLER.PACIFICA_2018_HYBRID, |
||||
'enableCamera': True, |
||||
}, |
||||
"b0c9d2329ad1606b|2019-01-06--10-11-23": { |
||||
'carFingerprint': CHRYSLER.PACIFICA_2017_HYBRID, |
||||
'enableCamera': True, |
||||
}, |
||||
"0607d2516fc2148f|2019-02-13--23-03-16": { |
||||
'carFingerprint': CHRYSLER.PACIFICA_2019_HYBRID, |
||||
'enableCamera': True, |
||||
}, |
||||
# This pacifica was removed because the fingerprint seemed from a Volt |
||||
#"9f7a7e50a51fb9db|2019-01-03--14-05-01": { |
||||
# 'carFingerprint': CHRYSLER.PACIFICA_2018, |
||||
# 'enableCamera': True, |
||||
#}, |
||||
"9f7a7e50a51fb9db|2019-01-17--18-34-21": { |
||||
'carFingerprint': CHRYSLER.JEEP_CHEROKEE, |
||||
'enableCamera': True, |
||||
}, |
||||
"192a598e34926b1e|2019-04-04--13-27-39": { |
||||
'carFingerprint': CHRYSLER.JEEP_CHEROKEE_2019, |
||||
'enableCamera': True, |
||||
}, |
||||
"f1b4c567731f4a1b|2018-04-18--11-29-37": { |
||||
'carFingerprint': FORD.FUSION, |
||||
'enableCamera': False, |
||||
}, |
||||
"f1b4c567731f4a1b|2018-04-30--10-15-35": { |
||||
'carFingerprint': FORD.FUSION, |
||||
'enableCamera': True, |
||||
}, |
||||
"7ed9cdf8d0c5f43e|2018-05-17--09-31-36": { |
||||
'carFingerprint': GM.CADILLAC_CT6, |
||||
'enableCamera': True, |
||||
}, |
||||
"265007255e794bce|2018-11-24--22-08-31": { |
||||
'carFingerprint': GM.CADILLAC_ATS, |
||||
'enableCamera': True, |
||||
}, |
||||
"c950e28c26b5b168|2018-05-30--22-03-41": { |
||||
'carFingerprint': GM.VOLT, |
||||
'enableCamera': True, |
||||
}, |
||||
# TODO: use another route that has radar data at start |
||||
"aadda448b49c99ad|2018-10-25--17-16-22": { |
||||
'carFingerprint': GM.MALIBU, |
||||
'enableCamera': True, |
||||
}, |
||||
"49c73650e65ff465|2018-11-19--16-58-04": { |
||||
'carFingerprint': GM.HOLDEN_ASTRA, |
||||
'enableCamera': True, |
||||
}, |
||||
"7cc2a8365b4dd8a9|2018-12-02--12-10-44": { |
||||
'carFingerprint': GM.ACADIA, |
||||
'enableCamera': True, |
||||
}, |
||||
"aa20e335f61ba898|2018-12-17--21-10-37": { |
||||
'carFingerprint': GM.BUICK_REGAL, |
||||
'enableCamera': False, |
||||
}, |
||||
"aa20e335f61ba898|2019-02-05--16-59-04": { |
||||
'carFingerprint': GM.BUICK_REGAL, |
||||
'enableCamera': True, |
||||
}, |
||||
"7d44af5b7a1b2c8e|2017-09-16--01-50-07": { |
||||
'carFingerprint': HONDA.CIVIC, |
||||
'enableCamera': True, |
||||
}, |
||||
"c9d60e5e02c04c5c|2018-01-08--16-01-49": { |
||||
'carFingerprint': HONDA.CRV, |
||||
'enableCamera': True, |
||||
}, |
||||
"1851183c395ef471|2018-05-31--18-07-21": { |
||||
'carFingerprint': HONDA.CRV_5G, |
||||
'enableCamera': True, |
||||
}, |
||||
"232585b7784c1af4|2019-04-08--14-12-14": { |
||||
'carFingerprint': HONDA.CRV_HYBRID, |
||||
'enableCamera': True, |
||||
}, |
||||
"2ac95059f70d76eb|2018-02-05--15-03-29": { |
||||
'carFingerprint': HONDA.ACURA_ILX, |
||||
'enableCamera': True, |
||||
}, |
||||
"21aa231dee2a68bd|2018-01-30--04-54-41": { |
||||
'carFingerprint': HONDA.ODYSSEY, |
||||
'enableCamera': True, |
||||
}, |
||||
"81722949a62ea724|2019-03-29--15-51-26": { |
||||
'carFingerprint': HONDA.ODYSSEY_CHN, |
||||
'enableCamera': False, |
||||
}, |
||||
"81722949a62ea724|2019-04-06--15-19-25": { |
||||
'carFingerprint': HONDA.ODYSSEY_CHN, |
||||
'enableCamera': True, |
||||
}, |
||||
"5a2cfe4bb362af9e|2018-02-02--23-41-07": { |
||||
'carFingerprint': HONDA.ACURA_RDX, |
||||
'enableCamera': True, |
||||
}, |
||||
"3e9592a1c78a3d63|2018-02-08--20-28-24": { |
||||
'carFingerprint': HONDA.PILOT, |
||||
'enableCamera': True, |
||||
}, |
||||
"34a84d2b765df688|2018-08-28--12-41-00": { |
||||
'carFingerprint': HONDA.PILOT_2019, |
||||
'enableCamera': True, |
||||
}, |
||||
"900ad17e536c3dc7|2018-04-12--22-02-36": { |
||||
'carFingerprint': HONDA.RIDGELINE, |
||||
'enableCamera': True, |
||||
}, |
||||
"f1b4c567731f4a1b|2018-06-06--14-43-46": { |
||||
'carFingerprint': HONDA.ACCORD, |
||||
'enableCamera': True, |
||||
}, |
||||
"1582e1dc57175194|2018-08-15--07-46-07": { |
||||
'carFingerprint': HONDA.ACCORD_15, |
||||
'enableCamera': True, |
||||
}, |
||||
# TODO: This doesnt fingerprint because the fingerprint overlaps with the Insight |
||||
# "690c4c9f9f2354c7|2018-09-15--17-36-05": { |
||||
# 'carFingerprint': HONDA.ACCORDH, |
||||
# 'enableCamera': True, |
||||
# }, |
||||
"1632088eda5e6c4d|2018-06-07--08-03-18": { |
||||
'carFingerprint': HONDA.CIVIC_BOSCH, |
||||
'enableCamera': True, |
||||
}, |
||||
#"18971a99f3f2b385|2018-11-14--19-09-31": { |
||||
# 'carFingerprint': HONDA.INSIGHT, |
||||
# 'enableCamera': True, |
||||
#}, |
||||
"38bfd238edecbcd7|2018-08-22--09-45-44": { |
||||
'carFingerprint': HYUNDAI.SANTA_FE, |
||||
'enableCamera': False, |
||||
}, |
||||
"38bfd238edecbcd7|2018-08-29--22-02-15": { |
||||
'carFingerprint': HYUNDAI.SANTA_FE, |
||||
'enableCamera': True, |
||||
}, |
||||
"a893a80e5c5f72c8|2019-01-14--20-02-59": { |
||||
'carFingerprint': HYUNDAI.GENESIS, |
||||
'enableCamera': True, |
||||
}, |
||||
"9d5fb4f0baa1b3e1|2019-01-14--17-45-59": { |
||||
'carFingerprint': HYUNDAI.KIA_SORENTO, |
||||
'enableCamera': True, |
||||
}, |
||||
"215cd70e9c349266|2018-11-25--22-22-12": { |
||||
'carFingerprint': HYUNDAI.KIA_STINGER, |
||||
'enableCamera': True, |
||||
}, |
||||
"31390e3eb6f7c29a|2019-01-23--08-56-00": { |
||||
'carFingerprint': HYUNDAI.KIA_OPTIMA, |
||||
'enableCamera': True, |
||||
}, |
||||
"53ac3251e03f95d7|2019-01-10--13-43-32": { |
||||
'carFingerprint': HYUNDAI.ELANTRA, |
||||
'enableCamera': True, |
||||
}, |
||||
"f7b6be73e3dfd36c|2019-05-12--18-07-16": { |
||||
'carFingerprint': TOYOTA.AVALON, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"f7b6be73e3dfd36c|2019-05-11--22-34-20": { |
||||
'carFingerprint': TOYOTA.AVALON, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"b0f5a01cf604185c|2018-01-26--00-54-32": { |
||||
'carFingerprint': TOYOTA.COROLLA, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"b0f5a01cf604185c|2018-01-26--10-54-38": { |
||||
'carFingerprint': TOYOTA.COROLLA, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"b0f5a01cf604185c|2018-01-26--10-59-31": { |
||||
'carFingerprint': TOYOTA.COROLLA, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"5f5afb36036506e4|2019-05-14--02-09-54": { |
||||
'carFingerprint': TOYOTA.COROLLA_TSS2, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"56fb1c86a9a86404|2017-11-10--10-18-43": { |
||||
'carFingerprint': TOYOTA.PRIUS, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"b0f5a01cf604185c|2017-12-18--20-32-32": { |
||||
'carFingerprint': TOYOTA.RAV4, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
'enableGasInterceptor': False, |
||||
}, |
||||
"b0c9d2329ad1606b|2019-04-02--13-24-43": { |
||||
'carFingerprint': TOYOTA.RAV4, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
'enableGasInterceptor': True, |
||||
}, |
||||
"cdf2f7de565d40ae|2019-04-25--03-53-41": { |
||||
'carFingerprint': TOYOTA.RAV4_TSS2, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"f49e8041283f2939|2019-05-29--13-48-33": { |
||||
'carFingerprint': TOYOTA.LEXUS_ESH_TSS2, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"f49e8041283f2939|2019-05-30--11-51-51": { |
||||
'carFingerprint': TOYOTA.LEXUS_ESH_TSS2, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"b0f5a01cf604185c|2018-02-01--21-12-28": { |
||||
'carFingerprint': TOYOTA.LEXUS_RXH, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
#FIXME: This works sometimes locally, but never in CI. Timing issue? |
||||
#"b0f5a01cf604185c|2018-01-31--20-11-39": { |
||||
# 'carFingerprint': TOYOTA.LEXUS_RXH, |
||||
# 'enableCamera': False, |
||||
# 'enableDsu': False, |
||||
#}, |
||||
"8ae193ceb56a0efe|2018-06-18--20-07-32": { |
||||
'carFingerprint': TOYOTA.RAV4H, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"fd10b9a107bb2e49|2018-07-24--16-32-42": { |
||||
'carFingerprint': TOYOTA.CHR, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"fd10b9a107bb2e49|2018-07-24--20-32-08": { |
||||
'carFingerprint': TOYOTA.CHR, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"b4c18bf13d5955da|2018-07-29--13-39-46": { |
||||
'carFingerprint': TOYOTA.CHRH, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"d2d8152227f7cb82|2018-07-25--13-40-56": { |
||||
'carFingerprint': TOYOTA.CAMRY, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"fbd011384db5e669|2018-07-26--20-51-48": { |
||||
'carFingerprint': TOYOTA.CAMRYH, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
# TODO: This replay has no good model/video |
||||
# "c9fa2dd0f76caf23|2018-02-10--13-40-28": { |
||||
# 'carFingerprint': TOYOTA.CAMRYH, |
||||
# 'enableCamera': False, |
||||
# 'enableDsu': False, |
||||
# }, |
||||
# TODO: missingsome combos for highlander |
||||
"aa659debdd1a7b54|2018-08-31--11-12-01": { |
||||
'carFingerprint': TOYOTA.HIGHLANDER, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"362d23d4d5bea2fa|2018-09-02--17-03-55": { |
||||
'carFingerprint': TOYOTA.HIGHLANDERH, |
||||
'enableCamera': True, |
||||
'enableDsu': True, |
||||
}, |
||||
"eb6acd681135480d|2019-06-20--20-00-00": { |
||||
'carFingerprint': TOYOTA.SIENNA, |
||||
'enableCamera': True, |
||||
'enableDsu': False, |
||||
}, |
||||
"362d23d4d5bea2fa|2018-08-10--13-31-40": { |
||||
'carFingerprint': TOYOTA.HIGHLANDERH, |
||||
'enableCamera': False, |
||||
'enableDsu': False, |
||||
}, |
||||
"791340bc01ed993d|2019-03-10--16-28-08": { |
||||
'carFingerprint': SUBARU.IMPREZA, |
||||
'enableCamera': True, |
||||
}, |
||||
# Tesla route, should result in mock car |
||||
"07cb8a788c31f645|2018-06-17--18-50-29": { |
||||
'carFingerprint': MOCK.MOCK, |
||||
}, |
||||
## Route with no can data, should result in mock car. This is not supported anymore |
||||
#"bfa17080b080f3ec|2018-06-28--23-27-47": { |
||||
# 'carFingerprint': MOCK.MOCK, |
||||
#}, |
||||
} |
||||
|
||||
passive_routes = [ |
||||
"07cb8a788c31f645|2018-06-17--18-50-29", |
||||
#"bfa17080b080f3ec|2018-06-28--23-27-47", |
||||
] |
||||
|
||||
public_routes = [ |
||||
"f1b4c567731f4a1b|2018-06-06--14-43-46", |
||||
"f1b4c567731f4a1b|2018-04-18--11-29-37", |
||||
"f1b4c567731f4a1b|2018-04-18--11-29-37", |
||||
"7ed9cdf8d0c5f43e|2018-05-17--09-31-36", |
||||
"38bfd238edecbcd7|2018-08-22--09-45-44", |
||||
"38bfd238edecbcd7|2018-08-29--22-02-15", |
||||
"b0f5a01cf604185c|2018-01-26--00-54-32", |
||||
"b0f5a01cf604185c|2018-01-26--10-54-38", |
||||
"b0f5a01cf604185c|2018-01-26--10-59-31", |
||||
"56fb1c86a9a86404|2017-11-10--10-18-43", |
||||
"b0f5a01cf604185c|2017-12-18--20-32-32", |
||||
"b0c9d2329ad1606b|2019-04-02--13-24-43", |
||||
"791340bc01ed993d|2019-03-10--16-28-08", |
||||
] |
||||
|
||||
if __name__ == "__main__": |
||||
|
||||
results = {} |
||||
for route, checks in routes.items(): |
||||
|
||||
if route not in public_routes: |
||||
print "route not public", route |
||||
continue |
||||
|
||||
get_route_logs(route) |
||||
|
||||
for _ in range(3): |
||||
shutil.rmtree('/data/params') |
||||
manager.gctx = {} |
||||
params = Params() |
||||
params.manager_start() |
||||
if route in passive_routes: |
||||
params.put("Passive", "1") |
||||
else: |
||||
params.put("Passive", "0") |
||||
|
||||
print "testing ", route, " ", checks['carFingerprint'] |
||||
print "Preparing processes" |
||||
manager.prepare_managed_process("radard") |
||||
manager.prepare_managed_process("controlsd") |
||||
manager.prepare_managed_process("plannerd") |
||||
print "Starting processes" |
||||
manager.start_managed_process("radard") |
||||
manager.start_managed_process("controlsd") |
||||
manager.start_managed_process("plannerd") |
||||
time.sleep(2) |
||||
|
||||
# Start unlogger |
||||
print "Start unlogger" |
||||
unlogger_cmd = [os.path.join(BASEDIR, 'tools/replay/unlogger.py'), '%s' % route, '/tmp', '--disable', 'frame,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl', '--no-interactive'] |
||||
unlogger = subprocess.Popen(unlogger_cmd, preexec_fn=os.setsid) |
||||
|
||||
print "Check sockets" |
||||
controls_state_result = wait_for_socket('controlsState', timeout=30) |
||||
radarstate_result = wait_for_socket('radarState', timeout=30) |
||||
plan_result = wait_for_socket('plan', timeout=30) |
||||
|
||||
if route not in passive_routes: # TODO The passive routes have very flaky models |
||||
path_plan_result = wait_for_socket('pathPlan', timeout=30) |
||||
else: |
||||
path_plan_result = True |
||||
|
||||
carstate_result = wait_for_socket('carState', timeout=30) |
||||
|
||||
print "Check if everything is running" |
||||
running = manager.get_running() |
||||
controlsd_running = running['controlsd'].is_alive() |
||||
radard_running = running['radard'].is_alive() |
||||
plannerd_running = running['plannerd'].is_alive() |
||||
|
||||
manager.kill_managed_process("controlsd") |
||||
manager.kill_managed_process("radard") |
||||
manager.kill_managed_process("plannerd") |
||||
os.killpg(os.getpgid(unlogger.pid), signal.SIGTERM) |
||||
|
||||
sockets_ok = all([ |
||||
controls_state_result, radarstate_result, plan_result, path_plan_result, carstate_result, |
||||
controlsd_running, radard_running, plannerd_running |
||||
]) |
||||
params_ok = True |
||||
failures = [] |
||||
|
||||
if not controlsd_running: |
||||
failures.append('controlsd') |
||||
if not radard_running: |
||||
failures.append('radard') |
||||
if not radarstate_result: |
||||
failures.append('radarState') |
||||
if not controls_state_result: |
||||
failures.append('controlsState') |
||||
if not plan_result: |
||||
failures.append('plan') |
||||
if not path_plan_result: |
||||
failures.append('pathPlan') |
||||
|
||||
try: |
||||
car_params = car.CarParams.from_bytes(params.get("CarParams")) |
||||
for k, v in checks.items(): |
||||
if not v == getattr(car_params, k): |
||||
params_ok = False |
||||
failures.append(k) |
||||
except: |
||||
params_ok = False |
||||
|
||||
if sockets_ok and params_ok: |
||||
print "Success" |
||||
results[route] = True, failures |
||||
break |
||||
else: |
||||
print "Failure" |
||||
results[route] = False, failures |
||||
|
||||
time.sleep(2) |
||||
|
||||
print results |
||||
params.put("Passive", "0") # put back not passive to not leave the params in an unintended state |
||||
if not all(passed for passed, _ in results.values()): |
||||
print "TEST FAILED" |
||||
sys.exit(1) |
||||
else: |
||||
print "TEST SUCESSFUL" |
@ -0,0 +1,2 @@ |
||||
*.bz2 |
||||
diff.txt |
@ -0,0 +1,15 @@ |
||||
# process replay |
||||
|
||||
Process replay is a regression test designed to identify any changes in the output of a process. This test replays a segment through individual processes and compares the output to a known good replay. Each make is represented in the test with a segment. |
||||
|
||||
If the test fails, make sure that you didn't unintentionally change anything. If there are intentional changes, the reference logs will be updated. |
||||
|
||||
Use `test_processes.py` to run the test locally. |
||||
|
||||
Currently the following processes are tested: |
||||
|
||||
* controlsd |
||||
* radard |
||||
* plannerd |
||||
* calibrationd |
||||
|
@ -0,0 +1,45 @@ |
||||
#!/usr/bin/env python2 |
||||
import bz2 |
||||
import os |
||||
import sys |
||||
|
||||
import dictdiffer |
||||
if "CI" in os.environ: |
||||
tqdm = lambda x: x |
||||
else: |
||||
from tqdm import tqdm |
||||
|
||||
from tools.lib.logreader import LogReader |
||||
|
||||
|
||||
def save_log(dest, log_msgs): |
||||
dat = "" |
||||
for msg in log_msgs: |
||||
dat += msg.as_builder().to_bytes() |
||||
dat = bz2.compress(dat) |
||||
|
||||
with open(dest, "w") as f: |
||||
f.write(dat) |
||||
|
||||
def compare_logs(log1, log2, ignore=[]): |
||||
assert len(log1) == len(log2), "logs are not same length" |
||||
|
||||
diff = [] |
||||
for msg1, msg2 in tqdm(zip(log1, log2)): |
||||
assert msg1.which() == msg2.which(), "msgs not aligned between logs" |
||||
|
||||
msg1_bytes = msg1.as_builder().to_bytes() |
||||
msg2_bytes = msg2.as_builder().to_bytes() |
||||
|
||||
if msg1_bytes != msg2_bytes: |
||||
msg1_dict = msg1.to_dict(verbose=True) |
||||
msg2_dict = msg2.to_dict(verbose=True) |
||||
dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore, tolerance=0) |
||||
diff.extend(dd) |
||||
return diff |
||||
|
||||
if __name__ == "__main__": |
||||
log1 = list(LogReader(sys.argv[1])) |
||||
log2 = list(LogReader(sys.argv[2])) |
||||
|
||||
compare_logs(log1, log2, sys.argv[3:]) |
@ -0,0 +1,185 @@ |
||||
#!/usr/bin/env python2 |
||||
import gc |
||||
import os |
||||
import time |
||||
|
||||
if "CI" in os.environ: |
||||
tqdm = lambda x: x |
||||
else: |
||||
from tqdm import tqdm |
||||
|
||||
from cereal import car |
||||
from selfdrive.car.car_helpers import get_car |
||||
import selfdrive.manager as manager |
||||
import selfdrive.messaging as messaging |
||||
from common.params import Params |
||||
from selfdrive.services import service_list |
||||
from collections import namedtuple |
||||
|
||||
ProcessConfig = namedtuple('ProcessConfig', ['proc_name', 'pub_sub', 'ignore', 'init_callback', 'should_recv_callback']) |
||||
|
||||
def fingerprint(msgs, pub_socks, sub_socks): |
||||
print "start fingerprinting" |
||||
manager.prepare_managed_process("logmessaged") |
||||
manager.start_managed_process("logmessaged") |
||||
|
||||
can = pub_socks["can"] |
||||
logMessage = messaging.sub_sock(service_list["logMessage"].port) |
||||
|
||||
time.sleep(1) |
||||
messaging.drain_sock(logMessage) |
||||
|
||||
# controlsd waits for a health packet before fingerprinting |
||||
msg = messaging.new_message() |
||||
msg.init("health") |
||||
pub_socks["health"].send(msg.to_bytes()) |
||||
|
||||
canmsgs = filter(lambda msg: msg.which() == "can", msgs) |
||||
for msg in canmsgs[:200]: |
||||
can.send(msg.as_builder().to_bytes()) |
||||
|
||||
time.sleep(0.005) |
||||
log = messaging.recv_one_or_none(logMessage) |
||||
if log is not None and "fingerprinted" in log.logMessage: |
||||
break |
||||
manager.kill_managed_process("logmessaged") |
||||
print "finished fingerprinting" |
||||
|
||||
def get_car_params(msgs, pub_socks, sub_socks): |
||||
sendcan = pub_socks.get("sendcan", None) |
||||
if sendcan is None: |
||||
sendcan = messaging.pub_sock(service_list["sendcan"].port) |
||||
logcan = sub_socks.get("can", None) |
||||
if logcan is None: |
||||
logcan = messaging.sub_sock(service_list["can"].port) |
||||
can = pub_socks.get("can", None) |
||||
if can is None: |
||||
can = messaging.pub_sock(service_list["can"].port) |
||||
|
||||
time.sleep(0.5) |
||||
|
||||
canmsgs = filter(lambda msg: msg.which() == "can", msgs) |
||||
for m in canmsgs[:200]: |
||||
can.send(m.as_builder().to_bytes()) |
||||
_, CP = get_car(logcan, sendcan) |
||||
Params().put("CarParams", CP.to_bytes()) |
||||
time.sleep(0.5) |
||||
messaging.drain_sock(logcan) |
||||
|
||||
def radar_rcv_callback(msg, CP): |
||||
if msg.which() != "can": |
||||
return [] |
||||
|
||||
# hyundai and subaru don't have radar |
||||
radar_msgs = {"honda": [0x445], "toyota": [0x19f, 0x22f], "gm": [0x475], |
||||
"hyundai": [], "chrysler": [0x2d4], "subaru": []}.get(CP.carName, None) |
||||
|
||||
if radar_msgs is None: |
||||
raise NotImplementedError |
||||
|
||||
for m in msg.can: |
||||
if m.src == 1 and m.address in radar_msgs: |
||||
return ["radarState", "liveTracks"] |
||||
|
||||
return [] |
||||
|
||||
def plannerd_rcv_callback(msg, CP): |
||||
if msg.which() in ["model", "radarState"]: |
||||
time.sleep(0.005) |
||||
else: |
||||
time.sleep(0.002) |
||||
return {"model": ["pathPlan"], "radarState": ["plan"]}.get(msg.which(), []) |
||||
|
||||
CONFIGS = [ |
||||
ProcessConfig( |
||||
proc_name="controlsd", |
||||
pub_sub={ |
||||
"can": ["controlsState", "carState", "carControl", "sendcan"], |
||||
"thermal": [], "health": [], "liveCalibration": [], "driverMonitoring": [], "plan": [], "pathPlan": [] |
||||
}, |
||||
ignore=["logMonoTime", "controlsState.startMonoTime", "controlsState.cumLagMs"], |
||||
init_callback=fingerprint, |
||||
should_recv_callback=None, |
||||
), |
||||
ProcessConfig( |
||||
proc_name="radard", |
||||
pub_sub={ |
||||
"can": ["radarState", "liveTracks"], |
||||
"liveParameters": [], "controlsState": [], "model": [], |
||||
}, |
||||
ignore=["logMonoTime", "radarState.cumLagMs"], |
||||
init_callback=get_car_params, |
||||
should_recv_callback=radar_rcv_callback, |
||||
), |
||||
ProcessConfig( |
||||
proc_name="plannerd", |
||||
pub_sub={ |
||||
"model": ["pathPlan"], "radarState": ["plan"], |
||||
"carState": [], "controlsState": [], "liveParameters": [], |
||||
}, |
||||
ignore=["logMonoTime", "valid", "plan.processingDelay"], |
||||
init_callback=get_car_params, |
||||
should_recv_callback=plannerd_rcv_callback, |
||||
), |
||||
ProcessConfig( |
||||
proc_name="calibrationd", |
||||
pub_sub={ |
||||
"cameraOdometry": ["liveCalibration"] |
||||
}, |
||||
ignore=["logMonoTime"], |
||||
init_callback=get_car_params, |
||||
should_recv_callback=None, |
||||
), |
||||
] |
||||
|
||||
def replay_process(cfg, lr): |
||||
gc.disable() # gc can occasionally cause canparser to timeout |
||||
|
||||
pub_socks, sub_socks = {}, {} |
||||
for pub, sub in cfg.pub_sub.iteritems(): |
||||
pub_socks[pub] = messaging.pub_sock(service_list[pub].port) |
||||
|
||||
for s in sub: |
||||
sub_socks[s] = messaging.sub_sock(service_list[s].port) |
||||
|
||||
all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime) |
||||
pub_msgs = filter(lambda msg: msg.which() in pub_socks.keys(), all_msgs) |
||||
|
||||
params = Params() |
||||
params.manager_start() |
||||
params.put("Passive", "0") |
||||
|
||||
manager.gctx = {} |
||||
manager.prepare_managed_process(cfg.proc_name) |
||||
manager.start_managed_process(cfg.proc_name) |
||||
time.sleep(3) # Wait for started process to be ready |
||||
|
||||
if cfg.init_callback is not None: |
||||
cfg.init_callback(all_msgs, pub_socks, sub_socks) |
||||
|
||||
CP = car.CarParams.from_bytes(params.get("CarParams", block=True)) |
||||
|
||||
log_msgs = [] |
||||
for msg in tqdm(pub_msgs): |
||||
if cfg.should_recv_callback is not None: |
||||
recv_socks = cfg.should_recv_callback(msg, CP) |
||||
else: |
||||
recv_socks = cfg.pub_sub[msg.which()] |
||||
|
||||
pub_socks[msg.which()].send(msg.as_builder().to_bytes()) |
||||
|
||||
if len(recv_socks): |
||||
# TODO: add timeout |
||||
for sock in recv_socks: |
||||
m = messaging.recv_one(sub_socks[sock]) |
||||
|
||||
# make these values fixed for faster comparison |
||||
m_builder = m.as_builder() |
||||
m_builder.logMonoTime = 0 |
||||
m_builder.valid = True |
||||
log_msgs.append(m_builder.as_reader()) |
||||
|
||||
gc.enable() |
||||
manager.kill_managed_process(cfg.proc_name) |
||||
return log_msgs |
||||
|
@ -0,0 +1 @@ |
||||
e3388c62ffb80f4b3ca8721da56a581a93c44e79 |
@ -0,0 +1,118 @@ |
||||
#!/usr/bin/env python2 |
||||
import os |
||||
import requests |
||||
import sys |
||||
import tempfile |
||||
|
||||
from selfdrive.test.tests.process_replay.compare_logs import compare_logs |
||||
from selfdrive.test.tests.process_replay.process_replay import replay_process, CONFIGS |
||||
from tools.lib.logreader import LogReader |
||||
|
||||
segments = [ |
||||
"0375fdf7b1ce594d|2019-06-13--08-32-25--3", # HONDA.ACCORD |
||||
"99c94dc769b5d96e|2019-08-03--14-19-59--2", # HONDA.CIVIC |
||||
"cce908f7eb8db67d|2019-08-02--15-09-51--3", # TOYOTA.COROLLA_TSS2 |
||||
"7ad88f53d406b787|2019-07-09--10-18-56--8", # GM.VOLT |
||||
"704b2230eb5190d6|2019-07-06--19-29-10--0", # HYUNDAI.KIA_SORENTO |
||||
"b6e1317e1bfbefa6|2019-07-06--04-05-26--5", # CHRYSLER.JEEP_CHEROKEE |
||||
"7873afaf022d36e2|2019-07-03--18-46-44--0", # SUBARU.IMPREZA |
||||
] |
||||
|
||||
def get_segment(segment_name): |
||||
route_name, segment_num = segment_name.rsplit("--", 1) |
||||
rlog_url = "https://commadataci.blob.core.windows.net/openpilotci/%s/%s/rlog.bz2" \ |
||||
% (route_name.replace("|", "/"), segment_num) |
||||
r = requests.get(rlog_url) |
||||
if r.status_code != 200: |
||||
return None |
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix=".bz2") as f: |
||||
f.write(r.content) |
||||
return f.name |
||||
|
||||
if __name__ == "__main__": |
||||
|
||||
process_replay_dir = os.path.dirname(os.path.abspath(__file__)) |
||||
ref_commit_fn = os.path.join(process_replay_dir, "ref_commit") |
||||
|
||||
if not os.path.isfile(ref_commit_fn): |
||||
print "couldn't find reference commit" |
||||
sys.exit(1) |
||||
|
||||
ref_commit = open(ref_commit_fn).read().strip() |
||||
print "***** testing against commit %s *****" % ref_commit |
||||
|
||||
results = {} |
||||
for segment in segments: |
||||
print "***** testing route segment %s *****\n" % segment |
||||
|
||||
results[segment] = {} |
||||
|
||||
rlog_fn = get_segment(segment) |
||||
|
||||
if rlog_fn is None: |
||||
print "failed to get segment %s" % segment |
||||
sys.exit(1) |
||||
|
||||
lr = LogReader(rlog_fn) |
||||
|
||||
for cfg in CONFIGS: |
||||
log_msgs = replay_process(cfg, lr) |
||||
|
||||
log_fn = os.path.join(process_replay_dir, "%s_%s_%s.bz2" % (segment, cfg.proc_name, ref_commit)) |
||||
|
||||
if not os.path.isfile(log_fn): |
||||
url = "https://commadataci.blob.core.windows.net/openpilotci/" |
||||
req = requests.get(url + os.path.basename(log_fn)) |
||||
if req.status_code != 200: |
||||
results[segment][cfg.proc_name] = "failed to download comparison log" |
||||
continue |
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".bz2") as f: |
||||
f.write(req.content) |
||||
f.flush() |
||||
f.seek(0) |
||||
cmp_log_msgs = list(LogReader(f.name)) |
||||
else: |
||||
cmp_log_msgs = list(LogReader(log_fn)) |
||||
|
||||
diff = compare_logs(cmp_log_msgs, log_msgs, cfg.ignore) |
||||
results[segment][cfg.proc_name] = diff |
||||
os.remove(rlog_fn) |
||||
|
||||
failed = False |
||||
with open(os.path.join(process_replay_dir, "diff.txt"), "w") as f: |
||||
f.write("***** tested against commit %s *****\n" % ref_commit) |
||||
|
||||
for segment, result in results.items(): |
||||
f.write("***** differences for segment %s *****\n" % segment) |
||||
print "***** results for segment %s *****" % segment |
||||
|
||||
for proc, diff in result.items(): |
||||
f.write("*** process: %s ***\n" % proc) |
||||
print "\t%s" % proc |
||||
|
||||
if isinstance(diff, str): |
||||
print "\t\t%s" % diff |
||||
failed = True |
||||
elif len(diff): |
||||
cnt = {} |
||||
for d in diff: |
||||
f.write("\t%s\n" % str(d)) |
||||
|
||||
k = str(d[1]) |
||||
cnt[k] = 1 if k not in cnt else cnt[k] + 1 |
||||
|
||||
for k, v in sorted(cnt.items()): |
||||
print "\t\t%s: %s" % (k, v) |
||||
failed = True |
||||
|
||||
if failed: |
||||
print "TEST FAILED" |
||||
else: |
||||
print "TEST SUCCEEDED" |
||||
|
||||
print "\n\nTo update the reference logs for this test run:" |
||||
print "./update_refs.py" |
||||
|
||||
sys.exit(int(failed)) |
@ -0,0 +1,42 @@ |
||||
#!/usr/bin/env python2 |
||||
import os |
||||
import sys |
||||
|
||||
from selfdrive.test.openpilotci_upload import upload_file |
||||
from selfdrive.test.tests.process_replay.compare_logs import save_log |
||||
from selfdrive.test.tests.process_replay.process_replay import replay_process, CONFIGS |
||||
from selfdrive.test.tests.process_replay.test_processes import segments, get_segment |
||||
from selfdrive.version import get_git_commit |
||||
from tools.lib.logreader import LogReader |
||||
|
||||
if __name__ == "__main__": |
||||
|
||||
no_upload = "--no-upload" in sys.argv |
||||
|
||||
process_replay_dir = os.path.dirname(os.path.abspath(__file__)) |
||||
ref_commit_fn = os.path.join(process_replay_dir, "ref_commit") |
||||
|
||||
ref_commit = get_git_commit() |
||||
with open(ref_commit_fn, "w") as f: |
||||
f.write(ref_commit) |
||||
|
||||
for segment in segments: |
||||
rlog_fn = get_segment(segment) |
||||
|
||||
if rlog_fn is None: |
||||
print "failed to get segment %s" % segment |
||||
sys.exit(1) |
||||
|
||||
lr = LogReader(rlog_fn) |
||||
|
||||
for cfg in CONFIGS: |
||||
log_msgs = replay_process(cfg, lr) |
||||
log_fn = os.path.join(process_replay_dir, "%s_%s_%s.bz2" % (segment, cfg.proc_name, ref_commit)) |
||||
save_log(log_fn, log_msgs) |
||||
|
||||
if not no_upload: |
||||
upload_file(log_fn, os.path.basename(log_fn)) |
||||
os.remove(log_fn) |
||||
os.remove(rlog_fn) |
||||
|
||||
print "done" |
@ -1,3 +1,3 @@ |
||||
version https://git-lfs.github.com/spec/v1 |
||||
oid sha256:11953df252f1cd63d7cd2101508b89c96f5de073b3181c4262f1a26d3c871ca1 |
||||
oid sha256:7a4f45d19c1d85792e4c48a60f7d9beb0264ce187ff5edccf8532fda37fe831d |
||||
size 239976 |
||||
|
Loading…
Reference in new issue