Scripts Reference - Forestry-Robotics-UC/fruc_dataset_apparatus GitHub Wiki

Scripts Reference Manual

Overview

This document provides detailed reference information for all shell scripts and utilities in the FRUC Dataset Apparatus system.

Main Launch Scripts

launch-system.sh

Location: ./launch-system.sh
Purpose: Main interactive launch script for the system
Platform: Works with KDE Plasma (kdialog)

Usage

./launch-system.sh

Function Flow

launch-system.sh
├── Generate Recording Name
│   ├── Read random adjectives from .names_01 and .names_02
│   ├── Generate timestamp (YYYY-MM-DD_HH-MM-SS)
│   └── Present kdialog for user confirmation/modification
│
├── Select Topics for Recording
│   ├── Present kdialog checklist
│   ├── Pre-select common topics (on/off)
│   └── Return selected topics as space-separated list
│
├── Select Bag Splitting Strategy
│   ├── Option 1: Split by size (GB)
│   │   └── Convert GB to bytes: GB * 1073741824
│   └── Option 2: Split by duration (seconds)
│
├── Select Compression Profile
│   ├── none - no compression
│   ├── fastwrite - fast compression
│   ├── zstd_fast - ZSTD fast mode
│   └── zstd_small - ZSTD maximum compression
│
├── Confirmation Dialog
│   ├── Display all settings
│   └── User confirms to start
│
└── Launch System
    ├── Start Docker containers (compose up)
    ├── Execute recording command
    ├── Monitor recording progress
    └── Save bag information to info.txt

Environment Variables Set

Variable Description
SCRIPT_DIR Directory containing the script
name1, name2 Random names from .names_* files
default_name Auto-generated recording name
recording_name User-selected recording name
topics Selected ROS topics for recording
recording_limit_option size OR duration
bag_limit_flag -b bytes OR -d seconds
storage_profile Compression profile

Return Values

  • 0: Recording completed successfully
  • 1: User cancelled or error occurred

Example Output

$ ./launch-system.sh

# Dialog 1: Name prompt
[kdialog] "Enter a name for the recording:"
[default] "2026-02-20_15-30-45__excited_maman-brigitte"

# Dialog 2: Topics checklist (selected items marked with *)
* /imu/data - Xsens IMU Data
* /imu/mag - Xsens IMU Magnetometer
* /heading - Heading
* /tf_static - Static TF
...

# Dialog 3: Splitting strategy
[kdialog] "Size (in GB)" selected -> "5"
-> bag_limit_flag="-b 5368709120"

# Dialog 4: Compression
[kdialog] Storage profile: "zstd_fast" selected

# Dialog 5: Confirmation
[kdialog] Start recording named: '2026-02-20_15-30-45__excited_maman-brigitte'

# Start recording...
Recording Started!

Topics Available (Configurable)

Located starting at line 25 in the script:

topics=$(kdialog --checklist "Topics to record" \
    /imu/data "Xsens IMU Data" on \
    /imu/mag "Xsens IMU Magnetometer" on \
    /heading "Heading" on \
    /tf_static "Static TF" on \
    /tf "TF" on \
    /robot_description "Robot Description" on \
    /ouster/lidar_packets "Ouster LiDAR Packets" on \
    /ouster/imu_packets "Ouster IMU Packets" on \
    /ouster/metadata "Ouster Metadata" on \
    ...and more
)

Modification Examples

Add a new topic to recording dialog:

# Find the kdialog --checklist section and add:
/new_sensor/data "New Sensor Data" on \

Change default compression:

# Find this line (around line 81):
storage_profile=$(kdialog --combobox "Select storage preset profile:" none fastwrite zstd_fast zstd_small --default none)

# Change --default to:
--default zstd_fast

Change default recording size:

# Find this line (around line 72):
bag_limit_value=$(kdialog --inputbox "Enter max bag size (GB):" "5")

# Change "5" to different default:
"10"  # For 10 GB default

gnome-launch-system.sh

Location: ./gnome-launch-system.sh
Purpose: Launch script for GNOME desktop environments
Platform: GNOME (Freedesktop standard)

Usage

./gnome-launch-system.sh

Differences from KDE Version

  • Uses zenity instead of kdialog for GUI dialogs
  • GNOME native dialog styling
  • Same functionality and flow as launch-system.sh

Zenity Dialog Commands

Component Command
Text input zenity --entry
Checklist zenity --list --checklist
Radio button zenity --list --radiolist
Dropdown zenity --list
Confirmation zenity --question
Info message zenity --info
Error message zenity --error

stop-system.sh

Location: ./stop-system.sh
Purpose: Gracefully stop the entire recording system
Platform: All Linux (Docker on desktop, Podman on SteamDeck)

Usage

./stop-system.sh

Sequence of Operations

The script uses Docker on desktop systems and Podman on SteamDeck. Example with Podman (SteamDeck):

#!/bin/bash

# 1. Send SIGINT to recording process (allows graceful shutdown)
podman exec recording pkill -SIGINT -f hector_recorder

# 2. Stop containers in dependency order
podman stop recording      # Stop recording first (in-flight writes)
podman stop monitoring     # Then monitoring
podman stop xsens          # Sensor containers
podman stop emlid
podman stop foxglove-bridge
podman stop realsense
podman stop ouster

For Desktop (Docker), simply replace podman with docker:

docker exec recording pkill -SIGINT -f hector_recorder
docker stop recording
# ... etc

Container Shutdown Order

The order is important:

  1. Recording - Must finish writing current data
  2. Monitoring - Stops collecting metrics
  3. Sensor Containers - Stop publishing data
  4. Visualization - Stop the UI bridge

Common Use Cases

Quick stop (all at once):

./stop-system.sh

Stop specific container (example for SteamDeck with Podman):

podman stop ros2-apparatus-realsense

# Or on Desktop with Docker:
docker stop ros2-apparatus-realsense

Force stop (ungraceful):

# SteamDeck (Podman):
podman kill ros2-apparatus-recording

# Desktop (Docker):
docker kill ros2-apparatus-recording

Specialized Scripts

gnome-stop-system.sh

Location: ./gnome-stop-system.sh
Purpose: GNOME variant of stop script
Usage: ./gnome-stop-system.sh

Same functionality as stop-system.sh with GNOME notification support. Automatically uses Docker on desktop or Podman on SteamDeck.


tty-perms.sh

Location: ./tty-perms.sh
Purpose: Set serial port permissions for sensor access
Platform: Linux

Usage

sudo bash tty-perms.sh

# Or manually:
sudo chmod 666 /dev/ttyUSB0  # Xsens
sudo chmod 666 /dev/ttyUSB1  # Other serial devices (if present)

What It Does

#!/bin/bash
# Sets read/write permissions on USB serial devices
# Allows non-root access to /dev/ttyUSB* without sudo

chmod 666 /dev/ttyUSB*  # All USB serial devices
chmod 666 /dev/ttyACM*  # USB ACM (modem) devices

Why It's Needed

By default, /dev/ttyUSB* devices have restricted permissions (rw-rw----) that only root or the dialout group can access. This script allows any user to access them.

Alternative: Add User to dialout Group

# More permanent solution
sudo usermod -aG dialout $USER

# Then log out and back in
exit

pre_recording_test.sh

Location: ./docker/pre_recording_test.sh
Purpose: Automated diagnostic test for sensor connectivity
Platform: Requires Docker/Podman

Usage

cd docker/
bash pre_recording_test.sh

Function Flow

pre_recording_test.sh
├── Generate test recording name
│   └── Format: YYYY-MM-DD_HH-MM-SS__pre_recording_check
│
├── Define test parameters
│   ├── Default topics: /imu/data, /ouster/*, /camera/*, /fix
│   ├── Split interval: 60 seconds per bag
│   ├── Total duration: 420 seconds (7 minutes)
│   └── Storage profile: zstd_fast
│
├── Start Docker containers
│   └── podman-compose up -d
│
├── Begin recording (background)
│   ├── Record for full duration
│   ├── Split bags every 60 seconds
│   └── Store in /rosbags/
│
├── Monitor recording progress
│   └── Display elapsed time
│
├── Stop recording gracefully
│   └── Collect final metrics
│
├── Analyze results
│   ├── List recorded bags
│   ├── Run: ros2 bag info
│   ├── Display topic frequencies
│   └── Check for errors
│
└── Generate diagnostic report
    └── Save to console and logs

Test Output Example

===============================================
 Starting Pre-Recording System Check
 Bag Name:     2026-03-30_10-15-22__pre_recording_check
 Duration:     420s total
 Split every:  60s
 Storage:      zstd_fast
 Topics:       /imu/data /ouster/lidar_packets ...
===============================================

Launching containers...
[OK] All containers started

Starting ROS2 bag recording...
Recording for 420s...
[████████░░] 50% complete (210s / 420s)
Recording finished.

Bag info and topic frequencies:
/imu/data: 200.0 Hz ✓
/ouster/lidar_packets: 10.0 Hz ✓
/camera/color/image_raw: 30.0 Hz ✓
...

Pre-recording check complete.

Common Use Cases

Before first major recording:

# Full system diagnostic
cd docker/
bash pre_recording_test.sh

# Wait for completion (~8 minutes)

Quick connectivity check (modify script):

# Edit pre_recording_test.sh
# Change: total_duration=420  →  total_duration=60
bash pre_recording_test.sh

Test after adding new sensor:

# Add new topic to `topics` variable
# Run pre_recording_test.sh
# Verify new sensor appears in output

Container Control Scripts

Sensor Launch Scripts (in docker_shared/scripts/)

These scripts are called by Docker containers to start sensor drivers.

xsens-launch.sh

Purpose: Initialize Xsens IMU driver
Called by: Dockerfile.xsens

#!/bin/bash
set -e

# Source ROS2 setup
source /docker_ws/install/setup.bash

# Patch driver with shared scripts (custom modifications)
cat /ros2_ws/shared/scripts/mtdevice.py > \
  /docker_ws/src/norlab_xsens_driver/xsens_driver/mtdevice.py
cat /ros2_ws/shared/scripts/mtnode.py > \
  /docker_ws/src/norlab_xsens_driver/xsens_driver/mtnode.py

# Launch Xsens driver with parameters
ros2 launch xsens_driver xsens_driver.launch.xml \
  baudrate:=460800 \          # Serial communication speed
  device:=/dev/ttyUSB0 \      # Serial port
  frame_id:=xsens_imu         # ROS TF frame

Parameters:

  • baudrate: 460800 (standard for Xsens)
  • device: Serial port (usually /dev/ttyUSB0)
  • frame_id: ROS coordinate frame name

realsense-launch.sh

Purpose: Initialize RealSense camera driver
Called by: Dockerfile.realsense

Launches RealSense ROS2 driver with custom configuration.

# Sources workspace and executes:
ros2 launch rslaunch rs_launch.py \
  use_sim_time:=False

emlid-launch.sh

Purpose: Initialize Emlid GNSS driver
Called by: Dockerfile.emlid

Launches nmea_navsat_driver for GPS/GNSS positioning.


Python Utility Scripts

mtnode.py & mtdevice.py

Location: docker/docker_shared/scripts/
Purpose: Xsens driver communication libraries
Language: Python 3

mtdevice.py:

  • Low-level serial communication with Xsens IMU
  • Device configuration and calibration
  • Packet parsing and formatting
  • Baud rate and protocol handling

mtnode.py:

  • ROS2 node wrapper for Xsens device
  • Topic publishing and subscription
  • Frame ID management
  • Data timestamp synchronization

ouster.launch.py

Location: docker/docker_shared/scripts/
Purpose: ROS2 launch configuration for Ouster LiDAR

# Key configuration options:
hostname = "169.254.49.182"     # Ouster IP address
lidar_port = 8308               # UDP lidar data port
imu_port = 8309                 # UDP IMU data port
udp_dest = "<host_ip>"          # Where to send UDP packets

Usage: Called by Ouster container via docker-compose


Docker Support Scripts

entrypoint.sh

Location: docker/docker_build/entrypoint.sh
Purpose: Container initialization script

#!/bin/bash
set -e

# Source ROS2 environment
source /opt/ros/jazzy/setup.bash

# If workspace exists, source it
if [ -d /docker_ws/src ]; then
    cd /docker_ws
    source /docker_ws/install/setup.bash
fi

# Execute the command passed to container
exec "$@"

Execution Flow:

  1. Set error exit on any failure
  2. Source system ROS2 setup
  3. Source container-built workspace (if exists)
  4. Execute the command specified in Docker CMD

This ensures all ROS2 environment variables are set before sensor drivers start.


Usage Patterns

Custom Recording with Script Modification

Example 1: Add new topic to recording

Edit launch-system.sh:

# Find the kdialog --checklist section around line 25
topics=$(kdialog --checklist "Topics to record" \
    /imu/data "Xsens IMU Data" on \
    # ... existing topics ...
    /new_topic/data "New Topic" on \    # Add this line
    /fix "GPS" on)

Example 2: Change default compression

Edit launch-system.sh:

# Find around line 91
--default none)

# Change to:
--default zstd_fast)

Automated Recording Script

Create auto_record.sh:

#!/bin/bash
RECORDING_DIR="rosbags/auto_$(date +%Y-%m-%d)"
mkdir -p "$RECORDING_DIR"

cd docker/
docker-compose up -d

sleep 5  # Wait for containers to initialize

podman run --rm -it --name recording --network docker_ros2-net \
  -v ../rosbags:/rosbags \
  localhost/docker_recording bash -c \
  "ros2 run hector_recorder record -d 3600 \
     --topics /imu/data /ouster/lidar_packets \
     -o /rosbags/$RECORDING_DIR/auto_recording"

./stop-system.sh

Batch Processing Multiple Recordings

#!/bin/bash
# Process all recordings in parallel

for recording_dir in rosbags/*/; do
    recording_name=$(basename "$recording_dir")
    
    # Extract point cloud
    ros2 bag convert -i "$recording_dir" \
        --topics /ouster/points \
        -f csv -o "pcd/${recording_name}.pcd" &
    
    # Create info file
    ros2 bag info "$recording_dir" \
        > "${recording_dir}/analysis.txt" &
done

wait  # Wait for all background jobs
echo "Processing complete"

Environment Variables in Scripts

Variable Set By Used For
SCRIPT_DIR launch-system.sh Script location detection
ROS_DOMAIN_ID Container env DDS domain isolation
DISPLAY docker-compose.yml X11 visualization
OUSTER_HOSTNAME Dockerfile.ouster LiDAR connection
TOPICS launch-system.sh Recording topic selection

Script Permissions

All scripts should be executable:

# Check current permissions
ls -la *.sh

# Make script executable
chmod +x launch-system.sh
chmod +x stop-system.sh

# For all scripts
chmod +x *.sh
chmod +x docker/*.sh
chmod +x docker/docker_shared/scripts/*.sh
chmod +x docker/docker_build/*.sh

Debugging Scripts

Enable Verbose Output

# Run with bash debug mode
bash -x launch-system.sh

# Or add to script header:
set -v  # Print commands
set -x  # Print commands with expansion

Check Syntax

# Verify script syntax before running
bash -n launch-system.sh
bash -n stop-system.sh

# Or use ShellCheck linter
shellcheck launch-system.sh

Log Script Execution

# Save output to file
./launch-system.sh 2>&1 | tee recording.log

# Later, review:
cat recording.log

Related Documentation


Last Updated: 2026-03-30

⚠️ **GitHub.com Fallback** ⚠️