Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

husarion_asset_msgs

An open ROS 2 interface for serving package:// assets — meshes, textures, URDF resources — over the ROS graph. This README is the specification: implement these two interfaces and the announce/routing rules below, and any conforming client (or the husarion_rosbridge router) can fetch your robot's assets with no baked-in mesh bundles.

It exists because the common web path bakes every mesh into the bridge image. Instead, meshes stay where the robot/sensor is defined and cross the container/snap boundary only as ordinary DDS service payloads — the same ROS graph the topics already use.

The two interfaces

srv/GetAsset

# Request
string uri          # e.g. "package://rosbot_description/meshes/rosbot_xl/body.dae"
uint64 offset       # byte offset to start at (0 = from the beginning)
uint32 length       # max bytes to return (0 = as many as fit in one response)
---
# Response
bool    success
string  error         # human-readable; empty on success
string  media_type    # optional, e.g. "model/stl", "model/vnd.collada+xml"
uint64  total_size    # full asset size in bytes — lets the client drive chunking
string  content_hash  # "sha256:..." of the FULL asset; stable across chunks (ETag/caching)
uint8[] data          # the requested byte range (empty on failure)

Chunking is part of the contract. DDS service responses have RMW-dependent size limits and meshes run to hundreds of KB, so the client requests [offset, offset+length) ranges sized under the RMW limit and stitches them. total_size + content_hash describe the whole asset, so the client knows when it is done and can cache across sessions. Small assets degenerate to a single offset:0, length:0 call.

msg/AssetProviderInfo

string                  node_name             # for diagnostics
string                  service_name          # the GetAsset service this provider hosts (unique)
string[]                packages              # package names this provider can resolve
builtin_interfaces/Time stamp                 # re-stamped on every heartbeat re-announce
float32                 heartbeat_period_sec  # provider's re-announce period

Discovery & routing semantics

  • Each provider hosts a uniquely-named GetAsset service (two servers on one name is illegal in ROS 2).
  • Each provider publishes AssetProviderInfo on a well-known topic — default /asset_providersTRANSIENT_LOCAL + keep-last, so a late-started router and late providers converge on the current set.
  • Liveness via heartbeat: providers re-announce periodically (re-stamping stamp); a router drops a provider after ~2× heartbeat_period_sec with no refresh, so a crashed provider's packages stop resolving rather than lingering. (Heartbeat, not DDS liveliness, which varies by RMW.)
  • On a request for package://PKG/…, the router looks up PKG, calls that provider's service (chunking as needed), and caches bytes by content_hash — invalidating when a provider re-announces a changed asset.
  • Transitive references (a .dae referencing textures/sub-meshes) are resolved by the client, one get_asset per URI. Providers stay bytes-only — no file-format parsing.
  • Overlap: if two providers announce the same package, the router dedups and picks one deterministically (e.g. first-registered).
  • Unknown package / not found: the provider returns success:false; the router relays a clean failure and the renderer applies its own fallback.

Provider security rules (normative)

A conforming provider MUST:

  • accept only package:// URIs; reject absolute paths and any .. traversal;
  • serve only packages in its announced owned set;
  • resolve package://PKG/REL via the ament index / resource_retriever against its own AMENT_PREFIX_PATH.

The recommended owned set is auto-derived: subscribe to the co-located robot_description, scrape every package://PKG/… out of the URDF, and announce exactly those PKGs. That makes overlap structurally impossible and needs no per-deployment config. See the reference husarion_asset_server.

Out of scope

No primitive/geometry/box semantics. The contract resolves URIs → bytes, full stop. Geometry fallback (e.g. a <collision> primitive when a mesh is missing) is URDF + renderer territory. Keeping the standard pure is deliberate.

Conformance

A conformance suite ships with the reference server (husarion_asset_server, the asset_conformance binary) so third-party providers can self-validate against this standard:

asset_conformance --service /your_provider/get_asset \
  --uri package://your_pkg/some/asset.dae

It checks full + chunked fetch, content_hash stability/determinism, and the security rules (unknown-package + .. traversal rejection), exiting non-zero on any failure.

Build

colcon build --packages-select husarion_asset_msgs

License

Apache-2.0.

About

Open ROS 2 interface for serving package:// assets (meshes, textures, URDF resources) over the ROS graph — the message contract shared by asset servers and clients.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages