dragonpilot beta3

date: 2023-10-09T10:55:55
commit: 91b6e3aecd7170f24bccacb10c515ec281c30295
This commit is contained in:
dragonpilot
2023-10-09 10:54:45 -07:00
parent a9ba3193e2
commit cfe0ae9b8a
518 changed files with 159749 additions and 17401 deletions
+41 -41
View File
@@ -1,32 +1,33 @@
#!/usr/bin/env python3
import os
import math
import time
from typing import SupportsFloat
from cereal import car, log
from common.numpy_fast import clip
from common.realtime import sec_since_boot, config_realtime_process, Priority, Ratekeeper, DT_CTRL
from common.profiler import Profiler
from common.params import Params, put_nonblocking, put_bool_nonblocking
from openpilot.common.numpy_fast import clip
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
from openpilot.common.profiler import Profiler
from openpilot.common.params import Params, put_nonblocking, put_bool_nonblocking
import cereal.messaging as messaging
from cereal.visionipc import VisionIpcClient, VisionStreamType
from common.conversions import Conversions as CV
from openpilot.common.conversions import Conversions as CV
from panda import ALTERNATIVE_EXPERIENCE
from system.swaglog import cloudlog
from system.version import is_release_branch, get_short_branch
from selfdrive.boardd.boardd import can_list_to_can_capnp
from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
from selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET
from selfdrive.controls.lib.drive_helpers import VCruiseHelper, get_lag_adjusted_curvature
from selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
from selfdrive.controls.lib.longcontrol import LongControl
from selfdrive.controls.lib.latcontrol_pid import LatControlPID
from selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
from selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from selfdrive.controls.lib.events import Events, ET
from selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
from selfdrive.controls.lib.vehicle_model import VehicleModel
from system.hardware import HARDWARE
from openpilot.system.swaglog import cloudlog
from openpilot.system.version import is_release_branch, get_short_branch
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
from openpilot.selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
from openpilot.selfdrive.controls.lib.lateral_planner import CAMERA_OFFSET
from openpilot.selfdrive.controls.lib.drive_helpers import VCruiseHelper, get_lag_adjusted_curvature
from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.selfdrive.controls.lib.events import Events, ET
from openpilot.selfdrive.controls.lib.alertmanager import AlertManager, set_offroad_alert
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
from openpilot.system.hardware import HARDWARE
SOFT_DISABLE_TIME = 3 # seconds
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
@@ -39,7 +40,6 @@ DP_LONG_MISSING_LEAD_SPEED = 22.22 # 80 kph
REPLAY = "REPLAY" in os.environ
SIMULATION = "SIMULATION" in os.environ
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
NOSENSOR = "NOSENSOR" in os.environ
IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"}
# dp related processes
IGNORE_PROCESSES.update({"mapd", "otisserv", "fileserv", "gpxd", "gpx_uploader"})
@@ -74,6 +74,7 @@ class Controls:
self.pm = messaging.PubMaster(['sendcan', 'controlsState', 'carState',
'carControl', 'carEvents', 'carParams', 'controlsStateExt'])
self.sensor_packets = ["accelerometer", "gyroscope"]
self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"]
self.dp_device_dm_unavailable_once = False
if dp_device_dm_unavailable:
@@ -98,12 +99,13 @@ class Controls:
self.dp_device_disable_temp_check = self.params.get_bool("dp_device_disable_temp_check")
self.sm = sm
if self.sm is None:
ignore = ['testJoystick']
ignore = self.sensor_packets + ['testJoystick']
if SIMULATION:
ignore += ['driverCameraState', 'managerState']
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
'driverMonitoringState', 'longitudinalPlan', 'lateralPlan', 'liveLocationKalman',
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters', 'testJoystick', 'longitudinalPlanExt'] + self.camera_packets,
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
'testJoystick', 'longitudinalPlanExt'] + self.camera_packets + self.sensor_packets,
ignore_alive=ignore, ignore_avg_freq=['radarState', 'testJoystick'])
if CI is None:
@@ -428,17 +430,20 @@ class Controls:
else:
self.logged_comm_issue = None
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
self.events.add(EventName.vehicleModelInvalid)
if not self.sm['lateralPlan'].mpcSolutionValid:
self.events.add(EventName.plannerError)
if not (self.sm['liveParameters'].sensorValid or self.sm['liveLocationKalman'].sensorsOK) and not NOSENSOR:
if self.sm.frame > 5 / DT_CTRL: # Give locationd some time to receive all the inputs
self.events.add(EventName.sensorDataInvalid)
if not self.sm['liveLocationKalman'].posenetOK:
self.events.add(EventName.posenetInvalid)
if not self.sm['liveLocationKalman'].deviceStable:
self.events.add(EventName.deviceFalling)
if not self.sm['liveLocationKalman'].inputsOK:
self.events.add(EventName.locationdTemporaryError)
if not self.sm['liveParameters'].valid and not TESTING_CLOSET and (not SIMULATION or REPLAY):
self.events.add(EventName.paramsdTemporaryError)
# conservative HW alert. if the data or frequency are off, locationd will throw an error
if any((self.sm.frame - self.sm.rcv_frame[s])*DT_CTRL > 10. for s in self.sensor_packets):
self.events.add(EventName.sensorDataInvalid)
if not REPLAY:
# Check for mismatch between openpilot and car's PCM
@@ -467,15 +472,12 @@ class Controls:
# TODO: fix simulator
if not SIMULATION or REPLAY:
if not NOSENSOR:
if not self.sm['liveLocationKalman'].gpsOK and self.sm['liveLocationKalman'].inputsOK and (self.distance_traveled > 1000):
# Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes
self.events.add(EventName.noGps)
if not self.sm['liveLocationKalman'].gpsOK and self.sm['liveLocationKalman'].inputsOK and (self.distance_traveled > 1000):
# Not show in first 1 km to allow for driving out of garage. This event shows after 5 minutes
self.events.add(EventName.noGps)
if self.sm['modelV2'].frameDropPerc > 20:
self.events.add(EventName.modeldLagging)
if self.sm['liveLocationKalman'].excessiveResets:
self.events.add(EventName.localizerMalfunction)
def data_sample(self):
"""Receive data from sockets and update carState"""
@@ -611,7 +613,7 @@ class Controls:
# Check if openpilot is engaged and actuators are enabled
self.enabled = self.state in ENABLED_STATES
self.active = self.state in ACTIVE_STATES
if self.active:
if self.active or self._dp_alka_active:
self.current_alert_types.append(ET.WARNING)
def state_control(self, CS):
@@ -693,8 +695,8 @@ class Controls:
if CC.latActive:
steer = clip(self.sm['testJoystick'].axes[1], -1, 1)
# max angle is 45 for angle-based cars
actuators.steer, actuators.steeringAngleDeg = steer, steer * 45.
# max angle is 45 for angle-based cars, max curvature is 0.02
actuators.steer, actuators.steeringAngleDeg, actuators.curvature = steer, steer * 45., steer * -0.02
lac_log.active = self.active
lac_log.steeringAngleDeg = CS.steeringAngleDeg
@@ -808,7 +810,7 @@ class Controls:
if not self.read_only and self.initialized:
# send car controls over can
now_nanos = self.can_log_mono_time if REPLAY else int(sec_since_boot() * 1e9)
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
self.last_actuators, can_sends = self.CI.apply(CC, now_nanos)
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
CC.actuatorsOutput = self.last_actuators
@@ -871,8 +873,6 @@ class Controls:
controlsState.lateralControlState.pidState = lac_log
elif lat_tuning == 'torque':
controlsState.lateralControlState.torqueState = lac_log
elif lat_tuning == 'indi':
controlsState.lateralControlState.indiState = lac_log
self.pm.send('controlsState', dat)
@@ -915,7 +915,7 @@ class Controls:
self.CC = CC
def step(self):
start_time = sec_since_boot()
start_time = time.monotonic()
self.prof.checkpoint("Ratekeeper", ignore=True)
self.is_metric = self.params.get_bool("IsMetric")
+31 -11
View File
@@ -1,4 +1,27 @@
from common.numpy_fast import interp
#!/usr/bin/env python3
# The MIT License
#
# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from openpilot.common.numpy_fast import interp
DP_ACCEL_STOCK = 0
DP_ACCEL_ECO = 1
@@ -6,18 +29,15 @@ DP_ACCEL_NORMAL = 2
DP_ACCEL_SPORT = 3
# accel profile by @arne182 modified by cgw
_DP_CRUISE_MIN_V = [-0.765, -0.765, -0.80, -0.80, -0.75, -0.70]
_DP_CRUISE_MIN_V_ECO = [-0.760, -0.760, -0.76, -0.76, -0.70, -0.65]
_DP_CRUISE_MIN_V_SPORT = [-0.770, -0.770, -0.90, -1.00, -0.90, -0.80]
_DP_CRUISE_MIN_BP = [0., 15.66, 17.88, 20., 30., 55.]
#DP_CRUISE_MIN_BP in mph=[0., 18, 35, 40, 45, 67, 123]
_DP_CRUISE_MIN_V = [-0.750, -0.750, -0.72, -0.72, -0.52, -0.40, -0.36, -0.32, -0.32, -0.25, -0.25]
_DP_CRUISE_MIN_V_ECO = [-0.730, -0.730, -0.68, -0.68, -0.50, -0.36, -0.32, -0.28, -0.28, -0.25, -0.25]
_DP_CRUISE_MIN_V_SPORT = [-0.750, -0.750, -0.75, -0.75, -0.54, -0.42, -0.40, -0.35, -0.35, -0.30, -0.30]
_DP_CRUISE_MIN_BP = [0., 2.0, 2.01, 11., 11.01, 18., 18.01, 28., 28.01, 33., 55.]
_DP_CRUISE_MAX_V = [3.4, 2.8, 1.8, 1.4, 1.06, .88, .68, .46, .35, .13]
_DP_CRUISE_MAX_V_ECO = [3.2, 2.6, 1.6, 1.2, .76, .62, .48, .36, .28, .09]
_DP_CRUISE_MAX_V_SPORT = [3.5, 3.0, 2.4, 2.9, 2.1, 1.7, 1.3, .9, .7, .5]
_DP_CRUISE_MAX_V = [3.5, 3.2, 2.6, 2.0, 1.3, 0.9, .71, .48, .36, .14]
_DP_CRUISE_MAX_V_ECO = [3.5, 3.0, 1.6, 1.2, .76, .62, .48, .36, .28, .09]
_DP_CRUISE_MAX_V_SPORT = [3.5, 3.5, 3.5, 3.5, 2.8, 2.0, 1.5, 1.0, .7, .5]
_DP_CRUISE_MAX_BP = [0., 3, 6., 8., 11., 15., 20., 25., 30., 55.]
#DP_CRUISE_MAX_BP in mph=[0., 6.7, 13, 18, 25, 33, 45, 56, 67, 123]
class AccelController:
+3 -3
View File
@@ -5,9 +5,9 @@ from collections import defaultdict
from dataclasses import dataclass
from typing import List, Dict, Optional
from common.basedir import BASEDIR
from common.params import Params
from selfdrive.controls.lib.events import Alert
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.selfdrive.controls.lib.events import Alert
with open(os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")) as f:
+2 -2
View File
@@ -1,6 +1,6 @@
from cereal import log
from common.conversions import Conversions as CV
from common.realtime import DT_MDL
from openpilot.common.conversions import Conversions as CV
from openpilot.common.realtime import DT_MDL
LaneChangeState = log.LateralPlan.LaneChangeState
LaneChangeDirection = log.LateralPlan.LaneChangeDirection
+4 -4
View File
@@ -1,10 +1,10 @@
import math
from cereal import car, log
from common.conversions import Conversions as CV
from common.numpy_fast import clip, interp
from common.realtime import DT_MDL
from selfdrive.modeld.constants import T_IDXS
from openpilot.common.conversions import Conversions as CV
from openpilot.common.numpy_fast import clip, interp
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.modeld.constants import T_IDXS
# WARNING: this value was determined based on the model's training distribution,
# model predictions above this speed can be unpredictable
@@ -1,129 +1,266 @@
#!/usr/bin/env python3
# The MIT License
#
# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Version = 0.1.2
from common.numpy_fast import interp
from common.params import Params
# d-e2e, from modeldata.h
TRAJECTORY_SIZE = 33
_DP_E2E_LEAD_COUNT = 5
LEAD_WINDOW_SIZE = 5
LEAD_PROB = 0.6
_DP_E2E_STOP_BP = [0., 10., 20., 30., 40., 50., 55.]
_DP_E2E_STOP_DIST = [10, 30., 50., 70., 80., 90., 120.]
_DP_E2E_STOP_COUNT = 3
SLOW_DOWN_WINDOW_SIZE = 5
SLOW_DOWN_PROB = 0.6
SLOW_DOWN_BP = [0., 10., 20., 30., 40., 50., 55.]
SLOW_DOWN_DIST = [10, 30., 50., 70., 80., 90., 120.]
_DP_E2E_SNG_COUNT = 3
_DP_E2E_SNG_ACC_COUNT = 3
_DP_E2E_SWAP_COUNT = 5
SLOWNESS_WINDOW_SIZE = 20
SLOWNESS_PROB = 0.6
SLOWNESS_CRUISE_OFFSET = 1.05
_DP_E2E_TF_COUNT = 5
DANGEROUS_TTC_WINDOW_SIZE = 5
DANGEROUS_TTC = 1.55
HIGHWAY_CRUISE_KPH = 75
STOP_AND_GO_FRAME = 500
MODE_SWITCH_DELAY_FRAME = 500
MAX_YREL_THRESHOLD = 0.25
class SNG_State:
off = 0
stopped = 1
going = 2
class GenericMovingAverageCalculator:
def __init__(self, window_size):
self.window_size = window_size
self.data = []
self.total = 0
def add_data(self, value):
if len(self.data) == self.window_size:
self.total -= self.data.pop(0)
self.data.append(value)
self.total += value
def get_moving_average(self):
if len(self.data) == 0:
return None
return self.total / len(self.data)
def reset_data(self):
self.data = []
self.total = 0
_DP_E2E_BLINKER_COUNT = 5
class DynamicEndtoEndController:
def __init__(self):
self._params = Params()
self._is_enabled = False
self._mode = 'acc'
self._mode_prev = 'acc'
self._mode_switch_allowed = True
self._mode_switch_frame = 0
self._frame = 0
# conditional e2e
self.dp_e2e_has_lead = False
self.dp_e2e_lead_last = False
self.dp_e2e_lead_count = 0
self.dp_e2e_sng = False
self.dp_e2e_sng_count = 0
self.dp_e2e_standstill_last = False
self.dp_e2e_swap_count = 0
self.dp_e2e_stop_count = 0
self.dp_e2e_tf_count = 0
self._lead_gmac = GenericMovingAverageCalculator(window_size=LEAD_WINDOW_SIZE)
self._has_lead_filtered = False
self._has_lead_filtered_prev = False
self.dp_e2e_blinker_count = 0
self._slow_down_gmac = GenericMovingAverageCalculator(window_size=SLOW_DOWN_WINDOW_SIZE)
self._has_slow_down = False
self._has_slow_down_prev = False
self._has_blinkers = False
self._has_blinkers_prev = False
self._slowness_gmac = GenericMovingAverageCalculator(window_size=SLOWNESS_WINDOW_SIZE)
self._has_slowness = False
self._has_slowness_prev = False
self._has_nav_enabled = False
self._has_nav_enabled_prev = False
self._dangerous_ttc_gmac = GenericMovingAverageCalculator(window_size=DANGEROUS_TTC_WINDOW_SIZE)
self._has_dangerous_ttc = False
self._has_dangerous_ttc_prev = False
self._v_ego_kph = 0.
self._v_cruise_kph = 0.
self._has_lead = False
self._has_lead_prev = False
self._has_standstill = False
self._has_standstill_prev = False
self._sng_transit_frame = 0
self._sng_state = SNG_State.off
pass
def _set_dp_e2e_mode(self, mode, force=False):
if force:
self.dp_e2e_swap_count = 0
self._mode = mode
def _update(self, car_state, lead_one, md, controls_state, radar_unavailable):
self._v_ego_kph = car_state.vEgo * 3.6
self._v_cruise_kph = controls_state.vCruise
self._has_lead = lead_one.status
self._has_standstill = car_state.standstill
# nav enable detection
self._has_nav_enabled = md.navEnabled
# lead detection
self._lead_gmac.add_data(lead_one.status)
self._has_lead_filtered = self._lead_gmac.get_moving_average() >= LEAD_PROB
self._has_lead_yrel = lead_one.yRel > MAX_YREL_THRESHOLD
# slow down detection
self._slow_down_gmac.add_data(len(md.orientation.x) == len(md.position.x) == TRAJECTORY_SIZE and md.position.x[TRAJECTORY_SIZE - 1] < interp(self._v_ego_kph, SLOW_DOWN_BP, SLOW_DOWN_DIST))
self._has_slow_down = self._slow_down_gmac.get_moving_average() >= SLOW_DOWN_PROB
# blinker detection
self._has_blinkers = car_state.leftBlinker or car_state.rightBlinker
# sng detection
if self._has_standstill:
self._sng_state = SNG_State.stopped
self._sng_transit_frame = 0
else:
if self._sng_transit_frame == 0:
if self._sng_state == SNG_State.stopped:
self._sng_state = SNG_State.going
self._sng_transit_frame = STOP_AND_GO_FRAME
elif self._sng_state == SNG_State.going:
self._sng_state = SNG_State.off
elif self._sng_transit_frame > 0:
self._sng_transit_frame -= 1
# slowness detection
self._slowness_gmac.add_data(self._v_ego_kph <= (self._v_cruise_kph*SLOWNESS_CRUISE_OFFSET))
self._has_slowness = self._slowness_gmac.get_moving_average() >= SLOWNESS_PROB
# dangerous TTC detection
if not self._has_lead_filtered and self._has_lead_filtered_prev:
self._dangerous_ttc_gmac.reset_data()
self._has_dangerous_ttc = False
if self._has_lead and car_state.vEgo >= 0.01:
self._dangerous_ttc_gmac.add_data(lead_one.dRel/car_state.vEgo)
self._has_dangerous_ttc = self._dangerous_ttc_gmac.get_moving_average() is not None and self._dangerous_ttc_gmac.get_moving_average() <= DANGEROUS_TTC
# keep prev values
self._has_standstill_prev = self._has_standstill
self._has_slowness_prev = self._has_slowness
self._has_slow_down_prev = self._has_slow_down
self._has_lead_filtered_prev = self._has_lead_filtered
self._frame += 1
def _blended_priority_mode(self):
# when blinker is on and speed is driving below highway cruise speed: blended
# we dont want it to switch mode at higher speed, blended may trigger hard brake
if self._has_blinkers and self._v_ego_kph < HIGHWAY_CRUISE_KPH:
self._mode = 'blended'
return
else:
# prevent switching in a short period of time.
if self._mode == mode:
self.dp_e2e_swap_count = 0
else:
self.dp_e2e_swap_count += 1
# when at highway cruise and SNG: blended
# ensuring blended mode is used because acc is bad at catching SNG lead car
# especially those who accel very fast and then brake very hard.
if self._sng_state == SNG_State.going and self._v_cruise_kph >= HIGHWAY_CRUISE_KPH:
self._mode = 'blended'
return
if self.dp_e2e_swap_count >= _DP_E2E_SWAP_COUNT:
self._mode = mode
# when standstill: blended
# in case of lead car suddenly move away under traffic light, acc mode wont brake at traffic light.
if self._has_standstill:
self._mode = 'blended'
return
def _process_conditional_e2e(self, radar_unavailable, car_state, lead_one, md):
v_ego_kph = car_state.vEgo * 3.6
# when detecting slow down scenario: blended
# e.g. traffic light, curve, stop sign etc.
if self._has_slow_down:
self._mode = 'blended'
return
# when blinker is on, use blended
if car_state.leftBlinker or car_state.rightBlinker:
self.dp_e2e_blinker_count += 1
else:
self.dp_e2e_blinker_count = 0
# when detecting lead slow down: blended
# use blended for higher braking capability
if self._has_dangerous_ttc:
self._mode = 'blended'
return
if self.dp_e2e_blinker_count > _DP_E2E_BLINKER_COUNT:
return self._set_dp_e2e_mode('blended', True)
# car driving at speed lower than set speed: acc
if self._has_slowness:
self._mode = 'acc'
return
# make sure it see lead enough time
if lead_one.status != self.dp_e2e_lead_last:
self.dp_e2e_lead_count = 0
else:
self.dp_e2e_lead_count += 1
if self.dp_e2e_lead_count >= _DP_E2E_LEAD_COUNT:
self.dp_e2e_has_lead = lead_one.status
self.dp_e2e_lead_last = lead_one.status
self._mode = 'blended'
# when standstill, always e2e
if car_state.standstill:
self.dp_e2e_sng_count = 0
self.dp_e2e_sng = False
return self._set_dp_e2e_mode('blended')
def _acc_priority_mode(self):
# If there is a filtered lead, the vehicle is not in standstill, and the lead vehicle's yRel meets the condition,
# e,g. stopped at the red light and car crossing the intersection.
if self._has_lead_filtered and not self._has_standstill and self._has_lead_yrel:
self._mode = 'acc'
return
if self.dp_e2e_standstill_last and not car_state.standstill:
self.dp_e2e_sng = True
# when blinker is on and speed is driving below highway cruise speed: blended
# we dont want it to switch mode at higher speed, blended may trigger hard brake
if self._has_blinkers and self._v_ego_kph < HIGHWAY_CRUISE_KPH:
self._mode = 'blended'
return
# when sng, we e2e for 0.5 secs
if self.dp_e2e_sng:
self.dp_e2e_sng_count += 1
if self.dp_e2e_sng_count > _DP_E2E_SNG_COUNT:
if self.dp_e2e_sng_count > _DP_E2E_SNG_ACC_COUNT:
self.dp_e2e_sng = False
return self._set_dp_e2e_mode('acc', True)
return self._set_dp_e2e_mode('blended')
# when standstill: blended
# in case of lead car suddenly move away under traffic light, acc mode wont brake at traffic light.
if self._has_standstill:
self._mode = 'blended'
return
# when we see a lead
if self.dp_e2e_has_lead:
# radar unavailable car, use blended first when distance is too close
if radar_unavailable:
if lead_one.dRel <= car_state.vEgo * 1.22:
self.dp_e2e_tf_count += 1
else:
self.dp_e2e_tf_count = 0
if self.dp_e2e_tf_count > _DP_E2E_TF_COUNT:
return self._set_dp_e2e_mode('blended', True)
# always use acc
else:
return self._set_dp_e2e_mode('acc', True)
# when detecting slow down scenario: blended
# e.g. traffic light, curve, stop sign etc.
if self._has_slow_down:
self._mode = 'blended'
return
# slow down detection
if len(md.orientation.x) == len(md.position.x) == TRAJECTORY_SIZE and md.position.x[TRAJECTORY_SIZE - 1] < interp(v_ego_kph, _DP_E2E_STOP_BP, _DP_E2E_STOP_DIST):
self.dp_e2e_stop_count += 1
else:
self.dp_e2e_stop_count = 0
# car driving at speed lower than set speed: acc
if self._has_slowness:
self._mode = 'acc'
return
if self.dp_e2e_stop_count >= _DP_E2E_STOP_COUNT:
return self._set_dp_e2e_mode('blended', True)
self._mode = 'acc'
return self._set_dp_e2e_mode('acc')
def get_mpc_mode(self, mode, radar_unavailable, car_state, lead_one, md):
self._mode = mode
def get_mpc_mode(self, radar_unavailable, car_state, lead_one, md, controls_state):
if self._is_enabled:
self._process_conditional_e2e(radar_unavailable, car_state, lead_one, md)
self._update(car_state, lead_one, md, controls_state, radar_unavailable)
if self._frame > self._mode_switch_frame:
self._mode_switch_allowed = True
if radar_unavailable:
self._blended_priority_mode()
else:
self._acc_priority_mode()
self._mode_prev = self._mode
return self._mode
def set_enabled(self, enabled):
+39 -28
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
# This Python file uses the following encoding: utf-8
# -*- coding: utf-8 -*-
from common.i18n import events
from openpilot.common.i18n import events
_ = events()
import math
@@ -10,10 +11,10 @@ from typing import Dict, Union, Callable, List, Optional
from cereal import log, car
import cereal.messaging as messaging
from common.conversions import Conversions as CV
from common.realtime import DT_CTRL
from selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from system.version import get_short_branch
from openpilot.common.conversions import Conversions as CV
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.system.version import get_short_branch
AlertSize = log.ControlsState.AlertSize
AlertStatus = log.ControlsState.AlertStatus
@@ -243,7 +244,7 @@ def below_steer_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.S
_("Steer Unavailable Below {speed}").format(speed=get_display_speed(CP.minSteerSpeed, metric)),
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
@@ -428,19 +429,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
# ********** events only containing alerts that display while engaged **********
# openpilot tries to learn certain parameters about your car by observing
# how the car behaves to steering inputs from both human and openpilot driving.
# This includes:
# - steer ratio: gear ratio of the steering rack. Steering angle divided by tire angle
# - tire stiffness: how much grip your tires have
# - angle offset: most steering angle sensors are offset and measure a non zero angle when driving straight
# This alert is thrown when any of these values exceed a sanity check. This can be caused by
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
EventName.vehicleModelInvalid: {
ET.NO_ENTRY: NoEntryAlert(_("Vehicle Parameter Identification Failed")),
ET.SOFT_DISABLE: soft_disable_alert(_("Vehicle Parameter Identification Failed")),
},
EventName.steerTempUnavailableSilent: {
ET.WARNING: Alert(
_("Steering Temporarily Unavailable"),
@@ -510,7 +498,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
_("Press Resume to Exit Standstill"),
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2),
Priority.MID, VisualAlert.none, AudibleAlert.none, .2),
},
EventName.belowSteerSpeed: {
@@ -580,11 +568,34 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
ET.PERMANENT: NormalPermanentAlert(_("GPS Malfunction"), _("Likely Hardware Issue")),
},
# When the GPS position and localizer diverge the localizer is reset to the
# current GPS position. This alert is thrown when the localizer is reset
# more often than expected.
EventName.localizerMalfunction: {
# ET.PERMANENT: NormalPermanentAlert("Sensor Malfunction", "Hardware Malfunction"),
EventName.locationdTemporaryError: {
ET.NO_ENTRY: NoEntryAlert("locationd Temporary Error"),
ET.SOFT_DISABLE: soft_disable_alert("locationd Temporary Error"),
},
EventName.locationdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("locationd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("locationd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("locationd Permanent Error"),
},
# openpilot tries to learn certain parameters about your car by observing
# how the car behaves to steering inputs from both human and openpilot driving.
# This includes:
# - steer ratio: gear ratio of the steering rack. Steering angle divided by tire angle
# - tire stiffness: how much grip your tires have
# - angle offset: most steering angle sensors are offset and measure a non zero angle when driving straight
# This alert is thrown when any of these values exceed a sanity check. This can be caused by
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
EventName.paramsdTemporaryError: {
ET.NO_ENTRY: NoEntryAlert("paramsd Temporary Error"),
ET.SOFT_DISABLE: soft_disable_alert("paramsd Temporary Error"),
},
EventName.paramsdPermanentError: {
ET.NO_ENTRY: NoEntryAlert("paramsd Permanent Error"),
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("paramsd Permanent Error"),
ET.PERMANENT: NormalPermanentAlert("paramsd Permanent Error"),
},
# ********** events that affect controls state transitions **********
@@ -682,7 +693,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
EventName.sensorDataInvalid: {
ET.PERMANENT: Alert(
_("Sensor Data Invalid"),
_("Ensure device is mounted securely"),
_("Possible Hardware Issue"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, .2, creation_delay=1.),
ET.NO_ENTRY: NoEntryAlert(_("Sensor Data Invalid")),
@@ -963,7 +974,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
if __name__ == '__main__':
# print all alerts by type and priority
from cereal.services import service_list
from cereal.services import SERVICE_LIST
from collections import defaultdict, OrderedDict
event_names = {v: k for k, v in EventName.schema.enumerants.items()}
@@ -971,7 +982,7 @@ if __name__ == '__main__':
CP = car.CarParams.new_message()
CS = car.CarState.new_message()
sm = messaging.SubMaster(list(service_list.keys()))
sm = messaging.SubMaster(list(SERVICE_LIST.keys()))
for i, alerts in EVENTS.items():
for et, alert in alerts.items():
+5 -5
View File
@@ -1,10 +1,10 @@
import numpy as np
from cereal import log
from common.filter_simple import FirstOrderFilter
from common.numpy_fast import interp
from common.realtime import DT_MDL
from selfdrive.hardware import TICI
from system.swaglog import cloudlog
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.numpy_fast import interp
from openpilot.common.realtime import DT_MDL
from openpilot.system.hardware import TICI
from openpilot.system.swaglog import cloudlog
TRAJECTORY_SIZE = 33
+2 -2
View File
@@ -1,7 +1,7 @@
from abc import abstractmethod, ABC
from common.numpy_fast import clip
from common.realtime import DT_CTRL
from openpilot.common.numpy_fast import clip
from openpilot.common.realtime import DT_CTRL
MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s
+1 -1
View File
@@ -1,7 +1,7 @@
import math
from cereal import log
from selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
+2 -2
View File
@@ -1,8 +1,8 @@
import math
from cereal import log
from selfdrive.controls.lib.latcontrol import LatControl
from selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.pid import PIDController
class LatControlPID(LatControl):
+4 -4
View File
@@ -1,10 +1,10 @@
import math
from cereal import log
from common.numpy_fast import interp
from selfdrive.controls.lib.latcontrol import LatControl
from selfdrive.controls.lib.pid import PIDController
from selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.numpy_fast import interp
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
# At higher speeds (25+mph) we can assume:
# Lateral acceleration achieved by a specific car correlates to
@@ -1,7 +1,7 @@
{
"acados_include_path": "/data/openpilot/third_party/acados/include",
"acados_lib_path": "/data/openpilot/third_party/acados/lib",
"code_export_directory": "/data/openpilot/selfdrive/controls/lib/lateral_mpc_lib/c_generated_code",
"acados_include_path": "/data/dp-private/third_party/acados/include",
"acados_lib_path": "/data/dp-private/third_party/acados/lib",
"code_export_directory": "/data/dp-private/selfdrive/controls/lib/lateral_mpc_lib/c_generated_code",
"constraints": {
"C": [],
"C_e": [],
@@ -261,7 +261,7 @@
"ny_e": 3,
"nz": 0
},
"json_file": "/data/openpilot/selfdrive/controls/lib/lateral_mpc_lib/acados_ocp_lat.json",
"json_file": "/data/dp-private/selfdrive/controls/lib/lateral_mpc_lib/acados_ocp_lat.json",
"model": {
"con_h_expr": null,
"con_h_expr_e": null,
@@ -1,16 +1,16 @@
#!/usr/bin/env python3
import os
import time
import numpy as np
from casadi import SX, vertcat, sin, cos
from common.realtime import sec_since_boot
# WARNING: imports outside of constants will not trigger a rebuild
from selfdrive.modeld.constants import T_IDXS
from openpilot.selfdrive.modeld.constants import T_IDXS
if __name__ == '__main__': # generating code
from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
from openpilot.third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else:
from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
from openpilot.selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
LAT_MPC_DIR = os.path.dirname(os.path.abspath(__file__))
EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code")
@@ -182,9 +182,9 @@ class LateralMpc():
self.solver.set(N, "p", p_cp[N])
self.solver.cost_set(N, "yref", self.yref[N][:COST_E_DIM])
t = sec_since_boot()
t = time.monotonic()
self.solution_status = self.solver.solve()
self.solve_time = sec_since_boot() - t
self.solve_time = time.monotonic() - t
for i in range(N+1):
self.x_sol[i] = self.solver.get(i, 'x')
+13 -12
View File
@@ -1,16 +1,17 @@
import time
import numpy as np
from common.realtime import sec_since_boot, DT_MDL
from common.numpy_fast import interp
from system.swaglog import cloudlog
from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc
from selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N
from selfdrive.controls.lib.drive_helpers import CONTROL_N, MIN_SPEED, get_speed_error
from selfdrive.controls.lib.desire_helper import DesireHelper
from openpilot.common.realtime import DT_MDL
from openpilot.common.numpy_fast import interp
from openpilot.system.swaglog import cloudlog
from openpilot.selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import LateralMpc
from openpilot.selfdrive.controls.lib.lateral_mpc_lib.lat_mpc import N as LAT_MPC_N
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, MIN_SPEED, get_speed_error
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
import cereal.messaging as messaging
from cereal import log
from selfdrive.controls.lib.lane_planner import LanePlanner
from common.params import Params
from selfdrive.controls.lib.road_edge_detector import RoadEdgeDetector
from openpilot.selfdrive.controls.lib.lane_planner import LanePlanner
from openpilot.common.params import Params
from openpilot.selfdrive.controls.lib.road_edge_detector import RoadEdgeDetector
TRAJECTORY_SIZE = 33
CAMERA_OFFSET = 0.04
@@ -133,7 +134,7 @@ class LateralPlanner:
# Check for infeasible MPC solution
mpc_nans = np.isnan(self.lat_mpc.x_sol[:, 3]).any()
t = sec_since_boot()
t = time.monotonic()
if mpc_nans or self.lat_mpc.solution_status != 0:
self.reset_mpc()
self.x0[3] = measured_curvature * self.v_ego
@@ -157,7 +158,7 @@ class LateralPlanner:
lateralPlan.psis = self.lat_mpc.x_sol[0:CONTROL_N, 2].tolist()
lateralPlan.curvatures = (self.lat_mpc.x_sol[0:CONTROL_N, 3]/self.v_ego).tolist()
lateralPlan.curvatureRates = [float(x/self.v_ego) for x in self.lat_mpc.u_sol[0:CONTROL_N - 1]] + [0.0]
lateralPlan.curvatureRates = [float(x.item() / self.v_ego) for x in self.lat_mpc.u_sol[0:CONTROL_N - 1]] + [0.0]
lateralPlan.mpcSolutionValid = bool(plan_solution_valid)
lateralPlan.solverExecutionTime = self.lat_mpc.solve_time
+5 -5
View File
@@ -1,9 +1,9 @@
from cereal import car
from common.numpy_fast import clip, interp
from common.realtime import DT_CTRL
from selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
from selfdrive.controls.lib.pid import PIDController
from selfdrive.modeld.constants import T_IDXS
from openpilot.common.numpy_fast import clip, interp
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, apply_deadzone
from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.modeld.constants import T_IDXS
LongCtrlState = car.CarControl.Actuators.LongControlState
+18 -18
View File
@@ -1,19 +1,19 @@
#!/usr/bin/env python3
import os
import time
import numpy as np
from cereal import log
from common.realtime import sec_since_boot
from common.numpy_fast import clip
from system.swaglog import cloudlog
from openpilot.common.numpy_fast import clip
from openpilot.system.swaglog import cloudlog
# WARNING: imports outside of constants will not trigger a rebuild
from selfdrive.modeld.constants import index_function
from selfdrive.car.interfaces import ACCEL_MIN
from selfdrive.controls.radard import _LEAD_ACCEL_TAU
from openpilot.selfdrive.modeld.constants import index_function
from openpilot.selfdrive.car.interfaces import ACCEL_MIN
from openpilot.selfdrive.controls.radard import _LEAD_ACCEL_TAU
if __name__ == '__main__': # generating code
from third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
from openpilot.third_party.acados.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else:
from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython
from casadi import SX, vertcat
@@ -79,14 +79,14 @@ def get_T_FOLLOW(personality=log.LongitudinalPersonality.standard):
def get_dynamic_follow(v_ego, personality=log.LongitudinalPersonality.standard):
if personality==log.LongitudinalPersonality.relaxed:
x_vel = [0, 3.05, 3.61, 4.16, 7.14, 11.11]
y_dist = [1.75, 1.75, 1.77, 1.75, 1.8, 1.8]
x_vel = [0.0, 5.55, 19.99, 20, 25, 40]
y_dist = [1.2, 1.5, 1.5, 1.7, 1.85, 2.0]
elif personality==log.LongitudinalPersonality.standard:
x_vel = [0, 3.05, 3.61, 4.16, 7.14, 11.11]
y_dist = [1.5, 1.5, 1.51, 1.5, 1.5, 1.45]
x_vel = [0.0, 5.55, 19.99, 20, 25, 40]
y_dist = [1.0, 1.35, 1.35, 1.5, 1.5, 1.5]
elif personality==log.LongitudinalPersonality.aggressive:
x_vel = [0, 3.05, 3.61, 4.16, 7.14, 11.11]
y_dist = [1.12, 1.12, 1.13, 1.12, 1.22, 1.22]
x_vel = [0.0, 2.0, 5.55, 19.99, 20, 25, 40]
y_dist = [0.9, 1.0, 1.07, 1.09, 1.11, 1.11, 1.2]
else:
raise NotImplementedError("Dynamic Follow personality not supported")
return np.interp(v_ego, x_vel, y_dist)
@@ -304,7 +304,7 @@ class LongitudinalMpc:
self.x0[1] = v
self.x0[2] = a
if abs(v_prev - v) > 2.: # probably only helps if v < v_prev
for i in range(0, N+1):
for i in range(N+1):
self.solver.set(i, 'x', self.x0)
@staticmethod
@@ -427,7 +427,7 @@ class LongitudinalMpc:
self.source = 'lead1'
def run(self):
# t0 = sec_since_boot()
# t0 = time.monotonic()
# reset = 0
for i in range(N+1):
self.solver.set(i, 'p', self.params[i])
@@ -458,14 +458,14 @@ class LongitudinalMpc:
self.prev_a = np.interp(T_IDXS + 0.05, T_IDXS, self.a_solution)
t = sec_since_boot()
t = time.monotonic()
if self.solution_status != 0:
if t > self.last_cloudlog_t + 5.0:
self.last_cloudlog_t = t
cloudlog.warning(f"Long mpc reset, solution_status: {self.solution_status}")
self.reset()
# reset = 1
# print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(sec_since_boot() - t0):.2e} qp {self.time_qp_solution:.2e}, \
# print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(time.monotonic() - t0):.2e} qp {self.time_qp_solution:.2e}, \
# lin {self.time_linearization:.2e} qp_iter {qp_iter}, reset {reset}")
+18 -18
View File
@@ -1,26 +1,26 @@
#!/usr/bin/env python3
import math
import numpy as np
from common.numpy_fast import clip, interp
from common.params import Params
from openpilot.common.numpy_fast import clip, interp
from openpilot.common.params import Params
from cereal import log
import cereal.messaging as messaging
from common.conversions import Conversions as CV
from common.filter_simple import FirstOrderFilter
from common.realtime import DT_MDL
from selfdrive.modeld.constants import T_IDXS
from selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX
from selfdrive.controls.lib.longcontrol import LongCtrlState
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N, get_speed_error
from system.swaglog import cloudlog
from selfdrive.controls.lib.vision_turn_controller import VisionTurnController
from selfdrive.controls.lib.speed_limit_controller import SpeedLimitController, SpeedLimitResolver
from selfdrive.controls.lib.turn_speed_controller import TurnSpeedController
from selfdrive.controls.lib.accel_controller import AccelController
from selfdrive.controls.lib.dynamic_endtoend_controller import DynamicEndtoEndController
from openpilot.common.conversions import Conversions as CV
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.modeld.constants import T_IDXS
from openpilot.selfdrive.car.interfaces import ACCEL_MIN, ACCEL_MAX
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX, CONTROL_N, get_speed_error
from openpilot.system.swaglog import cloudlog
from openpilot.selfdrive.controls.lib.vision_turn_controller import VisionTurnController
from openpilot.selfdrive.controls.lib.speed_limit_controller import SpeedLimitController, SpeedLimitResolver
from openpilot.selfdrive.controls.lib.turn_speed_controller import TurnSpeedController
from openpilot.selfdrive.controls.lib.accel_controller import AccelController
from openpilot.selfdrive.controls.lib.dynamic_endtoend_controller import DynamicEndtoEndController
LON_MPC_STEP = 0.2 # first step is 0.2s
A_CRUISE_MIN = -1.2
@@ -122,7 +122,7 @@ class LongitudinalPlanner:
self.param_read_counter += 1
if self.dynamic_endtoend_controller.is_enabled():
self.mpc.mode = self.dynamic_endtoend_controller.get_mpc_mode(self.mpc.mode, self.CP.radarUnavailable, sm['carState'], sm['radarState'].leadOne, sm['modelV2'])
self.mpc.mode = self.dynamic_endtoend_controller.get_mpc_mode(self.CP.radarUnavailable, sm['carState'], sm['radarState'].leadOne, sm['modelV2'], sm['controlsState'])
else:
self.mpc.mode = 'blended' if sm['controlsState'].experimentalMode else 'acc'
+1 -1
View File
@@ -1,7 +1,7 @@
import numpy as np
from numbers import Number
from common.numpy_fast import clip, interp
from openpilot.common.numpy_fast import clip, interp
class PIDController():
@@ -1,3 +1,26 @@
#!/usr/bin/env python3
# The MIT License
#
# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import numpy as np
class RoadEdgeDetector:
@@ -1,14 +1,14 @@
import numpy as np
import time
from common.numpy_fast import interp
from openpilot.common.numpy_fast import interp
from enum import IntEnum
from cereal import custom, car
from common.params import Params
from common.realtime import sec_since_boot
from selfdrive.controls.lib.drive_helpers import LIMIT_ADAPT_ACC, LIMIT_MIN_ACC, LIMIT_MAX_ACC, LIMIT_SPEED_OFFSET_TH, \
from openpilot.common.params import Params
#from openpilot.common.realtime import time.monotonic()
from openpilot.selfdrive.controls.lib.drive_helpers import LIMIT_ADAPT_ACC, LIMIT_MIN_ACC, LIMIT_MAX_ACC, LIMIT_SPEED_OFFSET_TH, \
LIMIT_MAX_MAP_DATA_AGE, CONTROL_N
# from selfdrive.controls.lib.events import Events
from selfdrive.modeld.constants import T_IDXS
from openpilot.selfdrive.modeld.constants import T_IDXS
import cereal.messaging as messaging
@@ -281,7 +281,7 @@ class SpeedLimitController():
# cause a temp inactive transition if the controller is updated before controlsd sets actual cruise
# speed.
if not self._op_enabled_prev and self._op_enabled:
self._last_op_enabled_time = sec_since_boot()
self._last_op_enabled_time = time.monotonic()
# Update change tracking variables
self._speed_limit_changed = self._speed_limit != self._speed_limit_prev
@@ -303,7 +303,7 @@ class SpeedLimitController():
# Ignore if a minimum ammount of time has not passed since activation. This is to prevent temp inactivations
# due to controlsd logic changing cruise setpoint when going active.
if self._v_cruise_setpoint_changed and \
sec_since_boot() > (self._last_op_enabled_time + _TEMP_INACTIVE_GUARD_PERIOD):
time.monotonic() > (self._last_op_enabled_time + _TEMP_INACTIVE_GUARD_PERIOD):
self.state = SpeedLimitControlState.tempInactive
return
@@ -1,11 +1,11 @@
import numpy as np
import time
from common.params import Params
from openpilot.common.params import Params
from cereal import custom
# from common.realtime import sec_since_boot
from selfdrive.controls.lib.drive_helpers import LIMIT_ADAPT_ACC, LIMIT_MIN_SPEED, LIMIT_MAX_MAP_DATA_AGE, \
from openpilot.selfdrive.controls.lib.drive_helpers import LIMIT_ADAPT_ACC, LIMIT_MIN_SPEED, LIMIT_MAX_MAP_DATA_AGE, \
LIMIT_SPEED_OFFSET_TH, CONTROL_N, LIMIT_MIN_ACC, LIMIT_MAX_ACC
from selfdrive.modeld.constants import T_IDXS
from openpilot.selfdrive.modeld.constants import T_IDXS
import cereal.messaging as messaging
@@ -1,12 +1,12 @@
import numpy as np
import math
from cereal import custom
from common.numpy_fast import interp
from openpilot.common.numpy_fast import interp
# from common.params import Params
# from common.realtime import sec_since_boot
from common.conversions import Conversions as CV
from openpilot.common.conversions import Conversions as CV
# from selfdrive.controls.lib.lane_planner import TRAJECTORY_SIZE
from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
import cereal.messaging as messaging
TRAJECTORY_SIZE = 33
+6 -6
View File
@@ -2,12 +2,12 @@
import os
import numpy as np
from cereal import car
from common.params import Params
from common.realtime import Priority, config_realtime_process
from system.swaglog import cloudlog
from selfdrive.modeld.constants import T_IDXS
from selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner
from selfdrive.controls.lib.lateral_planner import LateralPlanner
from openpilot.common.params import Params
from openpilot.common.realtime import Priority, config_realtime_process
from openpilot.system.swaglog import cloudlog
from openpilot.selfdrive.modeld.constants import T_IDXS
from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner
from openpilot.selfdrive.controls.lib.lateral_planner import LateralPlanner
import cereal.messaging as messaging
def cumtrapz(x, t):
+43 -55
View File
@@ -6,12 +6,12 @@ from typing import Optional, Dict, Any
import capnp
from cereal import messaging, log, car
from common.numpy_fast import interp
from common.params import Params
from common.realtime import Ratekeeper, Priority, config_realtime_process, DT_MDL
from system.swaglog import cloudlog
from openpilot.common.numpy_fast import interp
from openpilot.common.params import Params
from openpilot.common.realtime import Ratekeeper, Priority, config_realtime_process
from openpilot.system.swaglog import cloudlog
from common.kalman.simple_kalman import KF1D
from openpilot.common.kalman.simple_kalman import KF1D
# Default lead acceleration decay set to 50% at 1s
@@ -64,12 +64,8 @@ class Track:
self.dRel = d_rel # LONG_DIST
self.yRel = y_rel # -LAT_DIST
self.vRel = v_rel # REL_SPEED
self.measured = measured # measured or estimate
self.update_vlead(v_lead)
def update_vlead(self, v_lead: float):
self.vLead = v_lead
self.measured = measured # measured or estimate
# computed velocity and accelerations
if self.cnt > 0:
@@ -173,8 +169,7 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa
def get_lead(v_ego: float, ready: bool, tracks: Dict[int, Track], lead_msg: capnp._DynamicStructReader,
model_v_ego: float, low_speed_override: bool = True) -> Dict[str, Any]:
# Determine leads, this is where the essential logic happens
lead_msg_empty = any(len(c) == 0 for c in [lead_msg.x, lead_msg.y, lead_msg.v])
if len(tracks) > 0 and ready and not lead_msg_empty and lead_msg.prob > .5:
if len(tracks) > 0 and ready and lead_msg.prob > .5:
track = match_vision_to_track(v_ego, lead_msg, tracks)
else:
track = None
@@ -182,7 +177,7 @@ def get_lead(v_ego: float, ready: bool, tracks: Dict[int, Track], lead_msg: capn
lead_dict = {'status': False}
if track is not None:
lead_dict = track.get_RadarState(lead_msg.prob)
elif track is None and ready and not lead_msg_empty and lead_msg.prob > .5:
elif (track is None) and ready and (lead_msg.prob > .5):
lead_dict = get_RadarState_from_vision(lead_msg, v_ego, model_v_ego)
if low_speed_override:
@@ -212,14 +207,14 @@ class RadarD:
self.ready = False
def update(self, sm: messaging.SubMaster, radar_data: Optional[car.RadarData]):
def update(self, sm: messaging.SubMaster, rr: Optional[car.RadarData]):
self.current_time = 1e-9*max(sm.logMonoTime.values())
radar_points = []
radar_errors = []
if radar_data is not None:
radar_points = radar_data.points
radar_errors = radar_data.errors
if rr is not None:
radar_points = rr.points
radar_errors = rr.errors
if sm.updated['carState']:
self.v_ego = sm['carState'].vEgo
@@ -227,32 +222,26 @@ class RadarD:
if sm.updated['modelV2']:
self.ready = True
if radar_data is not None:
ar_pts = {}
for pt in radar_points:
ar_pts[pt.trackId] = [pt.dRel, pt.yRel, pt.vRel, pt.measured]
ar_pts = {}
for pt in radar_points:
ar_pts[pt.trackId] = [pt.dRel, pt.yRel, pt.vRel, pt.measured]
# *** remove missing points from meta data ***
for ids in list(self.tracks.keys()):
if ids not in ar_pts:
self.tracks.pop(ids, None)
# *** remove missing points from meta data ***
for ids in list(self.tracks.keys()):
if ids not in ar_pts:
self.tracks.pop(ids, None)
# *** compute the tracks ***
for ids in ar_pts:
rpt = ar_pts[ids]
# *** compute the tracks ***
for ids in ar_pts:
rpt = ar_pts[ids]
# align v_ego by a fixed time to align it with the radar measurement
v_lead = rpt[2] + self.v_ego_hist[0]
# align v_ego by a fixed time to align it with the radar measurement
v_lead = rpt[2] + self.v_ego_hist[0]
# create the track if it doesn't exist or it's a new track
if ids not in self.tracks:
self.tracks[ids] = Track(ids, v_lead, self.kalman_params)
self.tracks[ids].update(rpt[0], rpt[1], rpt[2], v_lead, rpt[3])
else:
# *** no radar points, keep existing tracks, update v_lead
for track in self.tracks.values():
v_lead = track.vRel + self.v_ego_hist[0]
track.update_vlead(v_lead)
# create the track if it doesn't exist or it's a new track
if ids not in self.tracks:
self.tracks[ids] = Track(ids, v_lead, self.kalman_params)
self.tracks[ids].update(rpt[0], rpt[1], rpt[2], v_lead, rpt[3])
# *** publish radarState ***
self.radar_state_valid = sm.all_checks() and len(radar_errors) == 0
@@ -305,33 +294,32 @@ def radard_thread(sm: Optional[messaging.SubMaster] = None, pm: Optional[messagi
cloudlog.info("radard is importing %s", CP.carName)
RadarInterface = importlib.import_module(f'selfdrive.car.{CP.carName}.radar_interface').RadarInterface
# setup messaging
# *** setup messaging
if can_sock is None:
can_sock = messaging.sub_sock('can')
if sm is None:
sm = messaging.SubMaster(['modelV2', 'carState'], poll=["modelV2"])
sm = messaging.SubMaster(['modelV2', 'carState'], ignore_avg_freq=['modelV2', 'carState']) # Can't check average frequency, since radar determines timing
if pm is None:
pm = messaging.PubMaster(['radarState', 'liveTracks'])
interface = RadarInterface(CP)
RI = RadarInterface(CP)
rk = Ratekeeper(1 / DT_MDL, print_delay_threshold=None)
radar = RadarD(DT_MDL, interface.delay)
rk = Ratekeeper(1.0 / CP.radarTimeStep, print_delay_threshold=None)
RD = RadarD(CP.radarTimeStep, RI.delay)
while True:
sm.update()
while 1:
can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True)
rr = RI.update(can_strings)
if sm.updated['modelV2']:
can_strings = messaging.drain_sock_raw(can_sock)
if len(can_strings) == 0:
radar_data = None
else:
radar_data = interface.update(can_strings)
if rr is None:
continue
radar.update(sm, radar_data)
radar.publish(pm, -rk.remaining*1000.0)
sm.update(0)
rk.monitor_time()
RD.update(sm, rr)
RD.publish(pm, -rk.remaining*1000.0)
rk.monitor_time()
def main(sm: Optional[messaging.SubMaster] = None, pm: Optional[messaging.PubMaster] = None, can_sock: messaging.SubSocket = None):