Skip to main content

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​

  1. 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
  2. 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​

  1. Launch a basic empty world:

    # Source your ROS 2 environment
    source /opt/ros/humble/setup.bash
    ros2 launch gazebo_ros empty_world.launch.py
  2. 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
  3. Take a screenshot of your empty Gazebo world for your lab report.

Step 3: Import and Test a Pre-built Robot Model​

  1. 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
  2. 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
  3. 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​

  1. Create a simple differential drive robot URDF:

    cd ~/gazebo_lab_ws/src
    mkdir simple_robot_description
    cd simple_robot_description
    mkdir urdf meshes launch
  2. 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>

Gazebo/GreenGazebo/Red1.01.0Gazebo/Red1.01.0

### 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>
&lt;link name="wall_1_link"&gt;
&lt;visual name="visual"&gt;
&lt;geometry&gt;
&lt;box&gt;
&lt;size&gt;5.0 0.2 1.0&lt;/size&gt;
&lt;/box&gt;
&lt;/geometry&gt;
&lt;material&gt;
&lt;ambient&gt;0.5 0.5 0.5 1&lt;/ambient&gt;
&lt;diffuse&gt;0.5 0.5 0.5 1&lt;/diffuse&gt;
&lt;specular&gt;0.1 0.1 0.1 1&lt;/specular&gt;
&lt;/material&gt;
&lt;/visual&gt;
&lt;collision name="collision"&gt;
&lt;geometry&gt;
&lt;box&gt;
&lt;size&gt;0.5 0.5 0.4&lt;/size&gt;
&lt;/box&gt;
&lt;/geometry&gt;
&lt;/collision&gt;
&lt;inertial&gt;
&lt;mass&gt;1.0&lt;/mass&gt;
&lt;inertia&gt;
&lt;ixx&gt;1.0&lt;/ixx&gt;
&lt;ixy&gt;0.0&lt;/ixy&gt;
&lt;ixz&gt;0.0&lt;/ixz&gt;
&lt;iyy&gt;1.0&lt;/iyy&gt;
&lt;iyz&gt;0.0&lt;/iyz&gt;
&lt;izz&gt;1.0&lt;/izz&gt;
&lt;/inertia&gt;
&lt;/inertial&gt;
&lt;/link&gt;
</model>

<model name="box_1">
<pose>2.0 -1.0 0.2 0 0 0</pose>
&lt;link name="box_1_link"&gt;
&lt;visual name="visual"&gt;
&lt;geometry&gt;
&lt;box&gt;
&lt;size&gt;0.5 0.5 0.4&lt;/size&gt;
&lt;/box&gt;
&lt;/geometry&gt;
&lt;material&gt;
&lt;ambient&gt;0.8 0.3 0.1 1&lt;/ambient&gt;
&lt;diffuse&gt;0.8 0.3 0.1 1&lt;/diffuse&gt;
&lt;specular&gt;0.1 0.1 0.1 1&lt;/specular&gt;
&lt;/material&gt;
&lt;/visual&gt;
&lt;collision name="collision"&gt;
&lt;geometry&gt;
&lt;box&gt;
&lt;size&gt;0.5 0.5 0.4&lt;/size&gt;
&lt;/box&gt;
&lt;/geometry&gt;
&lt;/collision&gt;
&lt;inertial&gt;
&lt;mass&gt;0.5&lt;/mass&gt;
&lt;inertia&gt;
&lt;ixx&gt;1.0&lt;/ixx&gt;
&lt;ixy&gt;0.0&lt;/ixy&gt;
&lt;ixz&gt;0.0&lt;/ixz&gt;
&lt;iyy&gt;1.0&lt;/iyy&gt;
&lt;iyz&gt;0.0&lt;/iyz&gt;
&lt;izz&gt;1.0&lt;/izz&gt;
&lt;/inertia&gt;
&lt;/inertial&gt;
&lt;/link&gt;
</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​

  1. 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​

  1. Build your package:

    cd ~/gazebo_lab_ws
    colcon build --packages-select simple_robot_description
    source install/setup.bash
  2. Launch your custom robot in the custom world:

    ros2 launch simple_robot_description simple_robot.launch.py
  3. 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​

  1. 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()
  2. 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:

  1. Setup Verification: Screenshots showing successful Gazebo startup and robot model loading
  2. Robot Design: Explanation of your custom robot model design choices
  3. Simulation Behavior: Description of how your robot responded to control commands
  4. World Design: Justification for the obstacles and environment you created
  5. Comparison: Key differences between simulated and real-world robot behavior
  6. Challenges: Any obstacles encountered and how you addressed them

Troubleshooting​

Common Issues and Solutions​

  1. 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
  2. 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
  3. URDF Loading Errors

    • Problem: Robot model isn't appearing in Gazebo
    • Solution: Verify URDF syntax with check_urdf tool; ensure all plugins are correctly defined
  4. 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:

  1. Sensor Integration: Add camera, LiDAR, or IMU sensors to your robot model
  2. Navigation Stack Integration: Connect your robot to ROS 2 navigation system
  3. Multi-Robot Simulation: Create a world with multiple robots and implement coordination
  4. 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.