
Maintain openpilot lateral control when the brake or gas pedals are used. Deactivation occurs only through the 'Cruise Control' button. Lots of credit goes to "pfeiferj"! Couldn't of done it without him! https: //github.com/pfeiferj/openpilot Co-Authored-By: Jacob Pfeifer <jacob@pfeifer.dev>
152 lines
5.2 KiB
Python
Executable File
152 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import os
|
|
import time
|
|
|
|
import cereal.messaging as messaging
|
|
|
|
from cereal import car
|
|
|
|
from panda import ALTERNATIVE_EXPERIENCE
|
|
|
|
from openpilot.common.params import Params
|
|
from openpilot.common.realtime import DT_CTRL
|
|
|
|
from openpilot.selfdrive.boardd.boardd import can_list_to_can_capnp
|
|
from openpilot.selfdrive.car.car_helpers import get_car, get_one_can
|
|
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
|
|
|
|
|
REPLAY = "REPLAY" in os.environ
|
|
|
|
|
|
class CarD:
|
|
CI: CarInterfaceBase
|
|
CS: car.CarState
|
|
|
|
def __init__(self, CI=None):
|
|
self.can_sock = messaging.sub_sock('can', timeout=20)
|
|
self.sm = messaging.SubMaster(['pandaStates'])
|
|
self.pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput', 'frogpilotCarState'])
|
|
|
|
self.can_rcv_timeout_counter = 0 # conseuctive timeout count
|
|
self.can_rcv_cum_timeout_counter = 0 # cumulative timeout count
|
|
|
|
self.CC_prev = car.CarControl.new_message()
|
|
|
|
self.last_actuators = None
|
|
|
|
self.params = Params()
|
|
|
|
if CI is None:
|
|
# wait for one pandaState and one CAN packet
|
|
print("Waiting for CAN messages...")
|
|
get_one_can(self.can_sock)
|
|
|
|
num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates)
|
|
experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled")
|
|
self.CI, self.CP = get_car(self.params, self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas)
|
|
else:
|
|
self.CI, self.CP = CI, CI.CP
|
|
|
|
# set alternative experiences from parameters
|
|
disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
|
|
self.CP.alternativeExperience = 0
|
|
if not disengage_on_accelerator:
|
|
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
|
|
|
|
self.always_on_lateral = self.params.get_bool("AlwaysOnLateral")
|
|
if self.always_on_lateral:
|
|
self.CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL
|
|
|
|
car_recognized = self.CP.carName != 'mock'
|
|
openpilot_enabled_toggle = self.params.get_bool("OpenpilotEnabledToggle")
|
|
|
|
controller_available = self.CI.CC is not None and openpilot_enabled_toggle and not self.CP.dashcamOnly
|
|
|
|
self.CP.passive = not car_recognized or not controller_available or self.CP.dashcamOnly
|
|
if self.CP.passive:
|
|
safety_config = car.CarParams.SafetyConfig.new_message()
|
|
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
|
|
self.CP.safetyConfigs = [safety_config]
|
|
|
|
# Write previous route's CarParams
|
|
prev_cp = self.params.get("CarParamsPersistent")
|
|
if prev_cp is not None:
|
|
self.params.put("CarParamsPrevRoute", prev_cp)
|
|
|
|
# Write CarParams for controls and radard
|
|
cp_bytes = self.CP.to_bytes()
|
|
self.params.put("CarParams", cp_bytes)
|
|
self.params.put_nonblocking("CarParamsCache", cp_bytes)
|
|
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
|
|
|
|
def initialize(self):
|
|
"""Initialize CarInterface, once controls are ready"""
|
|
self.CI.init(self.CP, self.can_sock, self.pm.sock['sendcan'])
|
|
|
|
def state_update(self, frogpilot_variables):
|
|
"""carState update loop, driven by can"""
|
|
|
|
# Update carState from CAN
|
|
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
|
|
self.CS, self.FPCS = self.CI.update(self.CC_prev, can_strs, frogpilot_variables)
|
|
|
|
self.sm.update(0)
|
|
|
|
can_rcv_valid = len(can_strs) > 0
|
|
|
|
# Check for CAN timeout
|
|
if not can_rcv_valid:
|
|
self.can_rcv_timeout_counter += 1
|
|
self.can_rcv_cum_timeout_counter += 1
|
|
else:
|
|
self.can_rcv_timeout_counter = 0
|
|
|
|
self.can_rcv_timeout = self.can_rcv_timeout_counter >= 5
|
|
|
|
if can_rcv_valid and REPLAY:
|
|
self.can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
|
|
|
|
self.state_publish()
|
|
|
|
return self.CS
|
|
|
|
def state_publish(self):
|
|
"""carState and carParams publish loop"""
|
|
|
|
# carState
|
|
cs_send = messaging.new_message('carState')
|
|
cs_send.valid = self.CS.canValid
|
|
cs_send.carState = self.CS
|
|
self.pm.send('carState', cs_send)
|
|
|
|
# carParams - logged every 50 seconds (> 1 per segment)
|
|
if (self.sm.frame % int(50. / DT_CTRL) == 0):
|
|
cp_send = messaging.new_message('carParams')
|
|
cp_send.valid = True
|
|
cp_send.carParams = self.CP
|
|
self.pm.send('carParams', cp_send)
|
|
|
|
# publish new carOutput
|
|
co_send = messaging.new_message('carOutput')
|
|
co_send.valid = True
|
|
if self.last_actuators is not None:
|
|
co_send.carOutput.actuatorsOutput = self.last_actuators
|
|
self.pm.send('carOutput', co_send)
|
|
|
|
# FrogPilot carState
|
|
fp_cs_send = messaging.new_message('frogpilotCarState')
|
|
fp_cs_send.valid = self.CS.canValid
|
|
fp_cs_send.frogpilotCarState = self.FPCS
|
|
self.pm.send('frogpilotCarState', fp_cs_send)
|
|
|
|
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)
|
|
self.last_actuators, 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))
|
|
|
|
self.CC_prev = CC
|