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.
		
		
		
		
		
			
		
			
				
					
					
						
							124 lines
						
					
					
						
							4.3 KiB
						
					
					
				
			
		
		
	
	
							124 lines
						
					
					
						
							4.3 KiB
						
					
					
				| import os
 | |
| import numpy as np
 | |
| 
 | |
| import selfdrive.messaging as messaging
 | |
| from selfdrive.swaglog import cloudlog
 | |
| from common.realtime import sec_since_boot
 | |
| from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU
 | |
| from selfdrive.controls.lib.longitudinal_mpc import libmpc_py
 | |
| from selfdrive.controls.lib.drive_helpers import MPC_COST_LONG
 | |
| 
 | |
| LOG_MPC = os.environ.get('LOG_MPC', False)
 | |
| 
 | |
| 
 | |
| class LongitudinalMpc(object):
 | |
|   def __init__(self, mpc_id):
 | |
|     self.mpc_id = mpc_id
 | |
| 
 | |
|     self.setup_mpc()
 | |
|     self.v_mpc = 0.0
 | |
|     self.v_mpc_future = 0.0
 | |
|     self.a_mpc = 0.0
 | |
|     self.v_cruise = 0.0
 | |
|     self.prev_lead_status = False
 | |
|     self.prev_lead_x = 0.0
 | |
|     self.new_lead = False
 | |
| 
 | |
|     self.last_cloudlog_t = 0.0
 | |
| 
 | |
|   def send_mpc_solution(self, pm, qp_iterations, calculation_time):
 | |
|     qp_iterations = max(0, qp_iterations)
 | |
|     dat = messaging.new_message()
 | |
|     dat.init('liveLongitudinalMpc')
 | |
|     dat.liveLongitudinalMpc.xEgo = list(self.mpc_solution[0].x_ego)
 | |
|     dat.liveLongitudinalMpc.vEgo = list(self.mpc_solution[0].v_ego)
 | |
|     dat.liveLongitudinalMpc.aEgo = list(self.mpc_solution[0].a_ego)
 | |
|     dat.liveLongitudinalMpc.xLead = list(self.mpc_solution[0].x_l)
 | |
|     dat.liveLongitudinalMpc.vLead = list(self.mpc_solution[0].v_l)
 | |
|     dat.liveLongitudinalMpc.cost = self.mpc_solution[0].cost
 | |
|     dat.liveLongitudinalMpc.aLeadTau = self.a_lead_tau
 | |
|     dat.liveLongitudinalMpc.qpIterations = qp_iterations
 | |
|     dat.liveLongitudinalMpc.mpcId = self.mpc_id
 | |
|     dat.liveLongitudinalMpc.calculationTime = calculation_time
 | |
|     pm.send('liveLongitudinalMpc', dat)
 | |
| 
 | |
|   def setup_mpc(self):
 | |
|     ffi, self.libmpc = libmpc_py.get_libmpc(self.mpc_id)
 | |
|     self.libmpc.init(MPC_COST_LONG.TTC, MPC_COST_LONG.DISTANCE,
 | |
|                      MPC_COST_LONG.ACCELERATION, MPC_COST_LONG.JERK)
 | |
| 
 | |
|     self.mpc_solution = ffi.new("log_t *")
 | |
|     self.cur_state = ffi.new("state_t *")
 | |
|     self.cur_state[0].v_ego = 0
 | |
|     self.cur_state[0].a_ego = 0
 | |
|     self.a_lead_tau = _LEAD_ACCEL_TAU
 | |
| 
 | |
|   def set_cur_state(self, v, a):
 | |
|     self.cur_state[0].v_ego = v
 | |
|     self.cur_state[0].a_ego = a
 | |
| 
 | |
|   def update(self, pm, CS, lead, v_cruise_setpoint):
 | |
|     v_ego = CS.vEgo
 | |
| 
 | |
|     # Setup current mpc state
 | |
|     self.cur_state[0].x_ego = 0.0
 | |
| 
 | |
|     if lead is not None and lead.status:
 | |
|       x_lead = lead.dRel
 | |
|       v_lead = max(0.0, lead.vLead)
 | |
|       a_lead = lead.aLeadK
 | |
| 
 | |
|       if (v_lead < 0.1 or -a_lead / 2.0 > v_lead):
 | |
|         v_lead = 0.0
 | |
|         a_lead = 0.0
 | |
| 
 | |
|       self.a_lead_tau = lead.aLeadTau
 | |
|       self.new_lead = False
 | |
|       if not self.prev_lead_status or abs(x_lead - self.prev_lead_x) > 2.5:
 | |
|         self.libmpc.init_with_simulation(self.v_mpc, x_lead, v_lead, a_lead, self.a_lead_tau)
 | |
|         self.new_lead = True
 | |
| 
 | |
|       self.prev_lead_status = True
 | |
|       self.prev_lead_x = x_lead
 | |
|       self.cur_state[0].x_l = x_lead
 | |
|       self.cur_state[0].v_l = v_lead
 | |
|     else:
 | |
|       self.prev_lead_status = False
 | |
|       # Fake a fast lead car, so mpc keeps running
 | |
|       self.cur_state[0].x_l = 50.0
 | |
|       self.cur_state[0].v_l = v_ego + 10.0
 | |
|       a_lead = 0.0
 | |
|       self.a_lead_tau = _LEAD_ACCEL_TAU
 | |
| 
 | |
|     # Calculate mpc
 | |
|     t = sec_since_boot()
 | |
|     n_its = self.libmpc.run_mpc(self.cur_state, self.mpc_solution, self.a_lead_tau, a_lead)
 | |
|     duration = int((sec_since_boot() - t) * 1e9)
 | |
| 
 | |
|     if LOG_MPC:
 | |
|       self.send_mpc_solution(pm, n_its, duration)
 | |
| 
 | |
|     # Get solution. MPC timestep is 0.2 s, so interpolation to 0.05 s is needed
 | |
|     self.v_mpc = self.mpc_solution[0].v_ego[1]
 | |
|     self.a_mpc = self.mpc_solution[0].a_ego[1]
 | |
|     self.v_mpc_future = self.mpc_solution[0].v_ego[10]
 | |
| 
 | |
|     # Reset if NaN or goes through lead car
 | |
|     dls = np.array(list(self.mpc_solution[0].x_l)) - np.array(list(self.mpc_solution[0].x_ego))
 | |
|     crashing = min(dls) < -50.0
 | |
|     nans = np.any(np.isnan(list(self.mpc_solution[0].v_ego)))
 | |
|     backwards = min(list(self.mpc_solution[0].v_ego)) < -0.01
 | |
| 
 | |
|     if ((backwards or crashing) and self.prev_lead_status) or nans:
 | |
|       if t > self.last_cloudlog_t + 5.0:
 | |
|         self.last_cloudlog_t = t
 | |
|         cloudlog.warning("Longitudinal mpc %d reset - backwards: %s crashing: %s nan: %s" % (
 | |
|                           self.mpc_id, backwards, crashing, nans))
 | |
| 
 | |
|       self.libmpc.init(MPC_COST_LONG.TTC, MPC_COST_LONG.DISTANCE,
 | |
|                        MPC_COST_LONG.ACCELERATION, MPC_COST_LONG.JERK)
 | |
|       self.cur_state[0].v_ego = v_ego
 | |
|       self.cur_state[0].a_ego = 0.0
 | |
|       self.v_mpc = v_ego
 | |
|       self.a_mpc = CS.aEgo
 | |
|       self.prev_lead_status = False
 | |
| 
 |