ROS2高效学习第十章 -- ros2 高级组件其四之 webots

2024-05-05 04:20

本文主要是介绍ROS2高效学习第十章 -- ros2 高级组件其四之 webots,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ros2 高级组件其四之 webots

  • 1 前言和资料
  • 2 正文
    • 2.1 webots 引入和学习资料
    • 2.2 webots 安装以及样例测试
    • 2.3 自编写 webots_demo
  • 3 总结

1 前言和资料

当前,在机器人仿真领域,有两大产品比较突出,一是来自 ros 社区的 gazebo,二是从商业转向开源的 webots。通常情况下,ros 的学习者都会深入研究 gazebo,比如本人之前的 ROS高效进阶系列。但由于 webots 转向开源,加上 ros 的支持,影响力越来越大,ros2 humble 官方 Tutorials 也正式引入了 webots 的内容。
本文先介绍 webots 以及学习资料,然后安装并测试 webots,最后基于 ros2 humble 官方 Tutorials 中 webots 的内容,利用 webots 实现一个差速轮式机器人的运动仿真。
本文参考资料如下:
(1)Simulation-Webots
(2)其他资料见文章内容

2 正文

2.1 webots 引入和学习资料

(1)webots 引入:webots 是来自瑞士的 Cyberbotics 公司(Cyberbotics 官网)推出的机器人仿真软件,旨在降低机器人技术开发的门槛,并加速从理论到实践的转化过程。该平台用户群体非常广泛,涵盖了教育、科研和工业界。2018年以前,webots 是一款商业软件,2018年12月以后,Webots作为开放源码软件在Apache 2.0许可下发布(webots github)。
(2)gazebo 和 webots 的比较:这里我推荐两篇博客,大家大致了解下他们的异同即可。本文不建议读者在这里花费太多时间,适当了解后,尽快学习才是王道!
第一,ROS仿真平台总结
第二,到底该用哪款神器来仿真我的机器人?
(3)webots 和 ros:webots 本身是一款独立的仿真软件,跟 ros 没有关系。后来,ros1 有了 webots_ros 软件包,ros2 有了 webots_ros2 软件包,从而打通了 ros 与 webots 之间的接口,使得两者之间可以顺利通信。本文我们将使用 webots_ros2 :webots_ros2 github
(4)webots 学习资料:这些资料都在 Cyberbotics 官网,有时会打不开,请多试几次。或者用翻墙梯子,体验会好很多。
第一,webots 入门手册 ,尤其是里面的 webots tutorials ,
补充:另外推荐 webots 中文系列教学博客,可供读者参考。
第二,webots 参考手册
第三,webots 自动驾驶仿真
(5)webots 学习路线:把上面的webots 学习资料按顺序学完,并动手实践。

2.2 webots 安装以及样例测试

(1)webots 安装:由于 webots 是从商业转向的开源,因此安装非常简单,如下。本系列 ros2 文章的基础环境是 Ubuntu22.04 + ros2 humble,安装的 webots 版本是 webotsR2023b。

cd ~
# 先安装 webots_ros2
sudo apt-get install ros-humble-webots-ros2
# 启动机器臂样例,程序会自动查找 webots ,如果没有找到,则会询问你是否自动安装,如果yes,则默认安装在: ~/.ros/webotsR2023b/webots
ros2 launch webots_ros2_universal_robot multirobot_launch.py
# 设置 WEBOTS_HOME,方便查找安装位置
export WEBOTS_HOME=/home/ycao/.ros/webotsR2023b/webots

在这里插入图片描述
(2)在 webots_ros2 中,利用 webots 实现了多种机器人仿真,包括 TurtleBot3 ,Tesla Model3,详细内容见:webots_ros2 Examples
测试 TurtleBot3 :

# 启动 TurtleBot3 仿真环境
ros2 launch webots_ros2_turtlebot robot_launch.py
# 再开一个窗口,控制 TurtleBot3 在仿真屋子里活动
ros2 run teleop_twist_keyboard teleop_twist_keyboard

在这里插入图片描述
测试 Tesla Model3(怎么让车动起来,我没有详细研究,图也就不放了):

ros2 launch webots_ros2_tesla robot_launch.py

2.3 自编写 webots_demo

(1)创建 webots_demo 软件包以及相关文件

cd ~/colcon_ws/src
ros2 pkg create --build-type ament_python --license Apache-2.0 webots_demo --dependencies rclpy geometry_msgs webots_ros2_driver
cd webots_demo 
mkdir launch worlds
touch launch/mbot_launch.py
touch resource/mbot.urdf
touch webots_demo/mbot_driver.py webots_demo/obstacle_avoider.py

(2)在 worlds 目录中添加 my_world.wbt,这个文件是 webots 的建模文件,里面包含虚拟仿真环境和一个差速轮式机器人。本文暂时不深究 webots 建模的细节,读者可以参考 webots tutorials 。
(3)编写 mbot_driver.py:这是差速轮式机器人车轮电机控制程序,内部有注释帮助理解

import rclpy
from geometry_msgs.msg import TwistHALF_DISTANCE_BETWEEN_WHEELS = 0.045
WHEEL_RADIUS = 0.025# MbotDriver 是机器人的控制器程序,他创建了一个 ros2 节点 mbot_driver,
# 订阅 cmd_vel 话题,接收 Twist 消息,然后根据 Twist 消息的线速度和角速度控制机器人的左右轮速度,从而实现机器人的运动控制。
class MbotDriver:def init(self, webots_node, properties):# 获取 webots 里的 robot 对象,在本样例就是 my_world.wbt 中的 mbot_carself._robot = webots_node.robot# 获取左右轮的电机对象,并设置电机的目标位置为极大(一直旋转)和速度为 0self._left_motor = self._robot.getDevice('left wheel motor')self._right_motor = self._robot.getDevice('right wheel motor')self._left_motor.setPosition(float('inf'))self._left_motor.setVelocity(0)self._right_motor.setPosition(float('inf'))self._right_motor.setVelocity(0)self._target_twist = Twist()# 创建一个 ros2 节点 mbot_driver,订阅 cmd_vel 话题,用来驱动 mbot_car# 接收到的 Twist 消息存入 self._target_twist 中,等待 step 函数处理rclpy.init(args=None)self._node = rclpy.create_node('mbot_driver')self._node.create_subscription(Twist, 'cmd_vel', self._cmd_vel_callback, 1)def _cmd_vel_callback(self, twist):self._target_twist = twist# step 由 webots_ros2_driver.webots_controller.WebotsController 调用,称之为 simulation step# 这里可以理解为是机器人控制器的主循环函数,周期调用def step(self):# 使用 spin_once 来处理 mbot_driver 的一次事件,这里是一次 cmd_vel 订阅# 如果没有这个函数,_cmd_vel_callback 是不会被执行的# 如果事件没来,会立即返回,不会阻塞,确保实时性rclpy.spin_once(self._node, timeout_sec=0)# 这里讲解了 Twist 理解 和 右手定则:https://blog.csdn.net/cy1641395022/article/details/131236155# 获取机器人的前进速度和旋转速度,根据右手定则:# 如果机器人向左转(顺时针),angular_speed为负;# 如果机器人向右转(逆时针),angular_speed为正;forward_speed = self._target_twist.linear.xangular_speed = self._target_twist.angular.z# 机器人的前进和旋转速度需要转换为左右轮转速,由于机器人是差速驱动,所以需要根据机器人的轮距和轮径来计算左右轮转速# HALF_DISTANCE_BETWEEN_WHEELS 是机器人的轮距的一半,乘以 angular_speed 就是机器人内外轮线速度的补偿值# 得到内外轮线速度后,再除以 WHEEL_RADIUS 就是内外轮的转速(角速度乘以旋转半径为线速度)# 简单的三个场景,可以帮助理解这个公式:# 第一,控制机器人直线前进(forward_speed 为正,angular_speed 为0),左右轮转速必须相同,且转向相同# 第二,控制机器人原地顺时针旋转(forward_speed 为0,angular_speed 为负),左右轮转速必须相同,且转向相反# 第三,控制机器人原地逆时针旋转(forward_speed 为0,angular_speed 为正),左右轮转速必须相同,且转向相反command_motor_left = (forward_speed - angular_speed * HALF_DISTANCE_BETWEEN_WHEELS) / WHEEL_RADIUScommand_motor_right = (forward_speed + angular_speed * HALF_DISTANCE_BETWEEN_WHEELS) / WHEEL_RADIUS# 设置左右轮的目标转速self._left_motor.setVelocity(command_motor_left)self._right_motor.setVelocity(command_motor_right)

(4)编写 mbot.urdf:这是差速轮式机器人的 URDF 描述文件(Unified Robot Description Format,统一的机器人描述文件格式,使用 xml 格式),为机器人添加了左右距离传感器,并指定了车轮电机控制器。

<?xml version="1.0" ?>
<robot name="My robot"><webots><device reference="ds0" type="DistanceSensor"><ros><topicName>/left_sensor</topicName><alwaysOn>true</alwaysOn></ros></device><device reference="ds1" type="DistanceSensor"><ros><topicName>/right_sensor</topicName><alwaysOn>true</alwaysOn></ros></device>    <plugin type="webots_demo.mbot_driver.MbotDriver" /></webots>
</robot>

(4)编写 obstacle_avoider.py:这个程序基于左右距离传感器的数据,通过 cmd_vel topic 控制机器人避障。

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Range
from geometry_msgs.msg import TwistMAX_RANGE = 0.15# ObstacleAvoider 是机器人行动的控制程序,主要是避障,防止机器人撞墙
# 他创建了一个 ros2 节点 obstacle_avoider,订阅了两个传感器话题 left_sensor 和 right_sensor,
# 接收 Range 消息,然后根据传感器的距离,通过 cmd_vel 发给 mbot_driver 控制机器人运动
class ObstacleAvoider(Node):def __init__(self):super().__init__('obstacle_avoider')self._publisher = self.create_publisher(Twist, 'cmd_vel', 1)self.create_subscription(Range, 'left_sensor', self._left_sensor_callback, 1)self.create_subscription(Range, 'right_sensor', self._right_sensor_callback, 1)def _left_sensor_callback(self, message):self._left_sensor_value = message.rangedef _right_sensor_callback(self, message):self._right_sensor_value = message.range# 每次收到一个传感器的数据,就计算一次机器人的运动控制command_message = Twist()command_message.linear.x = 0.1# 如果左右传感器的距离有一个小于 0.9 * MAX_RANGE,就让机器人向顺时针向右转,否则默认为0,即直线行驶if self._left_sensor_value < 0.9 * MAX_RANGE or self._right_sensor_value < 0.9 * MAX_RANGE:command_message.angular.z = -2.0self._publisher.publish(command_message)def main(args=None):rclpy.init(args=args)avoider = ObstacleAvoider()rclpy.spin(avoider)avoider.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()

(5)编写 mbot_launch.py :

import os
import launch
from launch_ros.actions import Node
from launch import LaunchDescription
from ament_index_python.packages import get_package_share_directory
from webots_ros2_driver.webots_launcher import WebotsLauncher
from webots_ros2_driver.webots_controller import WebotsControllerdef generate_launch_description():package_dir = get_package_share_directory('webots_demo')mbot_description_path = os.path.join(package_dir, 'resource', 'mbot.urdf')# 使用 webots_ros2_driver.webots_launcher.WebotsLauncher 来启动 webots,加载 my_world.wbt# my_world.wbt 内有一个 mbot_car 机器人# 补充:如何制作 my_world.wbt,可以参考:# https://cyberbotics.com/doc/guide/tutorialswebots_world = WebotsLauncher(world=os.path.join(package_dir, 'worlds', 'my_world.wbt'))# 使用 webots_ros2_driver.webots_controller.WebotsController 来启动 mbot_car 机器人的控制器# 参数 robot_description 为 mbot.urdf,里面指定了 webots_demo.mbot_driver.MbotDriver 为机器人的控制器mbot_controller = WebotsController(robot_name='mbot_car',parameters=[{'robot_description': mbot_description_path},], )# 额外启动一个避障控制器,订阅 mbot_car 发来的左右距离传感器数据,通过 cmd_vel,控制 mbot_car 机器人的运动obstacle_avoider = Node(package='webots_demo',executable='obstacle_avoider',)return LaunchDescription([webots_world,mbot_controller,obstacle_avoider,launch.actions.RegisterEventHandler(event_handler=launch.event_handlers.OnProcessExit(target_action=webots_world,on_exit=[launch.actions.EmitEvent(event=launch.events.Shutdown())],))])

(6)修改 setup.py

import os
from glob import glob
from setuptools import find_packages, setuppackage_name = 'webots_demo'setup(name=package_name,version='0.0.0',packages=find_packages(exclude=['test']),data_files=[('share/ament_index/resource_index/packages',['resource/' + package_name]),('share/' + package_name, ['package.xml']),(os.path.join('share', package_name, 'launch'), glob(os.path.join('launch', '*_launch.py'))),(os.path.join('share', package_name, 'worlds'), glob(os.path.join('worlds', '*.wbt'))),(os.path.join('share', package_name, 'resource'), glob(os.path.join('resource', '*.urdf')))],install_requires=['setuptools'],zip_safe=True,maintainer='ycao',maintainer_email='1641395022@qq.com',description='TODO: Package description',license='Apache-2.0',tests_require=['pytest'],entry_points={'console_scripts': ['mbot_driver = webots_demo.mbot_driver:main','obstacle_avoider = webots_demo.obstacle_avoider:main'],},
)

(7)编译并运行

cd ~/colcon_ws/src
colcon build --packages-select webots_demo
source install/local_setup.bash
ros2 launch webots_demo mbot_launch.py

在这里插入图片描述

3 总结

本文主要通过一个差速轮式机器人仿真样例,为大家引入 webots ,但没有深入探究 webots 的建模细节。尽快如此,读者可以在本文的基础上,利用文中提到的资料,对 webots 进行深入的学习和研究。
本文的代码托管在本人的 github 上:webots_demo

这篇关于ROS2高效学习第十章 -- ros2 高级组件其四之 webots的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/960799

相关文章

Python使用FFmpeg实现高效音频格式转换工具

《Python使用FFmpeg实现高效音频格式转换工具》在数字音频处理领域,音频格式转换是一项基础但至关重要的功能,本文主要为大家介绍了Python如何使用FFmpeg实现强大功能的图形化音频转换工具... 目录概述功能详解软件效果展示主界面布局转换过程截图完成提示开发步骤详解1. 环境准备2. 项目功能结

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

C++ RabbitMq消息队列组件详解

《C++RabbitMq消息队列组件详解》:本文主要介绍C++RabbitMq消息队列组件的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. RabbitMq介绍2. 安装RabbitMQ3. 安装 RabbitMQ 的 C++客户端库4. A

mysql中的group by高级用法详解

《mysql中的groupby高级用法详解》MySQL中的GROUPBY是数据聚合分析的核心功能,主要用于将结果集按指定列分组,并结合聚合函数进行统计计算,本文给大家介绍mysql中的groupby... 目录一、基本语法与核心功能二、基础用法示例1. 单列分组统计2. 多列组合分组3. 与WHERE结合使

Python Pandas高效处理Excel数据完整指南

《PythonPandas高效处理Excel数据完整指南》在数据驱动的时代,Excel仍是大量企业存储核心数据的工具,Python的Pandas库凭借其向量化计算、内存优化和丰富的数据处理接口,成为... 目录一、环境搭建与数据读取1.1 基础环境配置1.2 数据高效载入技巧二、数据清洗核心战术2.1 缺失

PyTorch高级特性与性能优化方式

《PyTorch高级特性与性能优化方式》:本文主要介绍PyTorch高级特性与性能优化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、自动化机制1.自动微分机制2.动态计算图二、性能优化1.内存管理2.GPU加速3.多GPU训练三、分布式训练1.分布式数据

PyQt6中QMainWindow组件的使用详解

《PyQt6中QMainWindow组件的使用详解》QMainWindow是PyQt6中用于构建桌面应用程序的基础组件,本文主要介绍了PyQt6中QMainWindow组件的使用,具有一定的参考价值,... 目录1. QMainWindow 组php件概述2. 使用 QMainWindow3. QMainW

Spring Boot集成SLF4j从基础到高级实践(最新推荐)

《SpringBoot集成SLF4j从基础到高级实践(最新推荐)》SLF4j(SimpleLoggingFacadeforJava)是一个日志门面(Facade),不是具体的日志实现,这篇文章主要介... 目录一、日志框架概述与SLF4j简介1.1 为什么需要日志框架1.2 主流日志框架对比1.3 SLF4

Spring Boot集成Logback终极指南之从基础到高级配置实战指南

《SpringBoot集成Logback终极指南之从基础到高级配置实战指南》Logback是一个可靠、通用且快速的Java日志框架,作为Log4j的继承者,由Log4j创始人设计,:本文主要介绍... 目录一、Logback简介与Spring Boot集成基础1.1 Logback是什么?1.2 Sprin

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示