Session 13: GO2 Simulation Setup¶
Week: 13 Element: ICTPRG439 Element 3.1-3.2 Duration: 4 hours Phase: GO2 Capstone Project
⚠️ Important Update — Server Race Condition Fix (Action Required Before Submission)
A race condition has been identified in the GO2 simulation where the built-in 60Hz controller fights your action server for joint control — causing the robot to snap back or joints to fail to hold position.
Before submitting your capstone, apply the freeze/unfreeze fix to your _execute_callback.
→ Read the full Server Race Condition Fix
Due to this issue, everyone has been granted an extension until 22/06/2026. Please submit a short video with your code to Blackboard to speed up marking.
Session Introduction¶
This session marks the beginning of your capstone project: creating a new behavior for the Unitree GO2 quadruped robot. You'll work with a pre-existing ROS2 simulation package (go2_ros2_sim_py), applying your ICTPRG439 component integration skills and preparing for the OOP implementation in upcoming sessions.
The GO2 is a sophisticated quadruped robot capable of walking, sitting, standing, and navigating complex terrain. Your goal over the next five sessions is to extend this robot with a high five action—making it lift a front leg and high five at people.
Today you'll:
- Clone and build the GO2 simulation package
- Run the Gazebo simulation
- Test existing behaviors (sit, stand, walk)
- Explore the codebase to understand its architecture
- Document your findings for ICTPRG439 portfolio evidence
Session Slides
View the presentation slides for this session (covers Sessions 13 & 14):
The slides contain: - GO2 robot overview and 5-session project roadmap - ROS2 topics vs services recap - CLI control: sit, stand, walk, teleop - Codebase tour and architecture - GO2Controller OOP wrapper class design - Implementation tasks and unit testing
Learning Objectives¶
By the end of this session, you will be able to:
- Clone and build a ROS2 simulation package from source
- Launch Gazebo simulation with the GO2 robot
- Control the robot using ROS2 CLI tools (services, topics)
- Navigate the codebase to identify key components
- Document component architecture for ICTPRG439 evidence
Session Structure¶
- Environment Setup - Clone repository, install dependencies, build
- Running the Simulation - Launch Gazebo, verify robot spawns
- Testing Existing Behaviors - Use ROS2 CLI to control robot
- Codebase Exploration - Understand package structure and behaviors
- Portfolio Documentation - Record findings for ICTPRG439
Part 1: Environment Setup (WSL2 + Ubuntu 24.04)¶
1.1 Prerequisites: WSL2 & Ubuntu 24.04¶
This course uses WSL2 (Windows Subsystem for Linux 2) with Ubuntu 24.04 (Noble) and ROS2 Jazzy.
What is WSL2?¶
WSL2 is a lightweight Linux environment running on Windows. For this course:
- Treat it like a virtual machine you manage
- Run all ROS2/robotics work inside WSL2, not on Windows
- Your files live in the Linux filesystem for performance
- GUI (Gazebo/RViz) displays on Windows via WSLg or VcXsrv
Checking your setup¶
Your should have by now installed WSL2 and Ubuntu 24.04 on your machine. Verify:
# Open WSL2 terminal (Start menu → Ubuntu 24.04, or Windows Terminal)
cat /etc/os-release | grep PRETTY_NAME
# Should show: Ubuntu 24.04 LTS (Noble) or similar
GPU & Display¶
If you have an NVIDIA GPU:
- Windows driver must be ≥ 510 (auto-exposed to WSL2)
- WSLg (Windows 11 / Win10 21H2+) works automatically
- Fallback:
export LIBGL_ALWAYS_SOFTWARE=1if Gazebo shows black screen
File Access¶
Keep ROS2 files inside the WSL2 Linux filesystem for performance:
- Linux files:
/home/<username>/...(use these for robotics) - Windows files:
/mnt/c/Users/<username>/...(slower, avoid for development) - File browser: Windows Start →
\\wsl$\Ubuntu-24.04\home\...
Opening WSL2 Terminal¶
Method 1 (Recommended): Windows Terminal
- Start menu → Windows Terminal
- Click dropdown → Ubuntu 24.04
Method 2: Direct launch - Start menu → Ubuntu 24.04
Method 3: PowerShell
Common Beginner Issues¶
| Issue | Solution |
|---|---|
| "ros2: command not found" | Forgot to source ~/go_sim/go2_sim.env |
| Gazebo black screen | Run export LIBGL_ALWAYS_SOFTWARE=1 then try again |
| Files not syncing | Keep files in /home/..., not /mnt/c/... |
| GUI won't display | Windows 11 WSLg works out of box; Win10 needs VcXsrv |
| Network issues | Restart WSL with wsl --shutdown in PowerShell, then reopen |
1.2 Run the WSL2 Installation Script¶
The new go2_ros2_sim_py repository includes a one-shot install script that handles everything (ROS2 Jazzy, Gazebo Harmonic, dependencies, workspace setup) in ~15 minutes.
# Inside WSL2 terminal
cd ~
# Download the install script
curl -O https://raw.githubusercontent.com/prgrobots/go2_ros2_sim_py/main/install%20/go2_sim_setup.sh
# Make it executable
chmod +x go2_sim_setup.sh
# Run it (answer 'y' to prompts, do NOT run as root)
./go2_sim_setup.sh
Script does (12 automated steps):
- Update system packages
- Install ROS2 Jazzy + Gazebo Harmonic
- Install Nav2 stack
- Install CycloneDDS + teleop tools
- Set up NVIDIA GPU passthrough (if available)
- Clone this repo + build simulation workspace
- Create
~/go_sim/go2_sim.env(environment file) - Clone real dog bridge (go2_ros2_sdk)
- Build SDK workspace
- Create
~/go2_sdk/go2_sdk.env - Configure CycloneDDS for loopback
After script completes:
# Verify installation
ls -la ~/ | grep go_sim
# Should show: go_sim/ directory
# Source the environment
source ~/go_sim/go2_sim.env
# Verify ROS2 Jazzy
echo $ROS_DISTRO
# Should show: jazzy
Installation Complete
You now have two workspaces:
- ~/go_sim/ — Simulation (this repo)
- ~/go2_sdk/ — Real robot bridge (for later)
Always source ~/go_sim/go2_sim.env before using the simulator.
1.3 Clone the GO2 Repository (Already Done by Script)¶
The install script already cloned the go2_ros2_sim_py repository into ~/go_sim/src/.
Verify the structure:
The go2_ros2_sim_py repository is your ICTPRG439 pre-existing component. You'll evaluate, integrate, and extend it.
ICTPRG439 Evidence Point
Take a screenshot of the ~/go_sim/src/ directory. This is evidence of Element 3.1: Configure development environment.
1.4 Verify Build Success¶
The script already built all packages. Verify:
# Source the environment
source ~/go_sim/go2_sim.env
# Check build outputs
ls -la ~/go_sim/install/
# You should see: gazebo_sim/, go2_description/, quadropted_controller/, etc.
Expected: Directories for each package. Warnings during build are acceptable.
1.5 Add Sourcing to .bashrc (Optional)¶
For convenience, auto-source the environment in every new terminal:
Then every new WSL2 terminal will have ROS2 ready.
Part 2: Running the Simulation¶
2.1 Source the Environment¶
The environment file (go2_sim.env) sets up everything automatically:
# Source the simulation environment
source ~/go_sim/go2_sim.env
# Verify ROS2 Jazzy is active
echo $ROS_DISTRO
# Should show: jazzy
2.2 Launch the Simulation¶
What you should see:
- Gazebo window opens
- GO2 robot appears in the world
- Robot is in default standing position
ICTPRG439 Evidence Point
Take a screenshot of Gazebo with the GO2 robot. This is evidence of Element 3.2: Construct test programs.
2.3 Troubleshooting¶
ROS2 command not found:
Gazebo black screen:
# Try software rendering fallback
export LIBGL_ALWAYS_SOFTWARE=1
source ~/go_sim/go2_sim.env
ros2 launch gazebo_sim launch.py
Gazebo doesn't start:
Part 3: Testing Existing Behaviors¶
3.1 Understanding the Robot Interface¶
Open a new terminal (keep Gazebo running) and explore the robot's ROS2 interface:
# Source environment (new terminal)
source ~/go_sim/go2_sim.env
# List all topics
ros2 topic list
# List all services
ros2 service list
Key topics you should see:
/robot1/cmd_vel- Velocity commands (Twist messages)/robot1/robot_mode- Robot mode commands
Key services you should see:
/robot1/robot_behavior_command- Behavior commands (sit, walk, up)
3.2 Robot Modes¶
The GO2 has three modes:
| Mode | Description | Movement |
|---|---|---|
REST |
Default position | Cannot move |
STAND |
Standing, can rotate | Rotation only |
TROT |
Walking mode | Full movement |
3.3 Testing Sit/Stand Behaviors¶
Use the behavior service to control the robot:
# Make the robot sit
ros2 service call /robot1/robot_behavior_command \
quadropted_msgs/srv/RobotBehaviorCommand "{command: 'sit'}"
Watch the Gazebo window—the robot should sit down!
# Make the robot stand and enable walking
ros2 service call /robot1/robot_behavior_command \
quadropted_msgs/srv/RobotBehaviorCommand "{command: 'walk'}"
# Make the robot stand (locked, no walking)
ros2 service call /robot1/robot_behavior_command \
quadropted_msgs/srv/RobotBehaviorCommand "{command: 'up'}"
Test Each Behavior
Try all three commands (sit, walk, up) and observe the robot's response in Gazebo.
3.4 Testing Movement¶
With the robot in walk mode, you can control movement:
# Use teleop keyboard (in a new terminal)
ros2 run teleop_twist_keyboard teleop_twist_keyboard \
--ros-args -r /cmd_vel:=/robot1/cmd_vel
Keyboard controls:
i- Move forward,- Move backwardj- Turn leftl- Turn rightk- Stop
ICTPRG439 Evidence Point
Record a short screen capture of you controlling the robot with teleop. This is evidence of Element 3.2: Use provided example programs.
Part 4: Codebase Exploration¶
Understanding the existing code is essential for extending it with your high five action.
4.1 Package Structure¶
Key directories:
| Directory | Contents | Relevance |
|---|---|---|
go2_description/ |
URDF, meshes | Robot model (don't modify) |
gazebo_sim/ |
Launch files, worlds | Simulation setup |
quadropted_controller/ |
Behavior code | Where you'll add high five |
quadropted_msgs/ |
Custom messages/services | Interface definitions |
4.2 Understanding the Controller¶
The controller is where behaviors are implemented:
Key files to examine:
# Look at the package structure
cat package.xml
# Find Python source files
find . -name "*.py" | head -20
4.3 Finding Behavior Implementation¶
Search for where sit, walk, and up commands are handled:
Key Finding
Note which file(s) handle the robot_behavior_command service. This is where you'll add your high five command in Session 15.
4.4 Document Your Findings¶
Create a simple architecture diagram showing: 1. The packages in the workspace 2. How they communicate (topics, services) 3. Where behavior logic lives
Part 5: ICTPRG439 Portfolio Evidence¶
5.1 Component Evaluation¶
For your portfolio, document the following about go2_ros2_sim_py:
Repository Info:
# Check repository details
cd ~/go_sim/src/go2_ros2_sim_py
git remote -v
# Should show: https://github.com/prgrobots/go2_ros2_sim_py.git
Licensing Analysis:
# Check for license file
ls -la | grep -i license
cat LICENSE
# Or check README for license information
Dependencies:
# List ROS2 dependencies
grep depend ~/go_sim/src/go2_ros2_sim_py/*/package.xml
# List Python dependencies
pip3 list | grep -E "numpy|scipy|transforms3d"
Suitability:
- Does it have the behaviors we need? (sit, stand ✓)
- Is it actively maintained?
- Can we extend it?
5.2 Evidence Checklist¶
By end of session, you should have:
- Screenshot of
~/go_sim/src/directory - Screenshot of Gazebo with GO2 robot
- Screen recording of teleop control
- Notes on codebase structure
- Repository information (URL, license)
- Dependency list
- Architecture diagram (simple sketch is fine)
Summary¶
Today you: 1. Set up the GO2 simulation environment 2. Tested existing behaviors (sit, stand, walk) 3. Explored the codebase to understand its structure 4. Documented findings for ICTPRG439 portfolio
Next session: You'll create your own ROS2 Python package (go2_high_five) with a GO2Controller wrapper class.
Coming up: Unit Testing with @patch
In Session 14 you'll write unit tests for the controller you build. Because the tests need to run without a real robot, you'll use @patch — a decorator from Python's built-in unittest.mock library that temporarily replaces a real object with a fake (MagicMock) for the duration of a single test.
You already know how to assert return values:
With @patch you do the same thing, but swap out a hardware dependency so the function under test thinks it's talking to a real robot:
from unittest.mock import patch
@patch('my_robot.driver.send_command') # replace real hardware call
def test_stand(self, mock_send):
mock_send.return_value = True # fake: pretend it succeeded
result = robot.stand()
self.assertTrue(result)
mock_send.assert_called_once_with('stand') # verify what was sent
The mock_send argument is injected automatically — you don't create it yourself.
Why this matters for robotics: Hardware may be shared, expensive, or simply not on your desk. Mocking lets you run a full test suite on a laptop with no robot connected. CI/CD pipelines (e.g. GitHub Actions) also have no hardware access — mock-based tests are the only way to get automated coverage.
Homework (3 hours)¶
- Complete evidence collection for ICTPRG439 portfolio
- Create component evaluation matrix comparing:
go2_ros2_sim_py(this package)unitree_mujoco(official Unitree simulator)- Building from scratch
- Identify the exact file where you'll add high five action
- Sketch pseudocode for high five (lift leg, oscillate)
Navigation¶
← Week 12 - ROS2 Services | Learning Plan | Week 14 - GO2Controller →