#!/usr/bin/env python3 import unittest import numpy as np from cereal import log import cereal.messaging as messaging from selfdrive.config import Conversions as CV from selfdrive.controls.lib.lead_mpc import LeadMpc def RW(v_ego, v_l): TR = 1.8 G = 9.81 return (v_ego * TR - (v_l - v_ego) * TR + v_ego * v_ego / (2 * G) - v_l * v_l / (2 * G)) class FakePubMaster(): def send(self, s, data): assert data def run_following_distance_simulation(v_lead, t_end=200.0): dt = 0.2 t = 0. x_lead = 200.0 x_ego = 0.0 v_ego = v_lead a_ego = 0.0 mpc = LeadMpc(0) first = True while t < t_end: # Setup CarState CS = messaging.new_message('carState') CS.carState.vEgo = v_ego CS.carState.aEgo = a_ego # Setup model packet radarstate = messaging.new_message('radarState') lead = log.RadarState.LeadData.new_message() lead.modelProb = .75 lead.dRel = x_lead - x_ego lead.vLead = v_lead lead.aLeadK = 0.0 lead.status = True radarstate.radarState.leadOne = lead # Run MPC mpc.set_cur_state(v_ego, a_ego) if first: # Make sure MPC is converged on first timestep for _ in range(20): mpc.update(CS.carState, radarstate.radarState, 0) mpc.update(CS.carState, radarstate.radarState, 0) # Choose slowest of two solutions v_ego, a_ego = mpc.mpc_solution.v_ego[5], mpc.mpc_solution.a_ego[5] # Update state x_lead += v_lead * dt x_ego += v_ego * dt t += dt first = False return x_lead - x_ego class TestFollowingDistance(unittest.TestCase): def test_following_distanc(self): for speed_mph in np.linspace(10, 100, num=10): v_lead = float(speed_mph * CV.MPH_TO_MS) simulation_steady_state = run_following_distance_simulation(v_lead) correct_steady_state = RW(v_lead, v_lead) + 4.0 self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=.1) if __name__ == "__main__": unittest.main()