🛠️ Actions & Services
Both are something the robot does on request. An action takes time and reports progress; a service is one request and one reply with nothing in between.
actions:
navigate_to:
ros_name: /navigate_to_pose
type: nav2_msgs/action/NavigateToPose
description: Drives to a target pose on the map.
message:
pose:
header: { frame_id: map }
pose:
position: { x: "${target_x}", y: "${target_y}", z: 0.0 }
parameters:
target_x: { type: float64, min_value: -50.0, max_value: 50.0 }
target_y: { type: float64, min_value: -50.0, max_value: 50.0 }
services:
reset_odom:
ros_name: /reset_odometry
type: std_srvs/srv/Trigger
description: Resets odometry to the origin.
# Trigger has no request fields, so neither message nor parameters
| field | type | bounds | absent means |
|---|---|---|---|
ros_name |
ROS graph name | absolute, at most 255 characters | required |
type |
ROS type name | the middle segment is action or srv, at most 255 characters |
required |
message |
message template | null refused at any depth |
an empty goal or request |
parameters |
map of names | at most 50 per entry | the message has no holes |
description |
text | 1 to 2000 characters | offered as description: null |
ros_name and type are required and nothing else is. The type carries its
middle segment the way ROS 2 spells it: nav2_msgs/action/NavigateToPose,
std_srvs/srv/Trigger, never the two-segment short form.
Clients never see ros_name. They address the entry by its slug, so a server
can be renamed on the robot without a single app changing.
One job per slug
At most one job runs per slug, for a service exactly as for an action. A
second call is refused with busy and a 409 that carries the running job,
and every observer of that slug sees the same job.
The checks run in a fixed order: parameters first, then whether the robot is online, then whether the slug is busy. Parameters are a property of the request and connectivity is a property of the world, so a developer testing against an offline robot still learns their parameters were wrong.
Actions report progress, services do not
An action’s job is something to watch. It moves through its states, carries feedback while it runs, and can be cancelled.
A service call returns with its result already on the job, so there is nothing
left to observe. Whatever the service does has to finish inside that one
reply, and anything long-running belongs in actions.
description is recommended and not required
Every exposure the caller’s role grants is listed by robot_describe. Skip
the description and the tool still works, listed with description: null.
What is lost is the only thing that says what the call means — the difference between a tool a model uses correctly and one it guesses at. The same holds for datapoints, publishers and cameras. Omission is the only way to say nothing, because an empty string is refused.
The message template and the parameter constraints are shared with publishers and have their own page.