2026-06-081 min read
Designing ROS2 lifecycle nodes for field robots
A practical pattern for keeping robot startup, recovery, and shutdown behavior observable and repeatable.
ROS2C++Architecture
Lifecycle nodes make robot behavior easier to reason about because each node exposes its state. In production systems, I use them for sensors, planners, controllers, and every component that has hardware or network dependencies.
State-first node design
The node should do almost nothing in its constructor. The expensive work belongs in on_configure, activation belongs in on_activate, and cleanup belongs in on_cleanup.
#include <rclcpp_lifecycle/lifecycle_node.hpp>
class MotorBridge : public rclcpp_lifecycle::LifecycleNode {
public:
MotorBridge() : LifecycleNode("motor_bridge") {}
CallbackReturn on_configure(const rclcpp_lifecycle::State &) override {
port_ = declare_parameter<std::string>("port", "/dev/ttyUSB0");
driver_.connect(port_);
return CallbackReturn::SUCCESS;
}
CallbackReturn on_activate(const rclcpp_lifecycle::State &) override {
command_sub_ = create_subscription<Twist>("cmd_vel", 10, onCommand);
return CallbackReturn::SUCCESS;
}
};
Launch with parameters
Keep lifecycle parameters explicit and versioned with the robot.
motor_bridge:
ros__parameters:
port: /dev/ttyUSB0
watchdog_ms: 250
frame_id: base_link
This pattern gives operators a predictable control surface and gives developers a cleaner way to test failure modes.