|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |
Launch files
Messages
Services
Plugins
Recent questions tagged automatika_ros_sugar at Robotics Stack Exchange
|
automatika_ros_sugar package from automatika_ros_sugar repoautomatika_ros_sugar |
ROS Distro
|
Package Summary
| Version | 0.8.2 |
| License | MIT |
| Build type | AMENT_CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Description | |
| Checkout URI | https://github.com/automatika-robotics/ros-sugar.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-21 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Automatika Robotics
Authors
**ROS 2, with the sugar on top** [](LICENSE) [](https://emos.automatikarobotics.com/getting-started/installation.html) [](https://discord.gg/B9ZU6qjzND) [**Documentation**](https://emos.automatikarobotics.com) · [**Developer Docs**](https://sugarcoat.automatikarobotics.com) · [**API Reference**](https://sugarcoat.automatikarobotics.com/apidocs/index.html) · [**Discord**](https://discord.gg/B9ZU6qjzND)
Sugarcoat is the foundation of EMOS, the Embodied Operating System. A ROS 2 application tends to end up as a pile of nodes, launch files and glue, with what the robot actually does scattered across all of them. Sugarcoat gives the robot a nervous system instead. A modern robot drives, watches, listens, speaks and grasps at the same time, in a world that rarely goes to plan, and what it does next has to come from all of it, the moment it happens. A recipe is one Python script in which you declare the components, say which events matter and what happens when they fire, and hand the lot to a launcher that brings the system up, keeps it healthy and takes it down again.
Building Blocks
| Block | What it gives you |
|---|---|
| Component | A ROS 2 lifecycle node with the plumbing done: declared inputs and outputs, a typed configuration that also loads from YAML, JSON or TOML, a health status, fallbacks, and actions callable by name. Driven by a timer, a trigger topic, a service or an action server. |
| Topic | A named, typed stream. Conversion between ROS messages and Python objects is done for you, spatial inputs arrive in the frame the algorithm needs, and use_plugin serves a topic from the robot’s plugin instead of ROS. |
| Event | A condition on live data in plain Python, Event(battery.msg.data < 20.0). Conditions combine across topics with and, or and not, fire on change, once or debounced, and any function returning bool can be polled as one. |
| Action | Anything callable with its arguments, ready to run when an event fires: a component method, a system action such as restart, reconfigure, publish or log, a plain function, or a plugin action. Arguments can come from topics at run time. A monitored action waits for a success condition, times out, retries and can be cancelled. |
| Routine | A named sequence of monitored steps with a retry and failure policy per step. It can be paused, resumed and aborted, publishes its progress, and is started by an event, from the web UI, or by an agent as a tool. |
| Fallbacks | Recovery a component runs on its own when its health status turns bad. An algorithm failure, a component failure and a system failure each get their own answer, from a retry to a restart. |
| Launcher | Turns the recipe into a running system: configures and activates components as threads or as processes, starts the drivers and external nodes the recipe needs, runs the Monitor that evaluates events and dispatches actions, and supervises until the recipe ends. No launch files. |
| Robot plugin | Adapts one robot or sensor to the interfaces recipes use: transports over ROS, UDP, HTTP or a vendor SDK, feedback decoders and command encoders, the robot’s own actions and events, drivers to start, sensor mounts published to TF, and how the robot maps. |
| Web UI and API | One call serves the recipe’s inputs, outputs, settings, actions and routines to a browser, and the same over a JSON and WebSocket API guarded by HTTPS and API keys. |
Key Features
- Recipes, not launch files. A whole system is one Python file. It names the components, attaches the robot’s plugin, and says which events matter and what should happen when they fire. The launcher does the rest. It configures and activates every component, as threads of one process or as processes of their own, keeps an eye on them while the recipe runs, and shuts the lot down cleanly when it is told to.
-
Events in plain Python.
Event(battery.msg.data < 20.0)is a complete event. Field paths are checked against the message type when the recipe is imported, so a typo fails on your desk rather than on the robot. A condition can span several topics, fire only when something changes or only once, and a topic can be given a timeout so that an event never fires on a reading that stopped arriving a minute ago. - Actions that know whether they worked. Give an action a success condition, a timeout, a retry budget and a cancel method, and the Monitor that every launcher runs will dispatch it, wait for the verdict and try again if it has to. Nothing in a component’s loop blocks for any of this.
- Routines for behaviours that take steps. Detect, approach, grasp, lift. A routine says a sequence like that in one place, with a policy for each step, and can be paused, resumed and aborted from an event, from the web UI, or by an agent that plans with it as a tool. Its progress is published while it runs.
- Components that heal. A component reports how it is doing rather than merely that it is alive, and when its status turns bad it runs the fallbacks it was given, whether that means a retry, a simpler algorithm, a reconnect or a restart. Nobody has to be watching.
- One recipe, any robot. A robot plugin adapts the hardware to the interfaces recipes use, whether the robot speaks ROS, UDP, HTTP or a vendor SDK, and brings the robot’s own actions and events along with it. Large feeds such as images and point clouds travel through shared memory.
- An interface for free. One call serves the recipe in the browser and over a JSON and WebSocket API, behind HTTPS and API keys, with every asset served from the robot, so it works wherever the robot is, internet or not.
Behaviour trees had their day. A tree is one structure ticked by one node, so everything the robot does has to be squeezed into it, and it notices the world only when the tick reaches a condition node someone remembered to put there. A sugarcoated system is richer on every count. Any topic, any component’s health or any reading from the robot can be an event, written in Python and checked against the message types before anything runs. Any event can trigger any action or routine anywhere in the system, and every event is watched at once, whatever the robot happens to be doing. Sequences live in routines where they belong, with a success test and a retry policy for each step and the means to pause, resume or abort them, while recovery lives with the component that needs it rather than in a branch of a tree. The robot reacts the moment something happens, not when the tick gets round to it.
Quick Start
A component that drives forward, and an event that slows it down when the battery runs low:
from ros_sugar import Launcher
from ros_sugar.core import Action, BaseComponent, Event
from ros_sugar.io import Topic
from ros_sugar.utils import ActionReturnType, component_action
battery = Topic(name="battery", msg_type="Float32")
cmd_vel = Topic(name="cmd_vel", msg_type="Twist")
class Patrol(BaseComponent):
"""Drives forward at a speed the recipe can change at run time."""
def init_variables(self):
self.speed = 0.5
def _execution_step(self):
self.publishers_dict["cmd_vel"].publish([self.speed, 0.0, 0.0])
@component_action
def slow_down(self, factor: float) -> ActionReturnType:
self.speed *= factor
return True, f"speed is now {self.speed:.2f} m/s"
patrol = Patrol(component_name="patrol", outputs=[cmd_vel])
low_battery = Event(battery.msg.data < 20.0, on_change=True)
launcher = Launcher()
launcher.add_pkg(components=[patrol])
launcher.on(low_battery, Action(patrol.slow_down, kwargs={"factor": 0.5}))
launcher.bringup()
Actions compose into routines. Here the same event starts a procedure whose steps are the component’s actions, declared like slow_down above, each with its own test for success, and the routine is served in the web UI with its steps checked off as it runs:
```python from ros_sugar.actions import wait
File truncated at 100 lines see the full file
Changelog for package automatika_ros_sugar
0.8.2 (2026-10-20)
- (fix) Broadcasts recipe frames to all components regardless of the addition order in the recipe
- (fix) prevents UI node from crashing in only inputs or only outputs are provided in the recipe
- (fix) Serializes and deserializes action args/kwargs in the action dict
- (fix) Calls stop_watching on event removal
- (fix) Fixes using plugin feedbacks as Event sources in Monitor and Component
- (chore) Updates routine tests
- (fix) Adds a flag to track if a cencel request is sent to the client to avoid handling multiple requests
- (fix) Fixes handling plugin feedbacks for plugin defined events when used with component defined actions so components subscribe to them correctly
- (fix) Execuldes 'Execute Method" service from the Browser UI
- (fix) Forbids UI of cancelling ongoing goals automatically
- (feature) Adds custom_settings to NativeMapping to allow robot plugins to pass custom mapping parameters
- (fix) Gives the UI node the plugins its topics use, so they bind to the plugin's ROS topics
- (fix) Allows setting pose heading in the UI by dragging on the map when publishing pose-like types
- (fix) Gives PoseWithCovariance(Stamped) inputs the pose widget with map picking, and fixes stamped pose widgets
- (feature) Adds automatic ros message header stamp for UI inputs and handles nested headers
- (feature) Allows using UI clicked points to publish to PoseWithCovariance(Stamped) types
- (feature) Adds geometry_msgs PoseWithCovariance(Stamped) to supported types
- (fix) Fixes shutting down of external process server by correctly waking and joining the accept thread
- (chore) Fixes misbehaving tests
- (refactor) Initial true condition evaluates for rising edge conditions
- (fix) Passes kwargs only in the decorator as the action itself would hold and apply the static arguments
- (fix) Fixes parsing event info for callable events which have no condition
- (fix) Fixes resetting Fallbacks retries counter
- (fix) Resets component fallbacks on activation
- (fix) Limites ExecuteMethod service to public methods and component actions/fallbacks
- (fix) Uses normalized topic name in ReplaceTopic action
- (fix) Ensures robot config is passed to all components in launcher regardless of the setting order in the Recipe
- (fix) Sets additional arguments to the executable in launcher regradless of the log_level setting
- (featue) Adds remove functions for runtime removal from the action registry
- (fix) Sets the clock to a publisher from the component and fixes setting the frame_id
- (fix) Check for the right initial state flag in component configure/unconfigure
- (fix) Fixes parsing Bool attributes in config update from str
- (fix) Allows setting float attributes with int values, and fixes setting bool attributes
- (fix) Parses reconfigure action response as tuple
- (feature) Uses abstract sockets instead of sock files for external processors and adds a user check for them when connecting
- (feature) Adds correct SIGTERM handling based on ros2/launch#712 upstream
- (fix) Adds destroying external processor clients during node teardown
- (refactor) Adds correct types for external processors
- (feature) Adds external processor type to the config module
- (feature) Adds server/client for running external processors
- (feature) Adds a generic function as an external processor type
- (fix) Stops plugin feedback ROS outputs quietly when the host node is destroyed on teardown
- (feature) Adds helper in mount to get one mount in anothers frame
- (feature) Adds a method in Launcher to publish a plugin feedback on ROS
- (fix) Lets launch own the process signals
- (fix) Keeps a component executor alive when a restart destroys what it is waiting on
- (chore) Adds test to ensure unique names usage across tests
- (chore) Adds timed component test
- (fix) Fixes laserscan transform and updates tests
- (fix) Clears exec_once flag on deactivation to allow a clean re-activation of the component
- (fix) Defaults QoS durability to the middleware default
- (feature) Gives every plugin action a whole tool schema in the action registry
- (feature) Adds a Plugin Actions/Events to the Monitor's registery to enable usage in Routines
- (chore) Updates UI tests
- (fix) Adds a warning in the Launcher about unregistered routines passed to the UI
- (chore) Refactors test
- (docs) Documents on_pause in the event system guide
- (fix) Stamps a decoded feedback before handing it to anyone
- (feature) Allows extendiong/customizing UI Task cards in child packages
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| automatika_embodied_agents | |
| kompass |