diff --git a/selfdrive/car/README.MD b/selfdrive/car/README.md similarity index 79% rename from selfdrive/car/README.MD rename to selfdrive/car/README.md index 2dcbf56059..b64472b2bc 100644 --- a/selfdrive/car/README.MD +++ b/selfdrive/car/README.md @@ -1,11 +1,10 @@ # selfdrive/car -### Check out this blogpost for a high level overview of car ports -https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/ +Check out [this blog post](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/) for a high-level overview of porting a car. ## Useful car porting utilities -Testing car ports in your car is very time consuming! Checkout these utilities to do basic checks on your work before running it in your car. +Testing car ports in your car is very time-consuming. Check out these utilities to do basic checks on your work before running it in your car. ### [Cabana](/tools/cabana/README.md) @@ -28,12 +27,12 @@ Attempting to add fw version for: SUBARU OUTBACK 6TH GEN ### [selfdrive/car/tests/test_car_interfaces.py](/selfdrive/car/tests/test_car_interfaces.py) -Finds common bugs for car interfaces, without even requiring a route! +Finds common bugs for car interfaces, without even requiring a route. #### Example: Typo in signal name ```bash -> pytest selfdrive/car/tests/test_car_interfaces.py -k subaru # (replace with the brand you are working on!) +> pytest selfdrive/car/tests/test_car_interfaces.py -k subaru # replace with the brand you are working on ===================================================================== FAILED selfdrive/car/tests/test_car_interfaces.py::TestCarInterfaces::test_car_interfaces_165_SUBARU_LEGACY_7TH_GEN - KeyError: 'CruiseControlOOPS' @@ -42,9 +41,9 @@ FAILED selfdrive/car/tests/test_car_interfaces.py::TestCarInterfaces::test_car_i ### [selfdrive/debug/test_car_model.py](/selfdrive/debug/test_car_model.py) -Given a route, runs most of the car interface to check for common errors like missing signals, blocked panda messages, and mismatches. +Given a route, runs most of the car interface to check for common errors like missing signals, blocked panda messages, and safety mismatches. -#### Example: Panda safety mismatch for gasPressed +#### Example: panda safety mismatch for gasPressed ```bash > python selfdrive/debug/test_car_model.py '4822a427b188122a|2023-08-14--16-22-21' @@ -59,7 +58,7 @@ AssertionError: 1 is not false : panda safety doesn't agree with openpilot: {'ga ``` -## Car Port structure +## Car port structure ### interface.py Generic interface to send and receive messages from CAN (controlsd uses this to communicate with car) @@ -71,7 +70,7 @@ Builds CAN messages to send to car Reads CAN from car and builds openpilot CarState message ##### values.py -Fingerprints, limits for actuation, car doc information, etc +Fingerprints, limits for actuation, and supported car documentation ##### radar_interface.py Interface for parsing radar points from the car diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py index 5c787b787a..9230d16ef9 100644 --- a/selfdrive/car/ford/carstate.py +++ b/selfdrive/car/ford/carstate.py @@ -18,15 +18,16 @@ class CarState(CarStateBase): self.shifter_values = can_define.dv["Gear_Shift_by_Wire_FD1"]["TrnRng_D_RqGsm"] self.vehicle_sensors_valid = False - self.hybrid_platform = False + self.unsupported_platform = False def update(self, cp, cp_cam): ret = car.CarState.new_message() - # Hybrid variants experience a bug where a message from the PCM sends invalid checksums, - # we do not support these cars at this time. + # Ford Q3 hybrid variants experience a bug where a message from the PCM sends invalid checksums, + # this must be root-caused before enabling support. Ford Q4 hybrids do not have this problem. # TrnAin_Tq_Actl and its quality flag are only set on ICE platform variants - self.hybrid_platform = cp.vl["VehicleOperatingModes"]["TrnAinTq_D_Qf"] == 0 + self.unsupported_platform = (cp.vl["VehicleOperatingModes"]["TrnAinTq_D_Qf"] == 0 and + self.CP.carFingerprint not in CANFD_CAR) # Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement # The vehicle usually recovers out of this state within a minute of normal driving diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 3045c317ff..993b4a511c 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -14,7 +14,7 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs): ret.carName = "ford" - ret.dashcamOnly = candidate in {CAR.F_150_MK14} + ret.dashcamOnly = candidate in CANFD_CAR ret.radarUnavailable = True ret.steerControlType = car.CarParams.SteerControlType.angle @@ -56,6 +56,12 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 17.0 ret.mass = 2000 + elif candidate == CAR.F_150_LIGHTNING_MK1: + # required trim only on SuperCrew + ret.wheelbase = 3.70 + ret.steerRatio = 16.9 + ret.mass = 2948 + elif candidate == CAR.FOCUS_MK4: ret.wheelbase = 2.7 ret.steerRatio = 15.0 @@ -94,7 +100,7 @@ class CarInterface(CarInterfaceBase): events = self.create_common_events(ret, extra_gears=[GearShifter.manumatic]) if not self.CS.vehicle_sensors_valid: events.add(car.CarEvent.EventName.vehicleSensorsInvalid) - if self.CS.hybrid_platform: + if self.CS.unsupported_platform: events.add(car.CarEvent.EventName.startupNoControl) ret.events = events.to_msg() diff --git a/selfdrive/car/ford/values.py b/selfdrive/car/ford/values.py index 68f276d4b5..98f94f26f6 100644 --- a/selfdrive/car/ford/values.py +++ b/selfdrive/car/ford/values.py @@ -47,9 +47,10 @@ class CAR(StrEnum): F_150_MK14 = "FORD F-150 14TH GEN" FOCUS_MK4 = "FORD FOCUS 4TH GEN" MAVERICK_MK1 = "FORD MAVERICK 1ST GEN" + F_150_LIGHTNING_MK1 = "FORD F-150 LIGHTNING 1ST GEN" -CANFD_CAR = {CAR.F_150_MK14} +CANFD_CAR = {CAR.F_150_MK14, CAR.F_150_LIGHTNING_MK1} class RADAR: @@ -61,6 +62,7 @@ DBC: Dict[str, Dict[str, str]] = defaultdict(lambda: dbc_dict("ford_lincoln_base # F-150 radar is not yet supported DBC[CAR.F_150_MK14] = dbc_dict("ford_lincoln_base_pt", None) +DBC[CAR.F_150_LIGHTNING_MK1] = dbc_dict("ford_lincoln_base_pt", None) class Footnote(Enum): @@ -94,6 +96,7 @@ CAR_INFO: Dict[str, Union[CarInfo, List[CarInfo]]] = { FordCarInfo("Lincoln Aviator 2020-21", "Co-Pilot360 Plus"), ], CAR.F_150_MK14: FordCarInfo("Ford F-150 2023", "Co-Pilot360 Active 2.0"), + CAR.F_150_LIGHTNING_MK1: FordCarInfo("Ford F-150 Lightning 2021-23", "Co-Pilot360 Active 2.0"), CAR.FOCUS_MK4: FordCarInfo("Ford Focus 2018", "Adaptive Cruise Control with Lane Centering", footnotes=[Footnote.FOCUS]), CAR.MAVERICK_MK1: [ FordCarInfo("Ford Maverick 2022", "LARIAT Luxury"), @@ -236,6 +239,20 @@ FW_VERSIONS = { (Ecu.engine, 0x7E0, None): [ b'PL3A-14C204-BRB\x00\x00\x00\x00\x00\x00\x00\x00\x00', ], + }, + CAR.F_150_LIGHTNING_MK1: { + (Ecu.abs, 0x760, None): [ + b'PL38-2D053-AA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdCamera, 0x706, None): [ + b'ML3T-14H102-ABT\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.fwdRadar, 0x764, None): [ + b'ML3T-14D049-AL\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], + (Ecu.engine, 0x7E0, None): [ + b'NL3A-14C204-BAR\x00\x00\x00\x00\x00\x00\x00\x00\x00', + ], }, CAR.FOCUS_MK4: { (Ecu.eps, 0x730, None): [ diff --git a/selfdrive/car/tests/routes.py b/selfdrive/car/tests/routes.py index 66dafc1312..bf16693f3c 100755 --- a/selfdrive/car/tests/routes.py +++ b/selfdrive/car/tests/routes.py @@ -52,6 +52,7 @@ routes = [ CarTestRoute("62241b0c7fea4589|2022-09-01--15-32-49", FORD.EXPLORER_MK6), CarTestRoute("e886087f430e7fe7|2023-06-16--23-06-36", FORD.FOCUS_MK4), CarTestRoute("bd37e43731e5964b|2023-04-30--10-42-26", FORD.MAVERICK_MK1), + CarTestRoute("112e4d6e0cad05e1|2023-11-14--08-21-43", FORD.F_150_LIGHTNING_MK1), #TestRoute("f1b4c567731f4a1b|2018-04-30--10-15-35", FORD.FUSION), CarTestRoute("7cc2a8365b4dd8a9|2018-12-02--12-10-44", GM.ACADIA), diff --git a/selfdrive/car/torque_data/override.yaml b/selfdrive/car/torque_data/override.yaml index 12b483cfa7..09a3456629 100644 --- a/selfdrive/car/torque_data/override.yaml +++ b/selfdrive/car/torque_data/override.yaml @@ -26,6 +26,7 @@ FORD EXPLORER 6TH GEN: [.nan, 1.5, .nan] FORD F-150 14TH GEN: [.nan, 1.5, .nan] FORD FOCUS 4TH GEN: [.nan, 1.5, .nan] FORD MAVERICK 1ST GEN: [.nan, 1.5, .nan] +FORD F-150 LIGHTNING 1ST GEN: [.nan, 1.5, .nan] ### # No steering wheel