ROS与GAZEBO实时硬件仿真(2)——urdf的gazebo属性

版权声明: https://blog.csdn.net/wubaobao1993/article/details/80960584

写在前面

通过上一节的博客,相信朋友们已经对urdf有了一个较为完整的认识,应该也可以自主的写一个urdf文件在ros和gazebo看到了,但是仅仅是这样,如果我们志在让机器人在gazebo中运行的话,其实还是差很多东西,原因还是那句话,gazebo是靠物理引擎驱动的,我们现在的urdf文件还差一些物理定律所需要的最基本的属性。
那么本节的主要目的就是给我们的urdf添加上更多的属性,让gazebo更加“欢迎”我们给予它的机器人描述文件。
tips:再次说明一下,本系列主要是想帮助朋友们更好的理解ros和gazebo是怎么联系在一起的(在我独自探索的时候,觉得这条主线的捋顺是最重要的),重点不在程序,也不在各式各样的标签上,因此对于标签和程序,这里不做过多讲解,有兴趣的可以更多的参考博客中给出的链接,那里面讲的要比我全面的多。


整体流程框架

依旧祭出官方的框架图
流程图

在上个博客中,虽然放上了该图,但是似乎并没有什么内容是与该图想对应的。诚然,上节的内容大多数是urdf的东西,在该图里面就是一个小方块,但是本节的内容就能在这里面体现的更多了。
废话不多说,下面开始我们的探索之旅。


把大象装进冰箱里第二步——给urdf打上gazebo的属性

这一步的目的其实很明显,就是为了让我们的机器人具备更多的属性,从而让我们的机器人在gazebo的仿真中能表现的更像在真实世界中一样!

对link使用gezebo标签

作用

我们知道,在现实世界中,一个物体光有质量和旋转惯量是完全不够的,这两个元素只是最基本的属性,
表征这个物体可以被物理引擎观测到,但是仅仅如此是达不到我们想用gazebo的初衷的——通过这个平台模拟机器人在真实世界中的表现。举个简单的例子,一个物体除了质量外,另一个很重要的属性就是表面摩擦系数了,而这个属性link标签根本没有对其进行定义,那么这时候gazebo标签就派上了用场。

流程

1.找到上节的urdf文件
2.将wheel的link和joint去掉,这时候运行下面的命令:

roslaunch urdf_sim_tutorial gazebo.launch model:=rbo.urdf.xacr

3.这时候在gazebo中你应该能看到白色的box,右键你的模型,在快捷菜单中点击“Apply Force/Torque”,这时候我们就能看到这样的情景
加力的场景

这里提醒一下,因为上节的时候,最后将base_link和car_link固连在了一起,中间差了一个轮子的高度,此时你力的着力点很有可能不在物体上,这时候你需要调整面板中的Application Point的XYZ值让着力点在模型上

之后我们在Force下面的X的编辑栏中填入10000N,之后点击Apply Force或者Apply All,就可以看到模型向X轴运动了,当然你也可以尝试编辑Torque中的值,如果你修改的是X或者Y轴的数值,你会看到模型弹腾一下,但是如果你修改的是Z轴的值,那么你就会看到模型的旋转啦!

特别注意的是,修改值的时候尽可能的大一些,虽然我们给予的外力很大,但是由于仿真中一步的时间很短,因此很小的力是根本看不出效果的

到这里,你可能会说:咦,说好的gazebo标签呢?那么下面开始我们的正题,在urdf的最后面(当然要在robot标签内!)中添加一个geazbo的标签。

4.在代码中添加如下的语句:

<!-- gazebo -->
<gazebo reference="car_link">
    <material>Gazebo/WoodFloor</material>
    <mu1>0.5</mu1>
    <mu2>0.5</mu2>
</gazebo>

这时候输入gazebo的显示命令之后,你就能看到一个木质地板做的模型:D 关于模型的材料,更详细的内容可以移步到here
效果图

但是,如果你此时在rviz中打开模型的话,你会发现模型并没有这么漂亮:( 还是原来那个样子
rviz效果

这也就是说,gazebo标签只是告诉gazebo怎么显示,并不会管ros中模型的形态以及属性,所以,这两个模块之间毫无疑问是有一个巨大的鸿沟隔着的!而能填补这个鸿沟的,就是整体框架图中的ros_control,不过这就是下节的内容了:D

不过话说回来,添加这个标签里面还有两个mu的值,我们似乎还没有看到他的作用呢,其实很简单,你只需要重复上面的给力操作的话,你就能发现,同样是10000N的力,这次能够移动的更远了~没错!默认情况下,当我们没有对gazebo标签内的属性赋值的话,gazebo会给予一个默认的值,让模型能够工作,例如这里表面摩擦系数就默认是1.0,因此当我们修改摩擦系数为0.5的时候,相同的力我们就能给予更大的加速度,因此推的就更远,感兴趣的也可以试试给0.0哈,gazebo会告诉你什么叫不可能:)

关于gazebo可以给link加的属性,因为比较多,也不能一一介绍,上面的代码给出的就是最常用的标签,其他的标签可以看下图,官方关于这个地方的讲解可以参考here

link gazebo

tips:如果对于标签的值不确定的话,最好的方式就是敬而远之,不要填写,gazebo会给予一个默认可用的值的!擅自的修改会导致不好的结果。


对joint使用gazebo标签

实际上,这部分目前接触的不是很多,所以这部分就一笔带过了,各个属性值可以看下面的图片

这里写图片描述

更详细的参考here


给joint添加真正的执行装置——transmission标签

这部分算是本博客的比较重要的部分了,因为一再强调,gazebo中的仿真都是基于物理引擎的,那么你想让一个模型运动,从本质上讲,必须要有力施加在模型上,就实际而言,我们必须在模型上加上执行器(通常情况下就是电机了),让模型运动起来。

作用

transmission标签主要的针对对象是joint(因为一般两个link连接处的地方如果是非固定的,那么一定会存在一个执行装置来改变两个link的相对位置),transmission标签的作用就是给这个joint打上某种执行器的标签,有了执行器,gazebo就可以在物理层面上对模型进行驱动了。

流程

  1. 修改上面的urdf,把整个机器人建立成一个四轮式的机器人
  2. 对于每一个joint,我们在下面添加它的transmission标签,这里直接给出我修改之后的程序
<?xml version="1.0"?>
<robot name="rbo" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- variable -->
    <xacro:property name="PI" value="3.1415926"/>
    <xacro:property name="car_width" value="1.0"/>
    <xacro:property name="car_length" value="2.0"/>
    <xacro:property name="car_height" value="0.3"/>
    <xacro:property name="wheel_length" value="0.13"/>
    <xacro:property name="wheel_radius" value="0.25"/>
    <xacro:property name="wheel_origin_xyz" value="0.0 0.0 0.0"/>
    <xacro:property name="wheel_origin_rpy" value="0.0 ${PI/2} 0.0"/>

    <!-- rviz color -->
    <material name="blue">
        <color rgba="0 0 1 1"/>
    </material>

    <material name="black">
        <color rgba="0 0 0 1"/>
    </material>

    <!-- macro -->
    <xacro:macro name="default_inertial" params="mass">
        <inertial>
            <mass value="${mass}" />
            <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0" />
        </inertial>
    </xacro:macro>

    <xacro:macro name="box_geometry" params="width length height">
        <geometry>
            <box size="${width} ${length} ${height}"/>
        </geometry>
    </xacro:macro>

    <xacro:macro name="cylinder_geometry" params="length radius">
        <geometry>
            <cylinder length="${length}" radius="${radius}"/>
        </geometry>
    </xacro:macro>

    <xacro:macro name="default_origin" params="xyz rpyaw">
        <origin xyz="${xyz}" rpy="${rpyaw}"/>
    </xacro:macro>

    <!-- links -->
    <link name="car_link">
        <visual>
            <xacro:box_geometry width="${car_width}" length="${car_length}" height="${car_height}"/>
            <material name="blue"/>
        </visual>
        <collision>
            <xacro:box_geometry width="${car_width}" length="${car_length}" height="${car_height}"/>
        </collision>
        <xacro:default_inertial mass="3.0"/>

    </link>

    <!-- gazebo -->
    <gazebo reference="car_link">
        <material>Gazebo/SkyBlue</material>
        <mu1>0.5</mu1>
        <mu2>0.5</mu2>
    </gazebo>

    <!-- wheel joint macro -->
    <!-- right:1 left:-1 -->
    <xacro:macro name="wheel_car_joint" params="wheel_name front_end left_right">
        <link name="${wheel_name}">
            <visual>
                <xacro:cylinder_geometry length="${wheel_length}" radius="${wheel_radius}"/>
                <xacro:default_origin xyz="${wheel_origin_xyz}" rpyaw="${wheel_origin_rpy}" />
                <material name="black"/>
            </visual>
            <collision>
                <xacro:cylinder_geometry length="${wheel_length}" radius="${wheel_radius}"/>
                <xacro:default_origin xyz="${wheel_origin_xyz}" rpyaw="${wheel_origin_rpy}" />
            </collision>
            <xacro:default_inertial mass="1.0"/>
        </link>

        <!-- joints -->
        <joint name="car_base_${wheel_name}" type="continuous">
            <origin xyz="${left_right*(wheel_length+car_width)/2.0} ${front_end*car_length*0.6/2.0} 0.0" rpy="0.0 0.0 0.0"/>
            <parent link="car_link"/>
            <child link="${wheel_name}"/>
            <axis xyz="0.0 1.0 0.0"/>
        </joint>

        <gazebo reference="${wheel_name}">
            <material>Gazebo/Black</material>
            <mu1>0.5</mu1>
            <mu2>0.5</mu2>
        </gazebo>

        <transmission name="${wheel_name}_transmission">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="car_base_${wheel_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${wheel_name}_motor">
                <mechanicalReducction>1</mechanicalReducction>
            </actuator>
        </transmission>
    </xacro:macro>

    <xacro:wheel_car_joint wheel_name="front_right_wheel" front_end="1.0" left_right="1.0"/>
    <xacro:wheel_car_joint wheel_name="front_left_wheel" front_end="1.0" left_right="-1.0"/>
    <xacro:wheel_car_joint wheel_name="end_right_wheel" front_end="-1.0" left_right="1.0"/>
    <xacro:wheel_car_joint wheel_name="end_left_wheel" front_end="-1.0" left_right="-1.0"/>

    <!-- base_link -->
    <link name="base_link"/>
    <joint name="base_link_car" type="fixed">
        <origin xyz="0.0 0.0 ${wheel_radius}" rpy="0.0 0.0 0.0"/>
        <parent link="base_link"/>
        <child link="car_link"/>
    </joint>

</robot>

这个程序的运行结果就是如下图

这里写图片描述

由于我在程序也在link标签内部加入了material的值,因此在rviz中,大家应该也可以看到一个相同颜色的小车

这里写图片描述

这里对transmission标签内部的属性值稍作介绍:
1. type: 这个标签不用担心了,只有一个值:transmission_interface/SimpleTransmission
2. joint:首先要指明transmission服务的joint的名称,之后其中包含一个必填属性
- hardwareInterface:该属性表明了这个joint是什么类型的,当前使用最多的(我的感觉是差不多只有这三种类型)是以下三个属性值:EffortJointInterface(通过输入功率控制电机),VelocityJointInterface(控制电机的转速),PositionJointInterface(控制电机的位置)。
3. actuator:首先要为你的执行器起一个名字(一般就是什么什么motor),之后指定执行器的内部属性
- mechanicalReduction:指明电机的减速比
- hardwareInterface:这个可以不指明,因为在joint中已经指明了

以上三个内部属性就是transmission的全部标签了,当然,有的朋友可能会问,作为执行器,必然是会有速度,功率的限制的,这个标签里面为什么没有这些参数?答:这些参数其实都有,只不过你要在上一节的joint标签中赋予相应的值,因为这些值说真的是属于joint的,并不属于transmission这个映射的属性,相应设定如下图,具体可以参考here
这里写图片描述


让执行器真正的能够进行硬件仿真——libgazebo_ros_control.so

回到最上面的整体流程图,我们可以看到,在simulaition那么方框内,gazebo的作用其实仅仅是一个simulator的作用,它需要writeSim这个接口来接受一些东西之后,才能在物理引擎的作用下模仿出真实的场景,完事儿之后,再把一些东西送出去,直接负责与之交互的就是这里的RobotHWSim。

作用

负责将上层应用程序的信号量传输给gazebo进行仿真。例如,PID Loop计算得到了name=“wheel”的这个执行器需要输入10W的功率,那么经过JointCommand这个接口之后,信号就转化为了只有Effort Joint才能识别的信号,送给RobotHWSim,RobotHWSim接到这个信号之后,会找这个节点对应的transmission的是否也是Effort类型的,如果不是的话,gazebo就跪给你看了(当然并不是退出,而是你的这个信号就根本不会产生价值);如果是的话,信号的取值也很合理,那就可以开心的把它转化为gazebo能识别的信号给它了;一段时间后,gazebo将仿真的结果送回来,RobotHWSim拿着这个结果一算:Oh,这个关节运动了多少多少,就开开心心的吧这个结果送给JointState接口,由它转化为ros的信号。当然上面全部是我的个人猜测,如果有大神知道里面的实际情况,也请在这里指导一下~不胜感激!

流程

在代码的任意位置添加如下代码:

 <!-- plagin -->
 <gazebo>
     <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
         <robotNamespace>/</robotNamespace>
         <robotSimType>gazebo_ros_control/DefaultRobotHWSim</robotSimType>
     </plugin>
 </gazebo>

这里命名空间是一个比较重要的东西,不过当前的内容还不涉及,到了下节的时候再详细的说明一下他的用处。


总结

那么到这里,今天的内容基本上就这些了,这节的内容着实不多,同时很多情况下修改了代码还看不出任何的效果。。。个人觉得这就是造机器人的过程,我们看到的永远都是外表,而内在的电机啊,传感器啊等等的,他们的安装也是搭建机器人的环节中不可或缺的一部分,而这节内容就类似于这个过程。。。
还是那句话,这个系列意在理清楚我们要想在gazebo中仿真需要做的主线任务,希望能对朋友们有所帮助。


附加

gazebo官方的material标签值:gazebo颜色标签

tips:根据上面的标签值,我们很容易的就可以将其转化到rviz上进行显示了,不过要在urdf中声明一下才能用,并不gazebo标签内可以直接使用

猜你喜欢

转载自blog.csdn.net/wubaobao1993/article/details/80960584