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
- Introduction - Complete system overview
- Quick Start - 5-minute tutorial
- Core Concepts - Architecture and design
User Guide
- CLI Usage Guide - Command-line tools
- Scripts Guide - Build and automation scripts
- Examples - Progressive learning examples
- Python Bindings - ROS2 rclpy compatible Python API
- Visualization - Built-in 3D visualization
Package Development
- Package Examples - Real-world package implementations
- API Reference - Complete API documentation
Advanced Topics
- Transport Architecture - Multi-transport design
- DDS Transport - ROS2 compatibility layer
- Performance Optimization - Benchmarks and tuning
Development
- CI/CD Automation - Development automation
🎯 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 Area | Content |
---|---|
Examples | 8 progressive tutorials from basic to complete systems |
API Reference | Complete coverage of all public APIs |
Languages | Rust and Python with ROS2 compatibility |
Visualization | Built-in 3D visualization with Rerun |
Architecture | Multi-transport system design |
Performance | Benchmarks and optimization guides |
Package Development | Real-world package examples |
CLI Tools | Comprehensive tooling documentation |
🚀 Getting Started Paths
For Beginners
- Introduction - Understand what miniROS-rs is
- Quick Start - Build your first system
- Examples - Learn step by step
- Package Examples - Real-world implementations
For ROS2 Users
- Core Concepts - Architecture differences
- Python Bindings - Familiar rclpy API
- DDS Transport - ROS2 compatibility
- Package Examples - Migration patterns
For System Architects
- Transport Architecture - Multi-transport design
- Performance Optimization - Production tuning
- Package Examples - System design patterns
- API Reference - Complete system interfaces
For Developers
- CLI Usage Guide - Development tools
- Scripts Guide - Build automation
- CI/CD Automation - Development workflow
- 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
- Complete Coverage: Document all features and APIs
- Progressive Learning: Start simple, build complexity
- Real Examples: Use actual working code
- ROS2 Compatibility: Emphasize familiar patterns
- 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:
- Quick Start - 5-minute setup and basic usage
- Examples - Progressive learning from basic to advanced
- Python Bindings - ROS2-compatible Python API
- 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
- Examples - Comprehensive learning examples
- Python Bindings - Complete Python API reference
- API Documentation - Full Rust API reference
- Visualization - 3D visualization with Rerun
- 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
- See Visualization for data display
- Check API Reference for complete documentation
- Try Examples for hands-on practice
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
Feature | Rust (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
)
- 🔨 Builds Rust CLI - Compiles
mini_ros
binary - 🐍 Installs Python CLI - Installs
mini_ros_py
package - 🔧 Configures Environment - Adds PATH, aliases, completions
- 📄 Backs Up Configs - Safely backs up shell config files
- 🧪 Tests Installation - Verifies everything works
- 💡 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
Command | CLI Choice | Reason |
---|---|---|
pkg | Rust | Package management performance |
launch | Rust | System orchestration |
run | Rust | Node execution performance |
examples | Python | Python-specific functionality |
test | Python | Python testing suite |
install | Python | Python package management |
run --list | Python | Python 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
- Start with 01-03 - Core patterns
- Try Python examples - ROS2 compatibility
- Add features - Actions, parameters as needed
- 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?; }
Navigation Visualization
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:
- Spawns the Rerun viewer application
- Establishes connection
- Begins streaming data
- 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
- Entity Naming: Use clear, hierarchical entity paths
- Update Frequency: Match visualization frequency to data importance
- Performance: Batch updates when possible
- Organization: Group related entities logically
- Testing: Use visualization to debug robot behavior
- 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:
Metric | Value | Notes |
---|---|---|
Control Loop Rate | 50 Hz | Real-time control performance |
Command Latency | <10ms | Keyboard to motor response |
Memory Usage | <50MB | Efficient resource utilization |
CPU Usage | <5% | Low system overhead |
Network Bandwidth | <1MB/s | Efficient 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
Feature | DDS Transport | TCP 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 Protocol | UDP multicast | TCP 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
- Start with TCP transport for simplicity
- Switch to DDS when you need ROS2 features
- Use domain 0 for initial testing
For Production
- Always use DDS transport for ROS2 compatibility
- Assign unique domain IDs to different robot fleets
- Document your domain allocation strategy
For Multi-Robot Systems
- Use DDS transport exclusively
- Plan domain allocation (0-232 range)
- 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
Metric | Value |
---|---|
Latency | < 1ms (local network) |
Throughput | > 100MB/s |
Max Message Size | 64KB |
Discovery Time | < 100ms |
Optimization Tips
- Use appropriate QoS: BestEffort for high-frequency data
- Batch small messages: Combine when possible
- Tune history depth: Balance memory vs. reliability
- Monitor network usage: Avoid multicast flooding
Comparison with Full DDS
Feature | MiniROS DDS | Full DDS (e.g., CycloneDX) |
---|---|---|
Standards Compliance | Simplified | Full RTPS/DDS |
Memory Usage | Low | Higher |
Feature Set | Core features | Complete |
Interoperability | Limited | Full ROS2 |
Learning Curve | Simple | Complex |
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
- Port conflicts: Use different domain IDs
- Multicast not working: Check network configuration
- Messages not received: Verify topic names and types
- 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:
- CI Pipeline - Runs tests on every push/PR
- Release Pipeline - Publishes packages when tags are created
Continuous Integration
The CI workflow (.github/workflows/ci.yml
) runs:
- Code Quality:
cargo fmt
andcargo clippy
- Rust Tests:
cargo test --all-features
- Python Package: Build and basic import test
Triggers
- Push to
main
ordevelop
branch - Pull requests to
main
ordevelop
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:
- Run tests
- Build Rust crate and Python wheels
- Publish to crates.io and PyPI (if tokens are set)
- Create GitHub release with artifacts
Manual Release
Alternatively, manually trigger the release workflow in GitHub Actions:
- Go to Actions → Release
- Click Run workflow
- 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.ioPYPI_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
- Test First: Always ensure tests pass before releasing
- Semantic Versioning: Use
v1.2.3
format for tags - Small Releases: Release frequently with small changes
- 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