Documentation Index
Fetch the complete documentation index at: https://docs.roboticks.io/llms.txt
Use this file to discover all available pages before exploring further.
Creating Modules
This guide walks through creating a new module from scratch using the SDK’s convention-over-configuration approach.
Module Structure
Every module follows this structure:
modules/MyModule/
├── config/
│ └── My.yaml # Module configuration
├── src/
│ ├── MyTask.hpp # Task header
│ └── MyTask.cpp # Task implementation
├── build/
│ └── generated/
│ └── MyTask.generated.hpp # Auto-generated
└── CMakeLists.txt
Step-by-Step Guide
Step 1: Create Directory Structure
# Create module directory (PascalCase)
mkdir -p modules/MyNewModule/{config,src,build}
cd modules/MyNewModule
Step 2: Create Configuration
Create config/MyNew.yaml:
# Module identification
name: MyNewModule
version: 1.0.0
description: "My custom robotics module"
# Module configuration
module:
tasks:
- name: MyNewTask
description: "Processes sensor data"
update_rate_hz: 10 # Called 10 times per second
# Define I/O ports (auto-generates C++ code)
inputs:
- name: sensor_data
topic: "/sensors/lidar"
message_type: "roboticks.messages.sensors.PointCloud"
qos: "BEST_EFFORT"
outputs:
- name: status
topic: "/my/status"
message_type: "roboticks.messages.common.StringMessage"
qos: "RELIABLE"
# Custom configuration values
custom:
threshold: 0.5
max_points: 1000
logging:
level: "INFO"
log_to_file: true
log_file: "/var/roboticks/logs/modules/mynew.log"
Step 3: Create CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(MyNewModule VERSION 1.0.0 LANGUAGES CXX)
# Find SDK root and include helpers
get_filename_component(ROBOTICKS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE)
include(${ROBOTICKS_ROOT}/packages/roboticks-module/cmake/RoboticksModuleHelpers.cmake)
# Auto-detects config, generates I/O code, verifies files
roboticks_module_init()
# Create the module executable
roboticks_add_module_executable(
TARGET ${PROJECT_NAME}
SOURCES src/MyNewTask.cpp
)
Create src/MyNewTask.hpp:
#pragma once
#include "MyNewTask.generated.hpp" // Auto-generated base class!
class MyNewTask : public roboticks::task::MyNewTaskIO {
public:
explicit MyNewTask(const std::string& config);
~MyNewTask() override = default;
protected:
// Lifecycle hooks
bool onInitialize() override;
bool onStart() override;
void onUpdate() override;
void onStop() override;
private:
double threshold_;
int max_points_;
int update_count_ = 0;
};
Step 5: Create Task Implementation
Create src/MyNewTask.cpp:
#include "MyNewTask.hpp"
#include <roboticks/module/TaskFactory.hpp>
// Auto-register with the task factory
static roboticks::module::TaskRegistrar<MyNewTask> registrar("MyNewTask");
MyNewTask::MyNewTask(const std::string& config)
: MyNewTaskIO(config) // Base class parses config
{
// Read custom config values
threshold_ = getConfigDouble("custom.threshold", 0.5);
max_points_ = getConfigInt("custom.max_points", 1000);
ROBOTICKS_INFO(*getLogger(),
"MyNewTask created with threshold={}, max_points={}",
threshold_, max_points_);
}
bool MyNewTask::onInitialize() {
ROBOTICKS_INFO(*getLogger(), "Initializing MyNewTask...");
// Setup resources here
return true;
}
bool MyNewTask::onStart() {
ROBOTICKS_INFO(*getLogger(), "Starting MyNewTask...");
return true;
}
void MyNewTask::onUpdate() {
update_count_++;
// Read from input port (auto-generated member: sensor_data_input_)
if (sensor_data_input_->hasData()) {
auto& data = sensor_data_input_->getData();
ROBOTICKS_DEBUG(*getLogger(), "Received {} points", data.points.size());
}
// Publish to output port (auto-generated member: status_output_)
roboticks::messages::common::StringMessage msg(
"Processing OK",
update_count_
);
status_output_->publish(msg);
}
void MyNewTask::onStop() {
ROBOTICKS_INFO(*getLogger(), "Stopped after {} updates", update_count_);
}
Step 6: Build and Run
cd build
cmake .. # Generates MyNewTask.generated.hpp
make -j$(nproc)
# Run the module
./MyNewModule
What Gets Auto-Generated
When CMake runs, it automatically:
- Finds config - Locates
config/MyNew.yaml
- Verifies source files - Checks
src/MyNewTask.hpp and .cpp exist
- Generates I/O code - Creates
build/generated/MyNewTask.generated.hpp:
// Auto-generated - DO NOT EDIT
namespace roboticks::task {
class MyNewTaskIO : public TaskBase {
protected:
// Input ports (from YAML inputs)
std::unique_ptr<Subscriber<PointCloud>> sensor_data_input_;
// Output ports (from YAML outputs)
std::unique_ptr<Publisher<StringMessage>> status_output_;
void setupPorts() override {
sensor_data_input_ = createSubscriber<PointCloud>(
"/sensors/lidar", QoS::BEST_EFFORT);
status_output_ = createPublisher<StringMessage>(
"/my/status", QoS::RELIABLE);
}
};
} // namespace
Naming Conventions
| Component | Convention | Example |
|---|
| Module directory | PascalCase | MyNewModule/ |
| Config file | {Name}.yaml | MyNew.yaml |
| Task class | {Name}Task | MyNewTask |
| Task files | {Name}Task.{hpp,cpp} | MyNewTask.cpp |
| Port members | {name}_{input,output}_ | sensor_data_input_ |
Configuration Options
Task Configuration
module:
tasks:
- name: TaskName
description: "Task description"
update_rate_hz: 10 # Update frequency
inputs: [] # Input ports
outputs: [] # Output ports
custom: # Custom key-value config
key: value
Port Configuration
inputs:
- name: sensor_data # Becomes sensor_data_input_
topic: "/topic/name" # Topic name
message_type: "..." # Message class
qos: "BEST_EFFORT" # RELIABLE or BEST_EFFORT
outputs:
- name: status # Becomes status_output_
topic: "/status/topic"
message_type: "..."
qos: "RELIABLE"
Logging Configuration
logging:
level: "DEBUG" # DEBUG, INFO, WARN, ERROR
log_to_file: true
log_file: "/path/to/log.log"
Best Practices
Each module should do one thing well. Split complex functionality into multiple modules that communicate via messaging.
Use meaningful topic names
Topic names should describe the data: /sensors/lidar/points, /control/velocity, /status/health
- Use
RELIABLE for critical data (commands, status)
- Use
BEST_EFFORT for high-frequency sensor data
Handle initialization failures
Return false from onInitialize() if setup fails - the framework will handle cleanup.
Next Steps
Messaging System
Learn about pub/sub messaging and QoS