ROS、OpenAI和Gazebo机器人与人工智能仿真与实践教研杂记(二)环境构建
这篇博文侧重环境,动态和静态,确定与不确定,结构与非结构化等。
如何利用ROS、OpenAI和Gazebo构建一种动态、不确定、非结构化的复杂环境,
用于机器人和人工智能算法的测试呢?
参考链接:
- https://github.com/onlytailei/gym_ped_sim
行人模型:
更多内容稍后补充。
参考gazebosim官网文档:http://gazebosim.org
制作动画模特(演员actor)
本教程适用于Gazebo 8+版本(Gazebo 8/9/10均可)
概述
本教程解释了如何使用Gazebo的“actor”来创建脚本动画。
如果希望在模拟仿真中使用预定义路径的实体而不受物理引擎影响,则动画非常有用。这意味着它们不会因重力而下落或与其他物体碰撞。然而,它们将具有可由RGB相机看到的3D可视化,以及可由基于GPU的深度传感器检测的3D网格。
该教程详细解释了如何创建不与模拟其余部分交互的开环轨迹。接下来,将快速浏览一个示例插件,该插件根据环境反馈控制动画。
演员actor
在Gazebo中,动画模型被称为actor
。Actors扩展了常见模型,增加了动画功能。
有两种类型的动画可以单独使用或组合使用:
- 骨架动画,是一个模型中链接之间的相对运动
- 沿着轨迹运动,将全世界所有演员的链接作为一个整体
- 两种类型的动作都可以组合起来,以实现在世界中移动的骨架动画
Gazebo的演员就像模特一样 ,所以你可以像往常一样把链接和关节放在里面。主要区别是:
演员总是静止的(即没有施加力,无论是重力还是接触或其他任何东西)
Actors支持从COLLADA和BVH文件导入的骨架动画。
演员可以在SDF中直接编写轨迹。
不能有嵌套在actor中的模型,因此我们仅限于动画网格,链接和关节。
提示:在此处查看
<actor>
SDF元素 的完整规范。
脚本轨迹
这是演员的高级动画,包括指定在特定时间到达的一系列姿势。Gazebo负责插入它们之间的运动,因此运动是流动的。
示例世界
让我们来看看Gazebo附带的简单示例世界:
gazebo worlds/animated_box.world
你会看到一个浮动的盒子一次又一次地以方形轨迹移动。轨迹经过四点世界,并在它们之间需要1秒。[-1, -1, 1]
[-1, 1, 1]
[1, 1,1]
[1, -1, 1]
代码解析
可以在这里看到整个世界的描述 。按部分来学习一下。
首先定义一个地平面和光源(太阳)的世界。
<?xml version="1.0" ?>
<sdf version="1.6"><world name="default"><!-- A ground plane --><include><uri>model://ground_plane</uri></include><!-- A global light source --><include><uri>model://sun</uri></include>
创建了一个名为的actor,animated_box
并给它一个带有视觉框的简单链接:
<!-- An actor --><actor name="animated_box"><link name="link"><visual name="visual"><geometry><box><size>.2 .2 .2</size></box></geometry></visual></link>
现在是actor演员,<script>
标签特有的部分。首先告诉它永远循环,并在世界加载后立即开始播放。
<script><loop>true</loop><delay_start>0.000000</delay_start><auto_start>true</auto_start>
可以使用以下参数:
loop
:将此设置为true,以便在循环中重复脚本。对于流体连续运动,确保最后一个航路点与第一个航路点匹配,如下所示。delay_start
:这是在启动脚本之前等待的时间(以秒为单位)。如果在循环中运行,则在开始每个循环之前将等待此时间。auto_start
:如果动画应在模拟开始播放后立即启动,则设置为true。如果动画只应在插件触发时才开始播放,则将其设置为false很有用。
最后,定义了一系列航点的轨迹(waypoint):
<trajectory id="0" type="square"><waypoint><time>0.0</time><pose>-1 -1 1 0 0 0</pose></waypoint><waypoint><time>1.0</time><pose>-1 1 1 0 0 0</pose></waypoint><waypoint><time>2.0</time><pose>1 1 1 0 0 0</pose></waypoint><waypoint><time>3.0</time><pose>1 -1 1 0 0 0</pose></waypoint><waypoint><time>4.0</time><pose>-1 -1 1 0 0 0</pose></waypoint></trajectory></script></actor></world>
</sdf>
在<trajectory>
标签内,可以描述一系列要遵循的关键帧。它有两个属性:一个是唯一的id
和一个type
。当在下一节中解释骨架动画时,该类型将非常有用。轨迹参数如下:
waypoint
:轨迹中可以有任意数量的航点。每个航路点由atime
和a组成pose
:time
:以脚为单位的时间,从脚本开头算起,应该达到姿势。pose
:应该达到的姿势
提示:定义航点的顺序并不重要,它们将遵循给定的时间。
注意:轨迹整体平滑。这意味着您将获得流畅的运动,但可能无法达到航路点中包含的确切姿势。
提示:非演员模型也可以遵循脚本轨迹,但这需要使用插件。请参阅本教程以了解具体方法。
现在轮到你实践了!在继续下一部分之前,尝试不同的trejctory描述!
骨架
Gazebo支持两种不同的骨架动画文件格式: COLLADA(.dae)和 Biovision Hierarchy(.bvh)。
尝试一下Gazebo附带的简单示例文件。首先,创建一个新的世界文件:
gedit walk.world
并粘贴以下SDF,它有一个sun和一个使用walk.dae 作为皮肤的 actor:
<?xml version="1.0" ?>
<sdf version="1.6"><world name="default"><include><uri>model://sun</uri></include><actor name="actor"><skin><filename>walk.dae</filename></skin></actor></world>
</sdf>
在Gazebo看看它,会看到一个人在原地走动。
gazebo walk.world
皮肤
上面示例中的actor非常简单,它加载的所有内容都是<skin>
标记中描述的COLLADA文件。
注意:如果之前制作过 自定义 Gazebo模型,则可能已将COLLADA文件用作模型的视觉效果和碰撞。在链接中使用时,COLLADA动画会被忽略,但在皮肤中使用时,它们会被加载!
指定的文件<filename>
可以是绝对路径,例如:
/home/<user>/my_gazebo_models/skeleton_model/skeleton.dae
还可以告诉Gazebo在环境变量中包含的所有目录中查找网格 GAZEBO_MODEL_PATH
,如下所示:
model://skeketon_model/skeleton.dae
最后,可以使用一些与Gazebo一起安装的示例网格,直接引用它们的文件名。以下是可用的列表。看看他们中的一些代替上面的walk.world
moonwalk.dae
run.dae
sit_down.dae
sitting.dae
stand_up.dae
stand.dae
talk_a.dae
talk_b.dae
walk.dae
动画
结合不同的皮肤和动画
有时,将不同的皮肤与不同的动画组合起来很有用。Gazebo允许我们从一个文件中获取皮肤,从另一个文件中获取动画,只要它们具有兼容的骨架。
例如,文件和兼容,这样他们可以相互混合。走路的人有一件绿色衬衫,月球徒步者穿着一件红色衬衫。walk.dae
moonwalk.dae
如果想一个人月球漫步与绿色衬衫,使用
walk
对皮肤和moonwalk
为动画。如果想一个人走了红衬衣,使用
moonwalk
对皮肤和walk
为动画。
动画标签与皮肤标签一起使用,它需要一个name
参数。像这样:
<?xml version="1.0" ?>
<sdf version="1.6"><world name="default"><include><uri>model://sun</uri></include><actor name="actor"><skin><filename>walk.dae</filename></skin><animation name="animation"><filename>moonwalk.dae</filename></animation></actor></world>
</sdf>
提示:查看本教程以了解有关COLLADA动画的更多信息。在凉亭的背景下,作为皮肤COLLADA文件必须有
<library_effects>
和<library_materials>
,而动画文件必须有<library_animations>
。要一起使用,两个文件必须匹配<library_geometries>
,<library_controllers>
并且<library_visual_scenes>
。
立即尝试不同的组合!
同步动画和轨迹
到目前为止,已经了解了创建轨迹和加载静态动画的所有信息。是时候学习如何组合它们了。
可能会想“只是添加<skin>
,<animation>
并<trajectory>
标记给我的演员,将一起工作”。继续尝试,我甚至会给你一个例子:
<sdf version="1.6"><world name="default"><include><uri>model://sun</uri></include><actor name="actor"><skin><filename>walk.dae</filename></skin><animation name="animation"><filename>walk.dae</filename></animation><script><trajectory id="0" type="walking"><waypoint><time>0</time><pose>0 2 0 0 0 -1.57</pose></waypoint><waypoint><time>2</time><pose>0 -2 0 0 0 -1.57</pose></waypoint><waypoint><time>2.5</time><pose>0 -2 0 0 0 1.57</pose></waypoint><waypoint><time>7</time><pose>0 2 0 0 0 1.57</pose></waypoint><waypoint><time>7.5</time><pose>0 2 0 0 0 -1.57</pose></waypoint></trajectory></script></actor></world>
</sdf>
继续加载它,看看会发生什么。这不是预期,对吗?演员的腿根本不动。那是因为Gazebo不知道哪个动画与哪个轨迹匹配。所以让改变动画名称以匹配轨迹类型,如下所示:
<animation name="walking"><filename>walk.dae</filename></animation>
好吧,所以演员都在世界上来回移动,并且移动他的腿。但那看起来不太自然,对吧?他的脚在地上滑动。
骨架动画在X轴上包含一个平移组件,通过运行没有任何轨迹的动画来注意到这一点。但是这个动画还没有与轨迹同步。可以通过<interpolate_x>
在内部设置为true 来启用它 <animation>
。
<animation name="walking"><filename>walk.dae</filename><interpolate_x>true</interpolate_x></animation>
注意:
y
或者z
轴没有插值标记,因此请确保您的原位动画沿x轴移动。
现在终于让两个动画完美同步了。应该看到这个人从一侧走到另一侧,一个方向更快,另一个方向更慢。
闭环轨迹
刚学会了如何创建演员并通过SDF设置他们的轨迹。对此的限制是轨迹在开环中运行,也就是说,它没有从环境中获取任何反馈。现在来看看如何使用插件改变轨迹的示例。
提示:如果不熟悉Gazebo插件,请先查看一些插件教程。
Gazebo有一个示范世界,演员四处移动,同时避开障碍物。看看它在运行:
gazebo worlds/cafe.world
SDF中的插件
就像模型一样,可以为任何actor编写自定义插件,并在SDF描述中分配插件。来看看 cafe.world 中引用视频中某个演员的部分:
<actor name="actor1"><pose>0 1 1.25 0 0 0</pose><skin><filename>moonwalk.dae</filename><scale>1.0</scale></skin><animation name="walking"><filename>walk.dae</filename><scale>1.000000</scale><interpolate_x>true</interpolate_x></animation><plugin name="actor1_plugin" filename="libActorPlugin.so"><target>0 -5 1.2138</target><target_weight>1.15</target_weight><obstacle_weight>1.8</obstacle_weight><animation_factor>5.1</animation_factor><ignore_obstacles><model>cafe</model><model>ground_plane</model></ignore_obstacles></plugin>
</actor>
可以看到,不是给出要遵循的特定路点列表,而是给出了一个插件。在插件标签内,有几个参数可以专门针对这个插件进行调整。我们不会详细介绍插件的工作原理,这里的目的是展示一些参数可以暴露出来,确定轨迹的逻辑将在插件内部。
插件C ++代码
ActorPlugin
可在此处找到 该源代码。而 这里 是头。
第一个技巧是听这样的世界更新开始事件:
this->connections.push_back(event::Events::ConnectWorldUpdateBegin(std::bind(&ActorPlugin::OnUpdate, this, std::placeholders::_1)));
这样,指定一个回调,它将在每次迭代时调用。这是我们将更新演员轨迹的功能。让看一下插件在该函数中的作用:ActorPlugin::OnUpdate
void ActorPlugin::OnUpdate(const common::UpdateInfo &_info)
{// Time deltadouble dt = (_info.simTime - this->lastUpdate).Double();ignition::math::Pose3d pose = this->actor->GetWorldPose().Ign();ignition::math::Vector3d pos = this->target - pose.Pos();ignition::math::Vector3d rpy = pose.Rot().Euler();double distance = pos.Length();// Choose a new target position if the actor has reached its current// target.if (distance < 0.3){this->ChooseNewTarget();pos = this->target - pose.Pos();}
它首先检查当前信息,如时间和演员姿势。如果它已经到达目标目的地,选择一个新目的地。
// Normalize the direction vector, and apply the target weightpos = pos.Normalize() * this->targetWeight;// Adjust the direction vector by avoiding obstaclesthis->HandleObstacles(pos);// Compute the yaw orientationignition::math::Angle yaw = atan2(pos.Y(), pos.X()) + 1.5707 - rpy.Z();yaw.Normalize();// Rotate in place, instead of jumping.if (std::abs(yaw.Radian()) > GZ_DTOR(10)){pose.Rot() = ignition::math::Quaterniond(1.5707, 0, rpy.Z()+yaw.Radian()*0.001);}else{pose.Pos() += pos * this->velocity * dt;pose.Rot() = ignition::math::Quaterniond(1.5707, 0, rpy.Z()+yaw.Radian());}// Make sure the actor stays within boundspose.Pos().X(std::max(-3.0, std::min(3.5, pose.Pos().X())));pose.Pos().Y(std::max(-10.0, std::min(2.0, pose.Pos().Y())));pose.Pos().Z(1.2138);
然后继续计算目标姿势,同时考虑障碍物并确保我们有平稳的运动。以下步骤是最重要的,因为它们涉及特定于actor的API。
// Distance traveled is used to coordinate motion with the walking// animationdouble distanceTraveled = (pose.Pos() -this->actor->GetWorldPose().Ign().Pos()).Length();this->actor->SetWorldPose(pose, false, false);this->actor->SetScriptTime(this->actor->ScriptTime() +(distanceTraveled * this->animationFactor));this->lastUpdate = _info.simTime;
}
首先将actor的世界姿势设置为静态模型SetWorldPose
。但这不会触发动画。这是通过告诉演员它的骨架动画应该在哪个点来完成的SetScriptTime
。
总之,在编写自己的插件时,可以使用您选择的逻辑在每个时间步骤定义所需的姿势。另外,不要忘记选择适当的脚本时间来同步动画。在此处查看该类 的完整API 。physics::Actor
中级教程:连接到ROS 1.0
概述
Velodyne传感器功能齐全,但没有像ROS这样的机器人中间件的插件。使用Gazebo和ROS的好处之一是它可以在现实世界和模拟世界之间轻松切换。为了实现这一目标,需要让我们的传感器与ROS生态系统很好地配合。
添加ROS传输
修改当前的插件以包含ROS传输机制,其方式与我们在前一个教程中添加Gazebo传输机制的方式类似。
我们假设您的系统上当前已经安装了ROS。
将头文件添加到文件中。
velodyne_plugin.cc
#include <thread> #include "ros/ros.h" #include "ros/callback_queue.h" #include "ros/subscribe_options.h" #include "std_msgs/Float32.h"
向插件添加一些成员变量。
/// \brief A node use for ROS transport private: std::unique_ptr<ros::NodeHandle> rosNode;/// \brief A ROS subscriber private: ros::Subscriber rosSub;/// \brief A ROS callbackqueue that helps process messages private: ros::CallbackQueue rosQueue;/// \brief A thread the keeps running the rosQueue private: std::thread rosQueueThread;
在
Load
函数结束时,添加以下内容。// Initialize ros, if it has not already bee initialized. if (!ros::isInitialized()) {int argc = 0;char **argv = NULL;ros::init(argc, argv, "gazebo_client",ros::init_options::NoSigintHandler); }// Create our ROS node. This acts in a similar manner to // the Gazebo node this->rosNode.reset(new ros::NodeHandle("gazebo_client"));// Create a named topic, and subscribe to it. ros::SubscribeOptions so =ros::SubscribeOptions::create<std_msgs::Float32>("/" + this->model->GetName() + "/vel_cmd",1,boost::bind(&VelodynePlugin::OnRosMsg, this, _1),ros::VoidPtr(), &this->rosQueue); this->rosSub = this->rosNode->subscribe(so);// Spin up the queue helper thread. this->rosQueueThread =std::thread(std::bind(&VelodynePlugin::QueueThread, this));
如果仔细阅读代码,会注意到需要两个新功能:
OnRosMsg
和QueueThread
。现在加上这些。/// \brief Handle an incoming message from ROS /// \param[in] _msg A float value that is used to set the velocity /// of the Velodyne. public: void OnRosMsg(const std_msgs::Float32ConstPtr &_msg) {this->SetVelocity(_msg->data); }/// \brief ROS helper function that processes messages private: void QueueThread() {static const double timeout = 0.01;while (this->rosNode->ok()){this->rosQueue.callAvailable(ros::WallDuration(timeout));} }
要处理的最后一项是cmake构建。
- 打开。
CMakeLists.txt
修改文件的顶部部分如下所示。
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)find_package(roscpp REQUIRED) find_package(std_msgs REQUIRED) include_directories(${roscpp_INCLUDE_DIRS}) include_directories(${std_msgs_INCLUDE_DIRS})
修改插件的目标链接库。
target_link_libraries(velodyne_plugin ${GAZEBO_LIBRARIES} ${roscpp_LIBRARIES})
现在应该是这样的。
CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)find_package(roscpp REQUIRED) find_package(std_msgs REQUIRED) include_directories(${roscpp_INCLUDE_DIRS}) include_directories(${std_msgs_INCLUDE_DIRS})# Find Gazebo find_package(gazebo REQUIRED) include_directories(${GAZEBO_INCLUDE_DIRS}) link_directories(${GAZEBO_LIBRARY_DIRS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GAZEBO_CXX_FLAGS}")# Build our plugin add_library(velodyne_plugin SHARED velodyne_plugin.cc) target_link_libraries(velodyne_plugin ${GAZEBO_LIBRARIES} ${roscpp_LIBRARIES})# Build the stand-alone test program add_executable(vel vel.cc)if (${gazebo_VERSION_MAJOR} LESS 6)include(FindBoost)find_package(Boost ${MIN_BOOST_VERSION} REQUIRED system filesystem regex)target_link_libraries(vel ${GAZEBO_LIBRARIES} ${Boost_LIBRARIES}) else()target_link_libraries(vel ${GAZEBO_LIBRARIES}) endif()
- 打开。
确保已经成功配置好ROS:
source /opt/ros/<DISTRO>/setup.bash
重新编译插件。
cd ~/velodyne_plugin/build cmake ../ make
从ROS控制Velodyne
我们现在可以像往常一样加载Gazebo插件,它将监听ROS主题以获取传入的浮动消息。然后,这些消息将用于设置Velodyne的旋转速度。
开始
roscore
source /opt/ros/<DISTRO>/setup.bash roscore
在新的终端,启动Gazebo
cd ~/velodyne_plugin/build source /opt/ros/<DISTRO>/setup.bash gazebo ../velodyne.world
在新终端中,用于
rostopic
发送速度消息。source /opt/ros/<DISTRO>/setup.bash rostopic pub /my_velodyne/vel_cmd std_msgs/Float32 1.0
更改上述命令的最后一个数字以设置不同的速度。
结论
恭喜,现在拥有构建自定义模型,共享模型和生成公共API的工具。玩得开心,快乐模拟!
ROS、OpenAI和Gazebo机器人与人工智能仿真与实践教研杂记(二)环境构建相关推荐
- ROS、OpenAI和Gazebo机器人与人工智能仿真与实践教研杂记(三)深度学习
机器人在环境中如何自主行驶呢?不同的机器人需要配置不同参数,差速或者其他动力学模型,如何获得更好的环境参数? 关于ROS.OpenAI和Gazebo已经测试过环境包括: Ubuntu 16.04 + ...
- ROS2GO+Cozmo=口袋机器人之人工智能仿真和实验平台
ROS2GO+Cozmo=口袋机器人之人工智能仿真和实验平台 Cozmo语音命令(CvC) - 版本0.6.8 向Cozmo发出多个语音命令,并观察他按顺序执行所有这些命令:高度可定制,您可以轻松添加 ...
- ROS入门(八)——仿真机器人四(Gazebo+Rviz+雷达、摄像头、kinet仿真显示)
所用的学习链接: [奥特学园]ROS机器人入门课程<ROS理论与实践>零基础教程P278-288 [以上视频笔记见http://www.autolabor.com.cn/book/ROST ...
- 【ROS】中级操作学习整理-gazebo机器人仿真
系列文章目录 ·[ROS]中级操作学习整理-gazebo机器人仿真 ·[ROS]中级操作学习整理-TF坐标变换 ·[ROS]中级操作学习整理-传感器建模 ·[ROS]中级操作学习整理-激光SLAM 目 ...
- ROS(1和2)机器人操作系统相关书籍、资料和学习路径
ROS机器人相关书籍与资料(更新日期2017年11月) ROS发展10年了,已经逐渐成为通用的机器人操作系统标准.ROS 2相关资料链接:http://blog.csdn.net/zhangrelay ...
- 多机器人编队人工势场法协同避障算法原理及实现
多机器人编队(二)多机器人编队人工势场法协同避障算法原理及实现 避障算法原理 避障算法仿真 多机器人协同编队需要将理论和实践紧密地结合起来,其应用包括编队队形生成.保持.变换和路径规划与避障等等都是基 ...
- MATLAB Simulink开发ROS无人车与机器人应用 详细教程
引言:MATLAB在机器人中的应用 现在大多数机器人开发者都会选择ROS,在ROS整个框架下"调包"极其容易.很多ROS开发者热衷于"调包"来实现功能,却难以在 ...
- Ubuntu18.04+ROS melodic 控制UR5机器人(持续更新)
目录 0 前言 1 前置准备工作 1.1 环境配置 1.1.1 使用虚拟机安装Ubuntu系统 1.1.2 ROS melodic安装 1.2 工作空间配置 1.2.1 创建工作空间 1.2.2 导入 ...
- ros学习之多机器人导航(仿真)
系列文章目录 (一).从solidworks转urdf文件,在gazebo中添加小车模型 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 系列文章目录 目录 前言 一.插件 二 ...
最新文章
- string中的Copy-on-Write技术
- 移动端调试 weinre
- mysql基础(一) 编译安装mysql5.5
- CString GetBuffer() GetString()
- 【干货】路由黑洞的5种解决方法大PK
- Citrix xenapp
- 华师大数据科学考研_2020年30所微电子院校考研信息详细汇总
- MFC改变static text颜色
- [20161006]windows下bbed使用注意.txt
- 二、kubernetes
- thinkphp商城系统 有什么优势 好在哪里
- CentOS | 资产管理软件GLPI+OCS安装与配置
- 【愚公系列】2022年01月 Django商城项目16-用户中心-地址管理之省市三联动功能实现
- MD5 密码破解 碰撞 网站
- JavaScript文档注释JSDoc注释
- 趣味实验python,Python小实验:疯狂填词
- 【论文泛读171】具有对抗性扰动的自监督对比学习,用于鲁棒的预训练语言模型
- 基于CEP的量化交易平台建设
- 图像增强:opencv去除图片的高光
- 详解ABAP Selection Screens