CommaCarSegments: public database of segments for each platform (#31114)
* comma car segments
* comma car segments for test_models
* oneliner
Co-authored-by: Shane Smiskol <shane@smiskol.com>
* better name
* not used here
* sort
* remove print
* better comment
---------
Co-authored-by: Shane Smiskol <shane@smiskol.com>
old-commit-hash: caa9153974
chrysler-long2
parent
dc6a23a1bc
commit
f447062b66
4 changed files with 128 additions and 3 deletions
@ -0,0 +1,82 @@ |
|||||||
|
import os |
||||||
|
import requests |
||||||
|
|
||||||
|
# Forks with additional car support can fork the commaCarSegments repo on huggingface or host the LFS files themselves |
||||||
|
COMMA_CAR_SEGMENTS_REPO = os.environ.get("COMMA_CAR_SEGMENTS_REPO", "https://huggingface.co/datasets/commaai/commaCarSegments") |
||||||
|
COMMA_CAR_SEGMENTS_BRANCH = os.environ.get("COMMA_CAR_SEGMENTS_BRANCH", "main") |
||||||
|
|
||||||
|
COMMA_CAR_SEGMENTS_LFS_INSTANCE = os.environ.get("COMMA_CAR_SEGMENTS_LFS_INSTANCE", "https://huggingface.co/datasets/commaai/commaCarSegments") |
||||||
|
|
||||||
|
def get_comma_car_segments_database(): |
||||||
|
return requests.get(get_repo_raw_url("database.json")).json() |
||||||
|
|
||||||
|
|
||||||
|
# Helpers related to interfacing with the openpilot-data repository, which contains a collection of public segments for users to perform validation on. |
||||||
|
|
||||||
|
def parse_lfs_pointer(text): |
||||||
|
header, lfs_version = text.splitlines()[0].split(" ") |
||||||
|
assert header == "version" |
||||||
|
assert lfs_version == "https://git-lfs.github.com/spec/v1" |
||||||
|
|
||||||
|
header, oid_raw = text.splitlines()[1].split(" ") |
||||||
|
assert header == "oid" |
||||||
|
header, oid = oid_raw.split(":") |
||||||
|
assert header == "sha256" |
||||||
|
|
||||||
|
header, size = text.splitlines()[2].split(" ") |
||||||
|
assert header == "size" |
||||||
|
|
||||||
|
return oid, size |
||||||
|
|
||||||
|
def get_lfs_file_url(oid, size): |
||||||
|
data = { |
||||||
|
"operation": "download", |
||||||
|
"transfers": [ "basic" ], |
||||||
|
"objects": [ |
||||||
|
{ |
||||||
|
"oid": oid, |
||||||
|
"size": int(size) |
||||||
|
} |
||||||
|
], |
||||||
|
"hash_algo": "sha256" |
||||||
|
} |
||||||
|
|
||||||
|
headers = { |
||||||
|
"Accept": "application/vnd.git-lfs+json", |
||||||
|
"Content-Type": "application/vnd.git-lfs+json" |
||||||
|
} |
||||||
|
|
||||||
|
response = requests.post(f"{COMMA_CAR_SEGMENTS_LFS_INSTANCE}.git/info/lfs/objects/batch", json=data, headers=headers) |
||||||
|
|
||||||
|
assert response.ok |
||||||
|
|
||||||
|
obj = response.json()["objects"][0] |
||||||
|
|
||||||
|
assert "error" not in obj, obj |
||||||
|
|
||||||
|
return obj["actions"]["download"]["href"] |
||||||
|
|
||||||
|
def get_repo_raw_url(path): |
||||||
|
if "huggingface" in COMMA_CAR_SEGMENTS_REPO: |
||||||
|
return f"{COMMA_CAR_SEGMENTS_REPO}/raw/{COMMA_CAR_SEGMENTS_BRANCH}/{path}" |
||||||
|
|
||||||
|
def get_repo_url(path): |
||||||
|
# Automatically switch to LFS if we are requesting a file that is stored in LFS |
||||||
|
|
||||||
|
response = requests.head(get_repo_raw_url(path)) |
||||||
|
|
||||||
|
if "text/plain" in response.headers.get("content-type"): |
||||||
|
# This is an LFS pointer, so download the raw data from lfs |
||||||
|
response = requests.get(get_repo_raw_url(path)) |
||||||
|
assert response.status_code == 200 |
||||||
|
oid, size = parse_lfs_pointer(response.text) |
||||||
|
|
||||||
|
return get_lfs_file_url(oid, size) |
||||||
|
else: |
||||||
|
# File has not been uploaded to LFS yet |
||||||
|
# (either we are on a fork where the data hasn't been pushed to LFS yet, or the CI job to push hasn't finished) |
||||||
|
return get_repo_raw_url(path) |
||||||
|
|
||||||
|
|
||||||
|
def get_url(route, segment, file="rlog.bz2"): |
||||||
|
return get_repo_url(f"segments/{route.replace('|', '/')}/{segment}/{file}") |
@ -0,0 +1,41 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import unittest |
||||||
|
|
||||||
|
import requests |
||||||
|
from openpilot.tools.lib.comma_car_segments import get_comma_car_segments_database, get_url |
||||||
|
from openpilot.tools.lib.logreader import LogReader, get_first_message |
||||||
|
from openpilot.tools.lib.route import SegmentRange |
||||||
|
|
||||||
|
|
||||||
|
class TestCommaCarSegments(unittest.TestCase): |
||||||
|
def test_database(self): |
||||||
|
database = get_comma_car_segments_database() |
||||||
|
|
||||||
|
platforms = database.keys() |
||||||
|
|
||||||
|
assert len(platforms) > 100 |
||||||
|
|
||||||
|
def test_download_segment(self): |
||||||
|
database = get_comma_car_segments_database() |
||||||
|
|
||||||
|
fp = "SUBARU FORESTER 2019" |
||||||
|
|
||||||
|
segment = database[fp][0] |
||||||
|
|
||||||
|
sr = SegmentRange(segment) |
||||||
|
|
||||||
|
url = get_url(sr.route_name, sr._slice) |
||||||
|
|
||||||
|
resp = requests.get(url) |
||||||
|
self.assertEqual(resp.status_code, 200) |
||||||
|
|
||||||
|
lr = LogReader(url) |
||||||
|
|
||||||
|
CP = get_first_message(lr, "carParams").carParams |
||||||
|
|
||||||
|
self.assertEqual(CP.carFingerprint, fp) |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
unittest.main() |
Loading…
Reference in new issue