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