Robotics Library建立自定义的机器人模型
利用RL库对机器人进行建模仿真
RL库是一个用于进行机器人建模、碰撞模拟,路径规划的专用库,其作者团队也在IEEE上发表了一系列文章。这个库建立在一系列开源库之上,函数手册中并没有给出太多说明,具体的函数功能需要根据命名以及源码进行理解,这也是RL库冷门的原因之一,但本人实际使用一段时间之后,发现这个开源库里还是有很多值得借鉴的地方的。
RL官网
github地址
源码编译
官网,以及github上仅提供了0.7.0以及更早的0.6.2两个版本的release版本,想要debug版本进行调试的话,就需要自己进行编译了。如不需要调试,直接莽,请跳过此部分。
准备工作
1.下载cmake,不多说,干这一行的必备工具。
2.从github下载rl和rl-3rdparty两个仓库
rl
rl-3rdparty
3.编译之前,从环境变量中删掉之前安装的rl库
4.一个你熟悉的CAD软件,我用的是FreeCAD,因为生成vrml文件比较方便。
编译依赖的三方库
cmake源码位置选择上述的rl-3rdparty路径,选好编译器和位数后(建议VS编译器,没有尝试过Mingw),选定CMAKE_INSTALL_PREFIX路径,不需要改动其他配置,一路config和generate就完事了。编译完了之后记得把生成的lib和dll路径加到环境变量里去,这样后面就不用一个一个慢慢选了。
编译源码
cmake源码路径选择上述的rl位置,一路config和generate,但是,注意依赖库的位置是不是上一步install的位置,否则大概率编译报错。值得一提,不要更改cmake的其他配置,atidaq会显示未找到,不要动他,否则后边在VS里会报错。
顺带一提,使用debug版本库进行路径规划时,速度会比release版本慢很多很多,可能这也是官方不发布debug版本库的原因之一。
模型建立
rl提供了两种建模方式,一种是DH模型,依赖于rl/kin部分,在官方的API说明部分建议不使用此模块。另一种则是简单的运动中心之间的相对坐标差,更适合我这种没多少机器人基础的菜鸟。下面详细介绍后者的建立过程。
CAD模型原点位置的统一
建模,首先得有CAD模型。在这里,以实验室的六自由度柔性关节臂为例,在freecad中,打开机器人的底座模型,画一条以(0,0,0)为起点,方向为z轴正向的线段。再以此直线为参照,把底座模型的底面圆心移到(0,0,0)位置,尽量精确一点。
后续的6个零件,把转动中心都移到(0,0,0)位置,如果零件之间是移动副,确保世界坐标系的坐标原点在移动平面就OK。
把这7个模型导出为vrml 2.0文件。
将各关节转动中心之间的关系写进vrml文件
在此步骤之前。可以在官方提供的现有模型中看到,一个机器人是由各个子零件的vrml和一个负责装配的vrml组成。这一步需要对7个零级进行装配,文件格式参考官方提供的文件,如下所示
#VRML V2.0 utf8
Transform {
children [
DEF link0 Transform {
children [
Inline {
url "link0.wrl"
}
]
}
DEF link1 Transform {
translation 0 0 208.5
rotation 1 0 0 0
children [
Inline {
url "link1.wrl"
}
]
}
DEF link2 Transform {
translation 42 0 300.5
rotation 1 0 0 0
children [
Inline {
url "link2.wrl"
}
]
}
DEF link3 Transform {
translation 0 0 669.5
rotation 1 0 0 0
children [
Inline {
url "link3.wrl"
}
]
}
DEF link4 Transform {
translation 29 0 750.5
rotation 1 0 0 0
children [
Inline {
url "link4.wrl"
}
]
}
DEF link5 Transform {
translation 0 0 1119.5
rotation 1 0 0 0
children [
Inline {
url "link5.wrl"
}
]
}
DEF link6 Transform {
translation 29 0 1200.5
rotation 1 0 0 0
children [
Inline {
url "link6.wrl"
}
]
}
]
}
方便起见,在各个零件装配时避免转角,装配之后应当是一个“一柱擎天”的造型,translation表示的是装配后,各个零件运动中心的坐标。(这里底座装反了方向,大家装配的时候尽量注意)
描述场景的vrml文件
这一步没有难度,照搬就行,定义一个机器人和一个工件
#VRML V2.0 utf8
Transform {
children [
DEF ACMM Transform {
children [
Inline {
url "ACMM/ACMM.wrl"
}
]
}
DEF DMISModel Inline {
url "TesaDemo3D.wrl"
}
]
}
描述场景的xml文件
同样没有难度的一步,不过"name"的值要和上面vrml文件中一直,不然后面读取的时候直接pass,不会显示出来。
<?xml version="1.0" encoding="UTF-8"?>
<rlsg xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="rlsg.xsd">
<scene href="ACMM_DMISModel.wrl">
<model name="ACMM">
<body name="link0"/>
<body name="link1"/>
<body name="link2"/>
<body name="link3"/>
<body name="link4"/>
<body name="link5"/>
<body name="link6"/>
</model>
<model name="DMISModel">
<body name=""/>
</model>
</scene>
</rlsg>
描述运动学模型的xml文件
这个文件里还是有很多坑的。
- 首先,body在声明时,会有对其他body的引用,这一点是忽略了这两个body之间的碰撞,在rl::mdl::xmlFactory的源码中可以找到详细的原因。没有这样的声明,后面路径规划的时候,模型的自检会一直报碰撞存在。
- body之间的frame是对坐标系原点的转换,这也是之前统一坐标系原点的原因。在这一步中,frame的x,y,z直接拿装配vrml文件中的坐标值做差就可以了。
- rl提供了相对齐全的关节类型,铰链型:revolute,滑动型:prismatic等等,可以在rlmdl/rlmdl.xsd文件中寻找相关的名称。
<?xml version="1.0" encoding="UTF-8"?>
<rlmdl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="rlmdl.xsd">
<model>
<manufacturer>HFUT</manufacturer>
<name>ACMM</name>
<world id="world">
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>0</x>
<y>0</y>
<z>0</z>
</translation>
<g>
<x>0</x>
<y>0</y>
<z>9.86055</z>
</g>
</world>
<body id="body0">
<ignore/>
<ignore idref="body1"/>
</body>
<frame id="frame0"/>
<body id="body1">
<ignore idref="body0"/>
<ignore idref="body2"/>
</body>
<frame id="frame1"/>
<body id="body2">
<ignore idref="body1"/>
<ignore idref="body3"/>
</body>
<frame id="frame2"/>
<body id="body3">
<ignore idref="body2"/>
<ignore idref="body4"/>
</body>
<frame id="frame3"/>
<body id="body4">
<ignore idref="body3"/>
<ignore idref="body5"/>
</body>
<frame id="frame4"/>
<body id="body5">
<ignore idref="body4"/>
<ignore idref="body6"/>
</body>
<frame id="frame5"/>
<body id="body6">
<ignore idref="body4"/>
<ignore idref="body5"/>
</body>
<frame id="frame6"/>
<fixed id="fixed0">
<frame>
<a idref="world"/>
<b idref="body0"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>0</x>
<y>0</y>
<z>0</z>
</translation>
</fixed>
<fixed id="fixed1">
<frame>
<a idref="body0"/>
<b idref="frame0"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>0</x>
<y>0</y>
<z>208.5</z>
</translation>
</fixed>
<revolute id="joint0">
<frame>
<a idref="frame0"/>
<b idref="body1"/>
</frame>
<axis>
<x>0</x>
<y>0</y>
<z>1</z>
</axis>
<max>360</max>
<min>-360</min>
<speed>180</speed>
</revolute>
<fixed id="fixed2">
<frame>
<a idref="body1"/>
<b idref="frame1"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>42</x>
<y>0</y>
<z>92</z>
</translation>
</fixed>
<revolute id="joint1">
<frame>
<a idref="frame1"/>
<b idref="body2"/>
</frame>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
<max>120</max>
<min>0</min>
<speed>180</speed>
</revolute>
<fixed id="fixed3">
<frame>
<a idref="body2"/>
<b idref="frame2"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>-42</x>
<y>0</y>
<z>369</z>
</translation>
</fixed>
<revolute id="joint2">
<frame>
<a idref="frame2"/>
<b idref="body3"/>
</frame>
<axis>
<x>0</x>
<y>0</y>
<z>1</z>
</axis>
<max>360</max>
<min>-360</min>
<speed>180</speed>
</revolute>
<fixed id="fixed4">
<frame>
<a idref="body3"/>
<b idref="frame3"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>29</x>
<y>0</y>
<z>81</z>
</translation>
</fixed>
<revolute id="joint3">
<frame>
<a idref="frame3"/>
<b idref="body4"/>
</frame>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
<max>120</max>
<min>0</min>
<speed>180</speed>
</revolute>
<fixed id="fixed5">
<frame>
<a idref="body4"/>
<b idref="frame4"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>-29</x>
<y>0</y>
<z>369</z>
</translation>
</fixed>
<revolute id="joint4">
<frame>
<a idref="frame4"/>
<b idref="body5"/>
</frame>
<axis>
<x>0</x>
<y>0</y>
<z>1</z>
</axis>
<max>360</max>
<min>-360</min>
<speed>180</speed>
</revolute>
<fixed id="fixed6">
<frame>
<a idref="body5"/>
<b idref="frame5"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>29</x>
<y>0</y>
<z>81</z>
</translation>
</fixed>
<revolute id="joint5">
<frame>
<a idref="frame5"/>
<b idref="body6"/>
</frame>
<axis>
<x>0</x>
<y>1</y>
<z>0</z>
</axis>
<max>120</max>
<min>0</min>
<speed>180</speed>
</revolute>
<fixed id="fixed6">
<frame>
<a idref="body6"/>
<b idref="frame6"/>
</frame>
<rotation>
<x>0</x>
<y>0</y>
<z>0</z>
</rotation>
<translation>
<x>-29</x>
<y>0</y>
<z>195.8</z>
</translation>
</fixed>
<home>
<q unit="deg">0</q>
<q unit="deg">24</q>
<q unit="deg">0</q>
<q unit="deg">109</q>
<q unit="deg">0</q>
<q unit="deg">27</q>
</home>
</model>
</rlmdl>
仿真及后续
模型建立完毕后,可以选择使用官方的demo进行初步的显示。这里需要对源码文件夹中的rlCoachMdl进行部分改动,新建一个pro文件,添加进文件夹下的文件,和部分必须的Qt模块,如opengl、network。然后添加rl库的头文件和.lib文件,以及两条预定义
熟悉rl库的建模流程之后,可以进行其他的一些列操作,如利用rl库仅进行计算,利用其他三方库进行显示;多机器人协同任务安排等。
萌新出于记录生活的目的,第一次写博客,诸多不足之处还请海涵,有疑问或者建议可私信。