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 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:3bf24d5dd606d364e339c8823a5b71b0a5271716b551a187ca8a8ea457a275d0 |
oid sha256:9eba15d8e77847b242a83fbd43dd67a5bd5d0c6d76f4f11f6fd6820621f69771 |
||||||
size 17042107 |
size 17096653 |
||||||
|
@ -1,7 +1,7 @@ |
|||||||
{ |
{ |
||||||
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f.zip", |
"ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11.zip", |
||||||
"ota_hash": "c992abb59cbaf6588f51055db52db619061107851773fc8480acb8bb5d77a28f", |
"ota_hash": "4db25072191d24e204a816d73ac9e8c727822a26ed3baf01ecae18167fa2eb11", |
||||||
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a.img", |
"recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662.img", |
||||||
"recovery_len": 15136044, |
"recovery_len": 15136044, |
||||||
"recovery_hash": "af099a84cfd7b91266090779238ac358278948dcde2dcfa0fbca6e8397366f0a" |
"recovery_hash": "31ef14206d3102edf18fb7417ef32ba2d9f37dd2f4443e234c374a70d1bf4662" |
||||||
} |
} |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:743ba86c3b4d643272c11eba28e2b0a8824c542caa613a94ff6a2f01c37e54a7 |
oid sha256:da43154c2563cfda1af50018a412a6105338c4fafc021f8b3c7442fcec514d44 |
||||||
size 2501656 |
size 2464536 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:32aef4d710c994e0c8a019b64eb2bd495f493be0dc0daa9f312f7dfeeb7f1568 |
oid sha256:f5fb0036eaaa6136b8b605c24ab255de45b14ce827af538e15c47a04a6b200af |
||||||
size 14761531 |
size 14438998 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:eb047afc34b4b5b9888dc1dfc796d4f83fc695734decac5f6a6057a70e468623 |
oid sha256:9fdd514ad8a38876468adf9fa106f511150c077223c13eb1cc3ae939bc414564 |
||||||
size 544528 |
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 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:c898025ae57cbc55d29af9381fe65fd2db4704beb46c606411c4522d059bfe0b |
oid sha256:f888f84627b4b69395cdf3f8bedf7a6a50c13253b30b7ddc2eda010c8be16b66 |
||||||
size 428188 |
size 40662 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:bd26959d1a73071764378885fbb1a2941cfd4a15650361a5b6fbeccf81900def |
oid sha256:113afc45a281e491a771bdd749f1375b96b174e9c74a8dff5ab1cd83f3cad406 |
||||||
size 159998 |
size 40654 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:6c0cf1b6fcdb5489146b2973aed01c4deb2bed34d9610e39b8dc3596d6e1e9af |
oid sha256:301eef864fa7b306527828bb9e8295208c08c24382026391a9206b19aca58a4e |
||||||
size 71030 |
size 40650 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:d39d45560063a9b3f0b2c473cda5ea1e052b38ee3fd7dcbd4465043b37f661ed |
oid sha256:9cffe1d8cd2dec399fb3fce5ce2833e0405bd44191d3a24d6085592cd8d31dd5 |
||||||
size 128798 |
size 21468 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:8249c685cab9896799290f28a53cc3751dd3fbf31c300e03fd039cd129e6c03c |
oid sha256:62580fd60d5784505f4f7697e5a5011cf0ae1f3c92ed1104700159bfbcd7de3e |
||||||
size 119446 |
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
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f1d93e7b412f1573e2b6b22b11587bbed076d59a1c1c6d8f6d69eddc3998518c |
oid sha256:b175a66de26ad7bd788086a2d6a7ef6243eb2a0aac1ddcff39b00554a8960d97 |
||||||
size 8823 |
size 8823 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:5cf12c96cffb69f1e659a20760c9ad3ab74ecce3d88aba1e50af359ab14c88da |
oid sha256:5848ec6e7975d6fee93187e0f41d6cba57cc0ebee6edf63ebddf3c7ad6f8f52c |
||||||
size 18662 |
size 18622 |
||||||
|
@ -1,3 +1,3 @@ |
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:269cf8ba0c80202e59352e7474d5aa768fa1ffc8268e051496d28629fa8cb144 |
oid sha256:a2c030dd09379475b0247609d8a02f161f3e468e85480740d4abcf9c80868de0 |
||||||
size 400285 |
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 |
version https://git-lfs.github.com/spec/v1 |
||||||
oid sha256:11953df252f1cd63d7cd2101508b89c96f5de073b3181c4262f1a26d3c871ca1 |
oid sha256:7a4f45d19c1d85792e4c48a60f7d9beb0264ce187ff5edccf8532fda37fe831d |
||||||
size 239976 |
size 239976 |
||||||
|
Loading…
Reference in new issue