Interesting Practice of Robot Programming 14-Robot 3D Simulation (Gazebo+TurtleBot3)

Before, I introduced basic concepts such as nodes, topics, services, and actions, as well as tools such as rqt and rosbag2.

The official revised two-dimensional environment is used, so now let's play with a more realistic three-dimensional simulation environment.

  • Simulation software Gazebo
  • Robot TurtleBot3

TurtleBot3 supports a simulation development environment, which can be programmed and developed with virtual robots in simulation. There are two development environments to do this, one is to use the fake node with 3D visualization tool RViz, and the other is to use the 3D robot simulator Gazebo.

  • Dummy nodes are suitable for testing with robot models and motions, but they do not support sensors.
  • If you need to perform SLAM or navigation, Gazebo will be a viable solution because it supports sensors such as IMU, LDS, and cameras.

Environment configuration

# TURTLEBOT3_MODELexport GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/home/zhangrelay/RobSoft/turtlebot3/src/simulations/turtlebot3_gazebo/modelsexport TURTLEBOT3_MODEL=burger # ROS2source /opt/ros/foxy/setup.bash #colconsource /usr/share/colcon_cd/function/colcon_cd.sh

Source code compilation

You can use deb to install directly:

  • sudo apt install ros-foxy-turtlebot3-gazebo

Note that the package must be fully installed.

Here, the source code is used to compile as follows:

  • colcon build

The list of feature packages is shown above.

Simulation practice

1 Startup environment

  • ros2 launch turtlebot3_gazebo empty_world.launch.py

The blue ray is the visual effect of the laser.

The empty_world.launch code is as follows:

import os from ament_index_python.packages import get_package_share_directoryfrom launch import LaunchDescriptionfrom launch.actions import ExecuteProcessfrom launch.actions import IncludeLaunchDescriptionfrom launch.launch_description_sources import PythonLaunchDescriptionSourcefrom launch.substitutions import LaunchConfiguration TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL']  def generate_launch_description():    use_sim_time = LaunchConfiguration('use_sim_time', default='True')    world_file_name = 'empty_worlds/' + TURTLEBOT3_MODEL + '.model'    world = os.path.join(get_package_share_directory('turtlebot3_gazebo'),                         'worlds', world_file_name)    launch_file_dir = os.path.join(get_package_share_directory('turtlebot3_gazebo'), 'launch')    pkg_gazebo_ros = get_package_share_directory('gazebo_ros')     return LaunchDescription([        IncludeLaunchDescription(            PythonLaunchDescriptionSource(                os.path.join(pkg_gazebo_ros, 'launch', 'gzserver.launch.py')            ),            launch_arguments={'world': world}.items(),        ),         IncludeLaunchDescription(            PythonLaunchDescriptionSource(                os.path.join(pkg_gazebo_ros, 'launch', 'gzclient.launch.py')            ),        ),         ExecuteProcess(            cmd=['ros2', 'param', 'set', '/gazebo', 'use_sim_time', use_sim_time],            output='screen'),         IncludeLaunchDescription(            PythonLaunchDescriptionSource([launch_file_dir, '/robot_state_publisher.launch.py']),            launch_arguments={'use_sim_time': use_sim_time}.items(),        ),    ])

2 Circular motion

The previous and previous instructions for circular motion in the two-dimensional environment are very similar.

  • ros2 topic pub --rate 2 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 1.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.8}}"

3 Keyboard remote control

Use the following command to start the keyboard remote control:

  • ros2 run turtlebot3_teleop teleop_keyboard

The keyboard remote control code is as follows:

import osimport selectimport sysimport rclpy from geometry_msgs.msg import Twistfrom rclpy.qos import QoSProfile if os.name == 'nt':    import msvcrtelse:    import termios    import tty BURGER_MAX_LIN_VEL = 0.22BURGER_MAX_ANG_VEL = 2.84 WAFFLE_MAX_LIN_VEL = 0.26WAFFLE_MAX_ANG_VEL = 1.82 LIN_VEL_STEP_SIZE = 0.01ANG_VEL_STEP_SIZE = 0.1 TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL'] msg = """Control Your TurtleBot3!---------------------------Moving around:        w   a    s    d        xw/x : increase/decrease linear velocity (Burger : ~ 0.22, Waffle and Waffle Pi : ~ 0.26)a/d : increase/decrease angular velocity (Burger : ~ 2.84, Waffle and Waffle Pi : ~ 1.82)space key, s : force stopCTRL-C to quit""" e = """Communications Failed"""  def get_key(settings):    if os.name == 'nt':        return msvcrt.getch().decode('utf-8')    tty.setraw(sys.stdin.fileno())    rlist, _, _ = select.select([sys.stdin], [], [], 0.1)    if rlist:        key = sys.stdin.read(1)    else:        key = ''     termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)    return key  def print_vels(target_linear_velocity, target_angular_velocity):    print('currently:\tlinear velocity {0}\t angular velocity {1} '.format(        target_linear_velocity,        target_angular_velocity))  def make_simple_profile(output, input, slop):    if input > output:        output = min(input, output + slop)    elif input < output:        output = max(input, output - slop)    else:        output = input     return output  def constrain(input_vel, low_bound, high_bound):    if input_vel < low_bound:        input_vel = low_bound    elif input_vel > high_bound:        input_vel = high_bound    else:        input_vel = input_vel     return input_vel  def check_linear_limit_velocity(velocity):    if TURTLEBOT3_MODEL == 'burger':        return constrain(velocity, -BURGER_MAX_LIN_VEL, BURGER_MAX_LIN_VEL)    else:        return constrain(velocity, -WAFFLE_MAX_LIN_VEL, WAFFLE_MAX_LIN_VEL)  def check_angular_limit_velocity(velocity):    if TURTLEBOT3_MODEL == 'burger':        return constrain(velocity, -BURGER_MAX_ANG_VEL, BURGER_MAX_ANG_VEL)    else:        return constrain(velocity, -WAFFLE_MAX_ANG_VEL, WAFFLE_MAX_ANG_VEL)  def main():    settings = None    if os.name != 'nt':        settings = termios.tcgetattr(sys.stdin)     rclpy.init()     qos = QoSProfile(depth=10)    node = rclpy.create_node('teleop_keyboard')    pub = node.create_publisher(Twist, 'cmd_vel', qos)     status = 0    target_linear_velocity = 0.0    target_angular_velocity = 0.0    control_linear_velocity = 0.0    control_angular_velocity = 0.0     try:        print(msg)        while(1):            key = get_key(settings)            if key == 'w':                target_linear_velocity =\                    check_linear_limit_velocity(target_linear_velocity + LIN_VEL_STEP_SIZE)                status = status + 1                print_vels(target_linear_velocity, target_angular_velocity)            elif key == 'x':                target_linear_velocity =\                    check_linear_limit_velocity(target_linear_velocity - LIN_VEL_STEP_SIZE)                status = status + 1                print_vels(target_linear_velocity, target_angular_velocity)            elif key == 'a':                target_angular_velocity =\                    check_angular_limit_velocity(target_angular_velocity + ANG_VEL_STEP_SIZE)                status = status + 1                print_vels(target_linear_velocity, target_angular_velocity)            elif key == 'd':                target_angular_velocity =\                    check_angular_limit_velocity(target_angular_velocity - ANG_VEL_STEP_SIZE)                status = status + 1                print_vels(target_linear_velocity, target_angular_velocity)            elif key == ' ' or key == 's':                target_linear_velocity = 0.0                control_linear_velocity = 0.0                target_angular_velocity = 0.0                control_angular_velocity = 0.0                print_vels(target_linear_velocity, target_angular_velocity)            else:                if (key == '\x03'):                    break             if status == 20:                print(msg)                status = 0             twist = Twist()             control_linear_velocity = make_simple_profile(                control_linear_velocity,                target_linear_velocity,                (LIN_VEL_STEP_SIZE / 2.0))             twist.linear.x = control_linear_velocity            twist.linear.y = 0.0            twist.linear.z = 0.0             control_angular_velocity = make_simple_profile(                control_angular_velocity,                target_angular_velocity,                (ANG_VEL_STEP_SIZE / 2.0))             twist.angular.x = 0.0            twist.angular.y = 0.0            twist.angular.z = control_angular_velocity             pub.publish(twist)     except Exception as e:        print(e)     finally:        twist = Twist()        twist.linear.x = 0.0        twist.linear.y = 0.0        twist.linear.z = 0.0         twist.angular.x = 0.0        twist.angular.y = 0.0        twist.angular.z = 0.0         pub.publish(twist)         if os.name != 'nt':            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)  if __name__ == '__main__':    main()

Simply add Chinese for easy use:

Reading the source code is very important.

4 nodes

5 topics

6 services

ros2 service list -t

  • /apply_joint_effort [gazebo_msgs/srv/ApplyJointEffort]
  • /apply_link_wrench [gazebo_msgs/srv/ApplyLinkWrench]
  • /clear_joint_efforts [gazebo_msgs/srv/JointRequest]
  • /clear_link_wrenches [gazebo_msgs/srv/LinkRequest]
  • /delete_entity [gazebo_msgs/srv/DeleteEntity]
  • /gazebo/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /gazebo/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /gazebo/get_parameters [rcl_interfaces/srv/GetParameters]
  • /gazebo/list_parameters [rcl_interfaces/srv/ListParameters]
  • /gazebo/set_parameters [rcl_interfaces/srv/SetParameters]
  • /gazebo/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /get_model_list [gazebo_msgs/srv/GetModelList]
  • /pause_physics [std_srvs/srv/Empty]
  • /reset_simulation [std_srvs/srv/Empty]
  • /reset_world [std_srvs/srv/Empty]
  • /robot_state_publisher/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /robot_state_publisher/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /robot_state_publisher/get_parameters [rcl_interfaces/srv/GetParameters]
  • /robot_state_publisher/list_parameters [rcl_interfaces/srv/ListParameters]
  • /robot_state_publisher/set_parameters [rcl_interfaces/srv/SetParameters]
  • /robot_state_publisher/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /rqt_gui_py_node_4338/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /rqt_gui_py_node_4338/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /rqt_gui_py_node_4338/get_parameters [rcl_interfaces/srv/GetParameters]
  • /rqt_gui_py_node_4338/list_parameters [rcl_interfaces/srv/ListParameters]
  • /rqt_gui_py_node_4338/set_parameters [rcl_interfaces/srv/SetParameters]
  • /rqt_gui_py_node_4338/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /spawn_entity [gazebo_msgs/srv/SpawnEntity]
  • /teleop_keyboard/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /teleop_keyboard/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /teleop_keyboard/get_parameters [rcl_interfaces/srv/GetParameters]
  • /teleop_keyboard/list_parameters [rcl_interfaces/srv/ListParameters]
  • /teleop_keyboard/set_parameters [rcl_interfaces/srv/SetParameters]
  • /teleop_keyboard/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /turtlebot3_diff_drive/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /turtlebot3_diff_drive/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /turtlebot3_diff_drive/get_parameters [rcl_interfaces/srv/GetParameters]
  • /turtlebot3_diff_drive/list_parameters [rcl_interfaces/srv/ListParameters]
  • /turtlebot3_diff_drive/set_parameters [rcl_interfaces/srv/SetParameters]
  • /turtlebot3_diff_drive/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /turtlebot3_imu/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /turtlebot3_imu/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /turtlebot3_imu/get_parameters [rcl_interfaces/srv/GetParameters]
  • /turtlebot3_imu/list_parameters [rcl_interfaces/srv/ListParameters]
  • /turtlebot3_imu/set_parameters [rcl_interfaces/srv/SetParameters]
  • /turtlebot3_imu/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /turtlebot3_joint_state/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /turtlebot3_joint_state/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /turtlebot3_joint_state/get_parameters [rcl_interfaces/srv/GetParameters]
  • /turtlebot3_joint_state/list_parameters [rcl_interfaces/srv/ListParameters]
  • /turtlebot3_joint_state/set_parameters [rcl_interfaces/srv/SetParameters]
  • /turtlebot3_joint_state/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /turtlebot3_laserscan/describe_parameters [rcl_interfaces/srv/DescribeParameters]
  • /turtlebot3_laserscan/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
  • /turtlebot3_laserscan/get_parameters [rcl_interfaces/srv/GetParameters]
  • /turtlebot3_laserscan/list_parameters [rcl_interfaces/srv/ListParameters]
  • /turtlebot3_laserscan/set_parameters [rcl_interfaces/srv/SetParameters]
  • /turtlebot3_laserscan/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
  • /unpause_physics [std_srvs/srv/Empty]

7 Action

Add when SLAM and navigation.

8 more

You can refer to the corresponding cases in the first 13 articles to practice in this three-dimensional environment.

to sum up

From the two-dimensional environment to the three-dimensional environment, the simulation is more cool, but the principles and instructions are almost the same, learn a trick and take full control!