Lab Exercise 1: Simulation Environment Setup
Objective
In this lab exercise, you will set up and configure a Gazebo simulation environment for robotics development. You'll learn to create custom robot models, design simulation worlds, and test robot behaviors in a safe virtual environment before deploying to physical hardware.
Learning Objectives
After completing this lab, you will be able to:
- Configure a Gazebo simulation environment with ROS 2 integration
- Create and import custom robot models into Gazebo
- Design simulation worlds with obstacles and interactive elements
- Run basic robot control commands in simulation
- Evaluate simulation fidelity compared to real-world performance
Prerequisites
- Completion of ROS 2 modules (Weeks 1-3)
- Understanding of robot URDF models
- Basic knowledge of ROS 2 message types for robot control
Equipment Required
- Computer with Ubuntu 22.04 and ROS 2 Humble
- NVIDIA GPU with OpenGL 3.3+ support (recommended)
- Minimum 8GB RAM, 20GB free disk space
- Internet connection for package installation
Lab Steps
Step 1: Environment Setup and Verification
-
Verify your ROS 2 and Gazebo installation:
# Check ROS 2 installation
echo $ROS_DISTRO
# Should return "humble"
# Check Gazebo installation
gazebo --version
# Should show Gazebo Garden or Harmonic version
# Verify required packages
ros2 pkg list | grep gazebo
# Should show gazebo_ros_pkgs and other gazebo-related packages -
Set up your lab workspace:
mkdir -p ~/gazebo_lab_ws/src
cd ~/gazebo_lab_ws
colcon build --symlink-install
source install/setup.bash
Step 2: Launch Basic Gazebo Environment
-
Launch a basic empty world:
# Source your ROS 2 environment
source /opt/ros/humble/setup.bash
ros2 launch gazebo_ros empty_world.launch.py -
Familiarize yourself with the Gazebo interface:
- Camera controls: Right-drag to rotate, middle-drag to pan, scroll to zoom
- Object manipulation tools: Translate, rotate, scale
- Model database: Browse and insert pre-built models
-
Take a screenshot of your empty Gazebo world for your lab report.
Step 3: Import and Test a Pre-built Robot Model
-
Launch Gazebo with a TurtleBot3 model:
# Install TurtleBot3 packages if not already installed
sudo apt update
sudo apt install ros-humble-turtlebot3-gazebo
# Set the robot model environment variable
export TURTLEBOT3_MODEL=waffle
# Launch TurtleBot3 simulation
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py -
Control the TurtleBot3 using teleoperation:
# In a new terminal, source the same workspace
source /opt/ros/humble/setup.bash
export TURTLEBOT3_MODEL=waffle
ros2 run turtlebot3_teleop teleop_keyboard
# Use the keyboard controls to move the robot -
Monitor robot topics to understand the control interface:
# List active topics
ros2 topic list
# Echo the laser scan data
ros2 topic echo /scan
# Echo the robot's position
ros2 topic echo /odom
Step 4: Create a Custom Simple Robot Model
-
Create a simple differential drive robot URDF:
cd ~/gazebo_lab_ws/src
mkdir simple_robot_description
cd simple_robot_description
mkdir urdf meshes launch -
Create a basic robot URDF file (
urdf/simple_robot.urdf):
<link name="base_link"> <visual> <geometry> <box size="0.5 0.3 0.15"/> </geometry> <material name="green"/> </visual> <collision> <geometry> <box size="0.5 0.3 0.15"/> </geometry> </collision> <inertial> <mass value="5.0"/> <inertia ixx="0.1" ixy="0.0" ixz="0.0" iyy="0.1" iyz="0.0" izz="0.1"/> </inertial> </link>
<link name="left_wheel"> <visual> <geometry> <cylinder radius="0.1" length="0.05"/> </geometry> <material name="red"/> </visual> <collision> <geometry> <cylinder radius="0.1" length="0.05"/> </geometry> </collision> <inertial> <mass value="0.5"/> <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.02"/> </inertial> </link>
<link name="right_wheel"> <visual> <geometry> <cylinder radius="0.1" length="0.05"/> </geometry> <material name="red"/> </visual> <collision> <geometry> <cylinder radius="0.1" length="0.05"/> </geometry> </collision> <inertial> <mass value="0.5"/> <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.02"/> </inertial> </link>
### Step 5: Create SDF World File
1. Create a custom world file (`simple_world.sdf`) in your launch directory:
```xml
<!-- XML declaration: <?xml version="1.0" ?> -->
<sdf version="1.7">
<world name="simple_world">
<!-- Include the default sun and ground plane -->
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<!-- Add some objects to the world -->
<model name="wall_1">
<pose>0.0 3.0 0.5 0 0 0</pose>
<link name="wall_1_link">
<visual name="visual">
<geometry>
<box>
<size>5.0 0.2 1.0</size>
</box>
</geometry>
<material>
<ambient>0.5 0.5 0.5 1</ambient>
<diffuse>0.5 0.5 0.5 1</diffuse>
<specular>0.1 0.1 0.1 1</specular>
</material>
</visual>
<collision name="collision">
<geometry>
<box>
<size>0.5 0.5 0.4</size>
</box>
</geometry>
</collision>
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>1.0</ixx>
<ixy>0.0</ixy>
<ixz>0.0</ixz>
<iyy>1.0</iyy>
<iyz>0.0</iyz>
<izz>1.0</izz>
</inertia>
</inertial>
</link>
</model>
<model name="box_1">
<pose>2.0 -1.0 0.2 0 0 0</pose>
<link name="box_1_link">
<visual name="visual">
<geometry>
<box>
<size>0.5 0.5 0.4</size>
</box>
</geometry>
<material>
<ambient>0.8 0.3 0.1 1</ambient>
<diffuse>0.8 0.3 0.1 1</diffuse>
<specular>0.1 0.1 0.1 1</specular>
</material>
</visual>
<collision name="collision">
<geometry>
<box>
<size>0.5 0.5 0.4</size>
</box>
</geometry>
</collision>
<inertial>
<mass>0.5</mass>
<inertia>
<ixx>1.0</ixx>
<ixy>0.0</ixy>
<ixz>0.0</ixz>
<iyy>1.0</iyy>
<iyz>0.0</iyz>
<izz>1.0</izz>
</inertia>
</inertial>
</link>
</model>
<!-- Add a simple robot model -->
<include>
<name>my_robot</name>
<pose>0 0 0.1 0 0 0</pose>
<uri>model://simple_robot</uri>
</include>
</world>
</sdf>
Step 6: Create Launch File
- Create a launch file (
launch/simple_robot.launch.py) to bring up your robot in the custom world:import os
from launch import LaunchDescription
from launch.actions import ExecuteProcess
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
def generate_launch_description():
package_dir = get_package_share_directory('simple_robot_description')
# Launch Gazebo with custom world
gazebo = ExecuteProcess(
cmd=['gz', 'sim', '-r', os.path.join(package_dir, 'launch', 'simple_world.sdf')],
output='screen'
)
# Robot State Publisher node
robot_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
name='robot_state_publisher',
parameters=[{
'robot_description': open(os.path.join(package_dir, 'urdf', 'simple_robot.urdf')).read()
}]
)
# Spawn robot in Gazebo
spawn_entity = Node(
package='gazebo_ros',
executable='spawn_entity.py',
arguments=[
'-topic', 'robot_description',
'-entity', 'simple_robot',
'-x', '0.0',
'-y', '0.0',
'-z', '0.1'
],
output='screen'
)
return LaunchDescription([
gazebo,
robot_state_publisher,
spawn_entity
])
Step 7: Test Robot Control in Simulation
-
Build your package:
cd ~/gazebo_lab_ws
colcon build --packages-select simple_robot_description
source install/setup.bash -
Launch your custom robot in the custom world:
ros2 launch simple_robot_description simple_robot.launch.py -
In a new terminal, verify the robot is publishing its state:
source ~/gazebo_lab_ws/install/setup.bash
ros2 run rviz2 rviz2
# Add RobotModel display and set Fixed Frame to "base_link"
Step 8: Implement Basic Movement Control
-
Create a basic movement controller (
scripts/move_robot.py):#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
import sys
import select
import tty
import termios
class SimpleRobotController(Node):
def __init__(self):
super().__init__('simple_robot_controller')
self.publisher = self.create_publisher(Twist, '/cmd_vel', 10)
self.timer = self.create_timer(0.1, self.publish_cmd)
self.cmd_msg = Twist()
def publish_cmd(self):
self.publisher.publish(self.cmd_msg)
def set_linear(self, x, y=0.0, z=0.0):
self.cmd_msg.linear.x = x
self.cmd_msg.linear.y = y
self.cmd_msg.linear.z = z
def set_angular(self, x, y=0.0, z=0.0):
self.cmd_msg.angular.x = x
self.cmd_msg.angular.y = y
self.cmd_msg.angular.z = z
def main(args=None):
rclpy.init(args=args)
controller = SimpleRobotController()
print("Simple Robot Controller")
print("Use 'w' to move forward, 's' to move backward")
print("Use 'a' to turn left, 'd' to turn right")
print("Press 'q' to quit")
# Save terminal settings
old_settings = termios.tcgetattr(sys.stdin)
try:
tty.cbreak(sys.stdin.fileno())
while True:
if select.select([sys.stdin], [], [], 0.1)[0]:
key = sys.stdin.read(1)
if key == 'q':
break
elif key == 'w':
controller.set_linear(0.5, 0.0, 0.0)
elif key == 's':
controller.set_linear(-0.5, 0.0, 0.0)
elif key == 'a':
controller.set_angular(0.0, 0.0, 0.5)
elif key == 'd':
controller.set_angular(0.0, 0.0, -0.5)
else:
controller.set_linear(0.0, 0.0, 0.0)
controller.set_angular(0.0, 0.0, 0.0)
rclpy.spin_once(controller, timeout_sec=0.1)
finally:
# Restore terminal settings
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
# Stop the robot
controller.set_linear(0.0, 0.0, 0.0)
controller.set_angular(0.0, 0.0, 0.0)
for _ in range(10): # Send stop command multiple times
controller.publish_cmd()
rclpy.spin_once(controller, timeout_sec=0.01)
controller.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main() -
Make the script executable and run it to control your robot:
chmod +x ~/gazebo_lab_ws/src/simple_robot_description/scripts/move_robot.py
ros2 run simple_robot_description move_robot.py
Lab Report
Submit a lab report including:
- Setup Verification: Screenshots showing successful Gazebo startup and robot model loading
- Robot Design: Explanation of your custom robot model design choices
- Simulation Behavior: Description of how your robot responded to control commands
- World Design: Justification for the obstacles and environment you created
- Comparison: Key differences between simulated and real-world robot behavior
- Challenges: Any obstacles encountered and how you addressed them
Troubleshooting
Common Issues and Solutions
-
Gazebo Not Starting
- Problem: Gazebo window doesn't appear or crashes immediately
- Solution: Check GPU drivers and OpenGL support; try running with
export LIBGL_ALWAYS_SOFTWARE=1
-
Robot Not Responding to Commands
- Problem: Robot doesn't move when sending velocity commands
- Solution: Verify topic names match (e.g.,
/cmd_vel); check robot's differential drive plugin configuration
-
URDF Loading Errors
- Problem: Robot model isn't appearing in Gazebo
- Solution: Verify URDF syntax with
check_urdftool; ensure all plugins are correctly defined
-
Simulation Running Slowly
- Problem: Low frame rate or unstable physics
- Solution: Simplify collision geometry; reduce world complexity; check CPU/GPU utilization
Extension Activities
For advanced learners, consider implementing:
- Sensor Integration: Add camera, LiDAR, or IMU sensors to your robot model
- Navigation Stack Integration: Connect your robot to ROS 2 navigation system
- Multi-Robot Simulation: Create a world with multiple robots and implement coordination
- Physics Parameter Tuning: Adjust friction, damping, and other physics parameters for more realistic simulation
Next Steps
In the next lab, you'll integrate sensors into your simulation environment and implement perception algorithms that process simulated sensor data in the same way as real sensors.