This document describes the multi-container architecture for the Python SLAM system, which separates the ROS2 SLAM processing backend from the PyQt5 visualization frontend.
The system is now split into two main containers:
- SLAM Backend (
slam-backend): Handles all ROS2 SLAM processing - SLAM Visualization (
slam-visualization): Provides PyQt5 GUI for visualization
- Separation of Concerns: Backend processing is isolated from GUI rendering
- Scalability: Backend can run on different hardware than visualization
- Flexibility: Visualization can connect to remote SLAM backends
- Development: Easier to develop and debug individual components
- Performance: GUI doesn't impact SLAM processing performance
- Deployment: Backend can run headless on robots while visualization runs on operator stations
- Image: Built from
docker/Dockerfile.backend - Purpose: ROS2 SLAM processing, sensor fusion, mapping
- Exposed Ports:
14540: PX4 connection5555: UCI command port / ZMQ visualization data5556: UCI telemetry port
- Key Components:
- SLAM node
- Feature extraction
- Pose estimation
- Mapping
- Loop closure
- Visualization bridge (ZMQ publisher)
- Image: Built from
docker/Dockerfile.visualization - Purpose: PyQt5 GUI for real-time visualization
- Features:
- 3D point cloud visualization
- Camera trajectory tracking
- Performance metrics
- Real-time status monitoring
- Connection: Connects to backend via ZMQ (tcp://slam-backend:5555)
- Docker and Docker Compose installed
- X11 forwarding for GUI (Linux/macOS)
-
Complete System (Backend + Visualization):
./run-multi.sh up
-
Backend Only:
./run-multi.sh backend
-
Visualization Only (requires running backend):
./run-multi.sh visualization
-
Development Mode:
./run-multi.sh dev
Environment variables are configured in .env.multi:
ROS_DOMAIN_ID=0
RMW_IMPLEMENTATION=rmw_cyclonedx_cpp
SLAM_BACKEND_ADDRESS=tcp://slam-backend:5555
ENABLE_PX4=false
ENABLE_UCI=false- All SLAM nodes communicate via ROS2 topics
- Uses CycloneDX DDS implementation
- Custom network configuration in
config/cyclonedx.xml
- Protocol: ZeroMQ (ZMQ)
- Pattern: Publisher/Subscriber
- Port: 5555
- Data Format: JSON
{
"timestamp": 1234567890.123,
"pose": {
"position": {"x": 0.0, "y": 0.0, "z": 0.0},
"orientation": {"x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0}
},
"trajectory": [[x1, y1, z1], [x2, y2, z2], ...],
"pointcloud": {
"points": [[x1, y1, z1], ...],
"frame_id": "map"
},
"map": {
"width": 1024,
"height": 1024,
"resolution": 0.05,
"data": [...]
}
}# Start backend development container
docker-compose -f docker-compose.multi.yml up slam-dev-backend
# Attach to container
docker exec -it python-slam-dev-backend bash
# Build and test
cd /workspace/src/python_slam
colcon build
source install/setup.bash
ros2 launch python_slam slam_backend_launch.py# Start visualization development container
docker-compose -f docker-compose.multi.yml up slam-dev-visualization
# Attach to container
docker exec -it python-slam-dev-visualization bash
# Run visualization
python3 src/python_slam/gui/slam_visualizer.py- Network:
slam-network(172.20.0.0/16) - DNS: Containers can resolve each other by name
- Ports: Only necessary ports are exposed to host
- Domain ID: 0 (configurable via ROS_DOMAIN_ID)
- Discovery: Uses CycloneDX with custom peer configuration
- QoS: Optimized profiles for different data types
./run-multi.sh status# All containers
./run-multi.sh logs
# Specific container
docker-compose -f docker-compose.multi.yml logs slam-backend
docker-compose -f docker-compose.multi.yml logs slam-visualization# List nodes
docker exec python-slam-backend ros2 node list
# Topic information
docker exec python-slam-backend ros2 topic list
docker exec python-slam-backend ros2 topic info /slam/pose
# Echo topics
docker exec python-slam-backend ros2 topic echo /slam/pose# Test ZMQ connection from visualization container
docker exec python-slam-visualization python3 -c "
import zmq
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect('tcp://slam-backend:5555')
socket.subscribe('')
socket.setsockopt(zmq.RCVTIMEO, 5000)
try:
message = socket.recv_json()
print('ZMQ connection working:', message.keys())
except:
print('ZMQ connection failed')
"-
GUI not displaying:
- Check X11 forwarding:
xhost +local:docker - Verify DISPLAY environment variable
- Check X11 forwarding:
-
Backend not connecting:
- Check ROS2 domain ID matches
- Verify network connectivity between containers
-
ZMQ connection failed:
- Ensure backend is fully started before visualization
- Check if backend is publishing data
-
Performance issues:
- Limit point cloud size in visualization
- Adjust update frequencies
- Monitor container resource usage
-
Backend Performance:
- Adjust SLAM processing frequency
- Optimize feature detection parameters
- Use appropriate QoS profiles
-
Visualization Performance:
- Limit maximum points displayed
- Reduce update frequency
- Adjust rendering quality
-
Network Performance:
- Use appropriate ZMQ message sizes
- Consider data compression for large point clouds
- Optimize ROS2 QoS settings
- Network Isolation: Containers run in isolated network
- Port Exposure: Only necessary ports exposed to host
- User Privileges: Containers run with minimal privileges
- Data Encryption: Consider TLS for production deployments
- Multi-Backend Support: Connect visualization to multiple SLAM backends
- Cloud Deployment: Support for Kubernetes deployment
- Data Recording: Built-in recording and playback capabilities
- Remote Access: Web-based visualization interface
- Distributed Computing: Split SLAM processing across multiple containers