feat(perception): map vegetation provider labels

This commit is contained in:
DCCONSTRUCTIONS
2026-08-27 21:53:25 +03:00
parent 92aa796c9d
commit 7594c71dd1
3 changed files with 218 additions and 0 deletions
@@ -0,0 +1,84 @@
{
"schema_version": "missioncore.vegetation-provider-label-map/v1",
"profile_id": "lab-v1-vegetation-provider-label-map/v1",
"policy_profile_id": "lab-v1-vegetation-mission-policy/v1",
"providers": {
"goose-fine-64": {
"unmapped_policy": "no-material-claim",
"class_granularity": "fine",
"can_distinguish_low_and_high_grass": true,
"can_distinguish_tree_trunk": true,
"labels": {
"asphalt": "hard_surface",
"bikeway": "hard_surface",
"cobble": "hard_surface",
"sidewalk": "hard_surface",
"gravel": "bare_soil",
"soil": "bare_soil",
"low_grass": "grass",
"high_grass": "herbaceous_vegetation",
"moss": "herbaceous_vegetation",
"crops": "cultivated_vegetation",
"bush": "woody_shrub",
"hedge": "woody_shrub",
"tree_trunk": "tree_or_trunk",
"tree_root": "tree_or_trunk",
"forest": "vegetation_unknown",
"leaves": "vegetation_unknown",
"scenery_vegetation": "vegetation_unknown",
"tree_crown": "vegetation_unknown"
}
},
"goose-category-12": {
"unmapped_policy": "no-material-claim",
"class_granularity": "coarse",
"can_distinguish_low_and_high_grass": false,
"can_distinguish_tree_trunk": false,
"labels": {
"artificial_ground": "hard_surface",
"vegetation": "vegetation_unknown"
}
},
"wildscenes-19": {
"unmapped_policy": "no-material-claim",
"class_granularity": "medium",
"can_distinguish_low_and_high_grass": false,
"can_distinguish_tree_trunk": true,
"labels": {
"asphalt/concrete": "hard_surface",
"dirt": "bare_soil",
"gravel": "bare_soil",
"grass": "grass",
"bush": "woody_shrub",
"tree-trunk": "tree_or_trunk",
"tree-foliage": "vegetation_unknown"
}
},
"rellis-20": {
"unmapped_policy": "no-material-claim",
"class_granularity": "medium",
"can_distinguish_low_and_high_grass": false,
"can_distinguish_tree_trunk": false,
"labels": {
"asphalt": "hard_surface",
"concrete": "hard_surface",
"grass": "grass",
"bush": "woody_shrub",
"tree": "tree_or_trunk"
}
},
"orfd-binary-freespace": {
"unmapped_policy": "no-material-claim",
"class_granularity": "binary-geometry-only",
"can_distinguish_low_and_high_grass": false,
"can_distinguish_tree_trunk": false,
"labels": {}
}
},
"invariants": {
"unmapped_label_means_free": false,
"coarse_vegetation_means_grass": false,
"binary_freespace_selects_material": false,
"provider_label_grants_actuation": false
}
}
@@ -9,6 +9,7 @@ from pathlib import Path
from typing import Any, Final
SCHEMA: Final = "missioncore.vegetation-mission-policy/v1"
PROVIDER_MAP_SCHEMA: Final = "missioncore.vegetation-provider-label-map/v1"
VEHICLE_SCHEMA: Final = "missioncore.m49-physical-safety-shadow-profile/v1"
_MAX_JSON_BYTES: Final = 1024 * 1024
@@ -163,6 +164,64 @@ def load_vegetation_mission_policy(
return policy
def load_vegetation_provider_label_map(
path: Path,
*,
policy: dict[str, Any],
) -> dict[str, Any]:
"""Load the provider-label adapter without inventing material claims."""
label_map = _json(path, "vegetation provider label map")
providers = label_map.get("providers")
invariants = label_map.get("invariants")
if (
label_map.get("schema_version") != PROVIDER_MAP_SCHEMA
or label_map.get("policy_profile_id") != policy.get("profile_id")
or not isinstance(providers, dict)
or not providers
or not isinstance(invariants, dict)
or any(value is not False for value in invariants.values())
):
raise VegetationMissionPolicyError("provider label map identity changed")
materials = set(policy["material_classes"])
for provider_id, provider in providers.items():
if not isinstance(provider_id, str) or not isinstance(provider, dict):
raise VegetationMissionPolicyError("provider label map is invalid")
labels = provider.get("labels")
if (
provider.get("unmapped_policy") != "no-material-claim"
or not isinstance(provider.get("class_granularity"), str)
or not isinstance(provider.get("can_distinguish_low_and_high_grass"), bool)
or not isinstance(provider.get("can_distinguish_tree_trunk"), bool)
or not isinstance(labels, dict)
or any(
not isinstance(label, str)
or not label
or not isinstance(material, str)
or material not in materials
for label, material in labels.items()
)
):
raise VegetationMissionPolicyError(f"provider label map is invalid: {provider_id}")
return label_map
def map_provider_material(
label_map: dict[str, Any],
*,
provider_id: str,
provider_label: str,
) -> str | None:
"""Return an exact material claim, or none when the provider did not make one."""
provider = label_map["providers"].get(provider_id)
if not isinstance(provider, dict):
raise VegetationMissionPolicyError(f"unknown vegetation provider: {provider_id}")
material = provider["labels"].get(provider_label)
return material if isinstance(material, str) else None
def resolve_terrain_policy(
policy: dict[str, Any],
*,
+75
View File
@@ -8,6 +8,8 @@ import pytest
from k1link.laboratory.vegetation_mission_policy import (
VegetationMissionPolicyError,
load_vegetation_mission_policy,
load_vegetation_provider_label_map,
map_provider_material,
resolve_terrain_policy,
)
@@ -21,12 +23,23 @@ CANDIDATE_MANIFEST_PATH = (
/ "perception"
/ "lab-v1-vegetation-candidate-manifest-v1.json"
)
PROVIDER_LABEL_MAP_PATH = (
REPOSITORY_ROOT
/ "config"
/ "perception"
/ "lab-v1-vegetation-provider-label-map-v1.json"
)
def _policy() -> dict[str, object]:
return load_vegetation_mission_policy(POLICY_PATH, repository_root=REPOSITORY_ROOT)
def _provider_label_map() -> dict[str, object]:
policy = _policy()
return load_vegetation_provider_label_map(PROVIDER_LABEL_MAP_PATH, policy=policy)
def test_presets_are_defaults_and_explicit_mission_rule_wins() -> None:
policy = _policy()
@@ -147,3 +160,65 @@ def test_candidate_manifest_freezes_unique_assets_sources_and_no_authority() ->
assert manifest["invariants"]["missing_or_unknown_is_free"] is False
assert manifest["invariants"]["navigation_authority"] is False
assert manifest["invariants"]["actuation_authority"] is False
@pytest.mark.parametrize(
("provider_id", "provider_label", "material"),
[
("goose-fine-64", "low_grass", "grass"),
("goose-fine-64", "high_grass", "herbaceous_vegetation"),
("goose-fine-64", "bush", "woody_shrub"),
("goose-fine-64", "tree_trunk", "tree_or_trunk"),
("wildscenes-19", "tree-trunk", "tree_or_trunk"),
("rellis-20", "tree", "tree_or_trunk"),
],
)
def test_fine_provider_labels_map_to_separate_material_claims(
provider_id: str,
provider_label: str,
material: str,
) -> None:
assert (
map_provider_material(
_provider_label_map(),
provider_id=provider_id,
provider_label=provider_label,
)
== material
)
def test_coarse_vegetation_never_becomes_grass_permission() -> None:
material = map_provider_material(
_provider_label_map(),
provider_id="goose-category-12",
provider_label="vegetation",
)
assert material == "vegetation_unknown"
decision = resolve_terrain_policy(
_policy(),
preset_id="offroad",
material_class=material,
evidence_state="SUPPORTED_GROUND",
)
assert decision.effective_action == "NO_GO"
def test_binary_freespace_and_unmapped_labels_make_no_material_claim() -> None:
label_map = _provider_label_map()
assert (
map_provider_material(
label_map,
provider_id="orfd-binary-freespace",
provider_label="freespace",
)
is None
)
assert (
map_provider_material(
label_map,
provider_id="goose-fine-64",
provider_label="person",
)
is None
)