From 8e8c6163484a3de55131ab99486fd74f61cc1728 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Sat, 31 Jan 2026 14:14:49 +0000 Subject: [PATCH] fix(turtlebot3): resolve port conflict between CPU and NVIDIA profiles - Add cpu/nvidia profiles to prevent simultaneous service startup - Add stop-demo.sh script for clean shutdown with --volumes/--images options - Add --update flag to pull latest images before running - Add --attached flag for foreground mode (daemon mode is now default) - Update README with daemon mode instructions and new scripts - Add instructions for viewing logs and interacting with ROS 2 in containers Fixes port 8080 conflict when running with --nvidia flag where both turtlebot3-demo and turtlebot3-demo-nvidia services tried to bind to the same port. Now --profile cpu (default) or --profile nvidia must be explicitly specified, ensuring mutual exclusivity. Changes: - docker-compose.yml: Add profiles=['cpu'] to default service - run-demo.sh: Default to --profile cpu, add daemon mode with -d flag - stop-demo.sh: New script for stopping containers with cleanup options - README.md: Update Quick Start, add daemon mode docs, add stop script --- demos/turtlebot3_integration/README.md | 63 ++++++++++++---- .../turtlebot3_integration/docker-compose.yml | 2 + demos/turtlebot3_integration/run-demo.sh | 56 +++++++++++++- demos/turtlebot3_integration/stop-demo.sh | 74 +++++++++++++++++++ 4 files changed, 178 insertions(+), 17 deletions(-) create mode 100755 demos/turtlebot3_integration/stop-demo.sh diff --git a/demos/turtlebot3_integration/README.md b/demos/turtlebot3_integration/README.md index eac671b..227d95b 100644 --- a/demos/turtlebot3_integration/README.md +++ b/demos/turtlebot3_integration/README.md @@ -38,29 +38,45 @@ That's it! The script will: 1. Build the Docker images (first run takes ~5-10 min, downloads ~4GB) 2. Setup X11 forwarding for Gazebo GUI -3. Launch TurtleBot3 simulation + Nav2 + ros2_medkit gateway +3. Launch TurtleBot3 simulation + Nav2 + ros2_medkit gateway in **daemon mode** (background) 4. Launch sovd_web_ui at -**Note:** By default, the demo runs with **Gazebo GUI** for visualization. Requires X11 display. +**Note:** By default, the demo runs in **daemon mode** with **Gazebo GUI** enabled. This allows you to interact with ROS 2 while the demo is running. -### Running Headless (Server Only) - -For CI/CD or remote servers without display: +### Available Options ```bash -HEADLESS=true docker compose up -# or: -./run-demo.sh --headless +./run-demo.sh # Daemon mode with GUI (default) +./run-demo.sh --attached # Foreground mode with live logs +./run-demo.sh --headless # Daemon mode without GUI (headless) +./run-demo.sh --nvidia # Use NVIDIA GPU acceleration +./run-demo.sh --update # Pull latest images before running +./run-demo.sh --no-cache # Rebuild without cache ``` -### Running with GUI (Default) +### Viewing Logs and Interacting with ROS 2 -With Gazebo visualization: +Since the demo runs in daemon mode by default, you can: ```bash -docker compose up -# or: -./run-demo.sh +# View live logs +docker compose --profile cpu logs -f + +# Enter the container to run ROS 2 commands +docker exec -it turtlebot3_medkit_demo bash + +# Inside the container: +ros2 node list +ros2 topic list +ros2 topic echo /odom +``` + +### Stopping the Demo + +```bash +./stop-demo.sh # Stop containers +./stop-demo.sh --volumes # Stop and remove volumes +./stop-demo.sh --images # Stop and remove images ``` ### 2. Access the Web UI @@ -85,7 +101,15 @@ For hardware-accelerated Gazebo rendering with NVIDIA GPU: You can also use Docker Compose directly: ```bash -docker compose --profile nvidia up --build +# CPU version (default profile) +docker compose --profile cpu up -d + +# NVIDIA version +docker compose --profile nvidia up -d + +# View logs +docker compose --profile cpu logs -f +docker compose --profile nvidia logs -f ``` ## Controlling the Robot @@ -118,7 +142,13 @@ curl -X PUT http://localhost:8080/api/v1/apps/turtlebot3-node/data/cmd_vel \ ### Via ROS2 CLI (inside container) +First, enter the running container: + ```bash +# Enter the container +docker exec -it turtlebot3_medkit_demo bash + +# Inside the container: # Send navigation goal ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose \ "{pose: {header: {frame_id: 'map'}, pose: {position: {x: 2.0, y: 0.5, z: 0.0}, orientation: {w: 1.0}}}}" @@ -126,6 +156,9 @@ ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose \ # Manual teleop ros2 topic pub /cmd_vel geometry_msgs/msg/Twist \ "{linear: {x: 0.2}, angular: {z: 0.0}}" --once + +# Exit container +exit ``` ## REST API Endpoints @@ -390,6 +423,7 @@ demos/turtlebot3_integration/ ├── Dockerfile # ROS 2 Jazzy + TurtleBot3 + Nav2 + ros2_medkit ├── docker-compose.yml # Docker Compose (CPU & GPU via profiles) ├── run-demo.sh # One-click demo launcher +├── stop-demo.sh # Stop and cleanup demo ├── send-nav-goal.sh # Send navigation goal via SOVD API ├── check-entities.sh # Explore SOVD entity hierarchy ├── check-faults.sh # View active faults @@ -412,6 +446,7 @@ demos/turtlebot3_integration/ | Script | Description | |--------|-------------| | `run-demo.sh` | Start the full demo (Docker) | +| `stop-demo.sh` | Stop containers and cleanup | | `send-nav-goal.sh [x] [y] [yaw]` | Send navigation goal via SOVD API | | `check-entities.sh` | Explore SOVD entity hierarchy | | `check-faults.sh` | View active faults from gateway | diff --git a/demos/turtlebot3_integration/docker-compose.yml b/demos/turtlebot3_integration/docker-compose.yml index 94352aa..7b1c78f 100644 --- a/demos/turtlebot3_integration/docker-compose.yml +++ b/demos/turtlebot3_integration/docker-compose.yml @@ -1,6 +1,8 @@ services: # CPU-only version (default) + # Use with: docker compose --profile cpu up turtlebot3-demo: + profiles: ["cpu"] build: context: . dockerfile: Dockerfile diff --git a/demos/turtlebot3_integration/run-demo.sh b/demos/turtlebot3_integration/run-demo.sh index 4ddadf8..cabab5d 100755 --- a/demos/turtlebot3_integration/run-demo.sh +++ b/demos/turtlebot3_integration/run-demo.sh @@ -41,6 +41,8 @@ trap cleanup EXIT COMPOSE_ARGS="" BUILD_ARGS="" HEADLESS_MODE="false" +UPDATE_IMAGES="false" +DETACH_MODE="true" usage() { echo "Usage: $0 [OPTIONS]" @@ -49,13 +51,17 @@ usage() { echo " --nvidia Use NVIDIA GPU acceleration" echo " --no-cache Build Docker images without cache" echo " --headless Run without Gazebo GUI (default: GUI enabled)" + echo " --update Pull latest images before running" + echo " --attached Run in foreground (default: daemon mode)" echo " -h, --help Show this help message" echo "" echo "Examples:" - echo " $0 # With Gazebo GUI (default)" + echo " $0 # Daemon mode (default)" + echo " $0 --attached # Foreground with logs" echo " $0 --headless # Headless mode (no GUI)" echo " $0 --nvidia # GPU acceleration + GUI" echo " $0 --no-cache # Rebuild without cache" + echo " $0 --update # Pull and run latest version" echo "" echo "Environment variables:" echo " HEADLESS=true|false Control GUI mode (default: false)" @@ -75,6 +81,14 @@ while [[ $# -gt 0 ]]; do echo "Running in headless mode (no GUI)" HEADLESS_MODE="true" ;; + --update) + echo "Will pull latest images" + UPDATE_IMAGES="true" + ;; + --attached) + echo "Running in foreground mode" + DETACH_MODE="false" + ;; -h|--help) usage exit 0 @@ -90,11 +104,13 @@ done if [[ -z "$COMPOSE_ARGS" ]]; then echo "Using CPU-only mode (use --nvidia flag for GPU acceleration)" + COMPOSE_ARGS="--profile cpu" fi # Export HEADLESS mode for docker-compose export HEADLESS=$HEADLESS_MODE echo "Gazebo mode: $([ "$HEADLESS_MODE" = "true" ] && echo "headless (no GUI)" || echo "GUI enabled")" +echo "Run mode: $([ "$DETACH_MODE" = "true" ] && echo "daemon (background)" || echo "attached (foreground)")" # Build and run echo " Building and starting demo..." @@ -108,12 +124,46 @@ echo "🌐 REST API available at: http://localhost:8080/api/v1/" echo "🌐 Web UI available at: http://localhost:3000/" echo "" +# Pull images if --update flag is set +if [[ "$UPDATE_IMAGES" == "true" ]]; then + echo "📥 Pulling latest images..." + if docker compose version &> /dev/null; then + # shellcheck disable=SC2086 + docker compose ${COMPOSE_ARGS} pull + else + # shellcheck disable=SC2086 + docker-compose ${COMPOSE_ARGS} pull + fi + echo "" +fi + +# Set detach flag +DETACH_FLAG="" +if [[ "$DETACH_MODE" == "true" ]]; then + DETACH_FLAG="-d" +fi + if docker compose version &> /dev/null; then # shellcheck disable=SC2086 docker compose ${COMPOSE_ARGS} build ${BUILD_ARGS} && \ - docker compose ${COMPOSE_ARGS} up + docker compose ${COMPOSE_ARGS} up ${DETACH_FLAG} else # shellcheck disable=SC2086 docker-compose ${COMPOSE_ARGS} build ${BUILD_ARGS} && \ - docker-compose ${COMPOSE_ARGS} up + docker-compose ${COMPOSE_ARGS} up ${DETACH_FLAG} +fi + +if [[ "$DETACH_MODE" == "true" ]]; then + echo "" + echo "✅ Demo started in background!" + echo "" + echo "📊 To view logs:" + echo " docker compose --profile cpu logs -f # CPU version" + echo " docker compose --profile nvidia logs -f # NVIDIA version" + echo "" + echo "🔧 To interact with ROS 2:" + echo " docker exec -it turtlebot3_medkit_demo bash # CPU" + echo " docker exec -it turtlebot3_medkit_demo_nvidia bash # NVIDIA" + echo "" + echo "🛑 To stop: ./stop-demo.sh" fi diff --git a/demos/turtlebot3_integration/stop-demo.sh b/demos/turtlebot3_integration/stop-demo.sh new file mode 100755 index 0000000..fab9365 --- /dev/null +++ b/demos/turtlebot3_integration/stop-demo.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# Stop TurtleBot3 + ros2_medkit Demo + +set -eu + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "🛑 Stopping TurtleBot3 + ros2_medkit Demo" +echo "==========================================" + +# Check for Docker +if ! command -v docker &> /dev/null; then + echo "Error: Docker is not installed" + exit 1 +fi + +# Parse arguments +REMOVE_VOLUMES="" +REMOVE_IMAGES="" + +usage() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " -v, --volumes Remove named volumes" + echo " --images Remove images" + echo " -h, --help Show this help message" + echo "" + echo "Examples:" + echo " $0 # Stop containers" + echo " $0 --volumes # Stop and remove volumes" + echo " $0 --images # Stop and remove images" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + -v|--volumes) + echo "Will remove named volumes" + REMOVE_VOLUMES="-v" + ;; + --images) + echo "Will remove images" + REMOVE_IMAGES="--rmi all" + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" + usage + exit 1 + ;; + esac + shift +done + +# Stop containers +echo "Stopping containers..." +if docker compose version &> /dev/null; then + # shellcheck disable=SC2086 + docker compose down ${REMOVE_VOLUMES} ${REMOVE_IMAGES} +else + # shellcheck disable=SC2086 + docker-compose down ${REMOVE_VOLUMES} ${REMOVE_IMAGES} +fi + +# Cleanup X11 +echo "Cleaning up X11 permissions..." +xhost -local:docker 2>/dev/null || true + +echo "" +echo "✅ Demo stopped successfully!"