Simplify longitudinal tests (#21337)
* first pass * passes! * little more cleanup * little more * fix sim * remove more plot stuff * fix crash check * fcw Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>pull/21403/head
parent
fb2eec03e1
commit
234971203b
6 changed files with 127 additions and 893 deletions
@ -1,2 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
docker run -v $(pwd)/docker_out:/tmp/openpilot/selfdrive/test/out openpilot_ci /bin/bash -c "rm -Rf /tmp/openpilot/selfdrive/test/out/longitudinal" |
|
@ -1,139 +0,0 @@ |
|||||||
import os |
|
||||||
|
|
||||||
import numpy as np |
|
||||||
import matplotlib.pyplot as plt |
|
||||||
import pylab |
|
||||||
|
|
||||||
from selfdrive.config import Conversions as CV |
|
||||||
|
|
||||||
class ManeuverPlot(): |
|
||||||
def __init__(self, title=None): |
|
||||||
self.time_array = [] |
|
||||||
|
|
||||||
self.gas_array = [] |
|
||||||
self.brake_array = [] |
|
||||||
self.steer_torque_array = [] |
|
||||||
|
|
||||||
self.distance_array = [] |
|
||||||
self.speed_array = [] |
|
||||||
self.acceleration_array = [] |
|
||||||
|
|
||||||
self.up_accel_cmd_array = [] |
|
||||||
self.ui_accel_cmd_array = [] |
|
||||||
self.uf_accel_cmd_array = [] |
|
||||||
|
|
||||||
self.d_rel_array = [] |
|
||||||
self.v_rel_array = [] |
|
||||||
self.v_lead_array = [] |
|
||||||
self.v_target_lead_array = [] |
|
||||||
self.pid_speed_array = [] |
|
||||||
self.cruise_speed_array = [] |
|
||||||
|
|
||||||
self.a_target_array = [] |
|
||||||
|
|
||||||
self.v_target_array = [] |
|
||||||
|
|
||||||
self.fcw_array = [] |
|
||||||
|
|
||||||
self.title = title |
|
||||||
|
|
||||||
def add_data(self, time, gas, brake, steer_torque, distance, speed, |
|
||||||
acceleration, up_accel_cmd, ui_accel_cmd, uf_accel_cmd, d_rel, v_rel, |
|
||||||
v_lead, v_target_lead, pid_speed, cruise_speed, a_target, fcw): |
|
||||||
self.time_array.append(time) |
|
||||||
self.gas_array.append(gas) |
|
||||||
self.brake_array.append(brake) |
|
||||||
self.steer_torque_array.append(steer_torque) |
|
||||||
self.distance_array.append(distance) |
|
||||||
self.speed_array.append(speed) |
|
||||||
self.acceleration_array.append(acceleration) |
|
||||||
self.up_accel_cmd_array.append(up_accel_cmd) |
|
||||||
self.ui_accel_cmd_array.append(ui_accel_cmd) |
|
||||||
self.uf_accel_cmd_array.append(uf_accel_cmd) |
|
||||||
self.d_rel_array.append(d_rel) |
|
||||||
self.v_rel_array.append(v_rel) |
|
||||||
self.v_lead_array.append(v_lead) |
|
||||||
self.v_target_lead_array.append(v_target_lead) |
|
||||||
self.pid_speed_array.append(pid_speed) |
|
||||||
self.cruise_speed_array.append(cruise_speed) |
|
||||||
self.a_target_array.append(a_target) |
|
||||||
self.fcw_array.append(fcw) |
|
||||||
|
|
||||||
def write_plot(self, path, maneuver_name): |
|
||||||
# title = self.title or maneuver_name |
|
||||||
# TODO: Missing plots from the old one: |
|
||||||
# long_control_state |
|
||||||
# proportional_gb, intergral_gb |
|
||||||
if not os.path.exists(path + "/" + maneuver_name): |
|
||||||
os.makedirs(path + "/" + maneuver_name) |
|
||||||
plt_num = 0 |
|
||||||
|
|
||||||
# speed chart =================== |
|
||||||
plt_num += 1 |
|
||||||
plt.figure(plt_num) |
|
||||||
plt.plot( |
|
||||||
np.array(self.time_array), np.array(self.speed_array) * CV.MS_TO_MPH, 'r', |
|
||||||
np.array(self.time_array), np.array(self.pid_speed_array) * CV.MS_TO_MPH, 'y--', |
|
||||||
np.array(self.time_array), np.array(self.v_target_lead_array) * CV.MS_TO_MPH, 'b', |
|
||||||
np.array(self.time_array), np.array(self.cruise_speed_array) * CV.KPH_TO_MPH, 'k', |
|
||||||
np.array(self.time_array), np.array(self.v_lead_array) * CV.MS_TO_MPH, 'm' |
|
||||||
) |
|
||||||
plt.xlabel('Time [s]') |
|
||||||
plt.ylabel('Speed [mph]') |
|
||||||
plt.legend(['speed', 'pid speed', 'Target (lead) speed', 'Cruise speed', 'Lead speed'], loc=0) |
|
||||||
plt.grid() |
|
||||||
pylab.savefig("/".join([path, maneuver_name, 'speeds.svg']), dpi=1000) |
|
||||||
|
|
||||||
# acceleration chart ============ |
|
||||||
plt_num += 1 |
|
||||||
plt.figure(plt_num) |
|
||||||
plt.plot( |
|
||||||
np.array(self.time_array), np.array(self.acceleration_array), 'g', |
|
||||||
np.array(self.time_array), np.array(self.a_target_array), 'k--', |
|
||||||
np.array(self.time_array), np.array(self.fcw_array), 'ro', |
|
||||||
) |
|
||||||
plt.xlabel('Time [s]') |
|
||||||
plt.ylabel('Acceleration [m/s^2]') |
|
||||||
plt.legend(['ego-plant', 'target', 'fcw'], loc=0) |
|
||||||
plt.grid() |
|
||||||
pylab.savefig("/".join([path, maneuver_name, 'acceleration.svg']), dpi=1000) |
|
||||||
|
|
||||||
# pedal chart =================== |
|
||||||
plt_num += 1 |
|
||||||
plt.figure(plt_num) |
|
||||||
plt.plot( |
|
||||||
np.array(self.time_array), np.array(self.gas_array), 'g', |
|
||||||
np.array(self.time_array), np.array(self.brake_array), 'r', |
|
||||||
) |
|
||||||
plt.xlabel('Time [s]') |
|
||||||
plt.ylabel('Pedal []') |
|
||||||
plt.legend(['Gas pedal', 'Brake pedal'], loc=0) |
|
||||||
plt.grid() |
|
||||||
pylab.savefig("/".join([path, maneuver_name, 'pedals.svg']), dpi=1000) |
|
||||||
|
|
||||||
# pid chart ====================== |
|
||||||
plt_num += 1 |
|
||||||
plt.figure(plt_num) |
|
||||||
plt.plot( |
|
||||||
np.array(self.time_array), np.array(self.up_accel_cmd_array), 'g', |
|
||||||
np.array(self.time_array), np.array(self.ui_accel_cmd_array), 'b', |
|
||||||
np.array(self.time_array), np.array(self.uf_accel_cmd_array), 'r' |
|
||||||
) |
|
||||||
plt.xlabel("Time, [s]") |
|
||||||
plt.ylabel("Accel Cmd [m/s^2]") |
|
||||||
plt.grid() |
|
||||||
plt.legend(["Proportional", "Integral", "feedforward"], loc=0) |
|
||||||
pylab.savefig("/".join([path, maneuver_name, "pid.svg"]), dpi=1000) |
|
||||||
|
|
||||||
# relative distances chart ======= |
|
||||||
plt_num += 1 |
|
||||||
plt.figure(plt_num) |
|
||||||
plt.plot( |
|
||||||
np.array(self.time_array), np.array(self.d_rel_array), 'g', |
|
||||||
) |
|
||||||
plt.xlabel('Time [s]') |
|
||||||
plt.ylabel('Relative Distance [m]') |
|
||||||
plt.grid() |
|
||||||
pylab.savefig("/".join([path, maneuver_name, 'distance.svg']), dpi=1000) |
|
||||||
|
|
||||||
plt.close("all") |
|
@ -1,467 +1,137 @@ |
|||||||
#!/usr/bin/env python3 |
#!/usr/bin/env python3 |
||||||
import binascii |
|
||||||
import os |
|
||||||
import struct |
|
||||||
import time |
import time |
||||||
from collections import namedtuple |
|
||||||
import numpy as np |
import numpy as np |
||||||
|
|
||||||
from opendbc import DBC_PATH |
from cereal import log |
||||||
|
|
||||||
from cereal import car, log |
|
||||||
from common.realtime import Ratekeeper |
|
||||||
from selfdrive.config import Conversions as CV |
|
||||||
import cereal.messaging as messaging |
import cereal.messaging as messaging |
||||||
from selfdrive.car import crc8_pedal |
from common.realtime import Ratekeeper, DT_MDL |
||||||
from selfdrive.car.honda.values import CAR |
from selfdrive.controls.lib.longcontrol import LongCtrlState |
||||||
from selfdrive.car.honda.carstate import get_can_signals |
|
||||||
from selfdrive.boardd.boardd import can_list_to_can_capnp |
|
||||||
|
|
||||||
from opendbc.can.parser import CANParser |
|
||||||
from selfdrive.car.honda.interface import CarInterface |
|
||||||
|
|
||||||
from opendbc.can.dbc import dbc |
|
||||||
honda = dbc(os.path.join(DBC_PATH, "honda_civic_touring_2016_can_generated.dbc")) |
|
||||||
|
|
||||||
# Trick: set 0x201 (interceptor) in fingerprints for gas is controlled like if there was an interceptor |
|
||||||
CP = CarInterface.get_params(CAR.CIVIC, {0: {0x201: 6}, 1: {}, 2: {}, 3: {}}) |
|
||||||
|
|
||||||
# Honda checksum |
|
||||||
def can_cksum(mm): |
|
||||||
s = 0 |
|
||||||
for c in mm: |
|
||||||
s += (c >> 4) |
|
||||||
s += c & 0xF |
|
||||||
s = 8-s |
|
||||||
s %= 0x10 |
|
||||||
return s |
|
||||||
|
|
||||||
def fix(msg, addr): |
|
||||||
msg2 = msg[0:-1] + (msg[-1] | can_cksum(struct.pack("I", addr)+msg)).to_bytes(1, 'little') |
|
||||||
return msg2 |
|
||||||
|
|
||||||
|
|
||||||
def car_plant(pos, speed, grade, gas, brake): |
|
||||||
# vehicle parameters |
|
||||||
mass = 1700 |
|
||||||
aero_cd = 0.3 |
|
||||||
force_peak = mass*3. |
|
||||||
force_brake_peak = -mass*10. # 1g |
|
||||||
power_peak = 100000 # 100kW |
|
||||||
speed_base = power_peak/force_peak |
|
||||||
rolling_res = 0.01 |
|
||||||
gravity = 9.81 |
|
||||||
frontal_area = 2.2 |
|
||||||
air_density = 1.225 |
|
||||||
gas_to_peak_linear_slope = 3.33 |
|
||||||
brake_to_peak_linear_slope = 0.3 |
|
||||||
creep_accel_v = [1., 0.] |
|
||||||
creep_accel_bp = [0., 1.5] |
|
||||||
|
|
||||||
#*** longitudinal model *** |
|
||||||
# find speed where peak torque meets peak power |
|
||||||
force_brake = brake * force_brake_peak * brake_to_peak_linear_slope |
|
||||||
if speed < speed_base: # torque control |
|
||||||
force_gas = gas * force_peak * gas_to_peak_linear_slope |
|
||||||
else: # power control |
|
||||||
force_gas = gas * power_peak / speed * gas_to_peak_linear_slope |
|
||||||
|
|
||||||
force_grade = - np.sin(np.arctan(grade)) * mass * gravity |
|
||||||
|
|
||||||
creep_accel = np.interp(speed, creep_accel_bp, creep_accel_v) |
|
||||||
force_creep = creep_accel * mass |
|
||||||
|
|
||||||
force_resistance = -(rolling_res * mass * gravity + 0.5 * speed**2 * aero_cd * air_density * frontal_area) |
|
||||||
force = force_gas + force_brake + force_resistance + force_grade + force_creep |
|
||||||
acceleration = force / mass |
|
||||||
|
|
||||||
# TODO: lateral model |
|
||||||
return speed, acceleration |
|
||||||
|
|
||||||
def get_car_can_parser(): |
|
||||||
dbc_f = 'honda_civic_touring_2016_can_generated' |
|
||||||
signals = [ |
|
||||||
("STEER_TORQUE", 0xe4, 0), |
|
||||||
("STEER_TORQUE_REQUEST", 0xe4, 0), |
|
||||||
("COMPUTER_BRAKE", 0x1fa, 0), |
|
||||||
("COMPUTER_BRAKE_REQUEST", 0x1fa, 0), |
|
||||||
("GAS_COMMAND", 0x200, 0), |
|
||||||
] |
|
||||||
checks = [ |
|
||||||
(0xe4, 100), |
|
||||||
(0x1fa, 50), |
|
||||||
(0x200, 50), |
|
||||||
] |
|
||||||
return CANParser(dbc_f, signals, checks, 0) |
|
||||||
|
|
||||||
def to_3_byte(x): |
|
||||||
# Convert into 12 bit value |
|
||||||
s = struct.pack("!H", int(x)) |
|
||||||
return binascii.hexlify(s)[1:] |
|
||||||
|
|
||||||
def to_3s_byte(x): |
|
||||||
s = struct.pack("!h", int(x)) |
|
||||||
return binascii.hexlify(s)[1:] |
|
||||||
|
|
||||||
class Plant(): |
class Plant(): |
||||||
messaging_initialized = False |
messaging_initialized = False |
||||||
|
|
||||||
def __init__(self, lead_relevancy=False, rate=100, speed=0.0, distance_lead=2.0): |
def __init__(self, lead_relevancy=False, speed=0.0, distance_lead=2.0): |
||||||
self.rate = rate |
self.rate = 1. / DT_MDL |
||||||
|
|
||||||
if not Plant.messaging_initialized: |
if not Plant.messaging_initialized: |
||||||
Plant.pm = messaging.PubMaster(['roadCameraState', 'driverCameraState', 'ubloxRaw']) |
Plant.radar = messaging.pub_sock('radarState') |
||||||
Plant.logcan = messaging.pub_sock('can') |
Plant.controls_state = messaging.pub_sock('controlsState') |
||||||
Plant.sendcan = messaging.sub_sock('sendcan') |
Plant.car_state = messaging.pub_sock('carState') |
||||||
Plant.model = messaging.pub_sock('modelV2') |
|
||||||
Plant.live_params = messaging.pub_sock('liveParameters') |
|
||||||
Plant.live_location_kalman = messaging.pub_sock('liveLocationKalman') |
|
||||||
Plant.pandaState = messaging.pub_sock('pandaState') |
|
||||||
Plant.deviceState = messaging.pub_sock('deviceState') |
|
||||||
Plant.driverMonitoringState = messaging.pub_sock('driverMonitoringState') |
|
||||||
Plant.cal = messaging.pub_sock('liveCalibration') |
|
||||||
Plant.controls_state = messaging.sub_sock('controlsState') |
|
||||||
Plant.plan = messaging.sub_sock('longitudinalPlan') |
Plant.plan = messaging.sub_sock('longitudinalPlan') |
||||||
Plant.messaging_initialized = True |
Plant.messaging_initialized = True |
||||||
|
|
||||||
self.frame = 0 |
self.v_lead_prev = 0.0 |
||||||
self.angle_steer = 0. |
|
||||||
self.gear_choice = 0 |
|
||||||
self.speed, self.speed_prev = 0., 0. |
|
||||||
|
|
||||||
self.esp_disabled = 0 |
self.distance = 0. |
||||||
self.main_on = 1 |
self.speed = speed |
||||||
self.user_gas = 0 |
self.acceleration = 0.0 |
||||||
self.computer_brake, self.user_brake = 0, 0 |
|
||||||
self.brake_pressed = 0 |
|
||||||
self.angle_steer_rate = 0 |
|
||||||
self.distance, self.distance_prev = 0., 0. |
|
||||||
self.speed, self.speed_prev = speed, speed |
|
||||||
self.steer_error, self.brake_error, self.steer_not_allowed = 0, 0, 0 |
|
||||||
self.gear_shifter = 8 # D gear |
|
||||||
self.pedal_gas = 0 |
|
||||||
self.cruise_setting = 0 |
|
||||||
|
|
||||||
self.seatbelt, self.door_all_closed = True, True |
|
||||||
self.steer_torque, self.v_cruise, self.acc_status = 0, 0, 0 # v_cruise is reported from can, not the one used for controls |
|
||||||
|
|
||||||
self.lead_relevancy = lead_relevancy |
|
||||||
|
|
||||||
# lead car |
# lead car |
||||||
self.distance_lead, self.distance_lead_prev = distance_lead , distance_lead |
self.distance_lead = distance_lead |
||||||
|
self.lead_relevancy = lead_relevancy |
||||||
self.rk = Ratekeeper(rate, print_delay_threshold=100.0) |
|
||||||
self.ts = 1./rate |
|
||||||
|
|
||||||
self.cp = get_car_can_parser() |
|
||||||
self.response_seen = False |
|
||||||
|
|
||||||
|
self.rk = Ratekeeper(self.rate, print_delay_threshold=100.0) |
||||||
|
self.ts = 1. / self.rate |
||||||
time.sleep(1) |
time.sleep(1) |
||||||
messaging.drain_sock(Plant.sendcan) |
self.sm = messaging.SubMaster(['longitudinalPlan']) |
||||||
messaging.drain_sock(Plant.controls_state) |
|
||||||
|
|
||||||
def close(self): |
|
||||||
Plant.logcan.close() |
|
||||||
Plant.model.close() |
|
||||||
Plant.live_params.close() |
|
||||||
Plant.live_location_kalman.close() |
|
||||||
|
|
||||||
def speed_sensor(self, speed): |
|
||||||
if speed < 0.3: |
|
||||||
return 0 |
|
||||||
else: |
|
||||||
return speed * CV.MS_TO_KPH |
|
||||||
|
|
||||||
def current_time(self): |
def current_time(self): |
||||||
return float(self.rk.frame) / self.rate |
return float(self.rk.frame) / self.rate |
||||||
|
|
||||||
def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model=True): |
def step(self, v_lead=0.0): |
||||||
gen_signals, _ = get_can_signals(CP) |
# ******** publish a fake model going straight and fake calibration ******** |
||||||
sgs = [s[0] for s in gen_signals] |
# note that this is worst case for MPC, since model will delay long mpc by one time step |
||||||
msgs = [s[1] for s in gen_signals] |
radar = messaging.new_message('radarState') |
||||||
|
control = messaging.new_message('controlsState') |
||||||
# ******** get messages sent to the car ******** |
car_state = messaging.new_message('carState') |
||||||
can_strings = messaging.drain_sock_raw(Plant.sendcan, wait_for_one=self.response_seen) |
a_lead = (v_lead - self.v_lead_prev)/self.ts |
||||||
|
self.v_lead_prev = v_lead |
||||||
|
|
||||||
# After the first response the car is done fingerprinting, so we can run in lockstep with controlsd |
if self.lead_relevancy: |
||||||
if can_strings: |
d_rel = np.maximum(0., self.distance_lead - self.distance) |
||||||
self.response_seen = True |
v_rel = v_lead - self.speed |
||||||
|
prob = 1.0 |
||||||
|
else: |
||||||
|
d_rel = 200. |
||||||
|
v_rel = 0. |
||||||
|
prob = 0.0 |
||||||
|
|
||||||
|
lead = log.RadarState.LeadData.new_message() |
||||||
|
lead.dRel = float(d_rel) |
||||||
|
lead.yRel = float(0.0) |
||||||
|
lead.vRel = float(v_rel) |
||||||
|
lead.aRel = float(a_lead - self.acceleration) |
||||||
|
lead.vLead = float(v_lead) |
||||||
|
lead.vLeadK = float(v_lead) |
||||||
|
lead.aLeadK = float(a_lead) |
||||||
|
lead.aLeadTau = float(1.5) |
||||||
|
lead.status = True |
||||||
|
lead.modelProb = prob |
||||||
|
radar.radarState.leadOne = lead |
||||||
|
radar.radarState.leadTwo = lead |
||||||
|
|
||||||
|
|
||||||
|
control.controlsState.longControlState = LongCtrlState.pid |
||||||
|
control.controlsState.vCruise = 130 |
||||||
|
car_state.carState.vEgo = self.speed |
||||||
|
Plant.radar.send(radar.to_bytes()) |
||||||
|
Plant.controls_state.send(control.to_bytes()) |
||||||
|
Plant.car_state.send(car_state.to_bytes()) |
||||||
|
|
||||||
self.cp.update_strings(can_strings, sendcan=True) |
|
||||||
|
|
||||||
# ******** get controlsState messages for plotting *** |
# ******** get controlsState messages for plotting *** |
||||||
controls_state_msgs = [] |
self.sm.update() |
||||||
for a in messaging.drain_sock(Plant.controls_state, wait_for_one=self.response_seen): |
while True: |
||||||
controls_state_msgs.append(a.controlsState) |
time.sleep(0.01) |
||||||
|
if self.sm.updated['longitudinalPlan']: |
||||||
|
plan = self.sm['longitudinalPlan'] |
||||||
|
self.acceleration = plan.aTarget |
||||||
|
fcw = plan.fcw |
||||||
|
break |
||||||
|
self.speed += self.ts*self.acceleration |
||||||
|
|
||||||
fcw = None |
|
||||||
for a in messaging.drain_sock(Plant.plan): |
|
||||||
if a.longitudinalPlan.fcw: |
|
||||||
fcw = True |
|
||||||
|
|
||||||
if self.cp.vl[0x1fa]['COMPUTER_BRAKE_REQUEST']: |
|
||||||
brake = self.cp.vl[0x1fa]['COMPUTER_BRAKE'] * 0.003906248 |
|
||||||
else: |
|
||||||
brake = 0.0 |
|
||||||
|
|
||||||
if self.cp.vl[0x200]['GAS_COMMAND'] > 0: |
|
||||||
gas = self.cp.vl[0x200]['GAS_COMMAND'] / 256.0 |
|
||||||
else: |
|
||||||
gas = 0.0 |
|
||||||
|
|
||||||
if self.cp.vl[0xe4]['STEER_TORQUE_REQUEST']: |
|
||||||
steer_torque = self.cp.vl[0xe4]['STEER_TORQUE']*1.0/0xf00 |
|
||||||
else: |
|
||||||
steer_torque = 0.0 |
|
||||||
|
|
||||||
distance_lead = self.distance_lead_prev + v_lead * self.ts |
self.distance_lead = self.distance_lead + v_lead * self.ts |
||||||
|
|
||||||
# ******** run the car ******** |
# ******** run the car ******** |
||||||
speed, acceleration = car_plant(self.distance_prev, self.speed_prev, grade, gas, brake) |
#print(self.distance, speed) |
||||||
distance = self.distance_prev + speed * self.ts |
if self.speed <= 0: |
||||||
speed = self.speed_prev + self.ts * acceleration |
self.speed = 0 |
||||||
if speed <= 0: |
self.acceleration = 0 |
||||||
speed = 0 |
self.distance = self.distance + self.speed * self.ts |
||||||
acceleration = 0 |
|
||||||
|
|
||||||
# ******** lateral ******** |
|
||||||
self.angle_steer -= (steer_torque/10.0) * self.ts |
|
||||||
|
|
||||||
# *** radar model *** |
# *** radar model *** |
||||||
if self.lead_relevancy: |
if self.lead_relevancy: |
||||||
d_rel = np.maximum(0., distance_lead - distance) |
d_rel = np.maximum(0., self.distance_lead - self.distance) |
||||||
v_rel = v_lead - speed |
v_rel = v_lead - self.speed |
||||||
else: |
else: |
||||||
d_rel = 200. |
d_rel = 200. |
||||||
v_rel = 0. |
v_rel = 0. |
||||||
lateral_pos_rel = 0. |
|
||||||
|
|
||||||
# print at 5hz |
# print at 5hz |
||||||
if (self.frame % (self.rate//5)) == 0: |
if (self.rk.frame % (self.rate // 5)) == 0: |
||||||
print("%6.2f m %6.2f m/s %6.2f m/s2 %.2f ang gas: %.2f brake: %.2f steer: %5.2f lead_rel: %6.2f m %6.2f m/s" |
print("%2.2f sec %6.2f m %6.2f m/s %6.2f m/s2 lead_rel: %6.2f m %6.2f m/s" |
||||||
% (distance, speed, acceleration, self.angle_steer, gas, brake, steer_torque, d_rel, v_rel)) |
% (self.current_time(), self.distance, self.speed, self.acceleration, d_rel, v_rel)) |
||||||
|
|
||||||
# ******** publish the car ******** |
|
||||||
vls_tuple = namedtuple('vls', [ |
|
||||||
'XMISSION_SPEED', |
|
||||||
'WHEEL_SPEED_FL', 'WHEEL_SPEED_FR', 'WHEEL_SPEED_RL', 'WHEEL_SPEED_RR', |
|
||||||
'STEER_ANGLE', 'STEER_ANGLE_RATE', 'STEER_TORQUE_SENSOR', 'STEER_TORQUE_MOTOR', |
|
||||||
'LEFT_BLINKER', 'RIGHT_BLINKER', |
|
||||||
'GEAR', |
|
||||||
'WHEELS_MOVING', |
|
||||||
'BRAKE_ERROR_1', 'BRAKE_ERROR_2', |
|
||||||
'SEATBELT_DRIVER_LAMP', 'SEATBELT_DRIVER_LATCHED', |
|
||||||
'BRAKE_PRESSED', 'BRAKE_SWITCH', |
|
||||||
'CRUISE_BUTTONS', |
|
||||||
'ESP_DISABLED', |
|
||||||
'HUD_LEAD', |
|
||||||
'USER_BRAKE', |
|
||||||
'STEER_STATUS', |
|
||||||
'GEAR_SHIFTER', |
|
||||||
'PEDAL_GAS', |
|
||||||
'CRUISE_SETTING', |
|
||||||
'ACC_STATUS', |
|
||||||
|
|
||||||
'CRUISE_SPEED_PCM', |
|
||||||
'CRUISE_SPEED_OFFSET', |
|
||||||
|
|
||||||
'DOOR_OPEN_FL', 'DOOR_OPEN_FR', 'DOOR_OPEN_RL', 'DOOR_OPEN_RR', |
|
||||||
|
|
||||||
'CAR_GAS', |
|
||||||
'MAIN_ON', |
|
||||||
'EPB_STATE', |
|
||||||
'BRAKE_HOLD_ACTIVE', |
|
||||||
'INTERCEPTOR_GAS', |
|
||||||
'INTERCEPTOR_GAS2', |
|
||||||
'IMPERIAL_UNIT', |
|
||||||
'MOTOR_TORQUE', |
|
||||||
]) |
|
||||||
vls = vls_tuple( |
|
||||||
self.speed_sensor(speed), |
|
||||||
self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), |
|
||||||
self.angle_steer, self.angle_steer_rate, 0, 0, # Steer torque sensor |
|
||||||
0, 0, # Blinkers |
|
||||||
self.gear_choice, |
|
||||||
speed != 0, |
|
||||||
self.brake_error, self.brake_error, |
|
||||||
not self.seatbelt, self.seatbelt, # Seatbelt |
|
||||||
self.brake_pressed, 0., # Brake pressed, Brake switch |
|
||||||
cruise_buttons, |
|
||||||
self.esp_disabled, |
|
||||||
0, # HUD lead |
|
||||||
self.user_brake, |
|
||||||
self.steer_error, |
|
||||||
self.gear_shifter, |
|
||||||
self.pedal_gas, |
|
||||||
self.cruise_setting, |
|
||||||
self.acc_status, |
|
||||||
|
|
||||||
self.v_cruise, |
|
||||||
0, # Cruise speed offset |
|
||||||
|
|
||||||
0, 0, 0, 0, # Doors |
|
||||||
|
|
||||||
self.user_gas, |
|
||||||
self.main_on, |
|
||||||
0, # EPB State |
|
||||||
0, # Brake hold |
|
||||||
0, # Interceptor feedback |
|
||||||
0, # Interceptor 2 feedback |
|
||||||
False, |
|
||||||
0, |
|
||||||
) |
|
||||||
|
|
||||||
# TODO: publish each message at proper frequency |
|
||||||
can_msgs = [] |
|
||||||
for msg in set(msgs): |
|
||||||
msg_struct = {} |
|
||||||
indxs = [i for i, x in enumerate(msgs) if msg == msgs[i]] |
|
||||||
for i in indxs: |
|
||||||
msg_struct[sgs[i]] = getattr(vls, sgs[i]) |
|
||||||
|
|
||||||
if "COUNTER" in honda.get_signals(msg): |
|
||||||
msg_struct["COUNTER"] = self.frame % 4 |
|
||||||
|
|
||||||
if "COUNTER_PEDAL" in honda.get_signals(msg): |
|
||||||
msg_struct["COUNTER_PEDAL"] = self.frame % 0xf |
|
||||||
|
|
||||||
msg = honda.lookup_msg_id(msg) |
|
||||||
msg_data = honda.encode(msg, msg_struct) |
|
||||||
|
|
||||||
if "CHECKSUM" in honda.get_signals(msg): |
|
||||||
msg_data = fix(msg_data, msg) |
|
||||||
|
|
||||||
if "CHECKSUM_PEDAL" in honda.get_signals(msg): |
|
||||||
msg_struct["CHECKSUM_PEDAL"] = crc8_pedal(msg_data[:-1]) |
|
||||||
msg_data = honda.encode(msg, msg_struct) |
|
||||||
|
|
||||||
can_msgs.append([msg, 0, msg_data, 0]) |
|
||||||
|
|
||||||
# add the radar message |
|
||||||
# TODO: use the DBC |
|
||||||
if self.frame % 5 == 0: |
|
||||||
radar_state_msg = b'\x79\x00\x00\x00\x00\x00\x00\x00' |
|
||||||
radar_msg = to_3_byte(d_rel * 16.0) + \ |
|
||||||
to_3_byte(int(lateral_pos_rel * 16.0) & 0x3ff) + \ |
|
||||||
to_3s_byte(int(v_rel * 32.0)) + \ |
|
||||||
b"0f00000" |
|
||||||
|
|
||||||
radar_msg = binascii.unhexlify(radar_msg) |
|
||||||
can_msgs.append([0x400, 0, radar_state_msg, 1]) |
|
||||||
can_msgs.append([0x445, 0, radar_msg, 1]) |
|
||||||
|
|
||||||
radar_messages = list(range(0x430, 0x43A)) + list(range(0x440, 0x445)) |
|
||||||
for m in radar_messages: |
|
||||||
can_msgs.append([m, 0, b'\x00'*8, 1]) |
|
||||||
|
|
||||||
msg_struct["COUNTER"] = self.frame % 4 |
|
||||||
camera_messages = [0x1FA, 0x30C, 0xE4] |
|
||||||
for m in camera_messages: |
|
||||||
msg = honda.lookup_msg_id(m) |
|
||||||
msg_data = honda.encode(msg, msg_struct) |
|
||||||
msg_data = fix(msg_data, m) |
|
||||||
can_msgs.append([m, 0, msg_data, 2]) |
|
||||||
|
|
||||||
# Fake sockets that controlsd subscribes to |
|
||||||
live_parameters = messaging.new_message('liveParameters') |
|
||||||
live_parameters.liveParameters.valid = True |
|
||||||
live_parameters.liveParameters.sensorValid = True |
|
||||||
live_parameters.liveParameters.posenetValid = True |
|
||||||
live_parameters.liveParameters.steerRatio = CP.steerRatio |
|
||||||
live_parameters.liveParameters.stiffnessFactor = 1.0 |
|
||||||
Plant.live_params.send(live_parameters.to_bytes()) |
|
||||||
|
|
||||||
dmon_state = messaging.new_message('driverMonitoringState') |
|
||||||
dmon_state.driverMonitoringState.isDistracted = False |
|
||||||
Plant.driverMonitoringState.send(dmon_state.to_bytes()) |
|
||||||
|
|
||||||
pandaState = messaging.new_message('pandaState') |
|
||||||
pandaState.pandaState.safetyModel = car.CarParams.SafetyModel.hondaNidec |
|
||||||
pandaState.pandaState.controlsAllowed = True |
|
||||||
Plant.pandaState.send(pandaState.to_bytes()) |
|
||||||
|
|
||||||
deviceState = messaging.new_message('deviceState') |
|
||||||
deviceState.deviceState.freeSpacePercent = 100 |
|
||||||
deviceState.deviceState.batteryPercent = 100 |
|
||||||
Plant.deviceState.send(deviceState.to_bytes()) |
|
||||||
|
|
||||||
live_location_kalman = messaging.new_message('liveLocationKalman') |
|
||||||
live_location_kalman.liveLocationKalman.inputsOK = True |
|
||||||
live_location_kalman.liveLocationKalman.gpsOK = True |
|
||||||
Plant.live_location_kalman.send(live_location_kalman.to_bytes()) |
|
||||||
|
|
||||||
# ******** publish a fake model going straight and fake calibration ******** |
|
||||||
# note that this is worst case for MPC, since model will delay long mpc by one time step |
|
||||||
if publish_model and self.frame % 5 == 0: |
|
||||||
md = messaging.new_message('modelV2') |
|
||||||
cal = messaging.new_message('liveCalibration') |
|
||||||
md.modelV2.frameId = 0 |
|
||||||
|
|
||||||
if self.lead_relevancy: |
|
||||||
d_rel = np.maximum(0., distance_lead - distance) |
|
||||||
v_rel = v_lead - speed |
|
||||||
prob = 1.0 |
|
||||||
else: |
|
||||||
d_rel = 200. |
|
||||||
v_rel = 0. |
|
||||||
prob = 0.0 |
|
||||||
|
|
||||||
lead = log.ModelDataV2.LeadDataV2.new_message() |
|
||||||
lead.xyva = [float(d_rel), 0.0, float(v_rel), 0.0] |
|
||||||
lead.xyvaStd = [1.0, 1.0, 1.0, 1.0] |
|
||||||
lead.prob = prob |
|
||||||
md.modelV2.leads = [lead, lead] |
|
||||||
|
|
||||||
cal.liveCalibration.calStatus = 1 |
|
||||||
cal.liveCalibration.calPerc = 100 |
|
||||||
cal.liveCalibration.rpyCalib = [0.] * 3 |
|
||||||
# fake values? |
|
||||||
Plant.model.send(md.to_bytes()) |
|
||||||
Plant.cal.send(cal.to_bytes()) |
|
||||||
for s in Plant.pm.sock.keys(): |
|
||||||
try: |
|
||||||
Plant.pm.send(s, messaging.new_message(s)) |
|
||||||
except Exception: |
|
||||||
Plant.pm.send(s, messaging.new_message(s, 1)) |
|
||||||
|
|
||||||
Plant.logcan.send(can_list_to_can_capnp(can_msgs)) |
|
||||||
|
|
||||||
# ******** update prevs ******** |
# ******** update prevs ******** |
||||||
self.frame += 1 |
self.rk.monitor_time() |
||||||
|
|
||||||
if self.response_seen: |
|
||||||
self.rk.monitor_time() |
|
||||||
|
|
||||||
self.speed = speed |
|
||||||
self.distance = distance |
|
||||||
self.distance_lead = distance_lead |
|
||||||
|
|
||||||
self.speed_prev = speed |
|
||||||
self.distance_prev = distance |
|
||||||
self.distance_lead_prev = distance_lead |
|
||||||
|
|
||||||
else: |
|
||||||
# Don't advance time when controlsd is not yet ready |
|
||||||
self.rk.keep_time() |
|
||||||
self.rk._frame = 0 |
|
||||||
|
|
||||||
return { |
return { |
||||||
"distance": distance, |
"distance": self.distance, |
||||||
"speed": speed, |
"speed": self.speed, |
||||||
"acceleration": acceleration, |
"acceleration": self.acceleration, |
||||||
"distance_lead": distance_lead, |
"distance_lead": self.distance_lead, |
||||||
"brake": brake, |
|
||||||
"gas": gas, |
|
||||||
"steer_torque": steer_torque, |
|
||||||
"fcw": fcw, |
"fcw": fcw, |
||||||
"controls_state_msgs": controls_state_msgs, |
|
||||||
} |
} |
||||||
|
|
||||||
# simple engage in standalone mode |
# simple engage in standalone mode |
||||||
def plant_thread(rate=100): |
def plant_thread(): |
||||||
plant = Plant(rate) |
plant = Plant() |
||||||
while 1: |
while 1: |
||||||
plant.step() |
plant.step() |
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": |
if __name__ == "__main__": |
||||||
plant_thread() |
plant_thread() |
||||||
|
Loading…
Reference in new issue