An open-source ROS 2 implementation of the ASAM OpenODD® v1.0.0 standard.
This monorepo brings the Operational Design Domain (ODD) specification to life in autonomous/robotic systems:
asam_open_odd_core— pure Python core (types, YAML parsers, evaluator).asam_open_odd_msgs— ROS 2 message definitions (COD, ODDReport, etc.).asam_open_odd_ros— ROS runtime node that builds a Current Operational Domain (COD) from topics, evaluates it against an ODD, and publishes results.
OpenODD provides a standard way to describe where and under what conditions an automated system may operate. This repo helps you:
- Parse standard-compliant taxonomies & ODDs from YAML.
- Construct a COD from live ROS topics (config-driven).
- Evaluate compliance with explainable reports (per-module reasons).
- Integrate cleanly via ROS 2 messages.
asam_open_odd_core/ # Core types, YAML parser, evaluator (pure Python)
asam_open_odd_msgs/ # ROS 2 messages (COD, ODDReport, etc.)
asam_open_odd_ros/ # ROS 2 node: odd_monitor + config/launch
- ROS 2 Humble or newer (tested on Jazzy)
- Python ≥ 3.10
- PyYAML
Build and source your workspace, then use the helper script:
colcon build --symlink-install
source install/setup.bash
chmod +x ./run_example.sh
./run_example.shThis launches odd_monitor with the bundled taxonomy, ODD, and mappings:
-
Taxonomy: asam_open_odd_core/examples/taxonomy_full.yaml
-
ODD: asam_open_odd_core/examples/odd_full.yaml
-
Mappings: asam_open_odd_ros/launch/mappings.yaml
You should see:
-
COD on /odd_monitor/cod
-
ODD report on /odd_monitor/report
- Typed dataclasses representing Taxonomy, Units, Modules, Conditions, etc.
- YAML → objects (taxonomies & ODDs).
- Evaluator with clear, human-readable explanations for why modules are enabled/disabled.
Minimal usage:
from asam_open_odd_core.openodd_yaml_parser import load_openodd_yaml
from asam_open_odd_core.openodd_evaluator import DictValueResolver, evaluate_odd, report_string
tax, odd = load_openodd_yaml(open("taxonomy.yaml").read())
_, odd = load_openodd_yaml(open("odd.yaml").read())
resolver = DictValueResolver({
"road.type": "motorway",
"env.visibility": 250.0,
})
report = evaluate_odd(odd, resolver)
print(report_string(report))ROS 2 interfaces that decouple the runtime from the rest of your graph:
Cod.msg— snapshot of the COD (list of taxonomy values, optional spatial extent).OddReport.msg— full evaluation report with per-module results and label truths.ModuleReport.msg,CheckNode.msg,TaxonomyValue.msg,LabelTruth.msg,SpatialExtent.msg.
Flattened CheckNode trees avoid recursive message types and are easy to render in tools/UI.
-
Loads three YAMLs (via parameters):
taxonomy_yaml— the taxonomy of concepts/units.odd_yaml— the ODD modules/conditions to enforce.mappings_yaml— how ROS topics map to taxonomy paths.
-
Subscribes to configured topics and maintains an in-memory COD.
-
Evaluates COD vs ODD periodically.
-
Publishes:
~/cod(asam_open_odd_msgs/Cod)~/report(asam_open_odd_msgs/OddReport)
ros2 run asam_open_odd_ros odd_monitor \
--ros-args \
-p taxonomy_yaml:=/path/to/taxonomy.yaml \
-p odd_yaml:=/path/to/odd.yaml \
-p mappings_yaml:=/path/to/mappings.yaml \
-p publish_hz:=5.0| Param | Type | Default | Description |
|---|---|---|---|
taxonomy_yaml |
string | (none) | Path to taxonomy YAML |
odd_yaml |
string | (none) | Path to ODD YAML |
mappings_yaml |
string | (none) | Path to mappings YAML |
publish_hz |
float | 5.0 |
Publish/evaluate frequency (Hz) |
-
Publishes
~/cod(asam_open_odd_msgs/Cod)~/report(asam_open_odd_msgs/OddReport)
-
Subscribes (configured via mappings YAML)
Each mapping links a ROS topic+field to a taxonomy path and optional transforms:
mappings:
- topic: /road/type
type: std_msgs/msg/String # ROS 2 interface type
field: data # dot path inside the message
taxonomy: road.type # taxonomy path (dot or slash)
enum_map: # optional category normalization
motorway: motorway
trunk: trunk
- topic: /env/wind_speed_kmh
type: std_msgs/msg/Float32
field: data
taxonomy: env.weather.wind.speed
unit_id: "m/s" # advisory; forwarded into COD
scale: 0.2777777778 # optional: value*scale + offset
offset: 0.0-
Prepare your three YAMLs (
taxonomy.yaml,odd.yaml,mappings.yaml). -
Launch the node and start publishing to the topics used in
mappings.yaml. -
Inspect outputs:
ros2 topic echo /odd_monitor/codros2 topic echo /odd_monitor/report
If a condition references a value that hasn’t arrived yet, the evaluator marks it as <missing> and the leaf fails (clean warm‑up behavior).
- Core tests (
asam_open_odd_core/test) cover parsing and evaluator behavior. - Add ROS integration tests to spin up fake publishers and assert on
OddReporttopics.
colcon test --packages-select asam_open_odd_core asam_open_odd_ros
colcon test-result --verbose-
The evaluator follows OpenODD semantics:
- Module truth =
(include_pass or include_absent) AND NOT(exclude_pass) - Missing inputs don’t crash; they render as
<missing>and the leaf fails.
- Module truth =
-
Units are currently advisory; add a converter hook to normalize numeric values as a future extension.
- Spatial extent checks (geofences, map feature IDs).
- Service interface:
EvaluateCOD(request:Cod, response:OddReport). - Import/export helpers (CSV/XML/DSL).
- Community examples (automotive, AMR, UAV).
- Add a converter hook to normalize numeric values as a future extension.
- More tests.
We welcome issues and PRs! Ideas:
- New parsers (CSV/XML), converters, or unit conversion hooks.
- Example taxonomies/ODDs and real-world mappings.
- ROS launch/test improvements and visualizations of
OddReporttrees.
See CONTRIBUTING.md for guidelines.
Apache-2.0 (see LICENSE).