FrogPilot Setup
This commit is contained in:
@@ -3,11 +3,12 @@ import os
|
||||
import math
|
||||
import time
|
||||
import threading
|
||||
from types import SimpleNamespace
|
||||
from typing import SupportsFloat
|
||||
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from cereal import car, log
|
||||
from cereal import car, log, custom
|
||||
from cereal.visionipc import VisionIpcClient, VisionStreamType
|
||||
|
||||
from panda import ALTERNATIVE_EXPERIENCE
|
||||
@@ -53,6 +54,7 @@ LaneChangeDirection = log.LaneChangeDirection
|
||||
EventName = car.CarEvent.EventName
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
GearShifter = car.CarState.GearShifter
|
||||
|
||||
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
|
||||
CSID_MAP = {"1": EventName.roadCameraError, "2": EventName.wideRoadCameraError, "0": EventName.driverCameraError}
|
||||
@@ -90,14 +92,14 @@ class CarD:
|
||||
"""Initialize CarInterface, once controls are ready"""
|
||||
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
|
||||
|
||||
def state_update(self, CC: car.CarControl):
|
||||
def state_update(self, CC: car.CarControl, frogpilot_variables):
|
||||
"""carState update loop, driven by can"""
|
||||
|
||||
# TODO: This should not depend on carControl
|
||||
|
||||
# Update carState from CAN
|
||||
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
|
||||
self.CS = self.CI.update(CC, can_strs)
|
||||
self.CS = self.CI.update(CC, can_strs, frogpilot_variables)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
@@ -136,12 +138,12 @@ class CarD:
|
||||
cp_send.carParams = self.CP
|
||||
self.pm.send('carParams', cp_send)
|
||||
|
||||
def controls_update(self, CC: car.CarControl):
|
||||
def controls_update(self, CC: car.CarControl, frogpilot_variables):
|
||||
"""control update loop, driven by carControl"""
|
||||
|
||||
# send car controls over can
|
||||
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
|
||||
actuators_output, can_sends = self.CI.apply(CC, now_nanos)
|
||||
actuators_output, can_sends = self.CI.apply(CC, now_nanos, frogpilot_variables)
|
||||
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=self.CS.canValid))
|
||||
|
||||
return actuators_output
|
||||
@@ -160,21 +162,28 @@ class Controls:
|
||||
self.branch = get_short_branch()
|
||||
|
||||
# Setup sockets
|
||||
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents'])
|
||||
self.pm = messaging.PubMaster(['controlsState', 'carControl', 'onroadEvents', 'frogpilotCarControl'])
|
||||
|
||||
self.sensor_packets = ["accelerometer", "gyroscope"]
|
||||
self.camera_packets = ["roadCameraState", "driverCameraState", "wideRoadCameraState"]
|
||||
|
||||
self.log_sock = messaging.sub_sock('androidLog')
|
||||
|
||||
# FrogPilot variables
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.frogpilot_variables = SimpleNamespace()
|
||||
|
||||
self.driving_gear = False
|
||||
|
||||
ignore = self.sensor_packets + ['testJoystick']
|
||||
if SIMULATION:
|
||||
ignore += ['driverCameraState', 'managerState']
|
||||
self.sm = messaging.SubMaster(['deviceState', 'pandaStates', 'peripheralState', 'modelV2', 'liveCalibration',
|
||||
'driverMonitoringState', 'longitudinalPlan', 'liveLocationKalman',
|
||||
'managerState', 'liveParameters', 'radarState', 'liveTorqueParameters',
|
||||
'testJoystick'] + self.camera_packets + self.sensor_packets,
|
||||
'testJoystick', 'frogpilotPlan'] + self.camera_packets + self.sensor_packets,
|
||||
ignore_alive=ignore, ignore_avg_freq=ignore+['radarState', 'testJoystick'], ignore_valid=['testJoystick', ],
|
||||
frequency=int(1/DT_CTRL))
|
||||
|
||||
@@ -191,6 +200,8 @@ class Controls:
|
||||
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
|
||||
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
# detect sound card presence and ensure successful init
|
||||
sounds_available = HARDWARE.get_sound_card_online()
|
||||
|
||||
@@ -222,6 +233,7 @@ class Controls:
|
||||
|
||||
self.CC = car.CarControl.new_message()
|
||||
self.CS_prev = car.CarState.new_message()
|
||||
self.FPCC = custom.FrogPilotCarControl.new_message()
|
||||
self.AM = AlertManager()
|
||||
self.events = Events()
|
||||
|
||||
@@ -291,6 +303,8 @@ class Controls:
|
||||
|
||||
self.events.clear()
|
||||
|
||||
frogpilot_plan = self.sm['frogpilotPlan']
|
||||
|
||||
# Add joystick event, static on cars, dynamic on nonCars
|
||||
if self.joystick_mode:
|
||||
self.events.add(EventName.joystickDebug)
|
||||
@@ -506,7 +520,7 @@ class Controls:
|
||||
def data_sample(self):
|
||||
"""Receive data from sockets and update carState"""
|
||||
|
||||
CS = self.card.state_update(self.CC)
|
||||
CS = self.card.state_update(self.CC, self.frogpilot_variables)
|
||||
|
||||
self.sm.update(0)
|
||||
|
||||
@@ -630,7 +644,7 @@ class Controls:
|
||||
else:
|
||||
self.state = State.enabled
|
||||
self.current_alert_types.append(ET.ENABLE)
|
||||
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode)
|
||||
self.v_cruise_helper.initialize_v_cruise(CS, self.experimental_mode, self.frogpilot_variables)
|
||||
|
||||
# Check if openpilot is engaged and actuators are enabled
|
||||
self.enabled = self.state in ENABLED_STATES
|
||||
@@ -660,6 +674,12 @@ class Controls:
|
||||
CC = car.CarControl.new_message()
|
||||
CC.enabled = self.enabled
|
||||
|
||||
# FrogPilot functions
|
||||
frogpilot_plan = self.sm['frogpilotPlan']
|
||||
|
||||
# Gear Check
|
||||
self.driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park, GearShifter.reverse, GearShifter.unknown)
|
||||
|
||||
# Check which actuators can be enabled
|
||||
standstill = CS.vEgo <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
|
||||
CC.latActive = self.active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
|
||||
@@ -826,7 +846,7 @@ class Controls:
|
||||
hudControl.visualAlert = current_alert.visual_alert
|
||||
|
||||
if not self.CP.passive and self.initialized:
|
||||
self.last_actuators = self.card.controls_update(CC)
|
||||
self.last_actuators = self.card.controls_update(CC, self.frogpilot_variables)
|
||||
CC.actuatorsOutput = self.last_actuators
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.steer_limited = abs(CC.actuators.steeringAngleDeg - CC.actuatorsOutput.steeringAngleDeg) > \
|
||||
@@ -910,6 +930,12 @@ class Controls:
|
||||
# copy CarControl to pass to CarInterface on the next iteration
|
||||
self.CC = CC
|
||||
|
||||
# Publish FrogPilot variables
|
||||
fpcs_send = messaging.new_message('frogpilotCarControl')
|
||||
fpcs_send.valid = CS.canValid
|
||||
fpcs_send.frogpilotCarControl = self.FPCC
|
||||
self.pm.send('frogpilotCarControl', fpcs_send)
|
||||
|
||||
def step(self):
|
||||
start_time = time.monotonic()
|
||||
|
||||
@@ -940,6 +966,10 @@ class Controls:
|
||||
self.joystick_mode = self.params.get_bool("JoystickDebugMode")
|
||||
time.sleep(0.1)
|
||||
|
||||
# Update FrogPilot parameters
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def controlsd_thread(self):
|
||||
e = threading.Event()
|
||||
t = threading.Thread(target=self.params_thread, args=(e, ))
|
||||
@@ -952,6 +982,14 @@ class Controls:
|
||||
e.set()
|
||||
t.join()
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
custom_alerts = self.params.get_bool("CustomAlerts")
|
||||
|
||||
lateral_tune = self.params.get_bool("LateralTune")
|
||||
|
||||
longitudinal_tune = self.params.get_bool("LongitudinalTune")
|
||||
|
||||
quality_of_life = self.params.get_bool("QOLControls")
|
||||
|
||||
def main():
|
||||
controls = Controls()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from cereal import log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
|
||||
LaneChangeState = log.LaneChangeState
|
||||
@@ -40,7 +41,13 @@ class DesireHelper:
|
||||
self.prev_one_blinker = False
|
||||
self.desire = log.Desire.none
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob):
|
||||
# FrogPilot variables
|
||||
self.params = Params()
|
||||
self.params_memory = Params("/dev/shm/params")
|
||||
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update(self, carstate, lateral_active, lane_change_prob, frogpilotPlan):
|
||||
v_ego = carstate.vEgo
|
||||
one_blinker = carstate.leftBlinker != carstate.rightBlinker
|
||||
below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN
|
||||
@@ -112,3 +119,9 @@ class DesireHelper:
|
||||
self.keep_pulse_timer = 0.0
|
||||
elif self.desire in (log.Desire.keepLeft, log.Desire.keepRight):
|
||||
self.desire = log.Desire.none
|
||||
|
||||
if self.params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
self.update_frogpilot_params()
|
||||
|
||||
def update_frogpilot_params(self):
|
||||
is_metric = self.params.get_bool("IsMetric")
|
||||
|
||||
@@ -3,6 +3,7 @@ import math
|
||||
from cereal import car, log
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
# WARNING: this value was determined based on the model's training distribution,
|
||||
@@ -45,6 +46,8 @@ class VCruiseHelper:
|
||||
self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0}
|
||||
self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers}
|
||||
|
||||
# FrogPilot variables
|
||||
|
||||
@property
|
||||
def v_cruise_initialized(self):
|
||||
return self.v_cruise_kph != V_CRUISE_UNSET
|
||||
@@ -125,7 +128,7 @@ class VCruiseHelper:
|
||||
self.button_timers[b.type.raw] = 1 if b.pressed else 0
|
||||
self.button_change_states[b.type.raw] = {"standstill": CS.cruiseState.standstill, "enabled": enabled}
|
||||
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool) -> None:
|
||||
def initialize_v_cruise(self, CS, experimental_mode: bool, frogpilot_variables) -> None:
|
||||
# initializing is handled by the PCM
|
||||
if self.CP.pcmCruise:
|
||||
return
|
||||
|
||||
@@ -228,7 +228,7 @@ def startup_master_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubM
|
||||
if "REPLAY" in os.environ:
|
||||
branch = "replay"
|
||||
|
||||
return StartupAlert("WARNING: This branch is not tested", branch, alert_status=AlertStatus.userPrompt)
|
||||
return StartupAlert("Hippity hoppity this is my property", "so I do what I want 🐸", alert_status=AlertStatus.frogpilot)
|
||||
|
||||
def below_engage_speed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert:
|
||||
return NoEntryAlert(f"Drive above {get_display_speed(CP.minEnableSpeed, metric)} to engage")
|
||||
@@ -332,6 +332,7 @@ def joystick_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster,
|
||||
return NormalPermanentAlert("Joystick Mode", vals)
|
||||
|
||||
|
||||
# FrogPilot alerts
|
||||
|
||||
EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
||||
# ********** events with no alerts **********
|
||||
@@ -956,6 +957,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = {
|
||||
ET.NO_ENTRY: NoEntryAlert("Vehicle Sensors Calibrating"),
|
||||
},
|
||||
|
||||
# FrogPilot Events
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -221,6 +221,8 @@ def gen_long_ocp():
|
||||
|
||||
class LongitudinalMpc:
|
||||
def __init__(self, mode='acc'):
|
||||
# FrogPilot variables
|
||||
|
||||
self.mode = mode
|
||||
self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
|
||||
self.reset()
|
||||
@@ -330,7 +332,7 @@ class LongitudinalMpc:
|
||||
self.cruise_min_a = min_a
|
||||
self.max_a = max_a
|
||||
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, personality=log.LongitudinalPersonality.standard):
|
||||
def update(self, radarstate, v_cruise, x, v, a, j, frogpilot_planner, personality=log.LongitudinalPersonality.standard):
|
||||
t_follow = get_T_FOLLOW(personality)
|
||||
v_ego = self.x0[1]
|
||||
self.status = radarstate.leadOne.status or radarstate.leadTwo.status
|
||||
|
||||
@@ -88,7 +88,7 @@ class LongitudinalPlanner:
|
||||
j = np.zeros(len(T_IDXS_MPC))
|
||||
return x, v, a, j
|
||||
|
||||
def update(self, sm):
|
||||
def update(self, sm, frogpilot_planner, params_memory):
|
||||
if self.param_read_counter % 50 == 0:
|
||||
self.read_param()
|
||||
self.param_read_counter += 1
|
||||
@@ -134,7 +134,7 @@ class LongitudinalPlanner:
|
||||
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
|
||||
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
|
||||
x, v, a, j = self.parse_model(sm['modelV2'], self.v_model_error)
|
||||
self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, personality=self.personality)
|
||||
self.mpc.update(sm['radarState'], frogpilot_planner.v_cruise, x, v, a, j, frogpilot_planner, personality=self.personality)
|
||||
|
||||
self.v_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, self.mpc.v_solution)
|
||||
self.a_desired_trajectory_full = np.interp(ModelConstants.T_IDXS, T_IDXS_MPC, self.mpc.a_solution)
|
||||
@@ -152,7 +152,9 @@ class LongitudinalPlanner:
|
||||
self.a_desired = float(interp(self.dt, ModelConstants.T_IDXS[:CONTROL_N], self.a_desired_trajectory))
|
||||
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0
|
||||
|
||||
def publish(self, sm, pm):
|
||||
frogpilot_planner.update(sm['carState'], sm['controlsState'], sm['modelV2'], self.mpc, sm, v_cruise, v_ego)
|
||||
|
||||
def publish(self, sm, pm, frogpilot_planner):
|
||||
plan_send = messaging.new_message('longitudinalPlan')
|
||||
|
||||
plan_send.valid = sm.all_checks(service_list=['carState', 'controlsState'])
|
||||
@@ -173,3 +175,5 @@ class LongitudinalPlanner:
|
||||
longitudinalPlan.personality = self.personality
|
||||
|
||||
pm.send('longitudinalPlan', plan_send)
|
||||
|
||||
frogpilot_planner.publish(sm, pm, self.mpc)
|
||||
|
||||
@@ -6,6 +6,8 @@ from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner
|
||||
import cereal.messaging as messaging
|
||||
|
||||
from openpilot.selfdrive.frogpilot.functions.frogpilot_planner import FrogPilotPlanner
|
||||
|
||||
def publish_ui_plan(sm, pm, longitudinal_planner):
|
||||
ui_send = messaging.new_message('uiPlan')
|
||||
ui_send.valid = sm.all_checks(service_list=['carState', 'controlsState', 'modelV2'])
|
||||
@@ -22,22 +24,27 @@ def plannerd_thread():
|
||||
|
||||
cloudlog.info("plannerd is waiting for CarParams")
|
||||
params = Params()
|
||||
params_memory = Params("/dev/shm/params")
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as msg:
|
||||
CP = msg
|
||||
cloudlog.info("plannerd got CarParams: %s", CP.carName)
|
||||
|
||||
frogpilot_planner = FrogPilotPlanner(CP, params, params_memory)
|
||||
longitudinal_planner = LongitudinalPlanner(CP)
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2'],
|
||||
pm = messaging.PubMaster(['longitudinalPlan', 'uiPlan', 'frogpilotPlan'])
|
||||
sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'radarState', 'modelV2', 'frogpilotNavigation'],
|
||||
poll='modelV2', ignore_avg_freq=['radarState'])
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
if sm.updated['modelV2']:
|
||||
longitudinal_planner.update(sm)
|
||||
longitudinal_planner.publish(sm, pm)
|
||||
longitudinal_planner.update(sm, frogpilot_planner, params_memory)
|
||||
longitudinal_planner.publish(sm, pm, frogpilot_planner)
|
||||
publish_ui_plan(sm, pm, longitudinal_planner)
|
||||
|
||||
if params_memory.get_bool("FrogPilotTogglesUpdated"):
|
||||
frogpilot_planner.update_frogpilot_params(params)
|
||||
|
||||
def main():
|
||||
plannerd_thread()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user