diff --git a/tools/car_porting/README.md b/tools/car_porting/README.md index 4197e3ab76..8db17b0976 100644 --- a/tools/car_porting/README.md +++ b/tools/car_porting/README.md @@ -71,4 +71,26 @@ An example of plotting the response of an actuator when it is active. ![brake pressure example](https://github.com/commaai/openpilot/assets/9648890/8f32cf1d-8fc0-4407-b540-70625ebbf082) -*a plot of the brake_pressure vs acceleration, where we can see it is a fairly linear response.* \ No newline at end of file +*a plot of the brake_pressure vs acceleration, where we can see it is a fairly linear response.* + +### [tools/car_porting/examples/ford_vin_fingerprint.ipynb](/tools/car_porting/examples/ford_vin_fingerprint.ipynb) + +In this example, we use the public comma car segments database to check if vin fingerprinting is feasible for ford. + +``` +vin: 1FM5K8GC7LGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: 00000000000XXXXXX real platform: FORD ESCAPE 4TH GEN determined platform: mock correct: False +vin: 3FTTW8F98NRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False +vin: 1FTVW1EL4NWXXXXXX real platform: FORD F-150 LIGHTNING 1ST GEN determined platform: FORD F-150 LIGHTNING 1ST GEN correct: True +vin: 1FM5K7LC0MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: WF0NXXGCHNJXXXXXX real platform: FORD FOCUS 4TH GEN determined platform: mock correct: False +vin: 1FMCU9J94MUXXXXXX real platform: FORD ESCAPE 4TH GEN determined platform: mock correct: False +vin: 5LM5J7XC9LGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: 3FMCR9B69NRXXXXXX real platform: FORD BRONCO SPORT 1ST GEN determined platform: mock correct: False +vin: 3FMTK3SU0MMXXXXXX real platform: FORD MUSTANG MACH-E 1ST GEN determined platform: FORD MUSTANG MACH-E 1ST GEN correct: True +vin: 1FM5K8HC7MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: 1FM5K8GC7NGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: 5LM5J7XC8MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False +vin: 3FTTW8E31PRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False +vin: 3FTTW8E99NRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False +``` \ No newline at end of file diff --git a/tools/car_porting/examples/ford_vin_fingerprint.ipynb b/tools/car_porting/examples/ford_vin_fingerprint.ipynb new file mode 100644 index 0000000000..bc689a5aad --- /dev/null +++ b/tools/car_porting/examples/ford_vin_fingerprint.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"In this example, we use the public comma car segments database to check if vin fingerprinting is feasible for ford.\"\"\"\n", + "\n", + "from openpilot.tools.lib.logreader import LogReader\n", + "from openpilot.tools.lib.comma_car_segments import get_comma_car_segments_database\n", + "from openpilot.selfdrive.car.ford.values import CAR\n", + "\n", + "database = get_comma_car_segments_database()\n", + "\n", + "platforms = [c.value for c in CAR]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Adapted from https://github.com/commaai/openpilot/issues/31052#issuecomment-1902690083\n", + "\n", + "MODEL_YEAR_CODES = {'M': 2021, 'N': 2022, 'P': 2023, 'R': 2024, 'S': 2025}\n", + "\n", + "\n", + "F150_CODES = ['F1C', 'F1E', 'W1C', 'W1E', 'X1C', 'X1E', 'W1R', 'W1P', 'W1S', 'W1T']\n", + "LIGHTNING_CODES = ['L', 'V']\n", + "MACHE_CODES = ['K1R', 'K1S', 'K2S', 'K3R', 'K3S', 'K4S']\n", + "\n", + "FORD_VIN_START = ['1FT', '3FM', '5LM']\n", + "\n", + "def ford_vin_fingerprint(vin): # Check if it's a Ford vehicle and determine the model\n", + " vin_positions_567 = vin[4:7]\n", + "\n", + " if vin.startswith('1FT'):\n", + " if vin_positions_567 in F150_CODES:\n", + " if vin[7] in LIGHTNING_CODES:\n", + " return f\"FORD F-150 LIGHTNING 1ST GEN\"\n", + " else:\n", + " return f\"FORD F-150 14TH GEN\"\n", + " elif vin.startswith('3FM'):\n", + " if vin_positions_567 in MACHE_CODES:\n", + " return f\"FORD MUSTANG MACH-E 1ST GEN\"\n", + " elif vin.startswith('5LM'):\n", + " pass\n", + "\n", + " return \"mock\"" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Skipping platform: FORD F-150 14TH GEN, no data available\n" + ] + } + ], + "source": [ + "from openpilot.tools.lib.logreader import comma_car_segments_source, get_first_message\n", + "\n", + "\n", + "VINS_TO_CHECK = set()\n", + "\n", + "for platform in platforms:\n", + " if platform not in database:\n", + " print(f\"Skipping platform: {platform}, no data available\")\n", + " continue\n", + "\n", + " for segment in database[platform]:\n", + " lr = LogReader(segment, default_source=comma_car_segments_source)\n", + " CP = get_first_message(lr, \"carParams\").carParams\n", + " VINS_TO_CHECK.add((CP.carVin, CP.carFingerprint))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "vin: 1FM5K8GC7LGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: 00000000000XXXXXX real platform: FORD ESCAPE 4TH GEN determined platform: mock correct: False\n", + "vin: 3FTTW8F98NRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False\n", + "vin: 1FTVW1EL4NWXXXXXX real platform: FORD F-150 LIGHTNING 1ST GEN determined platform: FORD F-150 LIGHTNING 1ST GEN correct: True\n", + "vin: 1FM5K7LC0MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: WF0NXXGCHNJXXXXXX real platform: FORD FOCUS 4TH GEN determined platform: mock correct: False\n", + "vin: 1FMCU9J94MUXXXXXX real platform: FORD ESCAPE 4TH GEN determined platform: mock correct: False\n", + "vin: 5LM5J7XC9LGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: 3FMCR9B69NRXXXXXX real platform: FORD BRONCO SPORT 1ST GEN determined platform: mock correct: False\n", + "vin: 3FMTK3SU0MMXXXXXX real platform: FORD MUSTANG MACH-E 1ST GEN determined platform: FORD MUSTANG MACH-E 1ST GEN correct: True\n", + "vin: 1FM5K8HC7MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: 1FM5K8GC7NGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: 5LM5J7XC8MGXXXXXX real platform: FORD EXPLORER 6TH GEN determined platform: mock correct: False\n", + "vin: 3FTTW8E31PRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False\n", + "vin: 3FTTW8E99NRXXXXXX real platform: FORD MAVERICK 1ST GEN determined platform: mock correct: False\n" + ] + } + ], + "source": [ + "for vin, real_fingerprint in VINS_TO_CHECK:\n", + " determined_fingerprint = ford_vin_fingerprint(vin)\n", + " print(f\"vin: {vin} real platform: {real_fingerprint: <30} determined platform: {determined_fingerprint: <30} correct: {real_fingerprint == determined_fingerprint}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 9334f542f6..c1f4f0f4a9 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -16,6 +16,7 @@ from typing import Iterable, Iterator, List, Type from urllib.parse import parse_qs, urlparse from cereal import log as capnp_log +from openpilot.tools.lib.comma_car_segments import get_url as get_comma_segments_url from openpilot.tools.lib.openpilotci import get_url from openpilot.tools.lib.filereader import FileReader, file_exists from openpilot.tools.lib.helpers import RE @@ -111,6 +112,11 @@ def openpilotci_source(sr: SegmentRange, route: Route, mode=ReadMode.RLOG): return [get_url(sr.route_name, seg, 'rlog' if mode == ReadMode.RLOG else 'qlog') for seg in segs] +def comma_car_segments_source(sr: SegmentRange, route: Route, mode=ReadMode.RLOG): + segs = parse_slice(sr, route) + + return [get_comma_segments_url(sr.route_name, seg) for seg in segs] + def direct_source(file_or_url): return [file_or_url]