当前位置: 首页 > news >正文

gazebo入门_Gazebo仿真控制中,有哪些你不知道的秘密?

大家好,我是(月更侠)小明,很高兴我们又见面啦。相信大家从我之前的文章中能看出来,我所讲的内容基本都面向ROS新人,因为大家刚入门时,往往很难一窥程序的深层运行逻辑,使得许多问题迟迟无法解决,甚是耽误时间。例如在和小伙伴们日常交流时,就反复遇到过一些关于Gazebo仿真控制的“经典”问题: A 我的模型一直抖动,怎么办? B PID参数该怎么设置啊?我怎么调都没用! C 我必须要设置PID参数吗?如果不设置会怎么样 D gazebo_ros_control插件可以完成计算力矩控制等更加复杂的控制策略吗? E 我的并联机器人模型只能用sdf创建,可以使用gazebo_ros_control进行控制吗? ...... 通过本篇文章的分析,我们将揭晓这些问题的答案。 在Gazebo仿真中,我们最常使用的控制插件就是是gazebo_ros_control,它是ros_control针对Gazebo仿真开发的插件。 6e63dec670f514ccb3baac898b8ecbbb.png 图 1 ros_control组成概览,其中左上角方框内就是gazebo_ros_control插件所实现的功能 该插件的详细使用方法,可参考古月居ROS探索总结系列的相关文章。简单来说,就是进行了如下三个操作:
  1. 在机器人模型的URDF文件中,添加gazebo_ros_control插件,并添加transmission指明了各关节控制器的类型信息
  2. 建立一个yaml文件,用来定义各控制器的pid参数
  3. 建立一个roslaunch,用来加载模型、控制参数、控制器,并发布tf
1、文件结构 接下来我们来看看gazebo_ros_control功能包究竟对这些文件做了什么。需要注意,gazebo_ros_control源码已经集成到了github帐号ros-simulation下的gazebo_ros_pkgs项目中,而ros_controls账号下的gazebo_ros_pkgs是旧版本,现在已经不再使用了。 该功能包的核心是硬件接口文件src/default_robot_hw_sim.cpp,该文件定义了以下函数,用以实现相应功能: clamp():区间限定函数,用以规范某些变量的上下限 DefaultRobotHWSim::initSim():初始化插件的各项属性 DefaultRobotHWSim::readSim():从Gazebo仿真器中读取模型的信息和状态 DefaultRobotHWSim::writeSim():将目标值写入Gazebo仿真器中 下面我们分析几个重点函数。 DefaultRobotHWSim::initSim()函数初始化了整个插件,首先处理了URDF文件中transmissions模块信息,主要是以下方面:
  • 定义了机器人的自由度数
  • 从transmissions中获取各个关节接口类型,名称
  • 判断是否使用PID控制,如果没有设置PID参数,则视为不使用PID
并对模型进行了以下处理:
  • 从gazebo模型中获取关节名称,并实例化各关节
  • 为各个关节gazebo模型的行程设置上下限
读取函数readSim()和写入函数writeSim(),分别实现以下功能:
  • 从gazebo仿真器中读取个关节的当前状态
  • 根据控制器类型将控制量写入仿真器
2、控制代码 我们看看各类型的控制方法具体是如何实现的

①力控制

力控制十分简单,直接将目标量写入了仿真器,其中SetForce()函数是Gazebo仿真器自带的关节力设置函数。
case EFFORT:{   const double effort = e_stop_active_ ? 0 : joint_effort_command_[j];   sim_joints_[j]->SetForce(0, effort);}break;
②PID位置控制 PID位置控制稍显复杂,首先计算当前状态下的位置误差error,其中对于REVOLUTE(转动副)类型的关节,还要考虑关节限位。再利用pid_controllers下的computeCommand()方法计算当前误差下应当施加到关节上的力,并使用区间限定函数clamp()来规范力的上下限。从此处可以看出,gazebo_ros_control插件实际上使用了输入力的PID位置控制,该方法的原理可见我在古月居发表的《PID控制是个啥?ROS实验让你恍然大悟》。最后,利用SetForce()函数将目标量写入了仿真器。
case POSITION_PID:{   double error;   switch (joint_types_[j])  {       case urdf::Joint::REVOLUTE:           angles::shortest_angular_distance_with_limits(joint_position_[j],                                                         joint_position_command_[j],                                                         joint_lower_limits_[j],                                                         joint_upper_limits_[j],                                                         error);           break;       case urdf::Joint::CONTINUOUS:           error = angles::shortest_angular_distance(joint_position_[j],                                                     joint_position_command_[j]);           break;       default:           error = joint_position_command_[j] - joint_position_[j];  }   const double effort_limit = joint_effort_limits_[j];   const double effort = clamp(pid_controllers_[j].computeCommand(error, period),                               -effort_limit, effort_limit);   sim_joints_[j]->SetForce(0, effort);}break;
③PID速度控制 PID速度控制函数和PID位置控制函数的逻辑完全一致,唯一的区别是误差error取的是速度误差。
case VELOCITY_PID:   double error;   if (e_stop_active_)       error = -joint_velocity_[j];   else       error = joint_velocity_command_[j] - joint_velocity_[j];   const double effort_limit = joint_effort_limits_[j];   const double effort = clamp(pid_controllers_[j].computeCommand(error, period),                               -effort_limit, effort_limit);   sim_joints_[j]->SetForce(0, effort);   break;
④非PID的位置控制和速度控制 如果不使用PID控制,那么硬件会直接调用Gazebo的SetPosition()和SetVelocity()接口,强行设置关节的位置和速度,而非通过输入力的方式进行控制。代码分别位于320行到330行,以及359行到372行。 3、答案揭晓 根据源码的分析,我们在Gazebo仿真中的很多“万年难题”就迎刃而解啦!例如: A 我的模型在仿真时一直抖动,怎么办? 答:在保证模型惯量属性、关节摩擦、阻尼合理的前提下,调整PID参数。从源码看到,控制器的PID控制实际上是输入力的PID控制,模型物理属性不符合真实情况、PID参数不合理必然导致关节振荡。这也提醒我们,良好的Gazebo仿真,其前提是真实的物理模型和合理的理论推导。务必不要将其当做纯动画制作软件! 7bb324262a8e79fe5139d182470afd43.gif f166de64c498e8e3b912cf118d80b15f.gif 图2 图3 由于质量属性\PID参数不合理,机械臂发生了细微的或鬼畜般的抖动。 B PID参数该怎么设置啊?我怎么调都没用! 答:自己努力吧孩子!还是如上一个问题所述,在仿真之前,先进行完整的控制理论推导,而非随便尝试。提供两个小技巧:动态配置插件Dynamic Reconfigure可以方便地动态调整PID参数,如图。另外尤其要注意一个问题:gazebo_ros_control对于PID中的积分增益i是默认锁定为0的,要想使用积分控制,需要在yaml文件中打开积分增益的上下限,否则无论怎么调积分增益都没有用的(坑...)。
 # pid增益的正确配置姿势(如要使用积分控制,必须打开积分增益的上下限,否则默认均为0)joint1_position_controller:  type: effort_controllers/JointPositionController  joint: joint_1  pid: {p: 100.0, i: 1.0, d: 10.0, ,i_clamp_max: 0.0, i_clamp_max: 1.0}
e72493377af2aa3a70095404e2f030fb.png 图4 PID参数动态配置插件Dynamic Reconfigure C 我必须要设置PID参数吗?如果不设置会怎么样 答:不是必要的,但推荐在yaml中设置PID参数。从源码中可以看到,gazebo_ros_control插件会自动判断用户是否在yaml文件中设置了PID参数。如果没有,当用户使用位置控制和速度控制时,就会调用Gazebo默认的位置和速度设置接口。而根据注释信息可以看到,如果你的Gazebo版本小于9,这样做就是有坏处的:仿真器不会模拟模型的重力,会导致动力学仿真异常。因此,我们最好还是在yaml文件中设置合理的PID参数。
ROS_WARN_ONCE("The default_robot_hw_sim plugin is using the Joint::SetPosition method without preserving the link velocity.");ROS_WARN_ONCE("As a result, gravity will not be simulated correctly for your model.");ROS_WARN_ONCE("Please set gazebo_pid parameters, switch to the VelocityJointInterface or EffortJointInterface, or upgrade to Gazebo 9.");ROS_WARN_ONCE("For details, see https://github.com/ros-simulation/gazebo_ros_pkgs/issues/612");
58a4c62b111531e0122ba173af84b1ea.gif 图5 在gazebo9以前的版本中,一只手由于没有设置PID参数导致重力异常,悬浮在空中。 D gazebo_ros_control插件可以完成计算力矩控制等更加复杂的控制策略吗? 答:需要基于插件的自定义接口自己编写程序。从源码中看到,插件所提供的控制策略只有基本的PID控制,其输入量的计算只考虑了误差,并没有考虑任何动力学模型。详见control_toolbox项目下的src/pid.cpp文件。 E 我的并联机器人模型只能用sdf创建,可以使用gazebo_ros_control进行控制吗? 答:不可以。从源码看出,控制器类型等相关信息必须从urdf下的transmissions获取,甚至在注册关节限位时也使用了urdf类,而并没有支持sdf格式。不过,由于sdf是Gazebo默认的支持格式,有完整的官方文档提供,因此根据gazebo_ros_control的逻辑重新创建一个适用于sdf的控制插件其实并不困难。 3df5fe0d4daa929dc0707665fb7144e1.png 图6 笔者利用sdf创建的六自由度并联机器人,使用自定义Gazebo控制插件 以上就是我们从源码中找到的答案,有没有解决你的一些疑惑呢? 如果你还想进一步交流,欢迎登录古月居网站,到这篇文章下给我留言,用户名也是小明工坊。微信公众号留言也可,但我需要拜托小编帮助回复,不能保证时效性。本次分享就到这里啦,期待我们下一次见面~

古月居原创作者签约计划已开启,网站(guyuehome.com)已上线【投稿】功能,欢迎大家积极投稿,原创优质文章作者将有机会成为古月居签约作者。

af7f0ffd8e6400ad28b1e661e8bab19d.png

MoveIt编程入门

课程特价倒计时

扫码查看→

ef60b3f317257baefde1028dc9fef351.png cb6fe3ce7a11fe30e02db185ea6a5e0d.png 4d96ebd58d8a33d5f121874978b3007a.gif 戳下方原文阅读 查看课程

相关文章:

  • bigsur降级回catalina_手贱升 macOS Big Sur 后,该如何降级?
  • eclipse如何连接mysql_idea、PyCharm连接MySQL错误如何解决?
  • component是什么接口_Spring Bean是什么
  • wpf textbox垂直对齐方式_果冻公开课第九课:打破传统布局方式的flex(上)
  • 4路组相连cache设计_写了多年代码,你却不知道的程序设计的5个底层逻辑
  • python爬取网页文本_python2、python3 伪装浏览器爬取网页内容的简单示例
  • idea html代码提示_Java后端精选基础教程:使用开发工具 IDEA「连载 4」
  • 各路由协议的协议号_离婚协议范本!
  • python按行拆分表格_Python对Excel按列值筛选并拆分表格到多个文件的代码
  • easyui datagrid重新加载detailview异常_tomcat类加载机制了解一下
  • 关于python格式对齐的问题_python格式对齐
  • css清除浮动的几种方法_小猿圈之HTML/css清除浮动的方法都有哪些?
  • python初学者编程指南源码_如何系统地自学 Python?
  • sublime编辑python_Sublime配置python开发环境
  • python快速入门naomiceder_零基础小白python入门必看之Cartopy的基础使用
  • [PHP内核探索]PHP中的哈希表
  • 5、React组件事件详解
  • android 一些 utils
  • Golang-长连接-状态推送
  • HTTP中GET与POST的区别 99%的错误认识
  • Java到底能干嘛?
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • Markdown 语法简单说明
  • python大佬养成计划----difflib模块
  • Twitter赢在开放,三年创造奇迹
  • underscore源码剖析之整体架构
  • Vue小说阅读器(仿追书神器)
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 试着探索高并发下的系统架构面貌
  • 栈实现走出迷宫(C++)
  • 整理一些计算机基础知识!
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (独孤九剑)--文件系统
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (九十四)函数和二维数组
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • .chm格式文件如何阅读
  • .NET4.0并行计算技术基础(1)
  • .NetCore项目nginx发布
  • @requestBody写与不写的情况
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [Avalon] Avalon中的Conditional Formatting.
  • [BT]BUUCTF刷题第4天(3.22)
  • [C]整形提升(转载)
  • [C++]二叉搜索树
  • [ccc3.0][数字钥匙] UWB配置和使用(二)
  • [CERC2017]Cumulative Code
  • [IDF]摩斯密码
  • [JS设计模式]Prototype Pattern