The executor is not a safety scheduler
A ROS 2 callback runs when the executor gets to it. That is fine for perception and navigation, and unsuitable for the one decision that has to be bounded — whether the robot is allowed to keep moving.
Solution · ROS 2
EdgeEmbed ships a standard ROS 2 package, so the integration arrives the way your team expects — colcon, params, launch files. But the node itself only translates messages into events. The decision loop deliberately runs inside the runtime, off the ROS executor path, because the one decision that must be bounded should not wait its turn in a callback queue.
How it fits
Your ROS stack keeps doing what it does. The bridge is the only thing that touches it — and everything downstream of the boundary is deterministic.
Perception, Nav2, behaviour trees — publishing on topics, scheduled by the DDS executor.
A thin ROS node that only translates: message in, event out. No decisions are taken here.
Policy, arbitration and the recorded decision — running off the ROS executor path, where the timing guarantee holds.
Vetted actions leave through backend plugins to the drive base, CAN bus, or e-stop line.
The design rule
It would be easier to put the policy in a ROS callback. It would also quietly forfeit the property the runtime exists to provide.
A ROS 2 callback runs when the executor gets to it. That is fine for perception and navigation, and unsuitable for the one decision that has to be bounded — whether the robot is allowed to keep moving.
Packaging as a ROS node is how the integration reaches you: colcon, params, launch files, all familiar. But the node only translates messages. The decision loop stays inside the runtime, where its guarantees are real.
The bridge carries generic hints — urgency, confidence, value — never domain payloads. The runtime decides on numbers and policy, so the same engine serves any robot without learning your message schemas.
Behaviour as data
Same idea as the policy bundle: what a topic means is declared, not compiled — so the integration is reviewable, versionable, and portable across robots.
Which topic becomes which event is declared in a YAML params file, not compiled in. The same bridge node serves every robot on the fleet; only the mapping file differs.
The mapping sits beside the policy bundle as plain, versioned configuration — readable by someone who needs to sign off on behaviour without reading C++.
The translation core is deliberately ROS-independent — it depends only on the public SDK headers, so it compiles and unit-tests with nothing but a C++17 compiler.
At a glance
Verified
Because the core is ROS-independent, its behaviour is unit-tested with only a C++17 compiler — no ROS install, no runtime binary, no robot.
Translation-core unit tests. Running the node in a live ROS 2 graph is done in your own ROS environment.
Pilots
If you have a ROS stack and a safety decision you need to make defensible — or a certification conversation coming — we would love to talk.