Merge remote-tracking branch 'upstream/master' into toyota-lta

pull/27494/head
Shane Smiskol 3 years ago
commit b14fc9fa0f
  1. 2
      .github/workflows/selfdrive_tests.yaml
  2. 5
      Jenkinsfile
  3. 13
      selfdrive/car/__init__.py
  4. 15
      selfdrive/car/nissan/carcontroller.py
  5. 7
      selfdrive/car/nissan/values.py
  6. 14
      selfdrive/car/tesla/carcontroller.py
  7. 7
      selfdrive/car/tesla/values.py
  8. 2
      selfdrive/controls/controlsd.py
  9. 16
      selfdrive/navd/map_renderer.cc
  10. 1
      selfdrive/navd/map_renderer.h
  11. 40
      selfdrive/test/process_replay/compare_logs.py
  12. 70
      selfdrive/test/process_replay/model_replay.py
  13. 2
      selfdrive/test/process_replay/model_replay_ref_commit
  14. 2
      selfdrive/ui/qt/widgets/cameraview.cc
  15. 2
      selfdrive/ui/soundd/sound.cc
  16. 2
      tools/cabana/binaryview.cc
  17. 2
      tools/cabana/cabana
  18. 12
      tools/cabana/cabana.cc
  19. 4
      tools/cabana/canmessages.cc
  20. 3
      tools/cabana/canmessages.h
  21. 2
      tools/cabana/dbcmanager.cc
  22. 2
      tools/cabana/videowidget.cc

@ -294,7 +294,7 @@ jobs:
- name: Run model replay with ONNX - name: Run model replay with ONNX
timeout-minutes: 2 timeout-minutes: 2
run: | run: |
${{ env.RUN_CL }} "ONNXCPU=1 CI=1 coverage run selfdrive/test/process_replay/model_replay.py && \ ${{ env.RUN_CL }} "ONNXCPU=1 CI=1 NO_NAV=1 coverage run selfdrive/test/process_replay/model_replay.py && \
coverage xml" coverage xml"
- name: Run unit tests - name: Run unit tests
timeout-minutes: 5 timeout-minutes: 5

5
Jenkinsfile vendored

@ -11,6 +11,7 @@ export SOURCE_DIR=${env.SOURCE_DIR}
export GIT_BRANCH=${env.GIT_BRANCH} export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT} export GIT_COMMIT=${env.GIT_COMMIT}
export AZURE_TOKEN='${env.AZURE_TOKEN}' export AZURE_TOKEN='${env.AZURE_TOKEN}'
export MAPBOX_TOKEN='${env.MAPBOX_TOKEN}'
source ~/.bash_profile source ~/.bash_profile
if [ -f /TICI ]; then if [ -f /TICI ]; then
@ -47,9 +48,11 @@ pipeline {
TEST_DIR = "/data/openpilot" TEST_DIR = "/data/openpilot"
SOURCE_DIR = "/data/openpilot_source/" SOURCE_DIR = "/data/openpilot_source/"
AZURE_TOKEN = credentials('azure_token') AZURE_TOKEN = credentials('azure_token')
MAPBOX_TOKEN = credentials('mapbox_token')
} }
options { options {
timeout(time: 4, unit: 'HOURS') timeout(time: 3, unit: 'HOURS')
disableConcurrentBuilds(abortPrevious: env.BRANCH_NAME != 'master')
} }
stages { stages {

@ -1,8 +1,9 @@
# functions common among cars # functions common among cars
import capnp import capnp
from collections import namedtuple
from cereal import car from cereal import car
from common.numpy_fast import clip from common.numpy_fast import clip, interp
from typing import Dict from typing import Dict
# kg of standard extra cargo to count for drive, gas, etc... # kg of standard extra cargo to count for drive, gas, etc...
@ -10,6 +11,7 @@ STD_CARGO_KG = 136.
ButtonType = car.CarState.ButtonEvent.Type ButtonType = car.CarState.ButtonEvent.Type
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v'])
def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float: def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float:
@ -111,6 +113,15 @@ def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torq
return int(round(float(apply_torque))) return int(round(float(apply_torque)))
def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS):
# pick angle rate limits based on wind up/down
steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last)
rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN
angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v)
return clip(apply_angle, apply_angle_last - angle_rate_lim, apply_angle_last + angle_rate_lim)
def crc8_pedal(data): def crc8_pedal(data):
crc = 0xFF # standard init value crc = 0xFF # standard init value
poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1 poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1

@ -1,6 +1,6 @@
from cereal import car from cereal import car
from common.numpy_fast import clip, interp
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_angle_limits
from selfdrive.car.nissan import nissancan from selfdrive.car.nissan import nissancan
from selfdrive.car.nissan.values import CAR, CarControllerParams from selfdrive.car.nissan.values import CAR, CarControllerParams
@ -14,7 +14,7 @@ class CarController:
self.frame = 0 self.frame = 0
self.lkas_max_torque = 0 self.lkas_max_torque = 0
self.last_angle = 0 self.apply_angle_last = 0
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
@ -28,18 +28,11 @@ class CarController:
### STEER ### ### STEER ###
lkas_hud_msg = CS.lkas_hud_msg lkas_hud_msg = CS.lkas_hud_msg
lkas_hud_info_msg = CS.lkas_hud_info_msg lkas_hud_info_msg = CS.lkas_hud_info_msg
apply_angle = actuators.steeringAngleDeg
steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0 steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
if CC.latActive: if CC.latActive:
# windup slower # windup slower
if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle): apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams)
angle_rate_lim = interp(CS.out.vEgo, CarControllerParams.ANGLE_DELTA_BP, CarControllerParams.ANGLE_DELTA_V)
else:
angle_rate_lim = interp(CS.out.vEgo, CarControllerParams.ANGLE_DELTA_BP, CarControllerParams.ANGLE_DELTA_VU)
apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim, self.last_angle + angle_rate_lim)
# Max torque from driver before EPS will give up and not apply torque # Max torque from driver before EPS will give up and not apply torque
if not bool(CS.out.steeringPressed): if not bool(CS.out.steeringPressed):
@ -57,7 +50,7 @@ class CarController:
apply_angle = CS.out.steeringAngleDeg apply_angle = CS.out.steeringAngleDeg
self.lkas_max_torque = 0 self.lkas_max_torque = 0
self.last_angle = apply_angle self.apply_angle_last = apply_angle
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and pcm_cancel_cmd: if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and pcm_cancel_cmd:
can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg)) can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg))

@ -4,7 +4,7 @@ from enum import Enum
from cereal import car from cereal import car
from panda.python import uds from panda.python import uds
from selfdrive.car import dbc_dict from selfdrive.car import AngleRateLimit, dbc_dict
from selfdrive.car.docs_definitions import CarInfo, Harness from selfdrive.car.docs_definitions import CarInfo, Harness
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
@ -12,9 +12,8 @@ Ecu = car.CarParams.Ecu
class CarControllerParams: class CarControllerParams:
ANGLE_DELTA_BP = [0., 5., 15.] ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., .8, .15])
ANGLE_DELTA_V = [5., .8, .15] # windup limit ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., 3.5, 0.4])
ANGLE_DELTA_VU = [5., 3.5, 0.4] # unwind limit
LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower LKAS_MAX_TORQUE = 1 # A value of 1 is easy to overpower
STEER_THRESHOLD = 1.0 STEER_THRESHOLD = 1.0

@ -1,5 +1,6 @@
from common.numpy_fast import clip, interp from common.numpy_fast import clip
from opendbc.can.packer import CANPacker from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_angle_limits
from selfdrive.car.tesla.teslacan import TeslaCAN from selfdrive.car.tesla.teslacan import TeslaCAN
from selfdrive.car.tesla.values import DBC, CANBUS, CarControllerParams from selfdrive.car.tesla.values import DBC, CANBUS, CarControllerParams
@ -8,7 +9,7 @@ class CarController:
def __init__(self, dbc_name, CP, VM): def __init__(self, dbc_name, CP, VM):
self.CP = CP self.CP = CP
self.frame = 0 self.frame = 0
self.last_angle = 0 self.apply_angle_last = 0
self.packer = CANPacker(dbc_name) self.packer = CANPacker(dbc_name)
self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt']) self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt'])
self.tesla_can = TeslaCAN(self.packer, self.pt_packer) self.tesla_can = TeslaCAN(self.packer, self.pt_packer)
@ -24,20 +25,15 @@ class CarController:
lkas_enabled = CC.latActive and not hands_on_fault lkas_enabled = CC.latActive and not hands_on_fault
if lkas_enabled: if lkas_enabled:
apply_angle = actuators.steeringAngleDeg
# Angular rate limit based on speed # Angular rate limit based on speed
steer_up = self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle) apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgo, CarControllerParams)
rate_limit = CarControllerParams.RATE_LIMIT_UP if steer_up else CarControllerParams.RATE_LIMIT_DOWN
max_angle_diff = interp(CS.out.vEgo, rate_limit.speed_points, rate_limit.max_angle_diff_points)
apply_angle = clip(apply_angle, self.last_angle - max_angle_diff, self.last_angle + max_angle_diff)
# To not fault the EPS # To not fault the EPS
apply_angle = clip(apply_angle, CS.out.steeringAngleDeg - 20, CS.out.steeringAngleDeg + 20) apply_angle = clip(apply_angle, CS.out.steeringAngleDeg - 20, CS.out.steeringAngleDeg + 20)
else: else:
apply_angle = CS.out.steeringAngleDeg apply_angle = CS.out.steeringAngleDeg
self.last_angle = apply_angle self.apply_angle_last = apply_angle
can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, self.frame)) can_sends.append(self.tesla_can.create_steering_control(apply_angle, lkas_enabled, self.frame))
# Longitudinal control (in sync with stock message, about 40Hz) # Longitudinal control (in sync with stock message, about 40Hz)

@ -2,14 +2,13 @@ from collections import namedtuple
from typing import Dict, List, Union from typing import Dict, List, Union
from cereal import car from cereal import car
from selfdrive.car import dbc_dict from selfdrive.car import AngleRateLimit, dbc_dict
from selfdrive.car.docs_definitions import CarInfo from selfdrive.car.docs_definitions import CarInfo
from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries from selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_points', 'max_angle_diff_points'])
class CAR: class CAR:
@ -104,8 +103,8 @@ BUTTONS = [
] ]
class CarControllerParams: class CarControllerParams:
RATE_LIMIT_UP = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., .8, .15]) ANGLE_RATE_LIMIT_UP = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., .8, .15])
RATE_LIMIT_DOWN = AngleRateLimit(speed_points=[0., 5., 15.], max_angle_diff_points=[5., 3.5, 0.4]) ANGLE_RATE_LIMIT_DOWN = AngleRateLimit(speed_bp=[0., 5., 15.], angle_v=[5., 3.5, 0.4])
JERK_LIMIT_MAX = 8 JERK_LIMIT_MAX = 8
JERK_LIMIT_MIN = -8 JERK_LIMIT_MIN = -8
ACCEL_TO_SPEED_MULTIPLIER = 3 ACCEL_TO_SPEED_MULTIPLIER = 3

@ -627,7 +627,7 @@ class Controls:
max_torque = abs(self.last_actuators.steer) > 0.99 max_torque = abs(self.last_actuators.steer) > 0.99
if undershooting and turning and good_speed and max_torque: if undershooting and turning and good_speed and max_torque:
self.events.add(EventName.steerSaturated) self.events.add(EventName.steerSaturated)
elif lac_log.active and not CS.steeringPressed and lac_log.saturated: elif lac_log.active and lac_log.saturated:
dpath_points = lat_plan.dPathPoints dpath_points = lat_plan.dPathPoints
if len(dpath_points): if len(dpath_points):
# Check if we deviated from the path # Check if we deviated from the path

@ -4,10 +4,10 @@
#include <string> #include <string>
#include <QApplication> #include <QApplication>
#include <QBuffer> #include <QBuffer>
#include <QDebug>
#include "common/util.h" #include "common/util.h"
#include "common/timing.h" #include "common/timing.h"
#include "common/swaglog.h"
#include "selfdrive/ui/qt/maps/map_helpers.h" #include "selfdrive/ui/qt/maps/map_helpers.h"
const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear const float DEFAULT_ZOOM = 13.5; // Don't go below 13 or features will start to disappear
@ -56,22 +56,27 @@ MapRenderer::MapRenderer(const QMapboxGLSettings &settings, bool online) : m_set
m_map->setFramebufferObject(fbo->handle(), fbo->size()); m_map->setFramebufferObject(fbo->handle(), fbo->size());
gl_functions->glViewport(0, 0, WIDTH, HEIGHT); gl_functions->glViewport(0, 0, WIDTH, HEIGHT);
QObject::connect(m_map.data(), &QMapboxGL::mapLoadingFailed, [=](QMapboxGL::MapLoadingFailure err_code, const QString &reason) {
LOGE("Map loading failed with %d: '%s'\n", err_code, reason.toStdString().c_str());
});
if (online) { if (online) {
vipc_server.reset(new VisionIpcServer("navd")); vipc_server.reset(new VisionIpcServer("navd"));
vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT); vipc_server->create_buffers(VisionStreamType::VISION_STREAM_MAP, NUM_VIPC_BUFFERS, false, WIDTH, HEIGHT);
vipc_server->start_listener(); vipc_server->start_listener();
pm.reset(new PubMaster({"navThumbnail"})); pm.reset(new PubMaster({"navThumbnail"}));
sm.reset(new SubMaster({"liveLocationKalman", "navRoute"})); sm.reset(new SubMaster({"liveLocationKalman", "navRoute"}, {"liveLocationKalman"}));
timer = new QTimer(this); timer = new QTimer(this);
timer->setSingleShot(true);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(msgUpdate())); QObject::connect(timer, SIGNAL(timeout()), this, SLOT(msgUpdate()));
timer->start(50); timer->start(0);
} }
} }
void MapRenderer::msgUpdate() { void MapRenderer::msgUpdate() {
sm->update(0); sm->update(1000);
if (sm->updated("liveLocationKalman")) { if (sm->updated("liveLocationKalman")) {
auto location = (*sm)["liveLocationKalman"].getLiveLocationKalman(); auto location = (*sm)["liveLocationKalman"].getLiveLocationKalman();
@ -92,6 +97,9 @@ void MapRenderer::msgUpdate() {
} }
updateRoute(route); updateRoute(route);
} }
// schedule next update
timer->start(0);
} }
void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) { void MapRenderer::updatePosition(QMapbox::Coordinate position, float bearing) {

@ -25,7 +25,6 @@ public:
bool loaded(); bool loaded();
~MapRenderer(); ~MapRenderer();
private: private:
std::unique_ptr<QOpenGLContext> ctx; std::unique_ptr<QOpenGLContext> ctx;
std::unique_ptr<QOffscreenSurface> surface; std::unique_ptr<QOffscreenSurface> surface;

@ -2,6 +2,7 @@
import bz2 import bz2
import sys import sys
import math import math
import capnp
import numbers import numbers
import dictdiffer import dictdiffer
from collections import Counter from collections import Counter
@ -30,20 +31,23 @@ def remove_ignored_fields(msg, ignore):
continue continue
for k in keys[:-1]: for k in keys[:-1]:
try: # indexing into list
attr = getattr(msg, k) if k.isdigit():
except AttributeError: attr = attr[int(k)]
break
else:
v = getattr(attr, keys[-1])
if isinstance(v, bool):
val = False
elif isinstance(v, numbers.Number):
val = 0
else: else:
raise NotImplementedError('Error ignoring field') attr = getattr(attr, k)
setattr(attr, keys[-1], val)
return msg.as_reader() v = getattr(attr, keys[-1])
if isinstance(v, bool):
val = False
elif isinstance(v, numbers.Number):
val = 0
elif isinstance(v, (list, capnp.lib.capnp._DynamicListBuilder)):
val = []
else:
raise NotImplementedError(f"Unknown type: {type(v)}")
setattr(attr, keys[-1], val)
return msg
def get_field_tolerance(diff_field, field_tolerances): def get_field_tolerance(diff_field, field_tolerances):
@ -79,12 +83,12 @@ def compare_logs(log1, log2, ignore_fields=None, ignore_msgs=None, tolerance=Non
print(msg1, msg2) print(msg1, msg2)
raise Exception("msgs not aligned between logs") raise Exception("msgs not aligned between logs")
msg1_bytes = remove_ignored_fields(msg1, ignore_fields).as_builder().to_bytes() msg1 = remove_ignored_fields(msg1, ignore_fields)
msg2_bytes = remove_ignored_fields(msg2, ignore_fields).as_builder().to_bytes() msg2 = remove_ignored_fields(msg2, ignore_fields)
if msg1_bytes != msg2_bytes: if msg1.to_bytes() != msg2.to_bytes():
msg1_dict = msg1.to_dict(verbose=True) msg1_dict = msg1.as_reader().to_dict(verbose=True)
msg2_dict = msg2.to_dict(verbose=True) msg2_dict = msg2.as_reader().to_dict(verbose=True)
dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields) dd = dictdiffer.diff(msg1_dict, msg2_dict, ignore=ignore_fields)

@ -20,14 +20,17 @@ from system.version import get_commit
from tools.lib.framereader import FrameReader from tools.lib.framereader import FrameReader
from tools.lib.logreader import LogReader from tools.lib.logreader import LogReader
TEST_ROUTE = "4cf7a6ad03080c90|2021-09-29--13-46-36" TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30"
SEGMENT = 0 SEGMENT = 6
MAX_FRAMES = 100 if PC else 600 MAX_FRAMES = 100 if PC else 600
NAV_FRAMES = 20
NO_NAV = "NO_NAV" in os.environ # TODO: make map renderer work in CI
SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0")) SEND_EXTRA_INPUTS = bool(os.getenv("SEND_EXTRA_INPUTS", "0"))
VIPC_STREAM = {"roadCameraState": VisionStreamType.VISION_STREAM_ROAD, "driverCameraState": VisionStreamType.VISION_STREAM_DRIVER, VIPC_STREAM = {"roadCameraState": VisionStreamType.VISION_STREAM_ROAD, "driverCameraState": VisionStreamType.VISION_STREAM_DRIVER,
"wideRoadCameraState": VisionStreamType.VISION_STREAM_WIDE_ROAD} "wideRoadCameraState": VisionStreamType.VISION_STREAM_WIDE_ROAD}
def get_log_fn(ref_commit, test_route): def get_log_fn(ref_commit, test_route):
return f"{test_route}_model_tici_{ref_commit}.bz2" return f"{test_route}_model_tici_{ref_commit}.bz2"
@ -39,6 +42,47 @@ def replace_calib(msg, calib):
return msg return msg
def nav_model_replay(lr):
pm = messaging.PubMaster(['liveLocationKalman', 'navRoute'])
sock = messaging.sub_sock('navModel', conflate=False, timeout=1000)
log_msgs = []
try:
managed_processes['mapsd'].start()
managed_processes['navmodeld'].start()
# setup position and route
nav = [m for m in lr if m.which() == 'navRoute']
llk = [m for m in lr if m.which() == 'liveLocationKalman']
assert len(nav) > 0 and len(llk) > 0
for _ in range(30):
for s in (llk, nav):
msg = s[0]
pm.send(msg.which(), msg.as_builder().to_bytes())
if messaging.recv_one(sock) is not None:
break
else:
raise Exception("no navmodeld outputs")
time.sleep(2)
messaging.drain_sock_raw(sock)
# run replay
for _ in range(NAV_FRAMES):
# 2Hz decimation
for _ in range(10):
pm.send(llk[0].which(), llk[0].as_builder().to_bytes())
time.sleep(0.1)
with Timeout(5, "timed out waiting for nav model outputs"):
log_msgs.append(messaging.recv_one_retry(sock))
finally:
managed_processes['mapsd'].stop()
managed_processes['navmodeld'].stop()
return log_msgs
def model_replay(lr, frs): def model_replay(lr, frs):
if not PC: if not PC:
spinner = Spinner() spinner = Spinner()
@ -154,8 +198,10 @@ if __name__ == "__main__":
'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True) 'wideRoadCameraState': FrameReader(get_url(TEST_ROUTE, SEGMENT, log_type="ecamera"), readahead=True)
} }
# run replay # run replays
log_msgs = model_replay(lr, frs) log_msgs = model_replay(lr, frs)
if not NO_NAV:
log_msgs += nav_model_replay(lr)
# get diff # get diff
failed = False failed = False
@ -164,15 +210,29 @@ if __name__ == "__main__":
ref_commit = f.read().strip() ref_commit = f.read().strip()
log_fn = get_log_fn(ref_commit, TEST_ROUTE) log_fn = get_log_fn(ref_commit, TEST_ROUTE)
try: try:
cmp_log = list(LogReader(BASE_URL + log_fn))[:2*MAX_FRAMES] expected_msgs = 2*MAX_FRAMES
if not NO_NAV:
expected_msgs += NAV_FRAMES
cmp_log = list(LogReader(BASE_URL + log_fn))[:expected_msgs]
ignore = [ ignore = [
'logMonoTime', 'logMonoTime',
'modelV2.frameDropPerc', 'modelV2.frameDropPerc',
'modelV2.modelExecutionTime', 'modelV2.modelExecutionTime',
'driverStateV2.modelExecutionTime', 'driverStateV2.modelExecutionTime',
'driverStateV2.dspExecutionTime' 'driverStateV2.dspExecutionTime',
'navModel.dspExecutionTime',
'navModel.modelExecutionTime',
] ]
if PC:
ignore += [
'modelV2.laneLines.0.t',
'modelV2.laneLines.1.t',
'modelV2.laneLines.2.t',
'modelV2.laneLines.3.t',
'modelV2.roadEdges.0.t',
'modelV2.roadEdges.1.t',
]
# TODO this tolerance is absurdly large # TODO this tolerance is absurdly large
tolerance = 2.0 if PC else None tolerance = 2.0 if PC else None
results: Any = {TEST_ROUTE: {}} results: Any = {TEST_ROUTE: {}}

@ -1 +1 @@
30efb4238327d723e17a3bda7e7c19c18f8a3b18 4b2c6516cd460ee443b9006f01233168edf3d170

@ -359,7 +359,7 @@ void CameraWidget::vipcThread() {
if (!vipc_client || cur_stream != requested_stream_type) { if (!vipc_client || cur_stream != requested_stream_type) {
clearFrames(); clearFrames();
qDebug() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; qDebug() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream;
cur_stream = requested_stream_type;; cur_stream = requested_stream_type;
vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false));
} }
active_stream_type = cur_stream; active_stream_type = cur_stream;

@ -48,7 +48,7 @@ void Sound::update() {
// scale volume using ambient noise level // scale volume using ambient noise level
if (sm.updated("microphone")) { if (sm.updated("microphone")) {
float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 52.f, 0.f, 1.f); float volume = util::map_val(sm["microphone"].getMicrophone().getFilteredSoundPressureWeightedDb(), 30.f, 54.f, 0.f, 1.f);
volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
Hardware::set_volume(volume); Hardware::set_volume(volume);
} }

@ -202,7 +202,7 @@ void BinaryViewModel::updateState() {
} }
} }
for (int i = 0; i < row_count; ++i) { for (int i = 0; i < row_count * column_count; ++i) {
if (i >= prev_items.size() || prev_items[i].val != items[i].val) { if (i >= prev_items.size() || prev_items[i].val != items[i].val) {
auto idx = index(i / column_count, i % column_count); auto idx = index(i / column_count, i % column_count);
emit dataChanged(idx, idx); emit dataChanged(idx, idx);

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
cd "$(dirname "$0")" cd "$(dirname "$0")"
export LD_LIBRARY_PATH="../../opendbc/can:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH="../../opendbc/can:$LD_LIBRARY_PATH"
exec ./_cabana "$1" exec ./_cabana "$@"

@ -15,6 +15,7 @@ int main(int argc, char *argv[]) {
cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai"); cmd_parser.addPositionalArgument("route", "the drive to replay. find your drives at connect.comma.ai");
cmd_parser.addOption({"demo", "use a demo route instead of providing your own"}); cmd_parser.addOption({"demo", "use a demo route instead of providing your own"});
cmd_parser.addOption({"qcam", "load qcamera"}); cmd_parser.addOption({"qcam", "load qcamera"});
cmd_parser.addOption({"ecam", "load wide road camera"});
cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"}); cmd_parser.addOption({"data_dir", "local directory with routes", "data_dir"});
cmd_parser.process(app); cmd_parser.process(app);
const QStringList args = cmd_parser.positionalArguments(); const QStringList args = cmd_parser.positionalArguments();
@ -29,10 +30,17 @@ int main(int argc, char *argv[]) {
dir.mkdir(msgq_path); dir.mkdir(msgq_path);
setenv("OPENPILOT_PREFIX", qPrintable(uuid), 1); setenv("OPENPILOT_PREFIX", qPrintable(uuid), 1);
int ret = 0;
const QString route = args.empty() ? DEMO_ROUTE : args.first(); const QString route = args.empty() ? DEMO_ROUTE : args.first();
uint32_t replay_flags = REPLAY_FLAG_NONE;
if (cmd_parser.isSet("ecam")) {
replay_flags |= REPLAY_FLAG_ECAM;
} else if (cmd_parser.isSet("qcam")) {
replay_flags |= REPLAY_FLAG_QCAMERA;
}
CANMessages p(&app); CANMessages p(&app);
if (p.loadRoute(route, cmd_parser.value("data_dir"), cmd_parser.isSet("qcam"))) { int ret = 0;
if (p.loadRoute(route, cmd_parser.value("data_dir"), replay_flags)) {
MainWindow w; MainWindow w;
w.showMaximized(); w.showMaximized();
ret = app.exec(); ret = app.exec();

@ -21,8 +21,8 @@ static bool event_filter(const Event *e, void *opaque) {
return c->eventFilter(e); return c->eventFilter(e);
} }
bool CANMessages::loadRoute(const QString &route, const QString &data_dir, bool use_qcam) { bool CANMessages::loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags) {
replay = new Replay(route, {"can", "roadEncodeIdx", "carParams"}, {}, nullptr, use_qcam ? REPLAY_FLAG_QCAMERA : 0, data_dir, this); replay = new Replay(route, {"can", "roadEncodeIdx", "wideRoadEncodeIdx", "carParams"}, {}, nullptr, replay_flags, data_dir, this);
replay->setSegmentCacheLimit(settings.cached_segment_limit); replay->setSegmentCacheLimit(settings.cached_segment_limit);
replay->installEventFilter(event_filter, this); replay->installEventFilter(event_filter, this);
QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged); QObject::connect(replay, &Replay::segmentsMerged, this, &CANMessages::eventsMerged);

@ -26,13 +26,14 @@ public:
enum FindFlags{ EQ, LT, GT }; enum FindFlags{ EQ, LT, GT };
CANMessages(QObject *parent); CANMessages(QObject *parent);
~CANMessages(); ~CANMessages();
bool loadRoute(const QString &route, const QString &data_dir, bool use_qcam); bool loadRoute(const QString &route, const QString &data_dir, uint32_t replay_flags = REPLAY_FLAG_NONE);
void seekTo(double ts); void seekTo(double ts);
QList<QPointF> findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count); QList<QPointF> findSignalValues(const QString&id, const Signal* signal, double value, FindFlags flag, int max_count);
bool eventFilter(const Event *event); bool eventFilter(const Event *event);
inline QString routeName() const { return replay->route()->name(); } inline QString routeName() const { return replay->route()->name(); }
inline QString carFingerprint() const { return replay->carFingerprint().c_str(); } inline QString carFingerprint() const { return replay->carFingerprint().c_str(); }
inline VisionStreamType visionStreamType() const { return replay->hasFlag(REPLAY_FLAG_ECAM) ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD; }
inline double totalSeconds() const { return replay->totalSeconds(); } inline double totalSeconds() const { return replay->totalSeconds(); }
inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; } inline double routeStartTime() const { return replay->routeStartTime() / (double)1e9; }
inline double currentSec() const { return replay->currentSeconds(); } inline double currentSec() const { return replay->currentSeconds(); }

@ -111,7 +111,7 @@ DBCManager *dbc() {
std::vector<const Signal*> DBCMsg::getSignals() const { std::vector<const Signal*> DBCMsg::getSignals() const {
std::vector<const Signal*> ret; std::vector<const Signal*> ret;
for (auto &[name, sig] : sigs) ret.push_back(&sig); for (auto &[_, sig] : sigs) ret.push_back(&sig);
std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; }); std::sort(ret.begin(), ret.end(), [](auto l, auto r) { return l->start_bit < r->start_bit; });
return ret; return ret;
} }

@ -21,7 +21,7 @@ VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this); QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setContentsMargins(0, 0, 0, 0); main_layout->setContentsMargins(0, 0, 0, 0);
cam_widget = new CameraWidget("camerad", VISION_STREAM_ROAD, false, this); cam_widget = new CameraWidget("camerad", can->visionStreamType(), false, this);
cam_widget->setFixedSize(parent->width(), parent->width() / 1.596); cam_widget->setFixedSize(parent->width(), parent->width() / 1.596);
main_layout->addWidget(cam_widget); main_layout->addWidget(cam_widget);

Loading…
Cancel
Save