Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Documentation Overview

📚 About This Documentation

This documentation covers the complete miniROS-rs robotics middleware system, built with the philosophy of maximum robotics performance, minimum complexity.

🛠️ Local Development

Prerequisites

# Install mdbook
cargo install mdbook

Build and Serve

cd docs

# Serve with live reload (recommended for development)
mdbook serve --open

# Or just build static files
mdbook build

The documentation will be available at http://localhost:3000

📁 Documentation Structure

Core Concepts

User Guide

Package Development

Advanced Topics

Development

🎯 Key Features Documented

Focused Robotics Middleware

  • Core ROS2 Patterns: Pub/Sub, Services, Actions, Parameters
  • 3D Visualization: Built-in Rerun integration
  • Multiple Transports: DDS, TCP, UDP support
  • Python Compatibility: ROS2 rclpy-compatible API
  • High Performance: Rust-based async implementation

Real-World Examples

  • TurtleBot Control System: Complete robotics package
  • Multi-Language Integration: Rust + Python workflows
  • Performance Benchmarks: Production-ready optimizations
  • Package Management: Professional development patterns

📊 Documentation Coverage

The miniROS-rs documentation provides:

Coverage AreaContent
Examples8 progressive tutorials from basic to complete systems
API ReferenceComplete coverage of all public APIs
LanguagesRust and Python with ROS2 compatibility
VisualizationBuilt-in 3D visualization with Rerun
ArchitectureMulti-transport system design
PerformanceBenchmarks and optimization guides
Package DevelopmentReal-world package examples
CLI ToolsComprehensive tooling documentation

🚀 Getting Started Paths

For Beginners

  1. Introduction - Understand what miniROS-rs is
  2. Quick Start - Build your first system
  3. Examples - Learn step by step
  4. Package Examples - Real-world implementations

For ROS2 Users

  1. Core Concepts - Architecture differences
  2. Python Bindings - Familiar rclpy API
  3. DDS Transport - ROS2 compatibility
  4. Package Examples - Migration patterns

For System Architects

  1. Transport Architecture - Multi-transport design
  2. Performance Optimization - Production tuning
  3. Package Examples - System design patterns
  4. API Reference - Complete system interfaces

For Developers

  1. CLI Usage Guide - Development tools
  2. Scripts Guide - Build automation
  3. CI/CD Automation - Development workflow
  4. API Reference - Implementation details

🎯 Best Practices Documented

Development Workflow

  • Smart CLI Tools: Dual Rust/Python CLI with intelligent routing
  • Package Structure: Modular design patterns
  • Testing Strategy: Unit and integration testing
  • Performance Monitoring: Built-in benchmarking

Production Deployment

  • Multi-Transport Setup: DDS, TCP, UDP configurations
  • Safety Patterns: Emergency stops and validation
  • System Integration: Cross-language communication
  • Monitoring: Health checks and diagnostics

Code Quality

  • Type Safety: Rust type system benefits
  • Error Handling: Robust error patterns
  • Async Programming: High-performance async patterns
  • Cross-Language: Seamless Rust-Python integration

✏️ Contributing to Documentation

Content Guidelines

  1. Complete Coverage: Document all features and APIs
  2. Progressive Learning: Start simple, build complexity
  3. Real Examples: Use actual working code
  4. ROS2 Compatibility: Emphasize familiar patterns
  5. Performance Focus: Include benchmarks and tips

Writing Style

  • Clear and Concise: Easy to understand explanations
  • Code-Heavy: Show don’t just tell
  • Beginner Friendly: Assume basic robotics knowledge only
  • Production Ready: Include real-world considerations

Philosophy: Maximum robotics performance, minimum complexity 🤖📚

Introduction

miniROS-rs is a lightweight, high-performance robotics middleware implementation written in Rust with Python bindings. It provides core communication primitives for building distributed robotics systems.

Core Philosophy

“Mini” means focused - miniROS-rs implements essential robotics communication patterns without the complexity of a full ROS2 distribution:

  • Publisher/Subscriber - Type-safe message passing
  • Services - Request/response communication
  • Actions - Long-running task management
  • Parameters - Dynamic configuration
  • Discovery - Automatic node detection

Key Features

Multi-Language Support

  • Rust Core - High-performance implementation with zero-cost abstractions
  • Python Bindings - ROS2 rclpy-compatible API for easy adoption
  • Type Safety - Compile-time message validation and serialization

Transport Flexibility

  • Memory Broker - In-process communication for single-node applications
  • TCP Transport - Reliable network communication with automatic reconnection
  • DDS Transport - Industry-standard distributed communication
  • UDP Transport - Low-latency multicast for real-time data

Built-in Visualization

  • Rerun Integration - 3D visualization for robotics data
  • Real-time Streaming - Live sensor data and robot state visualization
  • Multiple Data Types - Point clouds, poses, images, and custom data

Architecture

miniROS-rs follows a modular architecture:

┌─────────────────┐    ┌─────────────────┐
│   Application   │    │   Python API    │
│      Code       │    │  (rclpy-like)   │
└─────────────────┘    └─────────────────┘
         │                       │
         └───────────────────────┤
                                 ▼
         ┌─────────────────────────────────┐
         │         Rust Core              │
         │  • Node Management             │
         │  • Message Serialization       │
         │  • Type System                 │
         └─────────────────────────────────┘
                         │
                         ▼
         ┌─────────────────────────────────┐
         │      Transport Layer           │
         │  • Memory Broker               │
         │  • TCP/UDP                     │
         │  • DDS                         │
         └─────────────────────────────────┘

When to Use miniROS-rs

✅ Ideal For:

  • Learning robotics concepts - Simple, clear APIs
  • High-performance applications - Rust’s zero-cost abstractions
  • Prototyping - Quick iteration with Python compatibility
  • Embedded systems - Minimal resource requirements
  • Cross-platform development - Works on Linux, macOS, Windows

🤔 Consider ROS2 For:

  • Large, complex systems - Full ecosystem with navigation, perception
  • Established workflows - Teams already using ROS2 tools
  • Third-party packages - Extensive package ecosystem
  • Custom message types - Complex message definitions (coming soon)

Getting Started

The fastest way to understand miniROS-rs is through examples:

  1. Quick Start - 5-minute setup and basic usage
  2. Examples - Progressive learning from basic to advanced
  3. Python Bindings - ROS2-compatible Python API
  4. API Reference - Complete function and type documentation

Design Principles

Performance First

  • Async by default - Non-blocking I/O for maximum throughput
  • Zero-copy where possible - Minimize memory allocations
  • Type-safe serialization - Compile-time optimization

Developer Experience

  • Clear error messages - Helpful debugging information
  • Familiar APIs - ROS2-like interfaces for easy migration
  • Comprehensive documentation - Examples for every feature

Minimal Dependencies

  • Core functionality only - No unnecessary features
  • Optional features - Enable visualization, Python bindings as needed
  • Small binary size - Suitable for resource-constrained environments

miniROS-rs aims to provide 90% of ROS2’s functionality with 10% of the complexity, making it ideal for learning, prototyping, and high-performance robotics applications.


miniROS: Essential robotics, maximum efficiency

Quick Start

Get miniROS-rs running in 5 minutes with pub/sub, services, actions, and visualization.

📦 Installation

Rust

Add to your Cargo.toml:

[dependencies]
mini-ros = "0.1"
tokio = { version = "1.0", features = ["full"] }

# With visualization
mini-ros = { version = "0.1", features = ["visualization"] }

Python (ROS2 Compatible)

# Clone repository
git clone https://github.com/ruziniuuuuu/miniROS-rs
cd miniROS-rs

# Install build tools
pip install maturin

# Build Python bindings
maturin develop --features python

🚀 Basic Example

Rust: Complete Communication

Create src/main.rs:

use mini_ros::prelude::*;
use std::time::Duration;
use tokio::time::sleep;

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize logging
    tracing_subscriber::fmt::init();
    
    // Create and initialize node
    let mut node = Node::new("demo_node")?;
    node.init().await?;
    
    println!("🚀 miniROS-rs Demo Started");
    
    // Create publisher and subscriber
    let publisher = node.create_publisher::<StringMsg>("/hello").await?;
    let subscriber = node.create_subscriber::<StringMsg>("/hello").await?;
    
    // Set up message callback
    subscriber.on_message(|msg| {
        println!("📨 Received: {}", msg.data);
    })?;
    
    // Create service
    let _service = node.create_service("/add", |req: (i32, i32)| {
        Ok(req.0 + req.1)
    }).await?;
    
    let service_client = node.create_service_client::<(i32, i32), i32>("/add").await?;
    
    // Demo the system
    println!("=== Testing Communication ===");
    
    // Test pub/sub
    let message = StringMsg { data: "Hello miniROS-rs!".to_string() };
    publisher.publish(&message).await?;
    
    // Test service
    let result = service_client.call((10, 32)).await?;
    println!("🔧 Service result: 10 + 32 = {}", result);
    
    // Allow time for message processing
    sleep(Duration::from_millis(100)).await;
    
    println!("✅ Demo completed successfully!");
    Ok(())
}

Run with:

cargo run

Python: ROS2-Compatible API

Create demo.py:

#!/usr/bin/env python3
import mini_ros
import time

def main():
    print("🚀 miniROS-rs Python Demo")
    
    # Initialize (same as rclpy.init())
    mini_ros.init()
    
    # Create node (same as rclpy.Node)
    node = mini_ros.Node('demo_node')
    
    # Publisher (same as node.create_publisher)
    pub = node.create_publisher(mini_ros.StringMessage, '/hello', 10)
    
    # Subscriber (same as node.create_subscription)
    def callback(msg):
        print(f"📨 Received: {msg.data}")
    
    sub = node.create_subscription(mini_ros.StringMessage, '/hello', callback, 10)
    
    # Publish message
    msg = mini_ros.StringMessage()
    msg.data = "Hello from Python!"
    pub.publish(msg)
    
    # Brief pause for message processing
    time.sleep(0.1)
    
    print("✅ Python demo completed!")
    
    # Cleanup (same as rclpy.shutdown())
    node.destroy_node()
    mini_ros.shutdown()

if __name__ == '__main__':
    main()

Run with:

python demo.py

🎯 Core Concepts

Nodes

Computational units that manage communication:

#![allow(unused)]
fn main() {
// Basic node
let mut node = Node::new("robot_controller")?;
node.init().await?;

// Node with custom domain ID
let context = Context::with_domain_id(10)?;
let node = Node::with_context("isolated_robot", context)?;
}

Publishers

Send messages to topics:

#![allow(unused)]
fn main() {
// String messages
let pub = node.create_publisher::<StringMsg>("/status").await?;
pub.publish(&StringMsg { data: "Ready".into() }).await?;

// Numeric data
let int_pub = node.create_publisher::<Int32Msg>("/counter").await?;
int_pub.publish(&Int32Msg { data: 42 }).await?;
}

Subscribers

Receive messages from topics:

#![allow(unused)]
fn main() {
let sub = node.create_subscriber::<StringMsg>("/commands").await?;
sub.on_message(|msg| {
    println!("Command: {}", msg.data);
})?;
}

Services

Request/response communication:

#![allow(unused)]
fn main() {
// Service server
let service = node.create_service("/calculate", |x: i32| {
    Ok(x * x)  // Return square of input
}).await?;

// Service client
let client = node.create_service_client::<i32, i32>("/calculate").await?;
let result = client.call(5).await?; // Returns 25
}

Actions

Long-running tasks with feedback:

#![allow(unused)]
fn main() {
use mini_ros::action::{ActionServer, GoalStatus};

// Action server
let action_server = ActionServer::new(&node, "/navigate").await?;

action_server.on_goal(|goal| async move {
    println!("Navigating to: {:?}", goal);
    // Simulation of long-running task
    GoalStatus::Succeeded
}).await?;
}

Parameters

Dynamic configuration:

#![allow(unused)]
fn main() {
use mini_ros::parameter::{ParameterServer, ParameterValue};

let param_server = ParameterServer::new();
param_server.set_parameter("robot_name", ParameterValue::String("Bot1".into()))?;
param_server.set_parameter("max_speed", ParameterValue::Float(2.0))?;

// Retrieve parameters
if let Some(name) = param_server.get_parameter("robot_name")? {
    println!("Robot name: {:?}", name);
}
}

🎨 Visualization

With Rerun integration:

#![allow(unused)]
fn main() {
// Enable visualization feature
use mini_ros::visualization::RerunLogger;

let logger = RerunLogger::new("robot_demo")?;
logger.log_point_cloud(&points).await?;
logger.log_pose(&robot_pose).await?;
}

🌐 Transport Options

Memory Broker (Default)

Fastest for single-process communication:

#![allow(unused)]
fn main() {
let mut node = Node::new("local_node")?;
// Uses memory broker automatically
}

TCP Transport

For network communication:

#![allow(unused)]
fn main() {
// Enable TCP transport feature
let mut node = Node::new("network_node")?;
node.init().await?;
}

DDS Transport

ROS2 compatibility:

#![allow(unused)]
fn main() {
// Enable dds-transport feature
use mini_ros::dds_transport::DdsTransport;

let transport = DdsTransport::new(0).await?;
let publisher = transport.create_publisher::<StringMsg>("topic").await?;
}

📋 Examples Walkthrough

Run the provided examples to learn progressively:

# Basic pub/sub
cargo run --example 01_basic_pubsub

# Custom message types
cargo run --example 02_custom_messages

# Service communication
cargo run --example 03_services

# Actions and parameters
cargo run --example 04_actions_parameters

# Visualization (requires visualization feature)
cargo run --example 04_visualization_basic --features visualization

# Complete system demo
cargo run --example 07_integrated_system

🔧 Development Tips

Error Handling

#![allow(unused)]
fn main() {
use mini_ros::error::{MiniRosError, Result};

async fn robust_communication() -> Result<()> {
    let mut node = Node::new("robust_node")?;
    node.init().await?;
    
    match node.create_publisher::<StringMsg>("/topic").await {
        Ok(pub) => println!("Publisher created"),
        Err(e) => eprintln!("Failed to create publisher: {}", e),
    }
    
    Ok(())
}
}

Async Best Practices

#![allow(unused)]
fn main() {
// Spawn concurrent tasks
tokio::spawn(async move {
    while let Some(msg) = subscriber.recv().await {
        process_message(msg).await;
    }
});

// Use timeouts
use tokio::time::timeout;

let result = timeout(Duration::from_secs(5), service_client.call(request)).await;
}

🐍 Python Integration

miniROS-rs provides a Python API that closely mirrors ROS2’s rclpy:

# Nearly identical to ROS2 code
import mini_ros as rclpy  # Drop-in replacement
from mini_ros import StringMessage as String

# Standard ROS2 patterns work
rclpy.init()
node = rclpy.create_node('my_node')
pub = node.create_publisher(String, 'topic', 10)
node.destroy_node()
rclpy.shutdown()

📚 Next Steps

  1. Examples - Comprehensive learning examples
  2. Python Bindings - Complete Python API reference
  3. API Documentation - Full Rust API reference
  4. Visualization - 3D visualization with Rerun
  5. Performance - Optimization techniques

Start with the examples and gradually explore more advanced features!

Core Concepts

Understanding the building blocks of miniROS-rs.

Nodes

Nodes are independent processes that communicate with each other.

#![allow(unused)]
fn main() {
// Create a node
let mut node = Node::new("robot_controller")?;
node.init().await?;

// Each node has a unique name and can create publishers/subscribers
}

Key Points:

  • Each node runs independently
  • Nodes communicate via topics and services
  • Multiple nodes can run in the same process

Messages

Messages are data structures sent between nodes.

Built-in Messages

#![allow(unused)]
fn main() {
use mini_ros::message::*;

// Simple types
let string_msg = StringMsg { data: "Hello".to_string() };
let number_msg = Float64Msg { data: 42.0 };
let int_msg = Int32Msg { data: 100 };
}

Custom Messages

#![allow(unused)]
fn main() {
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct RobotPose {
    x: f64,
    y: f64,
    theta: f64,
}

// Automatically implements Message trait
}

Communication Patterns

Publisher/Subscriber

Asynchronous, many-to-many communication:

#![allow(unused)]
fn main() {
// Publisher side
let publisher = node.create_publisher::<StringMsg>("robot_status").await?;
publisher.publish(&StringMsg { data: "Moving".to_string() }).await?;

// Subscriber side  
let subscriber = node.create_subscriber::<StringMsg>("robot_status").await?;
subscriber.on_message(|msg| {
    println!("Robot status: {}", msg.data);
}).await?;
}

When to use: Sensor data, status updates, continuous streams

Services

Synchronous, one-to-one request/response:

#![allow(unused)]
fn main() {
// Server side
let _service = node.create_service("calculate_distance", |req: StringMsg| -> Result<Float64Msg> {
    let distance = req.data.len() as f64; // Simple calculation
    Ok(Float64Msg { data: distance })
}).await?;

// Client side
let client = node.create_service_client::<StringMsg, Float64Msg>("calculate_distance").await?;
let response = client.call(StringMsg { data: "test".to_string() }).await?;
}

When to use: Calculations, configuration, one-time requests

Topics

Topics are named channels for message passing:

#![allow(unused)]
fn main() {
// Topic names are strings
"/robot/pose"           // Robot position
"/sensors/lidar"        // Laser scan data  
"/camera/image"         // Camera images
"/mission/status"       // Mission updates
}

Naming Convention:

  • Use forward slashes for hierarchy
  • Lowercase with underscores
  • Descriptive and consistent

Error Handling

miniROS-rs uses Rust’s Result type:

use mini_ros::error::Result;

#[tokio::main]  
async fn main() -> Result<()> {
    let mut node = Node::new("my_node")?;  // Can fail
    node.init().await?;                    // Can fail
    
    // Handle specific errors
    match node.create_publisher::<StringMsg>("test").await {
        Ok(publisher) => { /* use publisher */ },
        Err(e) => println!("Failed to create publisher: {}", e),
    }
    
    Ok(())
}

Best Practices

Node Design

  • One node per logical component (sensor, controller, planner)
  • Keep nodes small and focused
  • Use descriptive names

Message Design

  • Keep messages simple and flat when possible
  • Use appropriate data types (f32 vs f64)
  • Include timestamps for time-sensitive data

Communication

  • Use pub/sub for streaming data
  • Use services for calculations and queries
  • Choose topic names carefully - they’re hard to change later

Next Steps

CLI Usage Guide

🤖 Two CLI Versions: Smart Design

miniROS provides two complementary CLI tools, following the “mini” philosophy: core functionality, minimum complexity.

🦀 Rust CLI: mini_ros

Primary Choice - High-Performance System Operations

# Core functionality - fast and reliable
mini_ros launch turtlebot simulation
mini_ros run turtlebot controller  
mini_ros pkg list

Use Cases:

  • Production deployments
  • High-performance requirements
  • Complex system orchestration
  • Package management and launch files

🐍 Python CLI: mini_ros_py

Python Ecosystem Specialized Tool

# Python-specific operations
mini_ros_py run minimal_publisher
mini_ros_py examples list
mini_ros_py test --coverage

Use Cases:

  • Python development and testing
  • Example code management
  • Rapid prototyping
  • Teaching and learning

🚀 Quick Start

1. Build Both CLIs

# Build Rust CLI (recommended first)
bash scripts/setup.sh

# Or manual build
cargo build --bin mini_ros
cd python && pip install -e .

2. Verify Installation

# Test Rust CLI
mini_ros --help

# Test Python CLI
mini_ros_py --help

3. Smart Wrapper (Optional)

# Use universal wrapper that auto-selects best CLI
bash scripts/mini_ros_wrapper.sh pkg list

📋 Command Comparison

FeatureRust (mini_ros)Python (mini_ros_py)
Package Management✅ Full support❌ Read-only
Launch System✅ Complete❌ Not available
Node Execution✅ Rust + Python✅ Python only
Examples❌ Basic✅ Advanced management
Testing❌ Not available✅ Full test suite
Performance🚀 Optimized🐍 Standard
Completions✅ All shells⚠️ Basic

🔧 Advanced Usage

Rust CLI Features

Package Management

# List all packages with details
mini_ros pkg list

# Create new package with Python support
mini_ros pkg create my_robot --path ./packages --python

# Show detailed package information
mini_ros pkg info turtlebot

Launch System

# Launch complete systems
mini_ros launch turtlebot full_system

# Launch with custom arguments
mini_ros launch my_pkg simulation --args debug verbose

Shell Completions

# Generate completions for your shell
mini_ros completions bash > ~/.bash_completion
mini_ros completions zsh > ~/.zsh_completions/_mini_ros

Python CLI Features

Example Management

# List available Python examples
mini_ros_py examples list

# Run specific example with arguments
mini_ros_py run turtlebot_controller --args --speed 0.5

# Install examples to custom directory
mini_ros_py examples install ~/my_examples

Testing and Development

# Run full test suite with coverage
mini_ros_py test --coverage --verbose

# Run specific test pattern
mini_ros_py test test_basic

# Install package in development mode
mini_ros_py install --dev

⚡ Performance Tips

When to Use Rust CLI

  • Production deployments
  • Multi-node systems
  • High-frequency operations
  • System integration

When to Use Python CLI

  • Python development workflow
  • Testing and validation
  • Learning and tutorials
  • Quick prototyping

🐛 Troubleshooting

Common Issues

CLI Not Found

# Rust CLI
bash scripts/setup.sh build
export PATH="$PWD/target/debug:$PATH"

# Python CLI
cd python && pip install -e .

Permission Errors

# Make scripts executable
chmod +x target/debug/mini_ros
chmod +x scripts/*.sh

Python Module Not Found

# Ensure Python package is installed
cd python && pip install -e .

# Check if mini_ros module is available
python -c "import mini_ros; print('✅ Available')"

Environment Variables

# Control logging level
export MINI_ROS_LOG=debug

# Override default package paths
export MINI_ROS_PACKAGE_PATH=/path/to/packages

🎯 Best Practices

1. Use the Right Tool

  • Rust CLI for system operations
  • Python CLI for Python development

2. Setup Shell Completions

# Add to your shell config
mini_ros completions $(basename $SHELL) > ~/.completion_mini_ros
source ~/.completion_mini_ros

3. Alias for Convenience

# Add to ~/.bashrc or ~/.zshrc
alias mrs="mini_ros"
alias mrspy="mini_ros_py"
alias mrsw="bash scripts/mini_ros_wrapper.sh"

4. Development Workflow

# Start with Python for rapid development
mini_ros_py run my_example

# Move to Rust for production
mini_ros run my_pkg my_node

📚 Examples

Complete Development Cycle

# 1. Create package (Rust CLI)
mini_ros pkg create my_robot --python

# 2. Develop with Python
mini_ros_py run minimal_publisher

# 3. Test thoroughly
mini_ros_py test --coverage

# 4. Deploy with Rust
mini_ros launch my_robot production

Cross-Language Development

# Run Rust node
mini_ros run turtlebot controller

# In another terminal, run Python utilities
mini_ros_py run turtlebot_monitor

# Both communicate via miniROS middleware

Philosophy: Maximum robotics performance, minimum complexity 🤖⚡

Scripts Guide

🤖 Script Architecture

miniROS provides a fully integrated script system, following the “mini” philosophy: minimum scripts, maximum functionality.

📁 Scripts Directory Structure

scripts/
├── setup.sh              # 🔧 Unified setup script (all-in-one)
└── mini_ros_wrapper.sh    # 🤖 Smart CLI wrapper

🚀 Main Setup Script: setup.sh

🎯 Philosophy

One script, all miniROS needs - Unified script handles all installation, configuration, and maintenance tasks.

📋 Available Commands

# Complete setup (recommended for new users)
bash scripts/setup.sh

# Show help and all commands
bash scripts/setup.sh help

# Build CLIs only (no environment configuration)
bash scripts/setup.sh build

# Setup environment only (if CLIs already built)
bash scripts/setup.sh env

# Test current installation
bash scripts/setup.sh test

# Clean build artifacts
bash scripts/setup.sh clean

🔧 What It Does

Complete Setup (bash scripts/setup.sh)

  1. 🔨 Builds Rust CLI - Compiles mini_ros binary
  2. 🐍 Installs Python CLI - Installs mini_ros_py package
  3. 🔧 Configures Environment - Adds PATH, aliases, completions
  4. 📄 Backs Up Configs - Safely backs up shell config files
  5. 🧪 Tests Installation - Verifies everything works
  6. 💡 Shows Next Steps - Guides you on usage

Build Only (bash scripts/setup.sh build)

  • Builds both Rust and Python CLIs
  • No environment modification
  • Perfect for CI/CD or when you want manual control

Environment Only (bash scripts/setup.sh env)

  • Configures shell environment (PATH, aliases, completions)
  • Assumes CLIs are already built
  • Useful for setting up new terminals

Test (bash scripts/setup.sh test)

  • Checks if CLIs are built and functional
  • Verifies environment setup
  • Great for troubleshooting

Clean (bash scripts/setup.sh clean)

  • Removes build artifacts
  • Cleans both Rust and Python builds
  • Fresh start capability

🛡️ Safety Features

  • Automatic Backups - Shell configs backed up with timestamps
  • Duplicate Detection - Won’t add duplicate PATH entries
  • Error Handling - Graceful failure with helpful messages
  • Shell Detection - Supports bash, zsh, fish automatically

🤖 Smart Wrapper: mini_ros_wrapper.sh

🎯 Philosophy

Automatic tool selection - Uses the best CLI for each task without user intervention.

🧠 Smart Logic

# System operations → Rust CLI (high performance)
bash scripts/mini_ros_wrapper.sh pkg list
bash scripts/mini_ros_wrapper.sh launch turtlebot simulation

# Python operations → Python CLI (specialized)
bash scripts/mini_ros_wrapper.sh examples list
bash scripts/mini_ros_wrapper.sh test --coverage

# Fallback → Python CLI if Rust unavailable

🔍 Selection Rules

CommandCLI ChoiceReason
pkgRustPackage management performance
launchRustSystem orchestration
runRustNode execution performance
examplesPythonPython-specific functionality
testPythonPython testing suite
installPythonPython package management
run --listPythonPython examples listing

💡 Usage Examples

# These automatically choose the optimal CLI:
bash scripts/mini_ros_wrapper.sh pkg list
bash scripts/mini_ros_wrapper.sh examples list
bash scripts/mini_ros_wrapper.sh launch turtlebot simulation
bash scripts/mini_ros_wrapper.sh test --verbose

🔄 Workflow Integration

🏁 First Time Setup

# Clone repository
git clone https://github.com/ruziniuuuuu/miniROS-rs
cd miniROS-rs

# One-command setup
bash scripts/setup.sh

# Restart terminal or source config
source ~/.zshrc

🔄 Daily Development

# Use direct commands (post-setup)
mini_ros pkg list
mini_ros_py examples list

# Or use smart wrapper
bash scripts/mini_ros_wrapper.sh pkg info turtlebot
bash scripts/mini_ros_wrapper.sh examples install ~/my-examples

🧹 Maintenance

# Test installation
bash scripts/setup.sh test

# Clean and rebuild
bash scripts/setup.sh clean
bash scripts/setup.sh build

# Update environment (new terminal)
bash scripts/setup.sh env

🐚 Shell Support

✅ Fully Supported

  • bash - .bashrc configuration
  • zsh - .zshrc configuration
  • fish - config.fish configuration

🔧 What Gets Added

Bash/Zsh Configuration

# miniROS CLI PATH (auto-generated)
if [ -d "/path/to/miniROS-rs/target/debug" ]; then
    export PATH="/path/to/miniROS-rs/target/debug:$PATH"
fi

# miniROS conveniences
alias mrs="mini_ros"
alias mrspy="mini_ros_py"
alias mrsw="bash /path/to/miniROS-rs/scripts/mini_ros_wrapper.sh"

# miniROS completion (if available)
if command -v mini_ros >/dev/null 2>&1; then
    if [ -n "$BASH_VERSION" ]; then
        eval "$(mini_ros completions bash 2>/dev/null || true)"
    elif [ -n "$ZSH_VERSION" ]; then
        eval "$(mini_ros completions zsh 2>/dev/null || true)"
    fi
fi

Fish Configuration

# miniROS CLI PATH (auto-generated)
if test -d "/path/to/miniROS-rs/target/debug"
    set -gx PATH "/path/to/miniROS-rs/target/debug" $PATH
end

# miniROS conveniences
alias mrs="mini_ros"
alias mrspy="mini_ros_py"
alias mrsw="bash /path/to/miniROS-rs/scripts/mini_ros_wrapper.sh"

🎯 Best Practices

1. Use Complete Setup First

bash scripts/setup.sh  # Recommended for all users

2. Test Before Using

bash scripts/setup.sh test  # Verify installation

3. Use Aliases for Speed

mrs pkg list      # Short for mini_ros
mrspy examples    # Short for mini_ros_py
mrsw pkg info     # Smart wrapper

4. Clean When Issues Arise

bash scripts/setup.sh clean
bash scripts/setup.sh build

🐛 Troubleshooting

Command Not Found

# Check installation
bash scripts/setup.sh test

# Reinstall environment
bash scripts/setup.sh env

# Source config manually
source ~/.zshrc

Build Failures

# Clean and rebuild
bash scripts/setup.sh clean
bash scripts/setup.sh build

Permission Issues

# Ensure scripts are executable
chmod +x scripts/*.sh

Philosophy: One script system, unlimited robotics potential 🤖⚡

Examples

Learn miniROS with focused examples. Each demonstrates one core concept.

Quick Start

git clone https://github.com/ruziniuuuuu/miniROS-rs
cd miniROS-rs

# Run any example
cargo run --example 01_basic_pubsub

Message Packages

16 - ROS2 Message Packages

cargo run --example 16_message_packages_demo

What you’ll learn: ROS2-compatible message types

  • std_msgs, geometry_msgs, nav_msgs
  • Message validation and serialization
  • Cross-language compatibility

17 - New Message Types

cargo run --example 17_new_message_types_demo

What you’ll learn: Sensor and diagnostic messages

  • sensor_msgs (LaserScan, IMU, Image)
  • action_msgs (Goal tracking)
  • diagnostic_msgs (System health)

Core Examples (Rust)

01 - Basic Pub/Sub

cargo run --example 01_basic_pubsub

What you’ll learn: Create publishers and subscribers

  • Node creation
  • Topic-based communication
  • Message types

02 - Custom Messages

cargo run --example 02_custom_messages

What you’ll learn: Define your own message types

  • Serde serialization
  • Custom structs as messages
  • Type safety

03 - Services

cargo run --example 03_services

What you’ll learn: Request/response communication

  • Service servers
  • Service clients
  • Synchronous communication

Python Examples

All Python examples use identical ROS2 API:

Minimal Publisher

python python/examples/minimal_publisher.py
import mini_ros

mini_ros.init()
node = mini_ros.Node('publisher')
pub = node.create_publisher(mini_ros.String, '/topic', 10)

msg = mini_ros.String()
msg.data = 'Hello!'
pub.publish(msg)

node.destroy_node()
mini_ros.shutdown()

Minimal Subscriber

python python/examples/minimal_subscriber.py
import mini_ros

def callback(msg):
    print(f'Received: {msg.data}')

mini_ros.init()
node = mini_ros.Node('subscriber')
sub = node.create_subscription(mini_ros.String, '/topic', callback, 10)
mini_ros.spin(node)

Advanced Examples (Optional Features)

Actions (Long-running tasks)

cargo run --example 04_actions --features actions

Parameters (Dynamic config)

cargo run --example 05_parameters --features parameters

Visualization (3D display)

cargo run --example 06_visualization --features visualization

Multi-Terminal Demo

Terminal 1 - Publisher

cargo run --example 01_basic_pubsub

Terminal 2 - Subscriber

cargo run --example 01_basic_pubsub

Terminal 3 - Python Node

python python/examples/minimal_subscriber.py

All nodes automatically discover each other. No configuration needed.

Transport Options

Default TCP

cargo run --example 01_basic_pubsub

ROS2 Compatible DDS

cargo run --example 01_basic_pubsub --features dds-transport

Interoperates with ROS2 nodes using DDS.

Example Output

[INFO] Node 'publisher' initialized
[INFO] Publishing to '/chat': Hello miniROS!
[INFO] Node 'subscriber' received: Hello miniROS!

Clean, minimal logging. No debug noise.

Troubleshooting

Port Conflicts

# Use different port
MINI_ROS_PORT=8080 cargo run --example 01_basic_pubsub

Discovery Issues

# Check network
ping localhost

# Restart with debug
RUST_LOG=debug cargo run --example 01_basic_pubsub

Next Steps

  1. Start with 01-03 - Core patterns
  2. Try Python examples - ROS2 compatibility
  3. Add features - Actions, parameters as needed
  4. Build your robot - Use patterns in your project

Examples: Learn by doing, one concept at a time

Python Bindings

miniROS provides Python bindings that exactly match ROS2 rclpy API for core features.

Drop-in ROS2 Replacement

Replace your ROS2 imports:

# Instead of:
# import rclpy
# from std_msgs.msg import String

# Use:
import mini_ros
from mini_ros import String

Everything else stays the same.

Quick Setup

pip install maturin
maturin develop --features python

Core API

Node & Lifecycle

import mini_ros

# Initialize (like rclpy.init())
mini_ros.init()

# Create node
node = mini_ros.Node('my_node')

# Spin (like rclpy.spin())
mini_ros.spin(node)

# Cleanup (like rclpy.shutdown())
node.destroy_node()
mini_ros.shutdown()

Publisher/Subscriber

# Publisher (identical to rclpy)
pub = node.create_publisher(mini_ros.String, '/topic', 10)

msg = mini_ros.String()
msg.data = 'Hello!'
pub.publish(msg)

# Subscriber (identical to rclpy)
def callback(msg):
    print(f'Received: {msg.data}')

sub = node.create_subscription(
    mini_ros.String, '/topic', callback, 10
)

Services

# Service server
def add_callback(request, response):
    response.sum = request.a + request.b
    return response

srv = node.create_service(mini_ros.AddTwoInts, '/add', add_callback)

# Service client
client = node.create_client(mini_ros.AddTwoInts, '/add')
request = mini_ros.AddTwoInts.Request()
request.a = 2
request.b = 3

future = client.call_async(request)
response = future.result()  # Sum: 5

Message Types

# Built-in types (like std_msgs)
mini_ros.String()
mini_ros.Int32()  
mini_ros.Float64()
mini_ros.Bool()

# Access data fields
msg = mini_ros.String()
msg.data = "hello"

Migration from ROS2

✅ Compatible (no changes needed)

  • Node creation and management
  • Publisher/subscriber patterns
  • Service client/server
  • Basic message types
  • Spin and lifecycle

🚧 Optional Features

# Enable as needed
import mini_ros.actions      # Action client/server
import mini_ros.parameters   # Parameter client/server  
import mini_ros.visualization # 3D visualization

❌ Not Implemented

  • Custom message definitions
  • Advanced QoS policies
  • Timers and callbacks
  • Transformations (tf2)

Examples

Minimal Publisher

import mini_ros

mini_ros.init()
node = mini_ros.Node('publisher')
pub = node.create_publisher(mini_ros.String, '/chat', 10)

msg = mini_ros.String()
msg.data = 'Hello miniROS!'
pub.publish(msg)

node.destroy_node()
mini_ros.shutdown()

Minimal Subscriber

import mini_ros

def callback(msg):
    print(f'Got: {msg.data}')

mini_ros.init()
node = mini_ros.Node('subscriber')
sub = node.create_subscription(mini_ros.String, '/chat', callback, 10)
mini_ros.spin(node)

Performance Benefits

vs ROS2 rclpy

  • 10x faster startup - No ROS2 middleware overhead
  • Lower latency - Direct Rust backend
  • Less memory - Minimal runtime footprint
  • Simpler deployment - Single binary, no ROS2 installation

Memory Usage

ROS2 node:     ~50MB
miniROS node:  ~5MB

When to Use

✅ Perfect for:

  • ROS2 migration - Gradual transition
  • Simple applications - Pub/sub + services
  • Performance critical - Embedded systems
  • Learning - Clean API, no complexity

❌ Stick with ROS2 for:

  • Custom messages - Complex message definitions
  • Advanced features - QoS, security, lifecycle
  • Large ecosystems - Navigation, perception stacks

Roadmap

  • Custom message support
  • Timer and callback system
  • Advanced QoS options
  • More std_msgs types

miniROS Python: All the power, none of the complexity

3D Visualization

miniROS-rs includes built-in 3D visualization powered by Rerun, providing real-time data visualization for robotics applications without external dependencies.

🎯 Why Built-in Visualization?

  • Zero Setup: No separate tools or installations required
  • Real-time: Live data streaming with automatic updates
  • 3D Native: Built for robotics coordinate frames and transforms
  • Performance: Optimized for high-frequency robot data
  • Integration: Deep integration with miniROS-rs message types

🚀 Quick Start

Enable Visualization

Add the visualization feature to your Cargo.toml:

[dependencies]
mini-ros = { version = "0.1.2", features = ["visualization"] }

Basic Example

use mini_ros::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    let mut node = Node::new("viz_demo")?;
    node.init().await?;
    
    // Create visualizer
    #[cfg(feature = "visualization")]
    {
        let viz = node.create_visualizer("robot_viz").await?;
        
        // Log a 3D point
        viz.log_point("robot/position", [1.0, 2.0, 0.5]).await?;
        
        // Log a trajectory
        let trajectory = vec![
            [0.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [1.0, 1.0, 0.0],
            [1.0, 1.0, 1.0],
        ];
        viz.log_path("robot/trajectory", &trajectory).await?;
        
        // Log text information
        viz.log_text("robot/status", "Navigation active").await?;
    }
    
    Ok(())
}

Run with:

cargo run --example basic_viz --features visualization

📊 Visualization API

Core Visualizer

#![allow(unused)]
fn main() {
// Create visualizer instance
let viz = node.create_visualizer("app_name").await?;

// The visualizer automatically:
// - Spawns Rerun viewer
// - Manages connections
// - Handles data streaming
}

3D Points

#![allow(unused)]
fn main() {
// Single point
viz.log_point("entity/path", [x, y, z]).await?;

// Multiple points
let points = vec![
    [0.0, 0.0, 0.0],
    [1.0, 0.0, 0.0],
    [1.0, 1.0, 0.0],
];
viz.log_points("entity/path", &points).await?;

// Points with colors
viz.log_points_with_colors("markers", &points, &colors).await?;
}

Trajectories and Paths

#![allow(unused)]
fn main() {
// Robot trajectory
let path = vec![
    [0.0, 0.0, 0.0],
    [1.0, 0.0, 0.0],
    [2.0, 1.0, 0.0],
    [3.0, 1.0, 1.0],
];
viz.log_path("robot/trajectory", &path).await?;

// Planned vs actual paths
viz.log_path("planning/planned_path", &planned_path).await?;
viz.log_path("navigation/actual_path", &actual_path).await?;
}

Text and Labels

#![allow(unused)]
fn main() {
// Status information
viz.log_text("robot/status", "Navigating to waypoint").await?;

// Error messages
viz.log_text("system/errors", "Battery low: 15%").await?;

// Dynamic information
viz.log_text("telemetry/speed", &format!("Speed: {:.2} m/s", speed)).await?;
}

3D Meshes and Models

#![allow(unused)]
fn main() {
// Robot model (placeholder)
viz.log_mesh("robot/model", mesh_data).await?;

// Obstacle representation
viz.log_mesh("environment/obstacles", obstacle_mesh).await?;
}

Coordinate Frames

#![allow(unused)]
fn main() {
// Robot base frame
viz.log_transform("robot/base_link", position, orientation).await?;

// Sensor frames
viz.log_transform("robot/camera_link", cam_pos, cam_orient).await?;
viz.log_transform("robot/lidar_link", lidar_pos, lidar_orient).await?;
}

🤖 Robotics-Specific Features

Sensor Data Visualization

LIDAR Point Clouds

#![allow(unused)]
fn main() {
// LIDAR scan visualization
let scan_points: Vec<[f32; 3]> = lidar_data
    .ranges
    .iter()
    .enumerate()
    .map(|(i, &range)| {
        let angle = lidar_data.angle_min + i as f32 * lidar_data.angle_increment;
        [
            range * angle.cos(),
            range * angle.sin(),
            0.0,
        ]
    })
    .collect();

viz.log_points("sensors/lidar", &scan_points).await?;
}

Camera Data

#![allow(unused)]
fn main() {
// Camera pose and field of view
viz.log_transform("sensors/camera", camera_pos, camera_orient).await?;
viz.log_text("sensors/camera/info", &format!("FOV: {}°", fov)).await?;
}

IMU Data

#![allow(unused)]
fn main() {
// Orientation visualization
viz.log_transform("sensors/imu", position, imu_orientation).await?;
viz.log_text("sensors/imu/data", &format!("Accel: {:.2}", acceleration)).await?;
}

Robot State Visualization

Joint States

#![allow(unused)]
fn main() {
// Robot arm joint positions
for (i, joint_pos) in joint_positions.iter().enumerate() {
    viz.log_text(
        &format!("robot/joints/joint_{}", i),
        &format!("{:.2}°", joint_pos.to_degrees())
    ).await?;
}
}

Velocity and Forces

#![allow(unused)]
fn main() {
// Velocity vector
let velocity_end = [
    position[0] + velocity[0],
    position[1] + velocity[1], 
    position[2] + velocity[2],
];
viz.log_path("robot/velocity", &[position, velocity_end]).await?;
}

Path Planning

#![allow(unused)]
fn main() {
// Global path
viz.log_path("navigation/global_path", &global_path).await?;

// Local path
viz.log_path("navigation/local_path", &local_path).await?;

// Waypoints
viz.log_points("navigation/waypoints", &waypoints).await?;
}

Obstacle Avoidance

#![allow(unused)]
fn main() {
// Detected obstacles
viz.log_points("navigation/obstacles", &obstacle_points).await?;

// Safety zones
viz.log_mesh("navigation/safety_zone", safety_zone_mesh).await?;
}

📈 Real-time Data Streaming

Continuous Updates

#![allow(unused)]
fn main() {
use tokio::time::{interval, Duration};

let mut timer = interval(Duration::from_millis(100)); // 10 Hz

loop {
    timer.tick().await;
    
    // Update robot position
    let current_pos = get_robot_position();
    viz.log_point("robot/position", current_pos).await?;
    
    // Update sensor data
    let lidar_data = get_lidar_scan();
    viz.log_points("sensors/lidar", &lidar_data).await?;
    
    // Update status
    let status = get_robot_status();
    viz.log_text("robot/status", &status).await?;
}
}

Performance Optimization

#![allow(unused)]
fn main() {
// Batch updates for efficiency
let updates = vec![
    ("robot/position", current_position),
    ("robot/velocity", velocity_vector),
    ("robot/acceleration", accel_vector),
];

for (entity, data) in updates {
    viz.log_point(entity, data).await?;
}

// Use appropriate update frequencies
// High frequency: Robot pose (100Hz)
// Medium frequency: Sensor data (30Hz) 
// Low frequency: Status text (1Hz)
}

🔧 Integration Examples

Complete Robot Visualizer

#![allow(unused)]
fn main() {
use mini_ros::prelude::*;
use tokio::time::{interval, Duration};

struct RobotVisualizer {
    viz: Visualizer,
    position_sub: Subscriber<RobotPose>,
    lidar_sub: Subscriber<LaserScan>,
    status_sub: Subscriber<StringMsg>,
}

impl RobotVisualizer {
    async fn new(node: &mut Node) -> Result<Self> {
        let viz = node.create_visualizer("robot_system").await?;
        
        let position_sub = node.create_subscriber("/robot/pose").await?;
        let lidar_sub = node.create_subscriber("/sensors/lidar").await?;
        let status_sub = node.create_subscriber("/robot/status").await?;
        
        Ok(Self {
            viz,
            position_sub,
            lidar_sub,
            status_sub,
        })
    }
    
    async fn start(&self) -> Result<()> {
        // Set up callbacks
        self.position_sub.on_message({
            let viz = self.viz.clone();
            move |pose: RobotPose| {
                tokio::spawn(async move {
                    viz.log_point("robot/position", pose.position).await?;
                    viz.log_transform("robot/base_link", pose.position, pose.orientation).await?;
                });
            }
        })?;
        
        self.lidar_sub.on_message({
            let viz = self.viz.clone();
            move |scan: LaserScan| {
                tokio::spawn(async move {
                    let points = convert_scan_to_points(&scan);
                    viz.log_points("sensors/lidar", &points).await?;
                });
            }
        })?;
        
        self.status_sub.on_message({
            let viz = self.viz.clone();
            move |status: StringMsg| {
                tokio::spawn(async move {
                    viz.log_text("robot/status", &status.data).await?;
                });
            }
        })?;
        
        Ok(())
    }
}
}

Multi-Robot Visualization

#![allow(unused)]
fn main() {
// Visualize multiple robots
for (i, robot_pose) in robot_poses.iter().enumerate() {
    let entity_path = format!("robots/robot_{}", i);
    viz.log_point(&format!("{}/position", entity_path), robot_pose.position).await?;
    viz.log_transform(&format!("{}/base_link", entity_path), 
                     robot_pose.position, robot_pose.orientation).await?;
    viz.log_text(&format!("{}/id", entity_path), &format!("Robot {}", i)).await?;
}
}

🎮 Interactive Features

Viewing Controls

The Rerun viewer provides:

  • 3D Navigation: Mouse-based camera control
  • Timeline: Scrub through historical data
  • Entity Tree: Toggle visibility of different entities
  • Measurements: Distance and angle measurements
  • Screenshots: Export visualizations

Entity Organization

#![allow(unused)]
fn main() {
// Organize entities hierarchically
viz.log_point("robots/robot_1/sensors/lidar", lidar_pos).await?;
viz.log_point("robots/robot_1/actuators/gripper", gripper_pos).await?;
viz.log_point("robots/robot_2/sensors/camera", camera_pos).await?;

// Environment entities
viz.log_points("environment/obstacles", &obstacles).await?;
viz.log_points("environment/landmarks", &landmarks).await?;
}

📱 Running Examples

Basic Visualization

cargo run --example 04_visualization_basic --features visualization

Advanced 3D Scene

cargo run --example 06_visualization_advanced --features visualization

Integrated System with Visualization

cargo run --example 07_integrated_system --features visualization

🔧 Configuration and Setup

Automatic Viewer Launch

The visualizer automatically:

  1. Spawns the Rerun viewer application
  2. Establishes connection
  3. Begins streaming data
  4. Handles viewer lifecycle

Manual Viewer Control

#![allow(unused)]
fn main() {
// For custom setups
use rerun as rr;

rr::init("custom_app")?;
rr::spawn()?; // Launch viewer manually

// Then use standard miniROS viz API
let viz = node.create_visualizer("custom_app").await?;
}

Environment Configuration

# Disable automatic viewer launch
export RERUN_NO_SPAWN=1

# Custom viewer settings
export RERUN_HOST=localhost
export RERUN_PORT=9876

🚧 Limitations and Future Work

Current Limitations

  • Mesh Support: Limited 3D mesh capabilities
  • Textures: No texture mapping support
  • Animation: No built-in animation features
  • Custom Shaders: No custom rendering pipeline

Planned Features

  • Advanced mesh rendering
  • Texture and material support
  • Robot URDF model loading
  • Custom visualization widgets
  • Web-based viewer option
  • VR/AR visualization support

💡 Tips and Best Practices

  1. Entity Naming: Use clear, hierarchical entity paths
  2. Update Frequency: Match visualization frequency to data importance
  3. Performance: Batch updates when possible
  4. Organization: Group related entities logically
  5. Testing: Use visualization to debug robot behavior
  6. Documentation: Label entities clearly for team collaboration

🔗 Integration with External Tools

ROS2 Bridge

#![allow(unused)]
fn main() {
// Visualize ROS2 data through miniROS-rs
let ros2_bridge = Ros2Bridge::new().await?;
ros2_bridge.subscribe("/turtle1/pose", |pose| {
    viz.log_point("turtle/position", [pose.x, pose.y, 0.0]).await?;
});
}

Gazebo Integration

#![allow(unused)]
fn main() {
// Sync with Gazebo simulation
let gazebo_sync = GazeboSync::new().await?;
gazebo_sync.on_model_update(|model| {
    viz.log_transform(&format!("gazebo/{}", model.name), 
                     model.position, model.orientation).await?;
});
}

The built-in visualization makes miniROS-rs a complete robotics development platform, providing immediate visual feedback for debugging, development, and demonstration! 🎨🤖

Package Examples

🤖 TurtleBot Control System

The TurtleBot package demonstrates a complete robotics system implementation using miniROS, showcasing package structure, multi-node communication, and real-world control patterns.

📁 Package Structure

packages/turtlebot/
├── package.yaml           # Package metadata and dependencies
├── config/               # Configuration files
├── launch/               # Launch configurations
│   ├── full_system.yaml # Complete system launch
│   ├── simulation.yaml  # Simulation mode
│   └── teleop.yaml      # Teleoperation mode
├── scripts/             # Python utilities
│   └── controller.py    # Python controller implementation
├── src/                 # Rust source code
│   ├── controller.rs    # Main controller logic
│   └── teleop.rs        # Teleoperation interface
└── README.md            # Package documentation

🎯 System Architecture

The TurtleBot system demonstrates a modular robotics architecture:

graph TD
    A[TurtleBot Controller] --> B[Motor Control]
    A --> C[Sensor Processing]
    D[Teleop Interface] --> A
    E[Simulation Engine] --> A
    A --> F[Status Publisher]
    G[Parameter Server] --> A
    A --> H[Action Server]

🔧 Core Components

1. Controller Node (controller.rs)

#![allow(unused)]
fn main() {
// High-performance control loop with configurable parameters
pub struct TurtleBotController {
    linear_speed: f64,
    angular_speed: f64,
    safety_enabled: bool,
    control_frequency: f64,
}

impl TurtleBotController {
    pub fn new() -> Self {
        Self {
            linear_speed: 0.2,      // m/s - safe default speed
            angular_speed: 0.5,     // rad/s - turning rate
            safety_enabled: true,   // collision avoidance
            control_frequency: 50.0, // Hz - control loop rate
        }
    }

    pub async fn run_control_loop(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        // Main control implementation
        // - Subscribe to velocity commands
        // - Process sensor data
        // - Publish motor commands
        // - Handle emergency stops
        Ok(())
    }
}
}

2. Teleoperation Interface (teleop.rs)

#![allow(unused)]
fn main() {
// Keyboard/joystick input processing
pub struct TeleopInterface {
    max_linear: f64,
    max_angular: f64,
    input_source: InputSource,
}

#[derive(Debug)]
pub enum InputSource {
    Keyboard,
    Joystick,
    WebInterface,
}
}

3. Python Integration (controller.py)

#!/usr/bin/env python3
"""
TurtleBot Python Controller - High-level coordination and monitoring
Demonstrates seamless Rust-Python integration in miniROS
"""

import mini_ros
import asyncio
from typing import Dict, Any

class TurtleBotMonitor:
    """High-level system monitor and coordinator"""
    
    def __init__(self):
        self.node = mini_ros.Node("turtlebot_monitor")
        self.system_status = {}
        self.alert_threshold = 0.95
    
    async def monitor_system(self):
        """Monitor system health and performance"""
        while True:
            # Check battery level
            # Monitor CPU usage
            # Validate sensor data
            # Report system status
            await asyncio.sleep(1.0)
    
    def handle_emergency(self, alert_type: str):
        """Emergency response coordination"""
        print(f"🚨 Emergency: {alert_type}")
        # Send stop commands
        # Activate safety protocols
        # Log incident

🚀 Launch Configurations

Full System Launch (launch/full_system.yaml)

name: "TurtleBot Full System"
description: "Complete TurtleBot control system with all components"

nodes:
  - name: "controller"
    package: "turtlebot"
    executable: "controller"
    parameters:
      linear_speed: 0.3
      angular_speed: 0.8
      safety_enabled: true
      
  - name: "teleop"
    package: "turtlebot"
    executable: "teleop"
    parameters:
      input_source: "keyboard"
      
  - name: "monitor"
    package: "turtlebot"
    executable: "python"
    script: "scripts/controller.py"

remappings:
  - from: "/cmd_vel"
    to: "/turtlebot/cmd_vel"
  - from: "/status"
    to: "/turtlebot/status"

Simulation Mode (launch/simulation.yaml)

name: "TurtleBot Simulation"
description: "TurtleBot in simulation environment"

parameters:
  simulation_mode: true
  physics_enabled: true
  visualization: true

nodes:
  - name: "simulator"
    package: "turtlebot"
    executable: "simulator"
    
  - name: "controller"
    package: "turtlebot"
    executable: "controller"
    parameters:
      simulation: true

📋 Usage Examples

1. Launch Complete System

# Start full TurtleBot system
mini_ros launch turtlebot full_system

# Start in simulation mode
mini_ros launch turtlebot simulation

# Teleoperation only
mini_ros launch turtlebot teleop

2. Run Individual Nodes

# Run controller with custom parameters
mini_ros run turtlebot controller --args --speed 0.5 --safety false

# Run Python monitor
mini_ros_py run turtlebot_controller

# Run teleop interface
mini_ros run turtlebot teleop --args --input joystick

3. Parameter Management

# List available parameters
mini_ros pkg info turtlebot

# Set runtime parameters
mini_ros param set /turtlebot/linear_speed 0.4
mini_ros param set /turtlebot/safety_enabled true

# Save parameter configuration
mini_ros param dump turtlebot_config.yaml

🧪 Testing and Validation

Unit Tests

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_controller_initialization() {
        let controller = TurtleBotController::new();
        assert_eq!(controller.linear_speed, 0.2);
        assert!(controller.safety_enabled);
    }
    
    #[test]
    fn test_speed_limits() {
        let mut controller = TurtleBotController::new();
        controller.set_linear_speed(10.0); // Should be clamped
        assert!(controller.linear_speed <= controller.max_linear_speed);
    }
}
}

Integration Tests

#!/usr/bin/env python3
"""Integration tests for TurtleBot system"""

import pytest
import mini_ros
import asyncio

class TestTurtleBotSystem:
    
    @pytest.mark.asyncio
    async def test_full_system_startup(self):
        """Test complete system startup sequence"""
        # Launch system
        # Verify all nodes are running
        # Check communication between nodes
        # Validate parameter settings
        pass
    
    @pytest.mark.asyncio
    async def test_emergency_stop(self):
        """Test emergency stop functionality"""
        # Send emergency stop command
        # Verify immediate response
        # Check safety protocols activated
        pass

📊 Performance Metrics

The TurtleBot package demonstrates miniROS performance characteristics:

MetricValueNotes
Control Loop Rate50 HzReal-time control performance
Command Latency<10msKeyboard to motor response
Memory Usage<50MBEfficient resource utilization
CPU Usage<5%Low system overhead
Network Bandwidth<1MB/sEfficient communication

🎯 Best Practices Demonstrated

1. Modular Design

  • Separate nodes for different responsibilities
  • Clear interfaces between components
  • Configurable behavior via parameters

2. Language Integration

  • Rust for performance-critical control loops
  • Python for high-level coordination
  • Seamless cross-language communication

3. Configuration Management

  • YAML-based launch files
  • Runtime parameter adjustment
  • Environment-specific configurations

4. Safety and Reliability

  • Emergency stop mechanisms
  • Input validation and bounds checking
  • System health monitoring

5. Testing Strategy

  • Unit tests for individual components
  • Integration tests for system behavior
  • Performance benchmarking

🔍 Other Package Examples

Basic Publisher-Subscriber Package

packages/basic_pubsub/
├── package.yaml
├── src/
│   ├── publisher.rs    # High-frequency data publisher
│   └── subscriber.rs   # Real-time data consumer
└── examples/
    └── demo.rs         # Usage demonstration

Service-Based Calculator Package

packages/calculator/
├── package.yaml
├── src/
│   ├── server.rs      # Math service implementation
│   └── client.rs      # Service consumer
└── services/
    └── math.rs        # Custom service definitions

Multi-Language Integration Package

packages/integration/
├── package.yaml
├── src/
│   └── rust_node.rs   # Rust performance node
├── scripts/
│   └── python_node.py # Python AI/ML node
└── launch/
    └── mixed.yaml     # Cross-language system

Philosophy: Real-world robotics complexity, miniROS simplicity 🤖🎯

API Reference

Essential API documentation for miniROS-rs.

Core Types

Node

#![allow(unused)]
fn main() {
impl Node {
    // Create new node
    pub fn new(name: &str) -> Result<Self>
    
    // Initialize node (must call before use)
    pub async fn init(&mut self) -> Result<()>
    
    // Create publisher
    pub async fn create_publisher<T: Message>(&self, topic: &str) -> Result<Publisher<T>>
    
    // Create subscriber  
    pub async fn create_subscriber<T: Message>(&self, topic: &str) -> Result<Subscriber<T>>
    
    // Create service provider
    pub async fn create_service<Req, Res, F>(&self, name: &str, callback: F) -> Result<Service<Req, Res>>
    where F: Fn(Req) -> Result<Res> + Send + Sync + 'static
    
    // Create service client
    pub async fn create_service_client<Req: Message, Res: Message>(&self, name: &str) -> Result<ServiceClient<Req, Res>>
}
}

Publisher

#![allow(unused)]
fn main() {
impl<T: Message> Publisher<T> {
    // Publish message
    pub async fn publish(&self, message: &T) -> Result<()>
    
    // Get topic name
    pub fn topic(&self) -> &str
}
}

Subscriber

#![allow(unused)]
fn main() {
impl<T: Message> Subscriber<T> {
    // Set message callback
    pub async fn on_message<F>(&self, callback: F) -> Result<()>
    where F: Fn(T) + Send + 'static
    
    // Get topic name
    pub fn topic(&self) -> &str
}
}

ServiceClient

#![allow(unused)]
fn main() {
impl<Req: Message, Res: Message> ServiceClient<Req, Res> {
    // Call service
    pub async fn call(&self, request: Req) -> Result<Res>
    
    // Call with timeout
    pub async fn call_with_timeout(&self, request: Req, timeout: Duration) -> Result<Res>
    
    // Wait for service to become available
    pub async fn wait_for_service(&self, timeout: Duration) -> Result<()>
}
}

Message Types

ROS2-Compatible Packages

#![allow(unused)]
fn main() {
// std_msgs - Basic types
use mini_ros::types::std_msgs::*;
let msg = String { data: "Hello".to_string() };
let num = Int32 { data: 42 };

// geometry_msgs - Geometric types  
use mini_ros::types::geometry_msgs::*;
let point = Point { x: 1.0, y: 2.0, z: 3.0 };
let twist = Twist { linear: Vector3 { x: 1.0, y: 0.0, z: 0.0 }, angular: Vector3::default() };

// sensor_msgs - Sensor data
use mini_ros::types::sensor_msgs::*;
let laser = LaserScan { /* laser data */ };
let imu = Imu { /* IMU data */ };

// action_msgs - Action system
use mini_ros::types::action_msgs::*;
let status = GoalStatus { /* goal status */ };

// diagnostic_msgs - System diagnostics
use mini_ros::types::diagnostic_msgs::*;
let diag = DiagnosticStatus { level: OK, name: "Motor".to_string(), /* ... */ };
}

Legacy Messages

#![allow(unused)]
fn main() {
// Legacy support (still available)
pub struct StringMsg { pub data: String }
pub struct Header { pub stamp: i64, pub frame_id: String }
}

Custom Messages

#![allow(unused)]
fn main() {
use serde::{Deserialize, Serialize};

// Any struct with Serialize + Deserialize + Clone + Send + Sync automatically implements Message
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomMessage {
    pub field1: String,
    pub field2: f64,
    pub field3: Vec<i32>,
}
}

Visualization

VisualizationClient

#![allow(unused)]
fn main() {
impl VisualizationClient {
    // Create new client
    pub fn new(config: VisualizationConfig) -> Result<Self>
    
    // Log scalar value (creates time series plot)
    pub fn log_scalar(&self, entity_path: &str, value: f64) -> Result<()>
    
    // Log text message
    pub fn log_text(&self, entity_path: &str, text: &str) -> Result<()>
    
    // Log 2D points
    pub fn log_points_2d(&self, entity_path: &str, points: Vec<[f32; 2]>) -> Result<()>
    
    // Log 3D points
    pub fn log_points_3d(&self, entity_path: &str, points: Vec<[f32; 3]>) -> Result<()>
    
    // Log 3D transform
    pub fn log_transform_3d(&self, entity_path: &str, translation: [f32; 3], rotation: [f32; 4]) -> Result<()>
}
}

VisualizationConfig

#![allow(unused)]
fn main() {
pub struct VisualizationConfig {
    pub application_id: String,  // Application name
    pub spawn_viewer: bool,      // Auto-start GUI
}
}

Visualizable Trait

#![allow(unused)]
fn main() {
pub trait Visualizable {
    fn visualize(&self, client: &VisualizationClient, entity_path: &str) -> Result<()>;
}

// Implemented for:
// - RobotPose
// - PointCloud  
// - LaserScan
}

Robot Data Types

#![allow(unused)]
fn main() {
// Robot pose with position and orientation
pub struct RobotPose {
    pub position: [f32; 3],      // [x, y, z]
    pub orientation: [f32; 4],   // Quaternion [x, y, z, w]
}

// 3D point cloud
pub struct PointCloud {
    pub points: Vec<[f32; 3]>,   // Array of [x, y, z] points
}

// 2D laser scan
pub struct LaserScan {
    pub ranges: Vec<f32>,        // Distance measurements
    pub angle_min: f32,          // Start angle (radians)
    pub angle_max: f32,          // End angle (radians)
}
}

Error Handling

Result Type

#![allow(unused)]
fn main() {
pub type Result<T> = std::result::Result<T, MiniRosError>;
}

Error Types

#![allow(unused)]
fn main() {
pub enum MiniRosError {
    NetworkError(String),        // Network/transport errors
    SerializationError(String),  // Message serialization errors
    NodeError(String),          // Node creation/management errors
    ServiceError(String),       // Service call errors
    Other(String),              // Other errors
}
}

Async Runtime

miniROS-rs requires Tokio async runtime:

#[tokio::main]
async fn main() -> Result<()> {
    // Your miniROS code here
    Ok(())
}

Or in non-main functions:

#![allow(unused)]
fn main() {
use tokio::runtime::Runtime;

fn sync_function() -> Result<()> {
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
        // Async miniROS code here
        Ok(())
    })
}
}

Feature Flags

Available Cargo features:

[dependencies]
mini-ros = { version = "0.1", features = ["visualization"] }
  • visualization - Enable Rerun visualization support (default)

Example Usage Patterns

Basic Node Setup

use mini_ros::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    let mut node = Node::new("my_node")?;
    node.init().await?;
    
    // Use node...
    
    Ok(())
}

Publisher Pattern

#![allow(unused)]
fn main() {
let publisher = node.create_publisher::<StringMsg>("topic").await?;

loop {
    publisher.publish(&StringMsg { data: "Hello".to_string() }).await?;
    tokio::time::sleep(Duration::from_secs(1)).await;
}
}

Subscriber Pattern

#![allow(unused)]
fn main() {
let subscriber = node.create_subscriber::<StringMsg>("topic").await?;

subscriber.on_message(|msg: StringMsg| {
    println!("Received: {}", msg.data);
}).await?;

// Keep node alive
tokio::signal::ctrl_c().await.unwrap();
}

Transport Architecture

miniROS provides multiple transport layers to match different use cases while maintaining ROS2 compatibility.

Transport Layer Overview

┌─────────────────────────────────────────────┐
│           Application Layer                 │
│        (Your Robot Code)                    │
├─────────────────────────────────────────────┤
│          miniROS API Layer                  │
│     (Publishers, Subscribers, Services)     │
├─────────────────────────────────────────────┤
│           Transport Selection               │
│                                             │
│  ┌─────────────┐    ┌─────────────────────┐ │
│  │ TCP/UDP     │    │ DDS (ROS2 Compat)  │ │
│  │ Transport   │    │ Transport           │ │
│  │ (Simple)    │    │ (Standard)          │ │
│  └─────────────┘    └─────────────────────┘ │
├─────────────────────────────────────────────┤
│           Network Layer                     │
│         (UDP/TCP Sockets)                   │
└─────────────────────────────────────────────┘

Why Multiple Transports?

DDS Transport (Default, ROS2 Compatible)

  • Purpose: Full ROS2 compatibility and interoperability
  • Protocol: Data Distribution Service (DDS) over UDP
  • Features:
    • Domain isolation (0-232)
    • Quality of Service (QoS) policies
    • Automatic discovery
    • ROS2 ecosystem compatibility
  • Use when: You need ROS2 interoperability or multi-robot systems
#![allow(unused)]
fn main() {
// Enable with feature flag
cargo run --features dds-transport

// Programmatic usage
let context = Context::with_domain_id(42)?;  // Isolated domain
let transport = DdsTransport::new(42).await?;
}

TCP Transport (Simple, Development)

  • Purpose: Simple development and testing
  • Protocol: Direct TCP connections
  • Features:
    • Reliable delivery
    • Simple configuration
    • Lower overhead
    • No external dependencies
  • Use when: Local development, testing, or simple scenarios
#![allow(unused)]
fn main() {
// Enable with feature flag (default)
cargo run --features tcp-transport

// Programmatic usage
let context = Context::new()?;  // Default TCP
}

DDS vs TCP/UDP Clarification

Important: DDS is NOT a replacement for TCP/UDP - it’s built ON TOP of UDP.

The Layering

ROS2 Application
       ↓
   DDS Layer      ← miniROS DDS transport implements this
       ↓
   UDP Layer      ← Network protocol (standard UDP sockets)
       ↓
   IP Layer
       ↓
   Ethernet

miniROS TCP Transport

For simplicity, miniROS also provides direct TCP transport that bypasses DDS:

miniROS Application
       ↓
  TCP Transport    ← Direct TCP, no DDS overhead
       ↓
   TCP Layer      ← Standard TCP sockets
       ↓
   IP Layer

Transport Comparison

FeatureDDS TransportTCP Transport
ROS2 Compatibility✅ Full❌ None
Domain Isolation✅ 0-232 domains❌ No isolation
Discovery✅ Automatic❌ Manual
QoS Policies✅ Full support❌ Basic
Multi-robot✅ Excellent❌ Limited
Simplicity⚠️ Complex✅ Very simple
Performance⚠️ Good✅ Excellent
Network ProtocolUDP multicastTCP point-to-point

Domain Isolation (DDS Only)

Domains provide network-level isolation between robot systems:

#![allow(unused)]
fn main() {
// Robot A uses domain 0
let robot_a = Context::with_domain_id(0)?;

// Robot B uses domain 1 (completely isolated)
let robot_b = Context::with_domain_id(1)?;

// They cannot communicate with each other
}

Domain ID Ranges

  • 0-232: Valid ROS2 domain IDs
  • Default: Domain 0
  • Recommendation: Use different domains for different robot fleets

Choosing Your Transport

Use DDS Transport When:

  • ✅ You need ROS2 ecosystem compatibility
  • ✅ Running multiple robots that need isolation
  • ✅ Production robotics systems
  • ✅ Need advanced QoS policies
  • ✅ Working with existing ROS2 tools

Use TCP Transport When:

  • ✅ Simple development and testing
  • ✅ Single robot systems
  • ✅ Learning miniROS concepts
  • ✅ Maximum performance (local only)
  • ✅ Minimal dependencies

Configuration Examples

Feature Flags in Cargo.toml

[dependencies]
mini-ros = { version = "0.1.2", features = ["dds-transport"] }
# OR
mini-ros = { version = "0.1.2", features = ["tcp-transport"] }

Runtime Selection

#![allow(unused)]
fn main() {
#[cfg(feature = "dds-transport")]
async fn setup_transport() -> Result<Context> {
    let domain_id = std::env::var("ROS_DOMAIN_ID")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(0);
    
    Context::with_domain_id(domain_id)
}

#[cfg(feature = "tcp-transport")]
async fn setup_transport() -> Result<Context> {
    Context::new()  // Simple TCP transport
}
}

Environment Variables

# DDS transport with custom domain
export ROS_DOMAIN_ID=42
cargo run --features dds-transport

# TCP transport (default)
cargo run --features tcp-transport

Best Practices

For Development

  1. Start with TCP transport for simplicity
  2. Switch to DDS when you need ROS2 features
  3. Use domain 0 for initial testing

For Production

  1. Always use DDS transport for ROS2 compatibility
  2. Assign unique domain IDs to different robot fleets
  3. Document your domain allocation strategy

For Multi-Robot Systems

  1. Use DDS transport exclusively
  2. Plan domain allocation (0-232 range)
  3. Test domain isolation thoroughly

Performance Considerations

DDS Transport

  • Latency: ~100-200μs (includes DDS overhead)
  • Throughput: High (UDP multicast)
  • CPU: Moderate (DDS processing)
  • Memory: Higher (DDS buffers)

TCP Transport

  • Latency: ~50μs (direct TCP)
  • Throughput: Very high (no DDS overhead)
  • CPU: Low (minimal processing)
  • Memory: Lower (simple buffers)

Migration Path

If you start with TCP and later need DDS:

#![allow(unused)]
fn main() {
// Before: TCP transport
let mut node = Node::new("robot")?;

// After: DDS transport (minimal changes)
let context = Context::with_domain_id(42)?;
let mut node = Node::with_context("robot", context)?;
}

The API remains the same - only the transport layer changes.


Choose the right transport for your needs: TCP for simplicity, DDS for ROS2 compatibility.

DDS Transport Layer

MiniROS uses a simplified Data Distribution Service (DDS) implementation to maintain compatibility with ROS2’s communication patterns while keeping the implementation minimal and focused on core functionality.

Overview

DDS is the middleware standard that ROS2 uses for communication. Our implementation provides:

  • Domain-based isolation: Different robots can operate in separate domains
  • Quality of Service (QoS): Reliability and durability policies
  • Multicast discovery: Automatic node and topic discovery
  • Type-safe messaging: Compile-time message type checking

Architecture

┌─────────────────────────────────────┐
│         Application Layer           │
├─────────────────────────────────────┤
│    DDS Publishers & Subscribers     │
├─────────────────────────────────────┤
│       Domain Participant            │
├─────────────────────────────────────┤
│     Multicast UDP Transport         │
├─────────────────────────────────────┤
│        Network Interface            │
└─────────────────────────────────────┘

Usage

Basic Setup

#![allow(unused)]
fn main() {
use mini_ros::dds_transport::{DdsTransport, QosPolicy};
use mini_ros::message::StringMsg;

// Create DDS transport with domain ID
let transport = DdsTransport::new(0).await?;

// Create publisher
let publisher = transport.create_publisher::<StringMsg>("chatter").await?;

// Create subscriber
let subscriber = transport.create_subscriber::<StringMsg>("chatter").await?;
}

Quality of Service (QoS)

#![allow(unused)]
fn main() {
use mini_ros::dds_transport::{QosPolicy, ReliabilityKind, DurabilityKind, HistoryKind};

let qos = QosPolicy {
    reliability: ReliabilityKind::Reliable,
    durability: DurabilityKind::TransientLocal,
    history: HistoryKind::KeepLast,
    depth: 10,
};

let publisher = transport.create_publisher_with_qos::<StringMsg>("topic", qos).await?;
}

Publishing Messages

#![allow(unused)]
fn main() {
let message = StringMsg {
    data: "Hello, DDS World!".to_string(),
};

publisher.publish(&message).await?;
}

Subscribing to Messages

#![allow(unused)]
fn main() {
// Callback-based subscription
subscriber.on_message(|msg: StringMsg| {
    println!("Received: {}", msg.data);
})?;

// Polling-based subscription
if let Some(message) = subscriber.try_recv::<StringMsg>() {
    println!("Received: {}", message.data);
}
}

Domain Management

Domain Isolation

Different domains operate independently:

#![allow(unused)]
fn main() {
// Robot 1 in domain 0
let transport1 = DdsTransport::new(0).await?;

// Robot 2 in domain 1 (isolated from domain 0)
let transport2 = DdsTransport::new(1).await?;
}

Port Assignment

Domains use different multicast ports:

  • Domain 0: Port 7400
  • Domain 1: Port 7401
  • Domain N: Port 7400 + N

QoS Policies

Reliability

  • BestEffort: Fast, may lose messages
  • Reliable: Guaranteed delivery (default)

Durability

  • Volatile: Messages not stored (default)
  • TransientLocal: Store messages for late-joining subscribers

History

  • KeepLast: Keep only latest N messages (default)
  • KeepAll: Keep all messages

Message Format

DDS messages include metadata:

#![allow(unused)]
fn main() {
struct DdsMessage {
    topic: String,           // Topic name
    sequence_number: u64,    // Message sequence
    timestamp: u64,          // Nanosecond timestamp
    data: Vec<u8>,          // Serialized payload
}
}

Network Configuration

Multicast Address

  • Default: 239.255.0.1
  • Configurable per domain
  • IPv4 multicast for local network discovery

Firewall Considerations

Ensure multicast traffic is allowed:

# Linux: Allow multicast
sudo iptables -A INPUT -m pkttype --pkt-type multicast -j ACCEPT

# macOS: Multicast generally works by default
# Windows: May require firewall configuration

Performance Characteristics

Benchmarks

MetricValue
Latency< 1ms (local network)
Throughput> 100MB/s
Max Message Size64KB
Discovery Time< 100ms

Optimization Tips

  1. Use appropriate QoS: BestEffort for high-frequency data
  2. Batch small messages: Combine when possible
  3. Tune history depth: Balance memory vs. reliability
  4. Monitor network usage: Avoid multicast flooding

Comparison with Full DDS

FeatureMiniROS DDSFull DDS (e.g., CycloneDX)
Standards ComplianceSimplifiedFull RTPS/DDS
Memory UsageLowHigher
Feature SetCore featuresComplete
InteroperabilityLimitedFull ROS2
Learning CurveSimpleComplex

Migration from TCP/UDP

If migrating from the legacy TCP/UDP transport:

#![allow(unused)]
fn main() {
// Old TCP/UDP transport
use mini_ros::transport::UdpTransport;

// New DDS transport
use mini_ros::dds_transport::DdsTransport;

// API is similar, but with QoS support
let transport = DdsTransport::new(domain_id).await?;
}

Troubleshooting

Common Issues

  1. Port conflicts: Use different domain IDs
  2. Multicast not working: Check network configuration
  3. Messages not received: Verify topic names and types
  4. High latency: Check network congestion

Debug Tools

#![allow(unused)]
fn main() {
// Enable detailed logging
tracing_subscriber::fmt::init();

// Check domain participant
println!("Domain ID: {}", transport.domain_id());

// Monitor message sequence numbers
publisher.publish(&message).await?;
}

Future Enhancements

  • Full RTPS protocol support
  • Dynamic discovery improvements
  • Security policies
  • Performance monitoring
  • ROS2 bridge compatibility

Performance Optimization

miniROS-rs is designed for high-performance robotics applications. This guide covers optimization strategies and implementation best practices.

Architecture Design

Async Runtime Benefits

The async architecture provides several performance advantages:

#![allow(unused)]
fn main() {
// Concurrent message processing
tokio::spawn(async move {
    while let Some(msg) = subscriber.recv().await {
        process_message(msg).await;
    }
});

// Non-blocking publishers
publisher.publish(&message).await?; // Doesn't block other tasks
}

Transport Layer Options

  • Memory Broker: Fastest for local communication within same process
  • TCP Transport: Reliable network communication with connection management
  • DDS Transport: Industry-standard for distributed robotics systems
  • UDP Transport: Low-latency multicast communication

Message Optimization

Efficient Message Design

#![allow(unused)]
fn main() {
// Efficient: Use fixed-size arrays when possible
#[derive(Serialize, Deserialize)]
struct RobotState {
    position: [f32; 3],    // Fixed-size arrays
    velocity: [f32; 3],
    joint_angles: Vec<f32>, // Vec only when size varies
}

// Efficient: Reuse message instances
let mut message = StringMsg::default();
loop {
    message.data = format!("Frame {}", frame_count);
    publisher.publish(&message).await?;
    frame_count += 1;
}
}

Built-in Message Types

Use appropriate built-in types for optimal performance:

#![allow(unused)]
fn main() {
use mini_ros::message::{
    StringMsg,    // For text data
    Int32Msg,     // For integer values
    Float64Msg,   // For numeric data
    BoolMsg,      // For boolean flags
};
}

Transport Configuration

DDS Transport with QoS

#![allow(unused)]
fn main() {
use mini_ros::dds_transport::{QosPolicy, ReliabilityKind};

// High-frequency sensor data
let sensor_qos = QosPolicy {
    reliability: ReliabilityKind::BestEffort, // Faster, occasional loss OK
    depth: 1, // Only keep latest
    ..Default::default()
};

// Critical commands
let command_qos = QosPolicy {
    reliability: ReliabilityKind::Reliable, // Ensure delivery
    depth: 10, // Keep multiple messages
    ..Default::default()
};
}

Domain Isolation

#![allow(unused)]
fn main() {
// Separate high-frequency data by domain
let sensor_transport = DdsTransport::new(0).await?; // Domain 0: sensors
let control_transport = DdsTransport::new(1).await?; // Domain 1: control
let ui_transport = DdsTransport::new(2).await?;     // Domain 2: UI/visualization
}

Memory Management

Publisher Pooling

#![allow(unused)]
fn main() {
use std::sync::Arc;
use tokio::sync::Mutex;
use std::collections::HashMap;

// Reuse publishers across tasks
struct PublisherPool {
    publishers: Arc<Mutex<HashMap<String, Publisher<StringMsg>>>>,
}

impl PublisherPool {
    async fn get_publisher(&self, topic: &str) -> Publisher<StringMsg> {
        let mut pubs = self.publishers.lock().await;
        pubs.entry(topic.to_string())
            .or_insert_with(|| create_publisher(topic))
            .clone()
    }
}
}

Message Pooling Pattern

#![allow(unused)]
fn main() {
use crossbeam_channel::{bounded, Receiver, Sender};

// Pre-allocate message pool to reduce allocations
struct MessagePool<T> {
    pool: Receiver<T>,
    return_sender: Sender<T>,
}

impl<T: Default> MessagePool<T> {
    fn new(size: usize) -> Self {
        let (send, recv) = bounded(size);
        let (return_send, _return_recv) = bounded(size);
        
        // Pre-fill pool
        for _ in 0..size {
            let _ = send.send(T::default());
        }
        
        Self {
            pool: recv,
            return_sender: return_send,
        }
    }
}
}

Async Task Optimization

Dedicated Runtime Configuration

#![allow(unused)]
fn main() {
// Configure runtime for specific workloads
let rt = tokio::runtime::Builder::new_multi_thread()
    .worker_threads(4)
    .thread_name("miniROS-worker")
    .enable_all()
    .build()?;

// Use runtime handle for spawning tasks
let handle = rt.handle();
handle.spawn(async move {
    // High-priority task
});
}

Batched Processing

#![allow(unused)]
fn main() {
// Process messages in batches for efficiency
let mut batch = Vec::with_capacity(100);

while let Ok(msg) = receiver.try_recv() {
    batch.push(msg);
    
    if batch.len() >= 100 {
        process_batch(&batch).await;
        batch.clear();
    }
}
}

Network Optimization

Multicast Configuration

For UDP/DDS transports on Linux:

# Optimize multicast buffer sizes
sudo sysctl -w net.core.rmem_max=134217728
sudo sysctl -w net.core.rmem_default=65536

# Monitor network usage
sudo iftop -i eth0 -f "dst net 239.255.0.0/24"

Topic Design

#![allow(unused)]
fn main() {
// Good: Hierarchical topics
"/robot1/sensors/imu"
"/robot1/actuators/wheel_speeds"
"/global/map_updates"

// Avoid: Flat namespace
"/imu_data"
"/wheel_data" 
"/map_data"
}

Monitoring and Profiling

Built-in Benchmarking

#![allow(unused)]
fn main() {
// Use built-in benchmarking tools
use mini_ros::benchmarks::{LatencyBenchmark, ThroughputBenchmark};

// Measure publisher-subscriber latency
let benchmark = LatencyBenchmark::new();
let results = benchmark.run_pubsub_latency(1000).await?;

println!("Average latency: {}μs", results.average_latency_micros());
}

Performance Monitoring

#![allow(unused)]
fn main() {
// Monitor system performance
use mini_ros::discovery::DiscoveryService;

let discovery = DiscoveryService::new(0)?;
let stats = discovery.get_performance_stats().await?;

println!("Active nodes: {}", stats.node_count);
println!("Message rate: {}/s", stats.message_rate);
}

Best Practices

1. Choose Appropriate Transport

  • Memory broker: Single-process applications
  • TCP: Reliable network communication
  • DDS: Multi-robot distributed systems
  • UDP: Low-latency sensor streaming

2. Optimize Message Frequency

#![allow(unused)]
fn main() {
// High-frequency: IMU, camera frames
const HIGH_FREQ: Duration = Duration::from_millis(1);  // 1000Hz

// Medium-frequency: robot state
const MED_FREQ: Duration = Duration::from_millis(10);  // 100Hz

// Low-frequency: configuration
const LOW_FREQ: Duration = Duration::from_millis(100); // 10Hz
}

3. Use Appropriate QoS

  • Best effort: High-frequency sensor data
  • Reliable: Commands and configuration
  • Volatile: Real-time data
  • Transient: Configuration that new nodes need

4. Monitor Resource Usage

// Use tokio-console for async task monitoring
#[tokio::main]
async fn main() {
    console_subscriber::init();
    // Your application code
}

Performance Testing

Latency Measurement

#![allow(unused)]
fn main() {
use std::time::Instant;

let start = Instant::now();
publisher.publish(&message).await?;
// Measure round-trip time with subscriber callback
let latency = start.elapsed();
}

Throughput Testing

#![allow(unused)]
fn main() {
let start = Instant::now();
let message_count = 10000;

for i in 0..message_count {
    publisher.publish(&create_message(i)).await?;
}

let duration = start.elapsed();
let throughput = message_count as f64 / duration.as_secs_f64();
println!("Throughput: {:.2} messages/second", throughput);
}

This performance guide focuses on practical optimization techniques that can be implemented with the current miniROS-rs architecture and feature set.

CI/CD Automation

miniROS-rs uses a simple and effective CI/CD pipeline to automate testing and releases.

Overview

The system consists of two main workflows:

  1. CI Pipeline - Runs tests on every push/PR
  2. Release Pipeline - Publishes packages when tags are created

Continuous Integration

The CI workflow (.github/workflows/ci.yml) runs:

  • Code Quality: cargo fmt and cargo clippy
  • Rust Tests: cargo test --all-features
  • Python Package: Build and basic import test

Triggers

  • Push to main or develop branch
  • Pull requests to main or develop branch

Release Process

Automatic Release

Create a git tag to trigger a release:

git tag v1.2.3
git push origin v1.2.3

This will:

  1. Run tests
  2. Build Rust crate and Python wheels
  3. Publish to crates.io and PyPI (if tokens are set)
  4. Create GitHub release with artifacts

Manual Release

Alternatively, manually trigger the release workflow in GitHub Actions:

  1. Go to ActionsRelease
  2. Click Run workflow
  3. Enter the version number (e.g., 1.2.3)

Setup

Required Secrets

Add these secrets in your GitHub repository settings:

  • CRATES_IO_TOKEN - For publishing to crates.io
  • PYPI_TOKEN - For publishing to PyPI

Getting Tokens

crates.io token:

# Login to crates.io and go to Account Settings → API Tokens
# Create a new token with publish scope

PyPI token:

# Login to PyPI and go to Account Settings → API tokens
# Create a new token with upload scope

Workflow Files

CI Workflow

name: CI
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
      - name: Run tests
        run: cargo test --all-features

Release Workflow

name: Release
on:
  push:
    tags: ['v*']

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Publish packages
        run: |
          cargo publish --token $CRATES_IO_TOKEN
          maturin build --release --features python
          twine upload dist/*.whl

Best Practices

  1. Test First: Always ensure tests pass before releasing
  2. Semantic Versioning: Use v1.2.3 format for tags
  3. Small Releases: Release frequently with small changes
  4. Documentation: Update docs with API changes

Troubleshooting

Release fails?

  • Check that tokens are correctly set in repository secrets
  • Ensure version number is unique (not already published)
  • Verify tests pass locally first

Python build fails?

  • Check that pyproject.toml is properly configured
  • Ensure maturin can find Rust source code

crates.io publish fails?

  • Verify package name is unique
  • Check that all required metadata is in Cargo.toml
  • Ensure no breaking changes without version bump