openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

176 lines
5.6 KiB

#!/usr/bin/env python3
import os
import time
import cereal.messaging as messaging
from cereal import car, log
from panda import ALTERNATIVE_EXPERIENCE
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, 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
from openpilot.selfdrive.controls.lib.events import Events
REPLAY = "REPLAY" in os.environ
State = log.ControlsState.OpenpilotState
EventName = car.CarEvent.EventName
def loop(CI=None):
can_sock = messaging.sub_sock('can', timeout=20)
sm = messaging.SubMaster(['pandaStates', 'carControl', 'controlsState'])
pm = messaging.PubMaster(['sendcan', 'carState', 'carParams', 'carOutput'])
can_rcv_timeout_counter = 0 # consecutive timeout count
can_rcv_cum_timeout_counter = 0 # cumulative timeout count
CC_prev = car.CarControl.new_message()
CS_prev = car.CarState.new_message()
controlsState_prev = car.CarState.new_message()
last_actuators_output = car.CarControl.Actuators.new_message()
params = Params()
if CI is None:
# wait for one pandaState and one CAN packet
print("Waiting for CAN messages...")
get_one_can(can_sock)
num_pandas = len(messaging.recv_one_retry(sm.sock['pandaStates']).pandaStates)
experimental_long_allowed = params.get_bool("ExperimentalLongitudinalEnabled")
CI, CP = get_car(can_sock, pm.sock['sendcan'], experimental_long_allowed, num_pandas)
else:
CI, CP = CI, CI.CP
# set alternative experiences from parameters
disengage_on_accelerator = params.get_bool("DisengageOnAccelerator")
CP.alternativeExperience = 0
if not disengage_on_accelerator:
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
controller_available = CI.CC is not None and openpilot_enabled_toggle and not CP.dashcamOnly
CP.passive = not controller_available or CP.dashcamOnly
if CP.passive:
safety_config = car.CarParams.SafetyConfig.new_message()
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
CP.safetyConfigs = [safety_config]
# Write previous route's CarParams
prev_cp = params.get("CarParamsPersistent")
if prev_cp is not None:
params.put("CarParamsPrevRoute", prev_cp)
# Write CarParams for controls and radard
cp_bytes = CP.to_bytes()
params.put("CarParams", cp_bytes)
params.put_nonblocking("CarParamsCache", cp_bytes)
params.put_nonblocking("CarParamsPersistent", cp_bytes)
events = Events()
# card is driven by can recv, expected at 100Hz
rk = Ratekeeper(100, print_delay_threshold=None)
while True:
# *** state update ***
"""carState update loop, driven by can"""
# Update carState from CAN
can_strs = messaging.drain_sock_raw(can_sock, wait_for_one=True)
CS = CI.update(CC_prev, can_strs)
sm.update(0)
can_rcv_valid = len(can_strs) > 0
# Check for CAN timeout
if not can_rcv_valid:
can_rcv_timeout_counter += 1
can_rcv_cum_timeout_counter += 1
else:
can_rcv_timeout_counter = 0
can_rcv_timeout = can_rcv_timeout_counter >= 5
if can_rcv_valid and REPLAY:
can_log_mono_time = messaging.log_from_bytes(can_strs[0]).logMonoTime
# *** update events ***
events.clear()
events.add_from_msg(CS.events)
# Disable on rising edge of accelerator or brake. Also disable on brake when speed > 0
if (CS.gasPressed and not CS_prev.gasPressed and disengage_on_accelerator) or \
(CS.brakePressed and (not CS_prev.brakePressed or not CS.standstill)) or \
(CS.regenBraking and (not CS_prev.regenBraking or not CS.standstill)):
events.add(EventName.pedalPressed)
CS.events = events.to_msg()
# *** state publish ***
"""carState and carParams publish loop"""
# carParams - logged every 50 seconds (> 1 per segment)
if sm.frame % int(50. / DT_CTRL) == 0:
cp_send = messaging.new_message('carParams')
cp_send.valid = True
cp_send.carParams = CP
pm.send('carParams', cp_send)
# publish new carOutput
co_send = messaging.new_message('carOutput')
co_send.valid = sm.all_checks(['carControl'])
co_send.carOutput.actuatorsOutput = last_actuators_output
pm.send('carOutput', co_send)
# kick off controlsd step while we actuate the latest carControl packet
cs_send = messaging.new_message('carState')
cs_send.valid = CS.canValid
cs_send.carState = CS
cs_send.carState.canRcvTimeout = can_rcv_timeout
cs_send.carState.canErrorCounter = can_rcv_cum_timeout_counter
cs_send.carState.cumLagMs = -rk.remaining * 1000.
pm.send('carState', cs_send)
# *** controls update ***
controlsState = sm['controlsState']
if not CP.passive and controlsState.initialized:
"""control update loop, driven by carControl"""
if not controlsState_prev.initialized:
# Initialize CarInterface, once controls are ready
CI.init(CP, can_sock, pm.sock['sendcan'])
if sm.all_checks(['carControl']):
# send car controls over can
CC = sm['carControl']
now_nanos = can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
last_actuators_output, can_sends = CI.apply(CC, now_nanos)
pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
CC_prev = CC
controlsState_prev = controlsState
CS_prev = CS.as_reader()
rk.monitor_time()
def main():
config_realtime_process(4, Priority.CTRL_HIGH)
loop()
if __name__ == "__main__":
main()