Skip to main content

ROS2 Examples

These examples demonstrate how to integrate ROS2 applications with Roboticks. All code is available in the roboticks-examples repository.

Hello World Example

A simple ROS2 node that publishes messages, managed by Roboticks. This is the perfect starting point for understanding the integration.

What It Does

  • Publishes “Hello from Roboticks!” messages at a configurable rate
  • Accepts input to dynamically update the message
  • Records all messages to a rosbag for later analysis
  • Demonstrates automatic restart on crash

Project Structure

Ros2HelloWorldModule/
├── ros2_ws/                    # Standard ROS2 workspace
│   └── src/
│       └── roboticks_hello_world/
│           ├── src/
│           │   └── hello_world_node.cpp
│           ├── launch/
│           │   └── hello_world.launch.py
│           ├── package.xml
│           └── CMakeLists.txt
├── src/                        # Roboticks module wrapper
│   ├── Ros2HelloWorldModule.cpp
│   └── Ros2HelloWorldModule.hpp
├── config/
│   └── Ros2HelloWorldModule.yaml
└── CMakeLists.txt

The ROS2 Node

A standard ROS2 node - nothing Roboticks-specific:
// hello_world_node.cpp
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>

class HelloWorldNode : public rclcpp::Node {
public:
    HelloWorldNode() : Node("roboticks_hello_world") {
        // Declare parameters
        this->declare_parameter<std::string>("message", "Hello from Roboticks!");
        this->declare_parameter<double>("rate_hz", 1.0);

        // Get parameters
        message_ = this->get_parameter("message").as_string();
        double rate_hz = this->get_parameter("rate_hz").as_double();

        // Create publisher
        publisher_ = this->create_publisher<std_msgs::msg::String>(
            "/roboticks/hello_world/output", 10);

        // Create timer
        timer_ = this->create_wall_timer(
            std::chrono::duration<double>(1.0 / rate_hz),
            [this]() { this->publish(); });
    }

private:
    void publish() {
        auto msg = std_msgs::msg::String();
        msg.data = message_;
        publisher_->publish(msg);
        RCLCPP_INFO(this->get_logger(), "Publishing: %s", msg.data.c_str());
    }

    std::string message_;
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char* argv[]) {
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<HelloWorldNode>());
    rclcpp::shutdown();
    return 0;
}

Module Configuration

The Roboticks module configuration tells the system how to manage your node:
# Ros2HelloWorldModule.yaml
name: Ros2HelloWorldModule
version: 1.0.0
description: "ROS2 HelloWorld node managed by Roboticks"

update_rate_hz: 10

custom:
  ros2:
    # Package and executable to launch
    package: "roboticks_hello_world"
    executable: "hello_world_node"

    # Node parameters
    message: "Hello from Roboticks!"
    rate_hz: 1.0

    # Topics
    output_topic: "/roboticks/hello_world/output"
    input_topic: "/roboticks/hello_world/input"

    # Process management
    auto_restart: true
    restart_delay_ms: 1000

  # Automatic rosbag recording
  rosbag:
    enabled: true
    output_dir: "/var/roboticks/ros2/bags/hello_world"
    topics: "/roboticks/hello_world/output, /roboticks/hello_world/status"

ROS2 Interface

TopicTypeDescription
/roboticks/hello_world/outputstd_msgs/StringPublished messages
/roboticks/hello_world/inputstd_msgs/StringUpdate the message dynamically
/roboticks/hello_world/statusstd_msgs/StringNode status (JSON)
ServiceTypeDescription
/roboticks/hello_world/enablestd_srvs/SetBoolEnable/disable publishing

Running the Example

Build the ROS2 package:
# Source ROS2
source /opt/ros/humble/setup.bash

# Build
cd examples/Ros2HelloWorldModule
./build_ros2_package.sh

# Source the workspace
source ros2_ws/install/setup.bash
Test standalone:
# Run directly
ros2 run roboticks_hello_world hello_world_node

# With parameters
ros2 run roboticks_hello_world hello_world_node --ros-args \
    -p message:="Custom message" \
    -p rate_hz:=2.0
Run with Roboticks:
# Start a session with the composition
roboticks session start --composition Ros2HelloWorldComposition --mode prod

Interacting with the Running Node

While the session is running, you can interact with the node via ROS2:
# Monitor output
ros2 topic echo /roboticks/hello_world/output

# Update message dynamically
ros2 topic pub --once /roboticks/hello_world/input \
    std_msgs/String "data: 'New message!'"

# Enable/disable publishing
ros2 service call /roboticks/hello_world/enable \
    std_srvs/srv/SetBool "{data: false}"

Composition Example

The composition bundles multiple modules together:
# Ros2HelloWorldComposition.yaml
name: Ros2HelloWorldComposition
version: 1.0.0
description: "ROS2 HelloWorld with Roboticks bridge"

modes:
  - name: prod
    description: "Production mode - bridge + HelloWorld"
    processes:
      - Ros2BridgeModule
      - Ros2HelloWorldModule

  - name: bridge_only
    description: "ROS2 bridge only"
    processes:
      - Ros2BridgeModule

processes:
  - name: Ros2BridgeModule
    type: module
    binary: "Ros2BridgeModule/Ros2BridgeModule"
    config: "Ros2BridgeModule/config/Ros2BridgeModule.yaml"
    restart_policy: on_failure
    initialization_order: 1
    description: "ROS2 to Roboticks bridge"

  - name: Ros2HelloWorldModule
    type: module
    binary: "Ros2HelloWorldModule/Ros2HelloWorldModule"
    config: "Ros2HelloWorldModule/config/Ros2HelloWorldModule.yaml"
    restart_policy: on_failure
    initialization_order: 2
    description: "ROS2 HelloWorld node"

What Gets Recorded

During a session, Roboticks automatically captures:
DataLocationAccess
Module logsCloudDashboard → Sessions → Logs
ROS2 node logsCloudDashboard → Sessions → Logs
Rosbag filesCloudDashboard → Sessions → Artifacts
Node statusCloudReal-time in dashboard

Best Practices

Use a consistent namespace for all your topics:
/my_robot/sensors/lidar
/my_robot/sensors/camera
/my_robot/control/cmd_vel
This makes rosbag recording and debugging easier.
Make your nodes configurable via ROS2 parameters:
this->declare_parameter<double>("rate_hz", 1.0);
double rate = this->get_parameter("rate_hz").as_double();
Roboticks can then set these parameters at launch time.
Add a status topic that publishes node health:
status_pub_ = this->create_publisher<std_msgs::msg::String>(
    "/my_robot/status", 10);
This helps with monitoring in the dashboard.
Your node should clean up properly on SIGTERM:
rclcpp::on_shutdown([this]() {
    RCLCPP_INFO(this->get_logger(), "Shutting down gracefully");
    // Cleanup code here
});

More Examples

Check the roboticks-examples repository for more examples:
  • Ros2BridgeModule - Bidirectional bridge between ROS2 and Roboticks
  • HelloWorldModule - Non-ROS2 example showing basic module concepts
  • Custom compositions - Examples of multi-module setups

Next Steps