位姿变换与六轴仿真
Axis6
稚晖君牛逼。看了他的六轴机器人之后,我感觉自己没学过自动化。为了证明自己是自动化专业的学生,我尝试学习以及手推了一下正逆运动学公式,手写了一个六轴机器人的控制、仿真(rviz以及Gazebo:
for those who doesn't know how to pronounce:
ɡəˈziːboʊ
,重音在前),代码放在了[Github🔗:Enigmatisms/Axis6]。本文包含如下内容:
- 位姿变换/正逆运动学的一些基本知识
- Gazebo的配置使用
- 仿真效果视频(
高清无码)
这里放两张图:
![]() |
![]() |
---|---|
rviz仿真结果 | Gazebo仿真结果 |
II. 前置知识
2.1 位姿变换左右乘
这个问题个人之前一直没有搞清楚,也没有静下心来推过。
给定空间中一个点p以及一个位姿变换
很多时候,我们接触的都会是合成变换。举一个例子:点云配准。假设点云A到点云B的位姿变换为T(点云A对应的激光器坐标系
需要经过变换T才能变换到点云B对应的激光器坐标系位置),已经存在一个粗糙的初始位姿变换:
参与变换复合的两个变换,是两个互不相关的,在同一个坐标系下讨论的绝对位姿变换,之间没有相对性。
而合成变换,则具有相对性。仍然以上面的点云配准为例子,
参与合成变换的两个变换,具有关联关系,其中的一个变换是基于另一个变换确定的坐标系来讨论的。
既然如此,那么在两种情况下的【合成的】变换分别是什么?
所以要回答左右乘问题,其中一个角度应该是:
- 左乘对应了绝对变换,右乘对应了追加变换,是在前一变换对应坐标系下讨论的。
2.2 左右乘讨论的衍生
为了方便理解,我画了一个图:
坐标系1经过位姿变换T变换到坐标系2,那么对于两个系中定义的一些点,其坐标变换公式是什么?假设点p在坐标系i下的坐标是
2.3 正逆运动学
关于D-H坐标与正逆运动学,这个人的博客讲得很清楚(非常推荐,他的博客写得不错,上一个我觉得写得不错的博客是苏剑林的):
关于正逆运动学的原理以及D-H坐标表示,我就不赘述了,上面链接的博客已经有了。我实现的六轴机器人,正逆运动学的思想是从以上博客以及Wikipedia中学来的,使用的是一个类似PUMA 560的简单带球腕六轴机器人,但是所有的关节中,link twist都与常见模型相反,所以运动学不得不自己推。
在此我只简述一下正逆运动学的思想:
实际上就是,给定各个关节的位姿,求解机器人手臂末端的位姿。这是个很容易的任务,就是疯狂地进行位姿变换合成。由于使用D-H坐标描述,使得描述机器人的参数最简,并且也描述了两个关节确定的坐标系之间的相对变换,所以可以轻易地使用位姿变换合成:
可以把这个问题看作是解方程:已知期望的末端位置,需要求解出每个关节的位姿(比如角度,平移)。复杂问题下,是需要引入优化的方式来求解的(可能没有简单的闭式解),而在一些简单的情形下,可以进行 解耦,也就是找到前后不相关联的位姿变换,分解问题为子问题,子问题下就有可能求解出闭式解。带有球腕的问题就是一个典型的简化情形。
我所使用的六轴机器人模型,参数定义如下:
1 | // link offset / link length / link twist / link angle |
小土的博客中,使用的是
顶部三个关节如何求解,小土的博客并没有说,但是思想大致还是一样的:将末端点变换到第四个关节对应的坐标系下,使用投影法求解。
2.4 多解问题&可行域
以底部的三个关节以及对应机械臂为例:
黑色和蓝色分别表示了两种不同解下的机械臂情形。对于同一个球腕位置(也就是右上角的交汇点),可能有两个解,两个解都是需要求出来的,不同的关节会形成解组。比如
给定末端姿态以及末端的位置,机械臂各个关节也不一定有解,比如:超出长度范围,或是没办法同时满足姿态和位置等等,这些都可能会使得求解结果成NaN,只需要限制在解为NaN时放弃本次控制。
III. Gazebo仿真
我想尝试一下除了rviz之外的可视化方法,rviz版本也已经在Axis6这个库里实现了,这个版本的可视化核心就在tf的使用,也没什么困难的,可视化时碰到的大多数问题实际上都是坐标系或者变换求解错误的问题。除了rviz之外,我能想到也就只有寥寥几个可视化工具:OpenGL以及其封装的Pangolin,Gazebo。由于我从来没有用过Gazebo,故想尝试一下这个新东西。
构建Gazebo机械臂主要有以下三步:
- 编写urdf(或者xacro)描述机器人,以及相应的gazebo文件(.sdf或者.gazebo以及.world)
- 构建机器人控制器(transmission),使用gazebo_ros以及gazebo_ros_control进行控制
- 调参。这一步都能放进来确实是我没想到的。
3.1 描述机器人
ROS wiki上对于描述机器人以及模型的文件是这么说的:
Xacro (XML Macros) Xacro is an XML macro language. With xacro, you can construct shorter and more readable XML files by using macros that expand to larger XML expressions.[1]
Xacro is just a scripting mechanism that allows more modularity and code re-use when defining a URDF model. When using it, what is actually uploaded to the parameter servers (per default as the "robot_description" parameter) actually is a URDF, as that gets generated from the xacro file in the launch file (by expanding the xacro macros used).[2]
这里主要给出四个部分的例子,主要看注释:以下两个部分来自于src/axis6/urdf/axis6.xacro
1 | <!-- 此处定义的是机械臂 --> |
1 | <!--此处定义的是关节信息,关节是连接机械臂(以及两个不同坐标系)的结构--> |
以下部分来自于src/axis6/urdf/axis6.sdf
:
1 | <!-- URDF需要转为gazebo能理解的sdf类型 --> |
定义机械臂的重力为0经常出现bug,一会儿说你有
multiple conflicting <gravity> tag
然后给你强制设为<gravity>true</gravity>
,又存在这个bug[3],导致gravity以及self_collide两个标签都不能被正确设置。
以下部分来自于src/axis6/world/axis6.world
:
1 | <world name="default"> |
3.2 传输控制
定义好这些文件后,写一个launch文件,如果编写正确,就能在Gazebo中生成出定义的机器人。但此时机器人是死的,没办法控制。使用gazebo_ros以及相关模块进行控制,这几个包都是需要自己下的,建议直接:
1 | sudo apt-get install ros-version-gazebo-ros* |
transmission定义的实际上是一个个电机:
1 | <transmission name="tran5"> |
需要配置一个相应的电机config文件(src/axis6/config/axis6_control.yaml
):
1 | axis6: |
2-5行是不可少的,此项配置了整个关节状态发布器。剩余的就一个个配置,配置其类型(位置控制电机,速度控制电机)以及pid参数(很难调)。
在加入这些信息之后,再生成Gazebo仿真,使用rostopic list命令可以看到一些新的topic(实际上是gazebo模型subscribe的,但因为没有配置ros端,暂时无publisher),可以直接使用如下命令进行简单测试:
1 | rostopic pub <topic_name:比如/axis6/joint1_state_controllers/command> <topic_type:一般是std_msgs::Float64> "data: <控制量,比如:1.0>" |
剩下的事情就是写一个控制节点,发布对应消息就能进行控制了,这里就不赘述了。
3.3 调参
仿真,顾名思义,一定要真。即使我把摩擦关了,碰撞检测关了,重力关了,控制也并没有想象的那么简单。问题主要是:
- 机械臂的质量以及质量分布设计得不合理(比如末端很重)
- PID参数 + 电机limit(见xacro文件按)设置的不合理。
导致以下三个问题(折磨了我一下午):
- 电机驱动力不够 + pid参数过小时,又慢又超调
- 电机驱动力充足 + pid参数较大时,机械臂抖动严重(末端尤为严重)
- 电机驱动力充足 + pid参数过大时,可能会炸开。。。机械臂直接飞了,这也太真实了
解决方案当然就是一个个电机调:
1 | joint0_position_controller: |
从最底部的关节开始(它应有的驱动能力最大,因为负载最大),关节号越高,其后的机械臂越少(载荷越小),那么显然,limit中的effort以及velocity应该越小,PID参数越小,机械臂也尽可能在末端变轻。
IV. 效果展示
最后的效果也就是:末端可以三轴方向平移,以及绕某一轴旋转。我复用了之前写的键盘控制函数(在LiDARSim2D库内)(多按键触发),故运动是可以合成的:
rviz:使用tf以及visualization_msg::Marker进行可视化:
Gazebo:花了好几个穿模的长方体(随便画的,没必要搞机械设计了):
Reference
[1] ROS wiki: xacro
[2] URDF or Xacro?
[3] Incorrect URDF to SDF conversion of gravity and self_collide tags #71