Technical Architecture - Forestry-Robotics-UC/fruc_dataset_apparatus GitHub Wiki

Technical Architecture

Overview

The FRUC Dataset Apparatus is a comprehensive multi-sensor recording system built on ROS2 (Jazzy distribution) using containerized architecture. It is designed to capture synchronized sensor data from multiple sources for robotics research and dataset collection.

System Architecture

High-Level Design

┌─────────────────────────────────────────────────────────────┐
│                   FRUC Dataset Apparatus                     │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────────────────────────────────────────────┐  │
│  │            Docker Compose Network (ROS2 Jazzy)      │  │
│  │                                                      │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌───────────┐ │  │
│  │  │   Xsens      │  │   Realsense  │  │  Ouster   │ │  │
│  │  │    IMU       │  │   D435i      │  │  LiDAR    │ │  │
│  │  │  Container   │  │  Container   │  │ Container │ │  │
│  │  └──────┬───────┘  └──────┬───────┘  └─────┬─────┘ │  │
│  │         │                 │                 │       │  │
│  │  ┌──────────────┐  ┌──────────────┐  ┌───────────┐ │  │
│  │  │    Emlid     │  │  Robot State │  │ Foxglove  │ │  │
│  │  │   GNSS       │  │  Publisher   │  │  Bridge   │ │  │
│  │  │  Container   │  │  Container   │  │(Visualization) │
│  │  └──────┬───────┘  └──────────────┘  └───────────┘ │  │
│  │         │                                          │  │
│  │         └──────────────┬──────────────────────────┘  │  │
│  │                        │                             │  │
│  │         ┌──────────────▼──────────────┐             │  │
│  │         │  Recording Container        │             │  │
│  │         │  (hector_recorder +         │             │  │
│  │         │   ros2 bag record)          │             │  │
│  │         └──────────────┬──────────────┘             │  │
│  │                        │                             │  │
│  └────────────────────────┼─────────────────────────────┘  │
│                           │                                │
│  ┌────────────────────────▼──────────────────────────────┐ │
│  │  Rosbag Output (/rosbags/)                          │ │
│  │  - Timestamped recordings                           │ │
│  │  - Configurable split (by size or duration)         │ │
│  │  - Compression profiles (zstd, etc.)               │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                           │
└─────────────────────────────────────────────────────────────┘

Container Structure

The system is organized as a collection of modular OCI (Open Container Initiative) compliant containers, each handling a specific sensor or functionality:

  • Desktop (Docker): Runs under Docker daemon and docker-compose
  • SteamDeck (Podman): Runs under Podman daemon and podman-compose
  • Compatibility: Identical container images work on both Docker and Podman - no modifications needed

Sensor Containers

  1. Xsens IMU Container (Dockerfile.xsens)

    • Runs the Norlab Xsens driver (ROS2 Jazzy branch)
    • Provides IMU data, magnetometer readings, and computed heading
    • Communicates via serial device /dev/ttyUSB0 (460800 baud rate)
    • Topics: /imu/data, /imu/mag, /heading
  2. RealSense Container (Dockerfile.realsense)

    • Compiles librealsense2 library with USB backend
    • Runs RealSense ROS2 driver with custom launch configuration
    • Supports RGB color, depth, and infrared streams
    • Publishes camera intrinsics and extrinsics
    • Topics: /camera/color/image_raw, /camera/aligned_depth_to_color/image_raw, etc.
  3. Ouster LiDAR Container (Dockerfile.ouster)

    • Runs Ouster ROS2 driver with custom configuration
    • Connects to Ouster sensor via network (169.254.49.182 by default)
    • Outputs raw lidar packets and processed point clouds
    • Topics: /ouster/lidar_packets, /ouster/imu_packets, /ouster/points, etc.
  4. Emlid GNSS Container (Dockerfile.emlid)

    • Runs nmea_navsat_driver for GNSS/GPS data
    • Provides position, velocity, and satellite information
    • Topics: /fix, /fix_velocity

Utility Containers

  1. Recording Container (Dockerfile.recording)

    • Handles ROS2 bag recording using hector_recorder and ros2 bag record
    • Splits bags by size or duration as configured
    • Stores rosbags in /rosbags mount
    • Applies compression profiles (none, fastwrite, zstd_fast, zstd_small)
  2. Publisher Container (Dockerfile.publisher)

    • Runs the robot state publisher from apparatus_description package
    • Publishes URDF transforms and TF frames
    • Topics: /tf, /tf_static, /robot_description
  3. Visualization Container (Foxglove Bridge)

    • Provides web-based real-time visualization
    • Accessible via port 9092
    • Bridges ROS2 topics to web interface

Time Synchronization

The system implements hardware time synchronization:

  • Raspberry Pi Pico coordinates time across all sensors
  • Each sensor driver receives synchronized timestamps
  • Ensures data alignment across heterogeneous sensors
  • Critical for multi-modal fusion applications

Network Architecture

Network: ros2-net (Docker bridge)
├─ Xsens IMU Container
├─ RealSense Container
├─ Ouster LiDAR Container
├─ Emlid GNSS Container
├─ Robot Publisher Container
├─ Recording Container
├─ Monitoring Container
└─ Foxglove Bridge (exposed on port 9092)

Optional: link-local-net (for specific deployments)

Data Flow

Recording Pipeline

  1. Sensor Data Acquisition

    • Each sensor container publishes data to ROS2 topics
    • Data timestamped with hardware synchronization
  2. Topic Selection

    • User selects which topics to record via interactive GUI
    • Selection passed to recording container
  3. Recording Process

    • Recording container subscribes to selected topics
    • Uses ros2 bag record with specified compression profile
    • Splits bags based on configured limits (size or time)
    • Stores in timestamped directories under /rosbags
  4. Post-Recording

    • Bag metadata saved to info.txt
    • metadata.yaml generated with recording information
    • Bags ready for offline processing

Topic Organization

IMU Topics:

  • /imu/data - Full IMU measurements (9-DOF)
  • /imu/mag - Magnetometer readings
  • /heading - Computed heading angle

LiDAR Topics:

  • /ouster/lidar_packets - Raw packet data
  • /ouster/imu_packets - Internal IMU from LiDAR
  • /ouster/metadata - Configuration metadata
  • /ouster/points - Processed point cloud
  • /ouster/imu - Processed IMU data
  • /ouster/range_image - Range visualization
  • /ouster/reflec_image - Reflectivity data

Camera Topics:

  • /camera/color/image_raw - RGB color image
  • /camera/color/camera_info - Color camera intrinsics
  • /camera/aligned_depth_to_color/image_raw - Aligned depth map
  • /camera/aligned_depth_to_color/camera_info - Depth camera intrinsics
  • /camera/left/image_raw - Left IR stream
  • /camera/right/image_raw - Right IR stream
  • /camera/extrinsics/depth_to_color - Extrinsic calibration

Navigation Topics:

  • /fix - GNSS position information
  • /fix_velocity - GNSS velocity information

Transform Topics:

  • /tf - Dynamic transform frames
  • /tf_static - Static transform frames
  • /robot_description - URDF robot model

Deployment Modes

Container Runtime

The system supports two container runtimes, transparently handled by launch scripts:

Runtime Platform Installation Notes
Docker Desktop/Workstation Manual installation required Standard Docker daemon
Podman SteamDeck Pre-installed, rootless mode Drop-in Docker replacement

Automatic Detection: Launch scripts automatically detect and use the appropriate runtime:

  • Desktop systems: Use docker and docker-compose
  • SteamDeck: Use podman and podman-compose

Command Compatibility: Podman and Docker use identical command syntax, so scripts work on both platforms.

Mode 1: Interactive GUI (KDE Desktop)

  • Launches via launch-system.sh
  • Provides kdialog menus for configuration
  • Suitable for desktop environments and SteamDeck
  • Runtime: Docker (desktop) / Podman (SteamDeck)

Mode 2: GNOME Desktop

  • Launches via gnome-launch-system.sh
  • Native GNOME integration
  • Runtime: Docker (desktop) / Podman (SteamDeck)

Mode 3: Direct Container Compose (Advanced)

Manual control via container compose commands:

Desktop (Docker):

docker-compose up -d

SteamDeck (Podman):

podman-compose up -d
  • No automatic recording
  • Useful for custom scripts and headless operations

Mode 4: Pre-Recording Test

  • Automated test via pre_recording_test.sh
  • Validates sensor connectivity
  • Records sample data for diagnostics
  • Runtime: Automatically detects Docker or Podman

Performance Characteristics

Sampling Rates

  • IMU (Xsens): Up to 2000 Hz (configurable)
  • LiDAR (Ouster): Up to 10 Hz point cloud, 2000 Hz IMU
  • RealSense D435i: 30 Hz RGB (1920x1080), 90 Hz depth (1280x720)
  • GNSS (Emlid): 10 Hz position updates

Storage Requirements

  • High-quality recording: ~2-5 GB/minute (uncompressed)
  • Compressed (zstd_fast): ~500 MB-1 GB/minute
  • Compressed (zstd_small): ~200-500 MB/minute
  • Bag splitting prevents operating system file size limits

Supported Compression Profiles

  • none - No compression (fastest)
  • fastwrite - Fast compression
  • zstd_fast - Fast ZSTD compression
  • zstd_small - High compression ratio (slower write)

Hardware Requirements

Host System

  • OS: Linux (Ubuntu recommended)
  • Docker: 20.10+ compatible
  • CPU: Quad-core minimum (8-core recommended)
  • RAM: 8 GB minimum (16 GB recommended)
  • Storage: Fast SSD (500 GB+ for extended recordings)

Supported Deployments

  • SteamDeck (with Linux environment)
  • Desktop Workstations
  • Embedded Systems (Jetson, etc.)

Sensor Requirements

  • Xsens MTi USB interface (460800 baud)
  • RealSense D435i USB 3.0
  • Ouster OS1/OS2 Ethernet connection (link-local 169.254.0.0/16)
  • Emlid Reach via serial or Ethernet

URDF and Transform Structure

The apparatus_description ROS2 package defines:

  • Robot kinematic chain and sensor mounting
  • URDF models with mesh definitions
  • Transform relationships between sensors
  • Static transforms to common reference frame

Stored in: /docker_build/apparatus_description/urdf/

Extensibility

The modular container design allows:

  1. Adding New Sensors: Create new Dockerfile, add to docker-compose.yml
  2. Custom Recording Logic: Modify hector_recorder or ros2 bag record parameters
  3. Post-Processing: Hooks for automatic dataset conversion (rosbag → MCAP, etc.)
  4. Visualization Tools: Replace or supplement Foxglove Bridge

What's Next?

See the following documents for more information: