__init__.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. # functions common among cars
  2. import capnp
  3. from collections import namedtuple
  4. from cereal import car
  5. from common.numpy_fast import clip, interp
  6. from typing import Dict
  7. # kg of standard extra cargo to count for drive, gas, etc...
  8. STD_CARGO_KG = 136.
  9. ButtonType = car.CarState.ButtonEvent.Type
  10. EventName = car.CarEvent.EventName
  11. AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v'])
  12. def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float:
  13. if val > val_steady + hyst_gap:
  14. val_steady = val - hyst_gap
  15. elif val < val_steady - hyst_gap:
  16. val_steady = val + hyst_gap
  17. return val_steady
  18. def create_button_event(cur_but: int, prev_but: int, buttons_dict: Dict[int, capnp.lib.capnp._EnumModule],
  19. unpressed: int = 0) -> capnp.lib.capnp._DynamicStructBuilder:
  20. if cur_but != unpressed:
  21. be = car.CarState.ButtonEvent(pressed=True)
  22. but = cur_but
  23. else:
  24. be = car.CarState.ButtonEvent(pressed=False)
  25. but = prev_but
  26. be.type = buttons_dict.get(but, ButtonType.unknown)
  27. return be
  28. def gen_empty_fingerprint():
  29. return {i: {} for i in range(0, 8)}
  30. # FIXME: hardcoding honda civic 2016 touring params so they can be used to
  31. # scale unknown params for other cars
  32. class CivicParams:
  33. MASS = 1326. + STD_CARGO_KG
  34. WHEELBASE = 2.70
  35. CENTER_TO_FRONT = WHEELBASE * 0.4
  36. CENTER_TO_REAR = WHEELBASE - CENTER_TO_FRONT
  37. ROTATIONAL_INERTIA = 2500
  38. TIRE_STIFFNESS_FRONT = 192150
  39. TIRE_STIFFNESS_REAR = 202500
  40. # TODO: get actual value, for now starting with reasonable value for
  41. # civic and scaling by mass and wheelbase
  42. def scale_rot_inertia(mass, wheelbase):
  43. return CivicParams.ROTATIONAL_INERTIA * mass * wheelbase ** 2 / (CivicParams.MASS * CivicParams.WHEELBASE ** 2)
  44. # TODO: start from empirically derived lateral slip stiffness for the civic and scale by
  45. # mass and CG position, so all cars will have approximately similar dyn behaviors
  46. def scale_tire_stiffness(mass, wheelbase, center_to_front, tire_stiffness_factor=1.0):
  47. center_to_rear = wheelbase - center_to_front
  48. tire_stiffness_front = (CivicParams.TIRE_STIFFNESS_FRONT * tire_stiffness_factor) * mass / CivicParams.MASS * \
  49. (center_to_rear / wheelbase) / (CivicParams.CENTER_TO_REAR / CivicParams.WHEELBASE)
  50. tire_stiffness_rear = (CivicParams.TIRE_STIFFNESS_REAR * tire_stiffness_factor) * mass / CivicParams.MASS * \
  51. (center_to_front / wheelbase) / (CivicParams.CENTER_TO_FRONT / CivicParams.WHEELBASE)
  52. return tire_stiffness_front, tire_stiffness_rear
  53. def dbc_dict(pt_dbc, radar_dbc, chassis_dbc=None, body_dbc=None) -> Dict[str, str]:
  54. return {'pt': pt_dbc, 'radar': radar_dbc, 'chassis': chassis_dbc, 'body': body_dbc}
  55. def apply_std_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS):
  56. # limits due to driver torque
  57. driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
  58. driver_min_torque = -LIMITS.STEER_MAX + (-LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
  59. max_steer_allowed = max(min(LIMITS.STEER_MAX, driver_max_torque), 0)
  60. min_steer_allowed = min(max(-LIMITS.STEER_MAX, driver_min_torque), 0)
  61. apply_torque = clip(apply_torque, min_steer_allowed, max_steer_allowed)
  62. # slow rate if steer torque increases in magnitude
  63. if apply_torque_last > 0:
  64. apply_torque = clip(apply_torque, max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP),
  65. apply_torque_last + LIMITS.STEER_DELTA_UP)
  66. else:
  67. apply_torque = clip(apply_torque, apply_torque_last - LIMITS.STEER_DELTA_UP,
  68. min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP))
  69. return int(round(float(apply_torque)))
  70. def apply_toyota_steer_torque_limits(apply_torque, apply_torque_last, motor_torque, LIMITS):
  71. # limits due to comparison of commanded torque VS motor reported torque
  72. max_lim = min(max(motor_torque + LIMITS.STEER_ERROR_MAX, LIMITS.STEER_ERROR_MAX), LIMITS.STEER_MAX)
  73. min_lim = max(min(motor_torque - LIMITS.STEER_ERROR_MAX, -LIMITS.STEER_ERROR_MAX), -LIMITS.STEER_MAX)
  74. apply_torque = clip(apply_torque, min_lim, max_lim)
  75. # slow rate if steer torque increases in magnitude
  76. if apply_torque_last > 0:
  77. apply_torque = clip(apply_torque,
  78. max(apply_torque_last - LIMITS.STEER_DELTA_DOWN, -LIMITS.STEER_DELTA_UP),
  79. apply_torque_last + LIMITS.STEER_DELTA_UP)
  80. else:
  81. apply_torque = clip(apply_torque,
  82. apply_torque_last - LIMITS.STEER_DELTA_UP,
  83. min(apply_torque_last + LIMITS.STEER_DELTA_DOWN, LIMITS.STEER_DELTA_UP))
  84. return int(round(float(apply_torque)))
  85. def apply_std_steer_angle_limits(apply_angle, apply_angle_last, v_ego, LIMITS):
  86. # pick angle rate limits based on wind up/down
  87. steer_up = apply_angle_last * apply_angle > 0. and abs(apply_angle) > abs(apply_angle_last)
  88. rate_limits = LIMITS.ANGLE_RATE_LIMIT_UP if steer_up else LIMITS.ANGLE_RATE_LIMIT_DOWN
  89. angle_rate_lim = interp(v_ego, rate_limits.speed_bp, rate_limits.angle_v)
  90. return clip(apply_angle, apply_angle_last - angle_rate_lim, apply_angle_last + angle_rate_lim)
  91. def crc8_pedal(data):
  92. crc = 0xFF # standard init value
  93. poly = 0xD5 # standard crc8: x8+x7+x6+x4+x2+1
  94. size = len(data)
  95. for i in range(size - 1, -1, -1):
  96. crc ^= data[i]
  97. for _ in range(8):
  98. if ((crc & 0x80) != 0):
  99. crc = ((crc << 1) ^ poly) & 0xFF
  100. else:
  101. crc <<= 1
  102. return crc
  103. def create_gas_interceptor_command(packer, gas_amount, idx):
  104. # Common gas pedal msg generator
  105. enable = gas_amount > 0.001
  106. values = {
  107. "ENABLE": enable,
  108. "COUNTER_PEDAL": idx & 0xF,
  109. }
  110. if enable:
  111. values["GAS_COMMAND"] = gas_amount * 255.
  112. values["GAS_COMMAND2"] = gas_amount * 255.
  113. dat = packer.make_can_msg("GAS_COMMAND", 0, values)[2]
  114. checksum = crc8_pedal(dat[:-1])
  115. values["CHECKSUM_PEDAL"] = checksum
  116. return packer.make_can_msg("GAS_COMMAND", 0, values)
  117. def make_can_msg(addr, dat, bus):
  118. return [addr, 0, dat, bus]
  119. def get_safety_config(safety_model, safety_param = None):
  120. ret = car.CarParams.SafetyConfig.new_message()
  121. ret.safetyModel = safety_model
  122. if safety_param is not None:
  123. ret.safetyParam = safety_param
  124. return ret