You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This proposal is an attempt at a standardized way for hardware components in `ros2_control` to report their status.
6
6
7
-
Right now, if you're writing a hardware interface, how you report things like health, errors, or connectivity is pretty much up to you. This usually means everyone rolls their own custom messages. While that works for a single project, it makes it really tough to build generic, reusable tools on top of `ros2_control` (and even internally!). This proposal is a first-pass attempt at defining a generic `HardwareStatus` message. The main goal is to find a good balance between a structured, predictable format that tools can rely on, and the flexibility needed to report all the weird, wonderful, and specific details of different hardware.
7
+
Right now, if you're writing a hardware component, how you report things like health, errors, or connectivity is pretty much up to you. This usually means everyone rolls their own custom messages. While that works for a single project, it makes it really tough to build generic, reusable tools on top of `ros2_control` (and even internally!). This proposal is a first-pass attempt at defining a generic `HardwareStatus` message. The main goal is to find a good balance between a structured, predictable format that tools can rely on, and the flexibility needed to report all the weird, wonderful, and specific details of different hardware.
8
8
9
9
This is very much a draft to get the conversation started, not a final solution!
10
10
@@ -14,17 +14,24 @@ Here's a diagram I put together to visualize it:
14
14
15
15
Let's discuss this in slightly more detail.
16
16
17
+
## 0. Note on Terminology
18
+
- Hardware Component: A Hardware Interface written for a Single Component, currently can be of form `System`, `Actuator` or `Sensor`, and have multiple sub-components.
19
+
- Ex - "pal_arm"
20
+
- Device: A sub-component of a Hardware Component.
21
+
- Ex - "base_motor"
22
+
17
23
## 1. The Idea: Structured vs. Unstructured
18
24
19
25
The core idea is to split status reporting into two complementary parts.
20
26
21
-
1.**Structured Status:**
22
-
- A fixed set of fields covering \~80% of common hardware needs—machine-readable, reliable, and directly consumable by controllers, watchdogs, automation tools and even for us internally.
23
-
- A compact, general-purpose block of enums and identifiers. If a device can’t fill one of these fields, it simply reports `UNKNOWN`.
27
+
1.**Structured, Standards-Based Status:**
28
+
- A fixed set of fields covering \~80% of common hardware needs - machine-readable, reliable, and directly consumable by controllers, watchdogs, automation tools and even for us internally.
29
+
- A collection of status messages, where each message type corresponds to a specific industry standard (e.g., `CANopenState`), providing a machine-readable and reliable format.
30
+
- A device in a hardware component populates only the status blocks relevant to it within a single, device-specific message(`HardwareDeviceStatus`), aggregates it into one message(`HardwareStatus`) which containes all the devices in the hardware, covering the common hardware needs for controllers, watchdogs, and automation tools.
24
31
25
-
2.**Unstructured Status:**
26
-
- A free-form array of key/value diagnostics for everything else—geared toward logs, dashboards, and human inspection only.
27
-
- A slower, richer stream of `diagnostic_msgs/KeyValue[]`, strictly for debugging and UI, ideally not parsed by control loops.
32
+
2.**Unstructured Status:**
33
+
- A free-form array of key/value diagnostics for everything else-geared toward logs, dashboards, and human inspection only.
34
+
- A slower, richer stream of `diagnostic_msgs/KeyValue[]`, strictly for debugging and UI, ideally not parsed by control loops.
28
35
29
36
## 2. Example Message Topology
30
37
@@ -37,37 +44,68 @@ We separate **real-time status** (fast, small) from **detailed diagnostics** (bu
37
44
38
45
## 3. Structured Status: `HardwareStatus`
39
46
47
+
The foundation of this approach is the `HardwareStatus` message. A single publisher per hardware component would publish `HardwareStatus` messages on the `/hardware_status` topic , each message is an array of `HardwareDeviceStatus` messages which contain the standard separated messages of a single device in the hardware component.
string hardware_id # unique per‐instance, e.g. "left_wheel/driver"
53
+
string hardware_id # unique per‐hardware-component, ideally the name of the hardware derived from HardwareInfo e.g. "pal_arm"
54
+
55
+
# --- Device Status Aggregation ---------------------------------
56
+
# An array containing the status of individual devices in the hardware component
57
+
HardwareDeviceStatus[] hardware_device_states
58
+
```
59
+
```
60
+
# control_msgs/msg/HardwareDeviceStatus
61
+
string device_id # unique per-device, e.g. "base_motor"
62
+
63
+
# --- Standard-Specific States --------------------------------------
64
+
# States populated based on the standards relevant to this device.
65
+
# A device will only fill the arrays for the standards it implements, rest will be empty
66
+
GenericState[] generic_hardware_status
67
+
CANopenState[] canopen_states
68
+
EtherCATState[] ethercat_states
69
+
VDA5050State[] vda5050_states
70
+
```
71
+
72
+
### 3.1. Standardized State Messages
73
+
74
+
Below are the proposed initial standard-specific messages, based on widely used industrial standards. Additions and opinions here would be really appreciated!
75
+
76
+
---
77
+
78
+
**`ros2_control` Generic State**
79
+
80
+
This message encapsulates the general-purpose status fields, serving as a baseline for any hardware component.
45
81
46
-
# ——— Health & Error ——————————————————————————————————————————————
82
+
```
83
+
# control_msgs/msg/GenericState
84
+
85
+
# --- Health & Error ----------------------------------------------
47
86
uint8 health_status # see HealthStatus enum
48
-
uint8[] error_domain # Array of device errors, because hardware can throw more than one, see ErrorDomain enum
87
+
uint8[] error_domain # Array of device errors, see ErrorDomain enum
49
88
50
-
# ——— Operational State ———————————————————————————————————————————
89
+
# --- Operational State -------------------------------------------
51
90
uint8 operational_mode # see ModeStatus enum
52
91
uint8 power_state # see PowerState enum
53
92
uint8 connectivity_status # see ConnectivityStatus enum
54
93
55
-
# ——— Vendor & Version Info ————————————————————————————————————————
94
+
# --- Vendor & Version Info ----------------------------------------
56
95
string manufacturer # e.g. "Bosch"
57
96
string model # e.g. "Lidar-XYZ-v2"
58
97
string firmware_version # e.g. "1.2.3"
59
98
60
-
# ——— Optional Details for Context —————————————————————————————————
99
+
# --- Optional Details for Context ---------------------------------
61
100
# Provides specific quantitative values related to the enums above.
62
101
# e.g., for power_state, could have {key: "voltage", value: "24.1"}
63
102
# e.g., for connectivity, could have {key: "signal_strength", value: "-55dBm"}
64
103
diagnostic_msgs/KeyValue[] state_details
65
104
```
66
105
67
-
### 3.1. Enums
68
-
106
+
#### `ROS2ControlState` Enums
69
107
```
70
-
# control_msgs/msg/HardwareStatus (continued)
108
+
# control_msgs/msg/GenericState (enums)
71
109
72
110
# High-level health
73
111
uint8 HEALTH_UNKNOWN=0
@@ -90,10 +128,7 @@ uint8 EMERGENCY_STOP_HW # state of the emergency stop hardware (i.e. e-stop butt
90
128
uint8 EMERGENCY_STOP_SW # state of the emergency stop software system (over travel, pinch point)
91
129
uint8 PROTECTIVE_STOP_HW # state of the protective stop hardware (i.e. safety field state)
92
130
uint8 PROTECTIVE_STOP_SW # state of the software protective stop
93
-
# Some protective stop errors need to be acknowledged before the hardware can reactivate
94
-
# see https://docs.universal-robots.com/Universal_Robots_ROS2_Documentation/doc/ur_robot_driver/ur_robot_driver/doc/dashboard_client.html#unlock-protective-stop-std-srvs-trigger
95
131
uint8 SAFETY_STOP
96
-
# Some hardware requires calibration on startup (for example a linear rail or quadruped)
97
132
unit8 CALIBRATION_REQUIRED
98
133
99
134
@@ -133,27 +168,72 @@ uint8 CONNECT_FAILURE =3
133
168
uint8 CONNECTION_SLOW # to tell the controlling system it is struggling to communicate at rate
134
169
```
135
170
136
-
#### 3.2. A Note on a Future Addition
171
+
---
137
172
138
-
A potential limitation of the single-value enums above is that a component can only report one state per category at a time. Consider the `error_domain`: what happens if a hardware fault (`ERROR_HW`) immediately causes a communication failure (`ERROR_COMM`)? With the current design, the hardware driver must choose to (or is limited to) report only one.
139
-
That or return an array of errors and let mission control sort out the correct action to recover.
173
+
**CANopen State**
140
174
141
-
A potential solution for this in a future iteration would be to define some enums as **bitfields**. This would involve assigning values as powers of 2, allowing multiple states to be combined using a bitwise `OR` operation.
175
+
Reports state according to CiA 301 and CiA 402, common for motor drives and I/O.
176
+
-**Source:**[CAN in Automation (CiA)](https://www.can-cia.org/) - CiA 301 & 402 specifications.
142
177
143
-
For example, the `ErrorDomain` enum could be redefined as a bitmask:
144
178
```
145
-
# Example ErrorDomain as a bitfield (why only an 8 bit number?)
146
-
uint8 ERROR_NONE = 0 # 0b00000000
147
-
uint8 ERROR_HW = 1 # 0b00000001
148
-
uint8 ERROR_FW = 2 # 0b00000010
149
-
uint8 ERROR_COMM = 4 # 0b00000100
150
-
uint8 ERROR_POWER = 8 # 0b00001000
151
-
# ... up to 4 more flags
179
+
# control_msgs/msg/CANopenState
180
+
181
+
uint8 node_id # The CANopen node ID of the device
182
+
183
+
# --- CiA 301 State -------------------------------------------------
184
+
uint8 nmt_state # Network Management state (e.g., OPERATIONAL)
185
+
186
+
# --- CiA 402 State (for drives) ------------------------------------
187
+
uint8 dsp_402_state # Drive state machine state (e.g., OPERATION_ENABLED)
uint32 last_emcy_code # Last Emergency (EMCY) error code received
152
191
```
153
192
154
-
A publisher could then report both a hardware and power fault simultaneously by setting the value to `ERROR_HW | ERROR_POWER` (which is `9`, or `0b00001001`). A subscriber could then check for a specific error using a bitwise `AND` (e.g., `if (status.error_domain & ERROR_HW)`).
193
+
---
194
+
195
+
**EtherCAT State**
196
+
197
+
Reports the EtherCAT slave state according to the EtherCAT State Machine (ESM).
198
+
-**Source:**[EtherCAT Technology Group (ETG)](https://www.ethercat.org/en/downloads.html) - ETG.1000.4 EtherCAT Protocol Specifications.
199
+
200
+
```
201
+
# control_msgs/msg/EtherCATState
155
202
156
-
The primary trade-off is that we would be limited by the size of the enum's underlying type. A `uint8` allows for exactly 8 unique flags. While this may be sufficient for now, it's a constraint to keep in mind as we finalize this design. We can add this if we hear from the community that this is needed.
203
+
uint16 slave_position # Position of the slave on the bus (0, 1, 2...)
204
+
string vendor_id # Unique vendor identifier
205
+
string product_code # Unique product code for the device
206
+
207
+
# --- EtherCAT State Machine (ESM) ----------------------------------
208
+
uint8 al_state # Application Layer state (INIT, PREOP, SAFEOP, OP)
209
+
bool has_error # True if the slave is in an error state
210
+
uint16 al_status_code # AL Status Code indicating the reason for an error
211
+
```
212
+
213
+
---
214
+
215
+
**VDA5050 State**
216
+
217
+
For AGVs and AMRs compliant with VDA5050, this provides a snapshot of the vehicle's high-level status.
218
+
-**Source:**[Verband der Automobilindustrie (VDA)](https://github.com/VDA5050/VDA5050) - VDA 5050 Specification.
219
+
220
+
```
221
+
# control_msgs/msg/VDA5050State
222
+
223
+
# --- Order and Action Status ---------------------------------------
224
+
string order_id # ID of the currently executed order
1. Is the current list of standardized state messages (`CANopen`, `EtherCAT`, `VDA5050`, `ISO10218`) a good starting point? Are there other non-proprietary standards that are critical to include?
262
+
2. Is this whole approach overly complicated? It would be good to avoid that pitfall.
181
263
182
-
1. Could we reuse `lifecycle_msgs/State` for `operational_mode`, or is a dedicated enum preferable for clarity?
183
-
2. I left some question marks in the diagrams, any categories we are missing?
184
-
3. Should `HardwareStatus` include a short `string error_message`, or strictly push error details into diagnostics only?
185
-
4. Also another thing, maybe we use one big message (`control_msgs/HardwareStatus`) to make it simpler rather than publish structured vs. unstructured data on separate topics (`/hardware_status` and `/hardware_diagnostics`)?
186
-
5. And the main questions that I have, Is this whole approach overly complicated, let's avoid that pitfall.
264
+
## 6. Alternative Publishing Strategies
187
265
188
-
Looking forward to hearing what everyone thinks!
266
+
While this proposal centers on a single topic with an array of device statuses, it's worth discussing the trade-offs of other possible architectures. How else could we structure the flow of status information?
189
267
190
-
## Hardware Status Interface
191
-
What does configuring the Hardware Status (per hardware because a mobile_base is likely different than the arm mounted on top of it) look like?
192
-
Should we have blocks of state (i.e. standardized messages) that can be added together if the hardware offers X, Y and Z features?
193
-
(For example my robot arm has a `safety interface` for e-stop/p-stop and a `hardware_status` interface to report power, operating mode and ...)
194
-
What does it look like at the interface level? Is there a separate read (and maybe write) method for status reporting and reconfiguration?
195
-
For example standard safety status (E-stop, P-stop), operating mode, [battery state](https://docs.ros2.org/foxy/api/sensor_msgs/msg/BatteryState.html).
196
-
197
-
JointState has been the standard ROS2 control works with. What about GPIO, SafetyStatus, BatteryState, .... these are interfaces that hardware frequently provides.
198
-
What if ros2_control made a set of messages to standardize it's interfaces for each subcategory?
199
-
[SensorMsgs](https://docs.ros2.org/foxy/api/sensor_msgs/index-msg.html) is a start of what we need.
200
-
For example the UR controller exposes lots of interfaces via [GPIO](https://github.com/UniversalRobots/Universal_Robots_ROS2_Description/blob/85d2ad8d1526ee6c0f21dca94e1e697c83706b71/urdf/ur.ros2_control.xacro#L294-L311) but not in a standardized way so if someone wanted to control it and then switch robots their codebase would likely need to change to handle auxiliary control and monitoring.
201
-
202
-
Some errors or states will be set as the hardware stops functioning.
203
-
Should the status broadcaster hold and continue to publish last known state?
204
-
Should the status broadcaster offer statistics on hardware DEACTIVATE/ERROR and ACTIVATIONS?
205
-
Lots of industrial applications would like to know how many e-stops, number of controller errors/faults, ____ per shift, week or some period of time
206
-
Could this open the option for custom or standard controllers to monitor and keep the system healthy? i.e. automatic arm fault reset controller,
268
+
- **Per Device Messages**
269
+
- One issue I see with the current aggregated status message approach is that it seems a tad bit complicated for simple systems, what if a hardware component has only 1 actuator?
270
+
- Then what if, instead of a single aggregated topic, each device in a hardware component published its own `HardwareDeviceStatus` message on the same `/hardware_status` topic which will now be of the type `HardwareDeviceStatus`
271
+
- Then receivers just listen to the same `/hardware_status` topic as before, but just have to parse the `device_id` to see if the data is relevant, and similarly, publishers have to also only fill in the `HardwareDeviceStatus` message and send it without need of aggregation
207
272
273
+
## References
208
274
Links of hardware interfaces and their attempt to convey hardware status and support other control modes
[fault_reset controller](https://github.com/Kinovarobotics/ros2_kortex/blob/main/kortex_description/arms/gen3/7dof/config/ros2_controllers.yaml#L17-L18) to report and reset faults.
0 commit comments