ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从旋转矩阵到指数坐标:机器人姿态表示的进阶指南

从旋转矩阵到指数坐标:机器人姿态表示的进阶指南 前阵子带学生调一个六轴机械臂现场示教器上的姿态数据一直在跳学生问我“这个欧拉角一会儿是179度一会儿是-179度明明末端只转了一点点数值怎么就跳变了呢”我看了看跟他说这个问题问得很好正好可以引出旋转表示里一个非常值得吃透的概念——转动的指数坐标表示。后来想想这个知识点在机器人运动学、姿态插值、视觉伺服里都会反复出现值得把心得整理出来分享。当时我说你把欧拉角忘掉绕开它从一个更“本质”的角度看旋转——绕某个固定轴转一个角度。这个“轴角”再配上“指数映射”这个数学工具就是标题里说的指数坐标。它不像欧拉角那样有万向锁也不像旋转矩阵那样动辄9个数它有明确的物理直觉又能跟角速度、运动学微分直接衔接是连接“直观理解”和“数学表达”的一座桥。这篇文章面向的是正在学机器人学、做运动学算法、或者被姿态表示绕晕的工程师和学生们。我会从为什么不能用旋转矩阵当坐标、指数坐标的数学直觉、与其他表示方法的对比、以及在工程里的实际应用和踩坑经验这几个方面展开尽量把“指数坐标”这件事讲透。1. 为什么旋转矩阵不适合直接当“坐标”用1.1 从示教器上的姿态数据说起用示教器手动拖拽机器人末端观察六轴机器人的姿态显示你会看到旋转矩阵、欧拉角、四元数几种不同表示可以切换。绝大多数时候默认显示的是欧拉角即绕X、Y、Z轴的三个转角。这是最直观的表示但它有一个很让人头疼的问题同一个姿态可以用多组欧拉角表示。回到开头那个场景179度和-179度之间就差了2度如果内部算法或者通信协议没有做角度归一化控制指令会经历一段“无意义”的大范围跳变。我见过好几次机器人运动过程中姿态数据在某个点位附近来回跳变现场工程师第一反应以为是硬件抖动实际上只是表示方式带来的数学假象。欧拉角用三个数字表示三个自由度旋转的自由度形式上像是三维空间里的坐标但这三个数字跟实际几何动作不是线性对应的。转动顺序一变同一个三元组描述的完全是另一个姿态。多数机器人厂家用ZYX或者ZYZ约定操作手册里写了但没几个调机的人真正关心过直到遇到问题才回头翻手册。1.2 旋转矩阵当坐标用的三个麻烦旋转矩阵的好处是数学性质极好单位正交、行列式为1、可逆、组合封闭。坏处也很明显。第一它是个3x3矩阵9个数但只有3个自由度。这意味着内部有6个冗余约束。如果直接把这9个数当作状态变量去优化、滤波、插值结果大概率不满足约束得到的“旋转矩阵”行列式不是1也不再正交。除非每一步之后都做一次SVD分解或者格拉姆-施密特正交化去强制修正否则误差会一路累积姿态越算越飘。第二矩阵的9个数和几何直觉毫无关联。看一眼旋转矩阵的第一行第二列数值你没法在脑子里浮现出末端到底转成了什么样子。调试的时候打印一个旋转矩阵人脑很难直接判断这个姿态是不是预期的样子。第三插值和微分都不直观。对两个旋转矩阵做线性插值中间值不能保持正交性差出来的矩阵没有实际物理意义。求导也不是简单的逐元素求导必须考虑约束条件。所以无论是为了做运动学解算还是做姿态平滑、状态估计我们都需要一个更贴近“旋转本质”的表示方式。旋转的本质是什么绕一根固定轴转过一个确定的角度。这就是轴角表示也就是指数坐标的物理内核。指数坐标的核心思想把旋转3个自由度拆成“转轴方向”2个自由度和“转角大小”1个自由度。用单位向量表示转轴用旋转角度表示大小两者相乘就得到一个三维向量。这个三维向量就是旋转的指数坐标。2. 指数坐标的数学直觉转轴与转角的融合2.1 从“无穷小旋转”理解指数映射如果你看过任何一本机器人学教材一定见过旋转矩阵的指数映射公式形式上跟标量的e的x次方很像旋转矩阵R e的[ω]θ次方这里ω是单位转轴θ是转角[ω]是ω对应的反对称矩阵。为什么旋转会和指数函数扯上关系我个人的理解是任何一个旋转都可以看成是绕着转轴连续做了无穷多个“无穷小旋转”的结果。就像你可以把“转90度”拆成“连续转n个小角度”当n趋近无穷时每个小角度趋近0。而无穷小旋转是可以近似线性化处理的跟速度积分一个道理。回忆一下刚体定轴转动时角速度与姿态变化率的关系。物体绕某个轴以角速度ω旋转经过dt时间后姿态的变化近似等于一个“小旋转”这个“小旋转”对应的旋转矩阵近似为I加上角速度反对称矩阵乘以dt。这里的反对称矩阵不是凭空冒出来的它是角速度叉乘矩阵也就是线性化之后旋转的“导数方向”。把这个小步骤在时间上连续累积起来指数映射就自然出现了。你可以这么记指数映射做的事情是把角速度方向的“速度信息”积分成“位置信息”——旋转矩阵。2.2 为什么角速度对应的是反对称矩阵上一小节的反对称矩阵很多初学者会困惑为什么角速度要和反对称矩阵绑定而不是普通的3x3矩阵回忆向量叉乘ω × p可以写成一个矩阵乘以p的形式。这个矩阵就是[ω]它是一个反对称矩阵对角线为0非对角线互为相反数。几何上叉乘的结果同时垂直于ω和p这种“垂直”性质正是旋转微分所需要的——无穷小旋转引起的位移变化总是垂直于当前矢量的方向。严格地说反对称矩阵的集合记为so(3)构成了旋转矩阵群记为SO(3)在单位元处的切空间。所有旋转的“无穷小变化方向”都在这个切空间里。这就是为什么旋转微分联系到的是反对称矩阵。这里我加一个动手理解的小技巧打开任意一个科学计算软件构造一个反对称矩阵然后计算它的矩阵指数。你再验证一下结果矩阵的行列式和正交性会发现指数映射输出的确实是一个标准旋转矩阵。多试几次不同参数你对这个抽象概念的“体感”会迅速建立起来。2.3 罗德里格斯公式指数映射的工程形态矩阵指数直接算在代码里可不是直接对每个元素取指数那完全是错的。实际工程中用的都是罗德里格斯公式R I sinθ · [ω] (1 - cosθ) · [ω]²这个公式才是真正落在代码里的东西。你用任何语言实现轴角转旋转矩阵写的基本上就是这个式子的变形。从数学上指数映射级数展开回代借助反对称矩阵的高次幂循环性质[ω]的三次方等于负[ω]就能把无穷级数收敛成sin和cos的封闭形式。代码实现时要注意的是当θ非常接近0时sinθ/θ和(1-cosθ)/θ²会出现数值病态因为分子分母都很小。这时候不能直接套公式需要做泰勒展开近似只保留前几项就足够精确了。现场调试时我习惯把“θ小于1e-6”作为阈值直接返回单位阵加线性近似项。曾经有段时间工件定位偶尔出现细微偏差就是因为在某个几乎不动的位置上直接用罗德里格斯公式导致数值丢精度后来改成小角度近似之后问题就消失了。3. 指数坐标和欧拉角、四元数放在一起比一比3.1 欧拉角的万向锁问题与顺序依赖欧拉角为什么让机器人工程师头疼核心问题是它依赖旋转顺序而且有万向锁。所谓万向锁是当中间的旋转角达到90度时第一个和第三个旋转轴重合系统丢失了一个自由度从这个状态附近会出现姿态的剧烈跳变。还有一个切肤之痛是插值问题。对两个欧拉角做线性插值视觉上末端走过的路径往往是歪的不是“绕最短路径转过去”。这是因为欧拉角的空间结构不是平坦的线性插值在这个非平坦空间里走的不是测地线而是“弯路”。万向锁问题不是理论上的杞人忧天是实打实的工程问题。有一个真实案例某个设备用欧拉角做云台姿态跟踪在俯仰接近90度时水平方位角突然发生180度翻转导致画面瞬间掉头——用户当然不会觉得这是数学问题只会觉得产品有bug。3.2 四元数和指数坐标其实是亲戚四元数现在在机器人、无人机、三维渲染里都是主流因为它没有万向锁插值有成熟的slerp球面线性插值计算效率也不错。但如果你把四元数和轴角放在一起看会发现四元数本质上可以理解为“轴角的另一个编码方式”。单位四元数q (cos(θ/2), ω·sin(θ/2))这个形式里唯一的几何参数仍然是ω和θ——转轴和转角。它跟指数坐标的核心物理是一样的只是换了一种代数包装。指数坐标的转角就是θ直接明了。四元数里存的是cos(θ/2)和sin(θ/2)要想看转角多少需要做一次反余弦。指数坐标是三维向量没有“单位长度”约束四元数有单位模长约束插值时也要归一化。工程上很多库内部把旋转存成四元数但在与人交互、可视化、调试的环节四元数很难直接看。我经常先把四元数转成轴角指数坐标来看懂当前姿态到底在转什么方向、转了多少度调试效率会高很多。3.3 工程选型不同场景怎么选做项目选型时我内部有个简单的决策逻辑场景推荐表示原因机械臂运动学正逆解旋转矩阵或指数积方便复合与微分计算姿态指令接口/示教欧拉角人可以直接读与操作姿态插补/平滑四元数或指数坐标无万向锁插值可控状态估计/滤波如卡尔曼滤波指数坐标小角度增量切空间加法无约束内部存储/通信四元数紧凑、稳定、无奇异调试可视化轴角/指数坐标直觉最直接注意表格里说的是“推荐”不是“绝对”。比如用扩展卡尔曼滤波做姿态估计时如果用四元数作为状态量归一化约束很难处理改用指数坐标做误差状态把旋转增量作为小量处理就非常自然。这就是为什么很多惯性导航和SLAM系统的核心代码里误差状态都是用指数坐标或者等效的轴角增量表示的。4. 指数坐标在机器人关键环节的真实应用4.1 指数积公式把关节转动的坐标表示用起来机械臂运动学正解的经典方法是DH参数法每个关节依次做平移加旋转的齐次变换矩阵连乘。DH模型用起来要小心坐标系建得是否合理、参数是否齐全不同的DH约定还容易引起混乱。指数积公式是另一种运动学建模方式它基于旋量理论。简单说每个关节的转动效果可以表示成一个旋量坐标末端位姿就是把每个关节的指数映射按顺序乘起来。这个表达式全球坐标系的几何逻辑直接不需要逐杆件建坐标系对串联机器人的建模有时候更直观。而旋量中的旋转部分正是指数坐标。比如一个简单的二连杆平面机器人每个关节都是绕Z轴的转动转动旋量分别是(0, 0, 1, 0, 0, 0)和(0, 0, 1, L1, 0, 0)其中平移部分和第二关节位置有关末端位置可以在几十行代码里写出来不需要建任何杆件坐标系。在实际调试中指数积公式最大的好处是可以把视觉标定、手眼标定和运动学统一在同一套数学框架里减少概念转换带来的混淆。如果你在做一个视觉引导机器人项目用旋量语言沟通时大家对这些量的理解更容易对齐。4.2 姿态插值为什么不能简单线性插值矩阵做轨迹规划时机械臂要从姿态A平滑过渡到姿态B。如果对两个旋转矩阵直接线性插值中间点的矩阵一般不再是旋转矩阵末端运动路径会“飘”。正确的做法是利用轴角/指数坐标的自然几何结构做插值。给定起始旋转矩阵R1和终止旋转矩阵R2先计算相对旋转R_rel R1的转置乘以R2即从姿态A变换到姿态B之间的相对旋转然后把这个相对旋转映射成指数坐标ωθ。如果想要中间某个比例t处的姿态把转角乘上t再用指数映射转回旋转矩阵左乘到R1上。这么做的几何意义是末端从起始姿态“绕固定轴匀速转过去”路径是旋转群上的测地线。从视觉上看机械臂末端的运动是“干净地绕一个轴转过去”用户观感会明显更舒服。工业机器人示教器上常见的“姿态插补”选项很多背后就是基于类似的轴角增量思路。当时我调试一个涂胶轨迹时连续几个路点间姿态角度变化较大如果用欧拉角逐点插值胶枪在转弯处会上下抖换成轴角增量插值之后轨迹立刻顺滑很多。4.3 角速度与指数坐标的时间导数指数坐标与角速度之间有非常漂亮的关系在视觉伺服和力控里经常用到。指数坐标r(t)对时间求导得到的导数向量与角速度ω(t)之间存在一个线性映射矩阵ω J(r) · dr/dt其中J(r)就是旋转矩阵对数映射的雅可比矩阵。这个矩阵在一些情况下是奇异矩阵——尤其是转角接近π的时候。这个公式有什么实际意义它让我们可以用指数坐标作为“广义坐标”来写运动方程。比如在设计控制律时把姿态误差表达成指数坐标形式误差向量天然就是三维的可以用标准的线性控制方法设计不必在旋转矩阵流形上做复杂的非线性控制设计。我当时做一个六轴机械臂的视觉伺服抓取项目图像反馈算出来的期望姿态变化就是用指数坐标形式当作控制偏差再乘上雅可比矩阵映射成关节角速度指令。整个控制环结构非常清晰调参也很快。5. 实操中踩过的坑多解、边界与数值稳定性5.1 同一个姿态对应无数个指数坐标这是初学者最容易忽略的问题。给定一个旋转矩阵可以从矩阵元素反解出转轴和转角即对数映射但结果不是唯一的。绕同一根轴转θ和转θ2kπ得到完全相同的旋转矩阵。那么矩阵对应的是θ还是θ-2π数学上都是合法的但几何上差别很大。实际使用中做控制时我们希望转角尽量小所以一般约定θ取值范围为[0, π]超过π的部分用反向转轴加互补角度来表示。举个例子绕Z轴转270度即-90度如果直接解得到的是转角270度、转轴为Z但如果约定范围应该表示为转角90度、转轴为-Z。这个转换如果没做好给控制器的姿态增量可能凭空多出180度的旋转量机械臂会多绕一大圈。排查这种问题时最直接的办法是输出调试信息时同时打印转轴和角度看看数值是否符合物理直觉。我在现场调试时遇到过类似现象机械臂到达同一个点有时走“远路”后来发现就是对数映射实现里没有做角度归一化统一到[0, π]后问题马上解决。5.2 旋转角接近π时的数值病态旋转矩阵反解指数坐标时当θ接近π即旋转180度附近会出现数值病态问题。因为此时旋转矩阵的迹约等于-1反余弦函数在-1附近斜率极大微小的矩阵数值误差会被放大成很大的角度误差。这种误差不是代码bug是数学结构本身的敏感性。解决思路通常是θ在接近π时改用旋转矩阵的反对称部分来解算转轴因为旋转矩阵减去转置后等于2sinθ[ω]这个量在θπ时仍然光滑稳定。实际实现时还可以用矩阵元素的大小比较来做数值分支选择。当年我在做双机器人协同搬运时两条机械臂经常需要保持180度对称姿态就遇到了这个问题。姿态对称意味着相对旋转接近π反解转轴时数值一直在抖后来查阅文献发现要在θ接近π时改用另一种分支公式问题才彻底解决。5.3 绕固定轴还是绕自身轴别搞混指数坐标表示的旋转是全局坐标系下的固定轴旋转。你头脑里想的“绕机械臂当前末端坐标系的某个轴转”和“绕世界坐标系的轴转”结果完全不同。展开来说绕固定轴旋转的旋转矩阵形式是R e^{[ω]·θ}一个指数对整体旋转的贡献是“左乘还是右乘”也有讲究。如果先绕世界坐标系转用左乘R_new R_rot·R_current如果绕自身坐标系转用右乘R_new R_current·R_rot。经常出现的错误是把从传感器读到的姿态变化直接当作固定轴旋转加在机器人末端上结果末端指向完全不对。排查了很久最后发现是左右乘顺序的问题。建议在代码注释里明确写明“此处左乘固定轴此处右乘本体系”并辅以单元测试验证能省掉后续很多麻烦。6. 工具链与动手验证从Pinocchio到Mujoco的参考实践6.1 用好现成库但必须能手算验证现在做机器人算法很少有团队需要从零实现旋转数学库。开源生态里Python生态有经典的scipy.spatial.transform.Rotation模块封装了轴角、四元数、旋转矩阵之间的转换直接用就好。C的机器人生态则有Eigen库里面AxisAngle、AngleAxis类型用得非常顺手。再往上一点的机器人专用库Pinocchio对旋量、运动学、动力学支持非常完善做研究或产品原型都很合适。我的建议是日常开发直接用库但必须能手写验证简单的例子否则库出问题时你没有判断能力。动手验证的小实验很简单取一个绕Z轴转90度的旋转指数坐标就是(0, 0, π/2)用库函数转换得到旋转矩阵再手算验证矩阵正确。然后做一次旋转矩阵到轴角的反解看是否回到(0, 0, π/2)。多试几组不同情况——小角度、接近180度、绕任意轴——你会发现库在各种边缘情况下的处理方式也建立起了自己的判断直觉。6.2 与SLAM和导航定位的实际衔接做移动机器人导航和SLAM时机器人姿态很大程度上依赖于位姿估计模块。目前主流方案中因子图优化的位姿变量往往用旋转矩阵或四元数表示但在优化结束后做回环检测、地图叠加、路径发布时都会把姿态转成轴角/指数坐标的形式去验证和可视化。举个例子在做二维激光SLAM建图时机器人位姿通常简化为(x, y, θ)θ就是一个绕Z轴的转角本质上是三维轴角的一个特例。看似简单但真要拓展到三维导航和三维建图时轴的表达方式就必须按完整指数坐标来考虑了。6.3 给初学者的一条学习路径建议如果你现在被各种旋转表示绕得头晕我建议你按这个顺序走一遍第一步把四元数、旋转矩阵、欧拉角、轴角相互转换程序全部用你熟悉的语言写一遍每组转换都拿不变量做单元测试例如转换后再转回来验证两个矩阵是否一致直到不再害怕公式。第二步拿一个开源的六轴机械臂运动学库仿真环境可以用Mujoco或Gazebo搭配ROS2找到它内部姿态表示与指数坐标相关的地方换一种表示方式重新实现一遍对比结果。第三步自己搭一个最小二乘姿态优化问题。比如给一堆带噪声的姿态观测用指数坐标表示增量做高斯牛顿优化估计最优姿态。这个练习做完你对“切空间”“流形优化”的理解会远超只看书的人。我个人的体会是旋转表示这东西光看公式永远隔着一层。真正上手写一遍转换、调一次bug、对比一次仿真与实机的效果那些看似抽象的数学概念就慢慢落地了之后再去读现代机器人学教材里关于指数坐标的章节你会觉得那些公式突然都变得亲切了。
返回列表