// SPDX-License-Identifier: MIT // SpatialDDS Specification 1.4 (© Open AR Cloud Initiative)
2. IDL Profiles
The SpatialDDS IDL bundle defines the schemas used to exchange real-world spatial data over DDS. It is organized into complementary profiles: Core, which provides the backbone for pose graphs, geometry, and geo-anchoring; Discovery, which enables lightweight announcements of services, coverage, anchors, and content; and Anchors, which adds support for publishing and updating sets of durable world-locked anchors. Together, these profiles give devices, services, and applications a common language for building, sharing, and aligning live world models—while staying codec-agnostic, forward-compatible, and simple enough to extend for domains such as robotics, AR/XR, IoT, and smart cities.
2.1 IDL Profile Versioning & Negotiation (Normative)
SpatialDDS uses semantic versioning tokens of the form name@MAJOR.MINOR.
- MAJOR increments for breaking schema or wire changes.
- MINOR increments for additive, compatible changes.
Participants advertise supported ranges via caps.supported_profiles (discovery) and manifest capabilities blocks. Consumers select the highest compatible minor within any shared major. Backward-compatibility clauses from 1.3 are retired; implementations only negotiate within their common majors. All legacy quaternion and field-compatibility shims are removed—SpatialDDS 1.4 uses a single canonical quaternion order (x, y, z, w) across manifests, discovery payloads, and IDL messages.
2.2 Optional Fields (Normative)
SpatialDDS encodes optionality explicitly. To avoid ambiguous parsing and sentinel misuse, producers and consumers SHALL follow these rules across every profile:
- Presence flags — For any scalar, struct, or array field that may be absent at runtime, producers SHALL introduce a boolean presence flag immediately before the field (
boolean has_field; Type field;). Consumers MUST ignore the field when the flag isfalse. - Discriminated unions — When exactly one of multiple alternatives may appear on the wire, model the choice as a discriminated union (e.g.,
CovMatrix). Do not overload presence flags for mutual exclusivity. - @extensibility(APPENDABLE) omission is only for evolution — Schema omission via
@extensibility(APPENDABLE)remains reserved for forward/backward compatibility. Producers SHALL NOT omit fields at runtime to signal “missing data.” - No NaN sentinels — Floating-point NaN (or other sentinel values) MUST NOT be used to indicate absence. Presence flags govern field validity.
These conventions apply globally (Core, Discovery, Anchors, and all Sensing extensions) and supersede earlier guidance that relied on NaN or implicit omission semantics.
Clarification:
@extensibility(APPENDABLE)omission remains reserved for schema evolution across versions. Runtime optionality SHALL be expressed with presence flags or discriminated unions. NaN sentinels and implicit omissions are deprecated as of SpatialDDS 1.5.
2.3 Core SpatialDDS
The Core profile defines the essential building blocks for representing and sharing a live world model over DDS. It focuses on a small, stable set of concepts: pose graphs, 3D geometry tiles, blob transport for large payloads, and geo-anchoring primitives such as anchors, transforms, and simple GeoPoses. The design is deliberately lightweight and codec-agnostic: tiles reference payloads but do not dictate mesh formats, and anchors define stable points without tying clients to a specific localization method. All quaternion fields follow the OGC GeoPose component order (x, y, z, w) so orientation data can flow between GeoPose-aware systems without reordering. By centering on graph + geometry + anchoring, the Core profile provides a neutral foundation that can support diverse pipelines across robotics, AR, IoT, and smart city contexts.
Frame Identifiers (Reference)
SpatialDDS uses structured frame references via the FrameRef { uuid, fqn } type.
See Appendix G Frame Identifiers (Normative) for the complete definition and naming rules.
2.4 Discovery
Discovery is how SpatialDDS peers find each other, advertise what they publish, and select compatible streams. Think of it as a built-in directory that rides the same bus: nodes announce, others filter and subscribe.
How it works (at a glance)
- Announce — each node periodically publishes an announcement with capabilities and topics.
- Query — clients publish simple filters (by profile version, type, QoS) to narrow results.
- Select — clients subscribe to chosen topics; negotiation picks the highest compatible minor per profile.
Key messages (abridged IDL)
// Message shapes shown for orientation only
@extensibility(APPENDABLE) struct ProfileSupport { string name; uint32 major; uint32 min_minor; uint32 max_minor; boolean preferred; }
@extensibility(APPENDABLE) struct Capabilities { sequence<ProfileSupport,64> supported_profiles; sequence<string,32> preferred_profiles; sequence<string,64> features; }
@extensibility(APPENDABLE) struct TopicMeta { string name; string type; string version; string qos_profile; float32 target_rate_hz; uint32 max_chunk_bytes; }
@extensibility(APPENDABLE) struct Announce {
// ... node identity, endpoints ...
Capabilities caps; // profiles, preferences, features
sequence<TopicMeta,128> topics; // typed topics offered by this node
}
@extensibility(APPENDABLE) struct CoverageQuery {
// minimal illustrative fields
string expr; // Appendix F.X grammar; e.g., "type==\"radar_tensor\" && profile==\"discovery@1.*\""
string reply_topic; // topic to receive results
string query_id; // correlate request/response
}
@extensibility(APPENDABLE) struct CoverageResponse {
string query_id;
sequence<Announce,256> results;
string next_page_token;
}
Minimal examples (JSON)
Announce (capabilities + topics)
{
"caps": {
"supported_profiles": [
{ "name": "core", "major": 1, "min_minor": 0, "max_minor": 3 },
{ "name": "discovery", "major": 1, "min_minor": 1, "max_minor": 2 }
],
"preferred_profiles": ["discovery@1.2"],
"features": ["blob.crc32"]
},
"topics": [
{ "name": "spatialdds/perception/cam_front/video_frame/v1", "type": "video_frame", "version": "v1", "qos_profile": "VIDEO_LIVE" },
{ "name": "spatialdds/perception/radar_1/radar_tensor/v1", "type": "radar_tensor", "version": "v1", "qos_profile": "RADAR_RT" }
]
}
Query + Response
{ "query_id": "q1", "expr": "type==\"radar_tensor\" && profile==\"discovery@1.*\"", "reply_topic": "spatialdds/sys/queries/q1" }
{ "query_id": "q1", "results": [ { "caps": { "supported_profiles": [ { "name": "discovery", "major": 1, "min_minor": 1, "max_minor": 2 } ] }, "topics": [ { "name": "spatialdds/perception/radar_1/radar_tensor/v1", "type": "radar_tensor", "version": "v1", "qos_profile": "RADAR_RT" } ] } ], "next_page_token": "" }
Norms & filters
- Announces MUST include
caps.supported_profiles; peers choose the highest compatible minor within a shared major. - Each advertised topic MUST declare
name,type,version, andqos_profileper Topic Identity (§2.4.1); optional throughput hints (target_rate_hz,max_chunk_bytes) are additive. caps.preferred_profilesis an optional tie-breaker within the same major.caps.featurescarries namespaced feature flags; unknown flags MUST be ignored.CoverageQuery.exprfollows the boolean grammar in Appendix F.X and MAY filter on profile tokens (name@MAJOR.*orname@MAJOR.MINOR), topictype, andqos_profilestrings.- Responders page large result sets via
next_page_token; every response MUST echo the caller’squery_id.
What fields mean (quick reference)
| Field | Use |
|---|---|
caps.supported_profiles |
Version ranges per profile. Peers select the highest compatible minor within a shared major. |
caps.preferred_profiles |
Optional tie-breaker hint (only within a major). |
caps.features |
Optional feature flags (namespaced strings). Unknown flags can be ignored. |
topics[].type / version / qos_profile |
Topic Identity keys used to filter and match streams. |
reply_topic, query_id |
Allows asynchronous, paged responses and correlation. |
Practical notes
- Announce messages stay small and periodic; re-announce whenever capabilities, coverage, or topics change.
- Queries are stateless filters. Responders may page through results; clients track
next_page_tokenuntil empty. - Topic names follow
spatialdds/<domain>/<stream>/<type>/<version>; filter bytypeandqos_profileinstead of parsing payloads. - Negotiation is automatic once peers see each other’s
supported_profiles; emit diagnostics likeNO_COMMON_MAJOR(name)when selection fails.
Summary
Discovery keeps the wire simple: nodes publish what they have, clients filter for what they need, and the system converges on compatible versions. Use typed topic metadata to choose streams, rely on capabilities to negotiate versions without handshakes, and treat discovery traffic as the lightweight directory for every SpatialDDS deployment.
2.4.1 Topic Identity & QoS (Normative)
SpatialDDS topics are identified by a structured name, a type, a version, and a declared Quality-of-Service (QoS) profile. Together these define both what a stream carries and how it behaves on the wire.
Topic Naming Pattern
Each topic follows this pattern:
spatialdds/<domain>/<stream>/<type>/<version>
| Segment | Meaning | Example |
|----------|----------|----------|
| <domain> | Logical app domain | perception |
| <stream> | Sensor or stream ID | cam_front |
| <type> | Registered data type | video_frame |
| <version> | Schema or message version | v1 |
Example
{
"name": "spatialdds/perception/radar_1/radar_tensor/v1",
"type": "radar_tensor",
"version": "v1",
"qos_profile": "RADAR_RT"
}
Registered Types (v1)
| Type | Typical Payload | Notes |
|---|---|---|
geometry_tile |
3D tile data (GLB, 3D Tiles) | Large, reliable transfers |
video_frame |
Encoded video/image | Real-time camera streams |
radar_tensor |
N-D float/int tensor | Structured radar data |
seg_mask |
Binary or PNG mask | Frame-aligned segmentation |
desc_array |
Feature descriptor sets | Vector or embedding batches |
These registered types ensure consistent topic semantics without altering wire framing. New types can be registered additively through this table or extensions.
Standard QoS Profiles (v1)
QoS profiles define delivery guarantees and timing expectations for each topic type.
| Profile | Reliability | Ordering | Typical Deadline | Use Case |
|---|---|---|---|---|
GEOM_TILE |
Reliable | Ordered | 200 ms | 3D geometry, large tile data |
VIDEO_LIVE |
Best-effort | Ordered | 33 ms | Live video feeds |
VIDEO_ARCHIVE |
Reliable | Ordered | 200 ms | Replay or stored media |
RADAR_RT |
Partial | Ordered | 20 ms | Real-time radar tensors |
SEG_MASK_RT |
Best-effort | Ordered | 33 ms | Live segmentation masks |
DESC_BATCH |
Reliable | Ordered | 100 ms | Descriptor or feature batches |
Notes
- Each topic advertises its
qos_profileduring discovery. - Profiles capture trade-offs between latency, reliability, and throughput.
- Implementations may tune low-level DDS settings, but the profile name is canonical.
- Mixing unrelated data (e.g., radar + video) in a single QoS lane is discouraged.
Discovery and Manifest Integration
Every Announce.topics[] entry and manifest topic reference SHALL include:
- type — one of the registered type values
- version — the schema or message version
- qos_profile — one of the standard or extended QoS names
Consumers use these three keys to match and filter streams without inspecting payload bytes. Brokers and routers SHOULD isolate lanes by (topic, stream_id, qos_profile) to avoid head-of-line blocking.
Implementation Guidance (Non-Normative)
- No change to on-wire framing — this metadata lives at the discovery layer.
- Named QoS profiles simplify cross-vendor interoperability and diagnostics.
- For custom types, follow the same naming pattern and document new QoS presets.
- All examples and tables herein are additive; legacy 1.3 compatibility language has been removed.
2.5 Anchors
The Anchors profile provides a structured way to share and update collections of durable, world-locked anchors. While Core includes individual GeoAnchor messages, this profile introduces constructs such as AnchorSet for publishing bundles (e.g., a venue’s anchor pack) and AnchorDelta for lightweight updates. This makes it easy for clients to fetch a set of anchors on startup, stay synchronized through incremental changes, and request full snapshots when needed. Anchors complement VPS results by providing the persistent landmarks that make AR content and multi-device alignment stable across sessions and users.
2.6 Canonical Ordering & Identity (Normative)
This section applies to any message that includes the trio: Time stamp, string source_id, and uint64 seq.
Field semantics
stamp— Event time chosen by the producer (may reflect device/measurement time and is not guaranteed globally monotonic across sources).source_id— Stable writer identity within a deployment (e.g., a sensor, process, or node).seq— Per-source_idstrictly monotonic unsigned 64-bit counter that increments by 1 for each new sample.
Identity & idempotency
- The canonical identity of a sample is the tuple (
source_id,seq). - Consumers MUST treat duplicated (
source_id,seq) as the same logical sample (idempotent). - If
seqwraps or resets, the producer MUST changesource_id(or use a profile that defines an explicit writer epoch).
Ordering rules
- Within a single source (intra-source): Order by
seqonly. - If two samples share the same
seq, the later-arriving one supersedes the earlier; implementations SHOULD log a single warning per stream. - Missing
seqvalues indicate loss under RELIABLE QoS and MAY trigger application-level recovery. - Across multiple sources (inter-source merge): Order by the tuple (
stamp,source_id,seq) within a bounded reordering window Δ chosen by the consumer (e.g., 100–200 ms). stampprovides the coarse global axis;source_idandseqdisambiguate ties and ensure stability.- Consumers MUST NOT enforce global monotonicity by
stampalone; clock skew and late arrivals MUST be tolerated within Δ.
Clock guidance
- Producers SHOULD time-sync (NTP/PTP) where feasible.
- Consumers SHOULD bound out-of-order buffering by Δ and proceed deterministically when the window elapses.
Notes
- These rules are additive to transport-level ordering; they define application-level determinism independent of QoS.
- Profiles MAY further refine recovery behavior on gaps (e.g., retries, hole-filling) without altering this canonical ordering.
2.6 Profiles Summary
The complete SpatialDDS IDL bundle is organized into the following profiles:
- Core Profile
Fundamental building blocks: pose graphs, geometry tiles, anchors, transforms, and blob transport. - Discovery Profile Lightweight announce messages plus active query/response bindings for services, coverage areas, anchors, and spatial content or experiences.
- Anchors Profile
Durable anchors and the Anchor Registry, enabling persistent world-locked reference points.
Together, Core, Discovery, and Anchors form the foundation of SpatialDDS, providing the minimal set required for interoperability.
- Extensions
- Sensing Module Family:
sensing.commondefines shared frame metadata, calibration, QoS hints, and codec descriptors. Radar, lidar, and vision profiles inherit those types and layer on their minimal deltas—RadDetectionSet/RadTensor/beam_paramsfor radar,PointCloud/ScanBlock/return_typefor lidar, andImageFrame/SegMask/FeatureArrayfor vision. Deployments MAY import the specialized profiles independently but SHOULD declare thesensing.common@1.xdependency when they do. - VIO Profile: Raw and fused IMU and magnetometer samples for visual-inertial pipelines.
- SLAM Frontend Profile: Features, descriptors, and keyframes for SLAM and SfM pipelines.
- Semantics Profile: 2D and 3D detections for AR occlusion, robotics perception, and analytics.
- AR+Geo Profile: GeoPose, frame transforms, and geo-anchoring structures for global alignment and persistent AR content.
- Provisional Extensions (Optional)
- Neural Profile: Metadata for neural fields (e.g., NeRFs, Gaussian splats) and optional view-synthesis requests.
- Agent Profile: Generic task and status messages for AI agents and planners.
Together, these profiles give SpatialDDS the flexibility to support robotics, AR/XR, digital twins, IoT, and AI world models—while ensuring that the wire format remains lightweight, codec-agnostic, and forward-compatible.
Profile Matrix (SpatialDDS 1.4)
- spatial.core/1.4
- spatial.discovery/1.4
- spatial.anchors/1.4
- spatial.argeo/1.4
- spatial.sensing.common/1.4
- spatial.sensing.rad/1.4
- spatial.sensing.lidar/1.4
- spatial.sensing.vision/1.4
- spatial.slam_frontend/1.4
- spatial.vio/1.4
- spatial.semantics/1.4
The Sensing module family keeps sensor data interoperable: sensing.common unifies pose stamps, calibration blobs, ROI negotiation, and quality reporting. Radar, lidar, and vision modules extend that base without redefining shared scaffolding, ensuring multi-sensor deployments can negotiate payload shapes and interpret frame metadata consistently.