diff --git a/examples/5_docker_turtlesim/README.md b/examples/5_docker_turtlesim/README.md index 06e0ad1..fe68a03 100644 --- a/examples/5_docker_turtlesim/README.md +++ b/examples/5_docker_turtlesim/README.md @@ -1,21 +1,33 @@ # Example - TurtleSim in Docker -For users who want to test the MCP server without needing to install ROS, this is an example that provides a dockerized ROS2 container preinstalled with the simplest possible 'robot' in the ROS ecosystem - TurtleSim. + +For users who want to test the MCP server without needing to install ROS, this is an example that provides a dockerized ROS2 container preinstalled with the simplest possible 'robot' in the ROS ecosystem - TurtleSim. Turtlesim is a lightweight simulator for learning ROS / ROS 2. It illustrates what ROS does at the most basic level to give you an idea of what you will do with a real robot or a robot simulation later on. ## Prerequisites -✅ **Note:** This tutorial is designed to be run on linux and has been tested with Ubuntu as well as [Ubuntu running on WSL](https://apps.microsoft.com/detail/9pn20msr04dw?hl=en-US&gl=US). Being a dockerized container, it is likely to work on other OS versions as well with the correct X11 forwarding settings. +✅ **Cross-Platform Support:** This tutorial works on Linux, macOS, and Windows with proper X11/display forwarding setup. Each platform has specific requirements detailed below. Before starting this tutorial, make sure you have the following installed: +### All Platforms - **Docker**: [Install Docker](https://docs.docker.com/get-docker/) - **Docker Compose**: Usually comes with Docker Desktop, or install separately -- **X Server** (for Windows): Install [X410](https://x410.dev/) or another X Server from Microsoft Store -- **X11 forwarding** (for Linux): `sudo apt-get install x11-apps` -- **XQuartz** (for macOS): Install from [XQuartz website](https://www.xquartz.org/) -**Note:** If your OS is Windows, take a look at the following: +### Platform-Specific Requirements + +#### macOS +- **XQuartz**: Install from [XQuartz website](https://www.xquartz.org/) +- **Important**: XQuartz setup can be complex - see [macOS Setup](#macos-setup) section below for detailed instructions + +#### Linux +- **X11 forwarding**: `sudo apt-get install x11-apps` +- Usually works out of the box with minimal setup + +#### Windows +- **X Server**: Install [X410](https://x410.dev/), [VcXsrv](https://sourceforge.net/projects/vcxsrv/), or another X Server from Microsoft Store +- **WSL recommended**: Works best with Windows Subsystem for Linux +
PowerShell and WSL (Windows) @@ -36,23 +48,38 @@ cd examples/5_docker_turtlesim docker compose build --no-cache turtlesim ``` -### 2. Start the Container +### 2. Launch Turtlesim + +#### Automatic Setup (Recommended) -Launch the turtlesim container +The easiest way to launch turtlesim with proper X11 setup: ```bash -docker compose up +./launch.sh ``` -If your OS is Windows and you want to launch docker in PowerShell, you first need to set the DISPLAY: +This script automatically detects your OS and handles all platform-specific X11 configuration. It will: +- **macOS**: Start XQuartz, detect display, configure IP-based forwarding +- **Linux**: Set up X11 permissions with `xhost +local:docker` +- **Windows**: Configure X server connection via `host.docker.internal` + +#### Manual Setup (Advanced) + +If you prefer manual control or the automatic script doesn't work: + +**macOS:** ```bash -$env:DISPLAY="host.docker.internal:0.0" +./docker/scripts/launch_macos.sh ``` -If your OS is Ubuntu/WSL and the docker doesn't run successfully, consider: +**Linux (or Windows WSL):** +```bash +./docker/scripts/launch_linux.sh +``` +**Windows:** ```bash -dos2unix docker/scripts/launch_turtlesim.sh +./docker/scripts/launch_windows.sh ``` The container will automatically start both turtlesim and rosbridge websocket server. You should see: @@ -69,8 +96,8 @@ Launch the container in the background: ```bash docker compose up -d ``` -And attach to the container +And attach to the container: ```bash docker exec -it ros2-turtlesim bash ``` @@ -78,7 +105,7 @@ docker exec -it ros2-turtlesim bash Once inside the container, you can manually launch turtle teleop to control the turtle: ```bash -source /opt/ros/humble/setup.bash +source /opt/ros/${ROS_DISTRO}$/setup.bash ros2 run turtlesim turtle_teleop_key ``` @@ -87,45 +114,145 @@ This will allow you to use arrow keys or WASD to manually move the turtle around ## Integration with MCP Server Once turtlesim and rosbridge are running, you can connect the MCP server to control the turtle programmatically. -Follow the [installation guide](../../docs/installation.md) for full setup instructions if you haven't already set up the MCP server. +Follow the [installation guide](../../docs/installation.md) for full setup instructions if you haven't already set up the MCP server. -Since it is running on the same machine, you can tell the LLM to connect to the robot on localhost. +Since it is running on the same machine, you can tell the LLM to connect to the robot on localhost. +## Platform-Specific Setup -## Troubleshooting +
+macOS Setup -### Display Issues (Linux) +macOS requires special X11 forwarding setup. Follow these steps carefully: -If you encounter display issues on Linux, run: +### Step 1: Install XQuartz +Download and install from [XQuartz website](https://www.xquartz.org/) +### Step 2: Configure XQuartz +1. **Start XQuartz**: `open -a XQuartz` +2. **Wait for it to fully load** (you'll see an xterm window) + +### Step 3: Detect Your Setup ```bash -xhost +local:docker +# Check if XQuartz is running and which display it's using +ps aux | grep -i xquartz + +# You should see something like: +# /opt/X11/bin/Xquartz :1 -listen tcp ... +# The `:1` or `:0` is your display number +``` + +### Step 4: Get Your Machine IP +```bash +# Get your machine's IP address +ifconfig en0 | grep inet | awk '$1=="inet" {print $2}' +# Example output: 10.1.56.72 +``` + +### Step 5: Set Up Environment +```bash +# Set DISPLAY for your Mac (use the display number from Step 3) +export DISPLAY=:1 # or :0 depending on what you found + +# Allow X11 connections +xhost + + +# Set DISPLAY for Docker (use your IP from Step 4 + display number) +export DOCKER_DISPLAY= # Replace with your actual IP ``` +
+ +## Troubleshooting -### Display Issues (macOS) +### macOS Display Issues -For macOS users, make sure XQuartz is running and configured: +
+Problem: qt.qpa.xcb: could not connect to display + +**Solutions**: + +1. **Check XQuartz is running**: + ```bash + ps aux | grep X11 + ``` + +2. **Verify display number**: + ```bash + # Look for :0 or :1 in the Xquartz process + ps aux | grep Xquartz | grep -o ":[0-9]" + ``` + +3. **Check your IP address**: + ```bash + ifconfig en0 | grep inet + ``` + +4. **Set correct DOCKER_DISPLAY**: + ```bash + export DOCKER_DISPLAY="YOUR_IP:DISPLAY_NUMBER" + # Example: export DOCKER_DISPLAY="10.1.56.72:1" + ``` + +5. **Allow X11 connections**: + ```bash + export DISPLAY=:1 # Use your display number + xhost + + ``` +
+ +
+Problem: xhost: unable to open display ":0" + +**Solution**: XQuartz might be using `:1` instead of `:0`: ```bash -# Start XQuartz -open -a XQuartz +export DISPLAY=:1 +xhost + +``` +
-# Allow connections from localhost -xhost +localhost +### Linux Display Issues + +
+Display issues on Linux + +If you encounter display issues on Linux, run: + +```bash +xhost +local:docker ``` +
+ +### Windows Display Issues + +
+Display issues on Windows -### Display Issues (Windows/PowerShell) For Windows users, make sure you install an X Server (X410) and set the DISPLAY: ```bash -$env:DISPLAY="host.docker.internal:0.0" +$env:DOCKER_DISPLAY="host.docker.internal:0.0" ``` +
+ +### General Issues + +
+Problem: Container starts but no window appears -### Container Networking +**Solutions**: +1. Check if the window is hidden behind other windows +2. Look in Mission Control (macOS) or Alt+Tab (Windows/Linux) +3. Verify your DOCKER_DISPLAY is set correctly for your platform +
-If you need to access the container from outside, the container uses host networking mode, so ROS2 topics should be accessible on localhost. +
+Problem: libGL error: No matching fbConfigs or visuals found -### Manual Launch (Alternative) +**Solution**: This is just a warning and doesn't prevent the GUI from working. The turtlesim window should still appear. +
+ +## Manual Launch (Alternative) If the automatic launch isn't working or you prefer to launch turtlesim manually, you can run these commands inside the container: @@ -134,7 +261,7 @@ If the automatic launch isn't working or you prefer to launch turtlesim manually docker exec -it ros2-turtlesim bash # Source ROS2 environment -source /opt/ros/humble/setup.bash +source /opt/ros/${ROS_DISTRO}$/setup.bash # Start turtlesim in one terminal ros2 run turtlesim turtlesim_node @@ -143,11 +270,11 @@ ros2 run turtlesim turtlesim_node ros2 run turtlesim turtle_teleop_key ``` -### Testing Turtlesim +## Testing Turtlesim If you need to verify that turtlesim is working correctly: -#### ROS2 Topic Inspection +### ROS2 Topic Inspection In a separate terminal, you can inspect the ROS2 topics: @@ -156,7 +283,7 @@ In a separate terminal, you can inspect the ROS2 topics: docker exec -it ros2-turtlesim bash # Source ROS2 environment -source /opt/ros/humble/setup.bash +source /opt/ros/${ROS_DISTRO}$/setup.bash # List all topics ros2 topic list @@ -168,7 +295,7 @@ ros2 topic echo /turtle1/pose ros2 topic echo /turtle1/cmd_vel ``` -#### ROS Bridge WebSocket Server +### ROS Bridge WebSocket Server The rosbridge websocket server is automatically started and available at `ws://localhost:9090`. You can test the connection using a WebSocket client or the MCP server. @@ -196,10 +323,8 @@ docker rmi ros-mcp-server_turtlesim Now that you have turtlesim running, you can: - 1. **Try more complex commands** like drawing shapes or following paths 2. **Install ROS Locally** to add more nodes and services 3. **Explore other examples in this repository** - -This example provides a foundation for understanding how the MCP server can interact with ROS2 systems, from simple simulators like turtlesim to complex robotic platforms. +This example provides a foundation for understanding how the MCP server can interact with ROS2 systems, from simple simulators like turtlesim to complex robotic platforms. \ No newline at end of file diff --git a/examples/5_docker_turtlesim/docker-compose.yml b/examples/5_docker_turtlesim/docker-compose.yml index 406fb8c..44ee388 100644 --- a/examples/5_docker_turtlesim/docker-compose.yml +++ b/examples/5_docker_turtlesim/docker-compose.yml @@ -7,10 +7,14 @@ services: environment: - DISPLAY=${DISPLAY} - ROS_DISTRO=humble + - QT_X11_NO_MITSHM=1 volumes: + # Mount launch file into the container + - ./launch_turtlesim.launch.py:/ros2_ws/launch/launch_turtlesim.launch.py:ro + # Linux X11 socket (only works on Linux) - /tmp/.X11-unix:/tmp/.X11-unix:rw - - ./docker/scripts:/ros2_ws/scripts:ro - network_mode: host + ports: + - "9090:9090" stdin_open: true tty: true - command: bash -c "/ros2_ws/scripts/launch_turtlesim.sh" + command: ["ros2", "launch", "/ros2_ws/launch/launch_turtlesim.launch.py"] diff --git a/examples/5_docker_turtlesim/docker/scripts/launch_turtlesim.sh b/examples/5_docker_turtlesim/docker/scripts/launch_turtlesim.sh deleted file mode 100755 index ed556f5..0000000 --- a/examples/5_docker_turtlesim/docker/scripts/launch_turtlesim.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail - -# Source ROS2 environment -source /opt/ros/humble/setup.bash - -echo "Starting ROS Bridge WebSocket server..." -echo "WebSocket server will be available at: ws://localhost:9090" - -# Launch rosbridge websocket server in the background -ros2 launch rosbridge_server rosbridge_websocket_launch.xml & - -# Wait a moment for rosbridge to start -sleep 3 - -echo "Starting Turtlesim..." -echo "Turtlesim window should appear shortly" -echo "You can control the turtle using:" -echo " - Arrow keys or WASD to move" -echo " - Ctrl+C to stop" - -# Launch turtlesim in the background -ros2 run turtlesim turtlesim_node & - -# Trap signals to clean up processes -cleanup() { - # Cleanup when teleop exits - echo "Stopping turtlesim and rosbridge..." - pkill -f turtlesim_node - pkill -f rosbridge_server - wait -} - -trap cleanup SIGINT SIGTERM - -wait \ No newline at end of file diff --git a/examples/5_docker_turtlesim/launch_turtlesim.launch.py b/examples/5_docker_turtlesim/launch_turtlesim.launch.py new file mode 100644 index 0000000..f1204eb --- /dev/null +++ b/examples/5_docker_turtlesim/launch_turtlesim.launch.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +""" +ROS2 Launch file for Turtlesim with Rosbridge WebSocket Server +Launches both turtlesim node and rosbridge server for MCP integration. +""" + +from launch.actions import DeclareLaunchArgument, LogInfo +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +from launch import LaunchDescription + + +def generate_launch_description(): + """Generate the launch description for turtlesim with rosbridge.""" + + # Declare launch arguments + port_arg = DeclareLaunchArgument( + "port", default_value="9090", description="Port for rosbridge websocket server" + ) + + address_arg = DeclareLaunchArgument( + "address", + default_value="", + description="Address for rosbridge websocket server (empty for all interfaces)", + ) + + log_level_arg = DeclareLaunchArgument( + "log_level", default_value="info", description="Log level for nodes" + ) + + # Turtlesim node + turtlesim_node = Node( + package="turtlesim", + executable="turtlesim_node", + name="turtlesim", + output="screen", + arguments=["--ros-args", "--log-level", LaunchConfiguration("log_level")], + ) + + # Rosbridge websocket server node + rosbridge_node = Node( + package="rosbridge_server", + executable="rosbridge_websocket", + name="rosbridge_websocket", + output="screen", + parameters=[ + { + "port": LaunchConfiguration("port"), + "address": LaunchConfiguration("address"), + "use_compression": False, + "max_message_size": 10000000, + "send_action_goals_in_new_thread": True, + "call_services_in_new_thread": True, + "default_call_service_timeout": 5.0, + } + ], + arguments=["--ros-args", "--log-level", LaunchConfiguration("log_level")], + ) + + # ROS API node (needed for some rosbridge operations) + rosapi_node = Node( + package="rosapi", + executable="rosapi_node", + name="rosapi", + output="screen", + arguments=["--ros-args", "--log-level", LaunchConfiguration("log_level")], + ) + + # Log info + log_info = LogInfo( + msg=[ + "Starting Turtlesim with Rosbridge WebSocket Server:", + " - Port: ", + LaunchConfiguration("port"), + " - Log level: ", + LaunchConfiguration("log_level"), + ] + ) + + return LaunchDescription( + [ + port_arg, + address_arg, + log_level_arg, + log_info, + rosbridge_node, + rosapi_node, + turtlesim_node, + ] + ) diff --git a/examples/5_docker_turtlesim/scripts/launch.sh b/examples/5_docker_turtlesim/scripts/launch.sh new file mode 100755 index 0000000..2bee89c --- /dev/null +++ b/examples/5_docker_turtlesim/scripts/launch.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Unified launcher for turtlesim - auto-detects OS and runs appropriate script + +set -e + +# Detect operating system +OS_TYPE=$(uname -s) + +case "$OS_TYPE" in + Darwin*) + echo "Detected macOS - launching with XQuartz support..." + ./docker/scripts/launch_macos.sh + ;; + Linux*) + echo "Detected Linux - launching with X11 support..." + ./docker/scripts/launch_linux.sh + ;; + MINGW*|MSYS*|CYGWIN*) + echo "Detected Windows - launching with X server support..." + ./docker/scripts/launch_windows.sh + ;; + *) + echo "Unsupported OS: $OS_TYPE" + echo " Please run the appropriate script manually:" + echo " - macOS: ./docker/scripts/launch_macos.sh" + echo " - Linux: ./docker/scripts/launch_linux.sh" + echo " - Windows: ./docker/scripts/launch_windows.sh" + exit 1 + ;; +esac diff --git a/examples/5_docker_turtlesim/scripts/launch_linux.sh b/examples/5_docker_turtlesim/scripts/launch_linux.sh new file mode 100755 index 0000000..33cb46d --- /dev/null +++ b/examples/5_docker_turtlesim/scripts/launch_linux.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Linux startup script for turtlesim GUI + +set -e + +echo "Starting Turtlesim on Linux with GUI" +echo "========================================" + +# Step 1: Check if X11 is available +if [[ -z "$DISPLAY" ]]; then + echo "ERROR: DISPLAY variable not set" + echo "X11 forwarding is required. Are you running in a GUI environment?" + exit 1 +fi + +echo "Using DISPLAY: $DISPLAY" + +# Step 2: Allow Docker to access X11 +if command -v xhost >/dev/null 2>&1; then + echo "Allowing Docker X11 access..." + xhost +local:docker >/dev/null 2>&1 || { + echo "WARNING: xhost command failed, trying without sudo..." + xhost + >/dev/null 2>&1 || echo "WARNING: Could not run xhost, X11 forwarding may not work" + } +else + echo "WARNING: xhost not found. Install with: sudo apt-get install x11-xserver-utils" + exit 1 +fi + +# Step 3: Export DISPLAY for Docker +echo "Docker will use DISPLAY=$DISPLAY" + +# Step 4: Start the container +echo "" +echo "Starting Turtlesim container..." +echo "If successful, you should see a window with a turtle!" +echo "" + +docker compose up turtlesim + +echo "" +echo "Done! The turtle window should be visible on your screen." diff --git a/examples/5_docker_turtlesim/scripts/launch_macos.sh b/examples/5_docker_turtlesim/scripts/launch_macos.sh new file mode 100755 index 0000000..63138b9 --- /dev/null +++ b/examples/5_docker_turtlesim/scripts/launch_macos.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# Simple macOS startup script for turtlesim GUI +# This script handles all the X11 forwarding complexity automatically + +set -e + +echo "Starting Turtlesim on macOS with GUI" +echo "========================================" + +# Function to detect display number +detect_display() { + if pgrep -f "Xquartz :1" > /dev/null; then + echo "1" + elif pgrep -f "Xquartz :0" > /dev/null; then + echo "0" + else + echo "0" # Default fallback + fi +} + +# Function to get machine IP +get_machine_ip() { + # Try en0 first (most common) + local ip=$(ifconfig en0 2>/dev/null | grep 'inet ' | awk '{print $2}' | head -n1) + + # If en0 doesn't work, try other interfaces + if [[ -z "$ip" ]]; then + ip=$(ifconfig 2>/dev/null | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | head -n1) + fi + + echo "$ip" +} + +# Step 1: Start XQuartz if not running +if ! pgrep -x "X11.bin" > /dev/null; then + echo "Starting XQuartz..." + open -a XQuartz + + # Wait for XQuartz to start (up to 10 seconds) + for i in {1..10}; do + if pgrep -x "X11.bin" > /dev/null; then + echo "XQuartz started" + break + fi + echo " Waiting for XQuartz... ($i/10)" + sleep 1 + done + + if ! pgrep -x "X11.bin" > /dev/null; then + echo "ERROR: XQuartz failed to start. Please start it manually." + exit 1 + fi +else + echo "XQuartz already running" +fi + +# Step 2: Detect display number and machine IP +DISPLAY_NUM=$(detect_display) +MACHINE_IP=$(get_machine_ip) + +if [[ -z "$MACHINE_IP" ]]; then + echo "ERROR: Could not detect machine IP address" + echo "Please run: ifconfig en0 | grep inet" + exit 1 +fi + +echo "Display detected: :$DISPLAY_NUM" +echo "Machine IP: $MACHINE_IP" + +# Step 3: Set up X11 permissions +export DISPLAY=:$DISPLAY_NUM +if command -v xhost >/dev/null 2>&1; then + echo "Allowing X11 connections..." + xhost + >/dev/null 2>&1 || echo "WARNING: xhost command failed, but continuing..." +else + echo "WARNING: xhost not found - X11 forwarding may not work" +fi + +# Step 4: Export DISPLAY for Docker +export DISPLAY="$MACHINE_IP:$DISPLAY_NUM" +echo "Docker will use DISPLAY=$DISPLAY" + +# Step 5: Start the container +echo "" +echo "Starting Turtlesim container..." +echo " If successful, you should see a window with a turtle!" +echo "" + +docker compose up turtlesim + +echo "" +echo "Done! The turtle window should be visible on your screen." \ No newline at end of file diff --git a/examples/5_docker_turtlesim/scripts/launch_windows.sh b/examples/5_docker_turtlesim/scripts/launch_windows.sh new file mode 100755 index 0000000..9fcd3e8 --- /dev/null +++ b/examples/5_docker_turtlesim/scripts/launch_windows.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Windows (WSL/Git Bash) startup script for turtlesim GUI +# Requires an X server like VcXsrv, X410, or Xming running on Windows + +set -e + +echo "Starting Turtlesim on Windows with GUI" +echo "==========================================" + +# Step 1: Check if running in WSL or Git Bash +if grep -qi microsoft /proc/version 2>/dev/null; then + PLATFORM="WSL" +elif uname -s | grep -qi "MINGW\|MSYS\|CYGWIN"; then + PLATFORM="Git Bash/MSYS" +else + PLATFORM="Unknown" +fi + +echo "Detected platform: $PLATFORM" + +# Step 2: Check if X server is running on Windows +echo "Checking for X server on Windows..." +echo " Make sure VcXsrv, X410, or another X server is running!" +echo " If not installed, get VcXsrv from: https://sourceforge.net/projects/vcxsrv/" + +# Step 3: Set DISPLAY for Docker +# Docker Desktop on Windows uses host.docker.internal to reach Windows host +export DISPLAY="host.docker.internal:0.0" +echo "Docker will use DISPLAY=$DISPLAY" + +# Step 4: Warn about common issues +cat << 'TIPS' + +Important Notes for Windows: + - Start your X server (VcXsrv/X410) BEFORE running this script + - In VcXsrv: disable "Native opengl" and enable "Disable access control" + - If GUI doesn't appear, check Windows Firewall settings + - Docker Desktop must be running + +TIPS + +# Step 5: Start the container +echo "" +echo "Starting Turtlesim container..." +echo " If successful, you should see a window with a turtle!" +echo "" + +docker compose up turtlesim + +echo "" +echo "Done! The turtle window should appear in your X server."