前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器人编程趣味实践14-机器人三维仿真(Gazebo+TurtleBot3)

机器人编程趣味实践14-机器人三维仿真(Gazebo+TurtleBot3)

作者头像
zhangrelay
发布2021-12-02 12:42:28
7930
发布2021-12-02 12:42:28
举报
文章被收录于专栏:机器人课程与技术

之前,介绍了节点、主题、服务和行动等基本概念,以及rqt和rosbag2等工具。

采用了官方改版的二维环境,那么现在玩耍一下更为逼真的三维仿真环境吧。

  • 仿真软件Gazebo
  • 机器人TurtleBot3

TurtleBot3支持仿真开发环境,可以在仿真中用虚拟机器人编程开发。 有两种开发环境可以做到这一点,一种是使用带有 3D 可视化工具 RViz 的假节点,另一种是使用 3D 机器人模拟器 Gazebo。

  • 假节点适合用机器人模型和运动进行测试,但不支持传感器。
  • 如果需要执行 SLAM 或导航,Gazebo 将是一个可行的解决方案,因为它支持 IMU、LDS 和摄像头等传感器。

环境配置

代码语言:javascript
复制
# TURTLEBOT3_MODEL
export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/home/zhangrelay/RobSoft/turtlebot3/src/simulations/turtlebot3_gazebo/models
export TURTLEBOT3_MODEL=burger

# ROS2
source /opt/ros/foxy/setup.bash

#colcon
source /usr/share/colcon_cd/function/colcon_cd.sh

源码编译

可以使用deb直接安装:

  • sudo apt install ros-foxy-turtlebot3-gazebo

注意包要装全。

这里,采用源码编译如下:

  • colcon build

功能包列表如上所示。

仿真实践

1 启动环境

  • ros2 launch turtlebot3_gazebo empty_world.launch.py

蓝色射线为激光的可视化效果。

empty_world.launch代码如下:

代码语言:javascript
复制
import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import ExecuteProcess
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from 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 圆周运动

之前和之前二维环境圆周运动的指令非常类似哦。

  • 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 键盘遥控

使用如下命令启动键盘遥控:

  • ros2 run turtlebot3_teleop teleop_keyboard

键盘遥控代码如下:

代码语言:javascript
复制
import os
import select
import sys
import rclpy

from geometry_msgs.msg import Twist
from rclpy.qos import QoSProfile

if os.name == 'nt':
    import msvcrt
else:
    import termios
    import tty

BURGER_MAX_LIN_VEL = 0.22
BURGER_MAX_ANG_VEL = 2.84

WAFFLE_MAX_LIN_VEL = 0.26
WAFFLE_MAX_ANG_VEL = 1.82

LIN_VEL_STEP_SIZE = 0.01
ANG_VEL_STEP_SIZE = 0.1

TURTLEBOT3_MODEL = os.environ['TURTLEBOT3_MODEL']

msg = """
Control Your TurtleBot3!
---------------------------
Moving around:
        w
   a    s    d
        x

w/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 stop

CTRL-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()

简单加入中文方便使用:

阅读源码非常重要。

4 节点

5 主题

6 服务

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 行动

SLAM和导航时候再补充。

8 更多

可参考前13篇中对应案例,在此三维环境中进行实践哦。

总结

由二维环境到三维环境,仿真更炫酷,但是原理和指令几乎一样,学一招全掌控!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/06/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境配置
  • 源码编译
  • 仿真实践
    • 1 启动环境
      • 2 圆周运动
        • 3 键盘遥控
          • 4 节点
            • 5 主题
              • 6 服务
                • 7 行动
                  • 8 更多
                  • 总结
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档