机器人逆运动学进阶:李代数、矩阵指数与旋转流形计算

做机器人逆运动学(IK)的时候,你迟早会遇到矩阵指数和对数这些东西。为什么呢?因为计算三维旋转的误差,不能简单地用欧氏距离那一套,那只对位置有效。旋转得用另一套方法——你需要算两个旋转矩阵之间的差异,这就涉及到矩阵对数了。

这篇文章就是要把这事儿说清楚:从旋转矩阵构成的李群开始,到流形和切空间,再到怎么用叉积算旋转矩阵的导数,如何对旋转矩阵做增量更新,最后是如何计算从一个姿态到另一个姿态需要的角速度。

SO(3):三维旋转的数学结构

机器人的姿态其实就是一个三维坐标系。这个坐标系由三个互相垂直、长度为1的向量组成,比如最简单的情况:(1,0,0)ᵀ、(0,1,0)ᵀ、(0,0,1)ᵀ。把这三个向量当作列向量排在一起,就得到了一个3×3的旋转矩阵。

虽然这个矩阵在数学上属于ℝ³ˣ³空间,但实际上能表示旋转的矩阵组合要少得多,它们形成一个特殊的群,叫做三维特殊正交群SO(3)。类似的还有二维旋转SO(2)、四维变换矩阵等等,这些都属于李群家族。

流形和切空间:几何概念

实数是一条直线,但SO(3)不是,它在ℝ³ˣ³里形成一个弯曲的流形。这个流形是连续的、可微的,你可以在上面定义距离。想在这个弯曲的表面上移动,就得沿着切线方向走,这就引出了切空间的概念。

就像函数的切线斜率由导数决定一样,我们也可以通过计算流形切线的"斜率"来得到它的导数。

计算旋转矩阵的导数

现在问题来了:一个旋转矩阵R和一个角速度向量ω,怎么算R的变化率Ṙ?

答案是这样的:

这里⎣ω⎦是ω对应的反对称矩阵:

为什么要搞成反对称矩阵?因为实际上是想算ω和R每一列的叉积。有时候你会看到这个操作写成帽子符号,都是一个意思。

所有3×3实反对称矩阵构成的空间叫做𝖘𝖔(3),这是SO(3)的李代数,也就是SO(3)在单位矩阵处的切空间。虽然它在矩阵乘法下不构成群,但它是个李代数,让我们能在非线性的SO(3)流形上做线性计算。

叉积的几何意义

我们来仔细看看叉积ω×v是什么意思。两个向量的叉积结果是一个同时垂直于这两个向量的新向量,长度正比于两向量夹角的正弦值。

把ω变成反对称矩阵形式,就能用矩阵乘法实现叉积运算:

对矩阵R做这个操作,就等于对R的每一列都做一次叉积。

这里有个细节要注意:这个运算可以左乘也可以右乘,取决于ω是在机体坐标系还是世界坐标系下给出的。一般我们假设ω在机体坐标系,所以⎣ω⎦右乘到R上。

把ω想象成旋转轴,|ω|是转速,这样理解叉积就直观多了。如果v指向某个点,那么ω×v就是这个点绕ω轴旋转时的速度方向。

矩阵指数:精确的旋转更新

有了上面的理解,我们再看这个微分方程:

R的每一列代表一个坐标轴,和ω做叉积得到的矩阵描述了各个轴因为旋转产生的速度。那怎么得到更新后的旋转矩阵呢?

一个朴素的想法是用欧拉积分,就是把R⎣ω⎦乘个小时间步长然后加起来。但这样做有问题:无法保证结果还是正交矩阵,也就是说可能跳出SO(3)。虽然可以每步都强制归一化,但有更精确的方法。

上面那个微分方程其实是个线性常微分方程,解是:

矩阵指数函数通过泰勒展开定义,大部分线性代数库都有实现。

看看用这个方法绕ω=(1.0,1.0,1.0)ᵀ旋转的效果:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

矩阵对数:解决逆运动学问题

有时候我们需要反过来算:给定当前姿态R(0)和目标姿态R(t),需要什么旋转向量才能从一个到另一个?这就像算位置的欧氏距离一样。

对于旋转,我们把R(0)移到等式另一边,算矩阵对数,再除以时间t:

但事情还没完。真正的逆运动学问题需要算误差对关节角的导数。对于n个关节的机器人,我们要算一个3×n的雅可比矩阵:

要对R(t)关于q求导,得先过一遍对数,然后用链式法则。具体怎么做,作者说在另一篇文章里有。

代码实现

下面是生成上面动画的代码。关键是用scipy的expm函数实现矩阵指数,核心更新就是一行:

R = R @ expm(hat(omega) * dt)

 import numpy as np  
from scipy.linalg import expm  
import matplotlib.pyplot as plt  
from mpl_toolkits.mplot3d import Axes3D  
from matplotlib.animation import FuncAnimation  def hat(omega):  return np.array([  [0,         -omega[2],  omega[1]],  [omega[2],   0,        -omega[0]],  [-omega[1],  omega[0],  0]  ])  # Angular velocity vector (rad/s)  
omega = np.array([1.0, 1.0, 1.0])  dt = 0.05  
T = 5  
N = int(T / dt)  # Initialize rotation matrix as identity  
R = np.eye(3)  # Store rotation matrices  
Rs = [R.copy()]  
for _ in range(N):  R = R @ expm(hat(omega) * dt)  Rs.append(R.copy())  fig = plt.figure()  
ax = fig.add_subplot(111, projection='3d')  # Set plot limits and labels  
ax.set_xlim([-1.5, 1.5])  
ax.set_ylim([-1.5, 1.5])  
ax.set_zlim([-1.5, 1.5])  
ax.set_xlabel('X')  
ax.set_ylabel('Y')  
ax.set_zlabel('Z')  
ax.set_title('Rotating 3D Coordinate Frame')  # Initialize quiver objects for x, y, z axes  
quiver_x = ax.quiver(0, 0, 0, 1, 0, 0, color='r', length=1, normalize=True)  
quiver_y = ax.quiver(0, 0, 0, 0, 1, 0, color='g', length=1, normalize=True)  
quiver_z = ax.quiver(0, 0, 0, 0, 0, 1, color='b', length=1, normalize=True)  def update(num):  # Remove previous quivers (if any)  for artist in ax.collections:  artist.remove()  R = Rs[num]  x_axis = R[:, 0]  y_axis = R[:, 1]  z_axis = R[:, 2]  ax.quiver(0, 0, 0, *x_axis, color='r', length=1, normalize=True)  ax.quiver(0, 0, 0, *y_axis, color='g', length=1, normalize=True)  ax.quiver(0, 0, 0, *z_axis, color='b', length=1, normalize=True)  return []  ani = FuncAnimation(fig, update, frames=len(Rs), interval=50, blit=False)  from matplotlib.animation import PillowWriter  
ani.save("rotation.gif", writer=PillowWriter(fps=20))  plt.show()

总结

本文从理论到实践全面介绍了矩阵指数在机器人逆运动学中的应用。我们从SO(3)李群和𝖘𝖔(3)李代数的数学结构出发,解释了为什么旋转计算需要特殊的数学工具。通过流形和切空间的几何概念,我们理解了旋转矩阵导数的计算方法,并学会了使用反对称矩阵实现叉积运算。矩阵指数函数提供了精确的旋转更新方法,能够保证旋转矩阵在更新过程中始终保持正交性,避免了传统欧拉积分可能导致的数值不稳定问题。而矩阵对数则解决了逆向问题——如何计算从当前姿态到目标姿态所需的旋转误差和角速度。这套方法的核心优势在于能够在非线性的旋转空间中进行精确计算,为逆运动学算法提供了必要的数学工具,特别是在计算雅可比矩阵时所需的旋转导数。对于需要高精度姿态控制的机器人应用,这些数学工具是必不可少的。

https://avoid.overfit.cn/post/352201d5dfd749e48e2b6ccf8e81abf0

作者:Nikolaus Correll

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96572.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉(opencv)实战十八——图像透视转换

图像透视变换详解与实战在图像处理中,透视变换(Perspective Transform) 是一种常见的几何变换,用来将图像中某个四边形区域拉伸或压缩,映射到一个矩形区域。常见应用场景包括:纠正拍照时的倾斜(…

【飞书多维表格插件】

coze中添加飞书多维表格记录插件 添加单条记录 [{"fields":{"任务详情":"选项1","是否完成":"未完成"}}]添加多条记录 [{"fields":{"任务详情":"选项1","是否完成":"已完…

Java基础 9.14

1.Collection接口遍历对象方式2-for循环增强增强for循环,可以代替iterator选代器,特点:增强for就是简化版的iterator本质一样 只能用于遍历集合或数组package com.logic.collection_;import java.util.ArrayList; import java.util.Collectio…

数据结构(C语言篇):(十三)堆的应用

目录 前言 一、堆排序 1.1 版本一:基于已有数组建堆、取栈顶元素完成排序 1.1.1 实现逻辑 1.1.2 底层原理 1.1.3 应用示例 1.1.4 执行流程 1.2 版本二:原地排序 —— 标准堆排序 1.2.1 实现逻辑 1.2.2 底层原理 1.2.3 时间复杂度计算…

4步OpenCV-----扫秒身份证号

这段代码用 OpenCV 做了一份“数字模板字典”,然后在银行卡/身份证照片里自动找到身份证号那一行,把每个数字切出来跟模板比对,最终输出并高亮显示出完整的身份证号码,下面是代码解释:模块 1 工具箱(通用函…

冯诺依曼体系:现代计算机的基石与未来展望

冯诺依曼体系:现代计算机的基石与未来展望 引人入胜的开篇 当你用手机刷视频、用电脑办公时,是否想过这些设备背后共享的底层逻辑?从指尖轻滑切换APP,到电脑秒开文档,这种「无缝衔接」的体验,其实藏着一个改…

前端基础 —— C / JavaScript基础语法

以下是对《3.JavaScript(基础语法).pdf》的内容大纲总结:---📘 一、JavaScript 简介 - 定义:脚本语言,最初用于表单验证,现为通用编程语言。 - 应用:网页开发、游戏、服务器(Node.js&#xff09…

springboot 二手物品交易系统设计与实现

springboot 二手物品交易系统设计与实现 目录 【SpringBoot二手交易系统全解析】从0到1搭建你的专属平台! 🔍 需求确认:沟通对接 🗣 📊 系统功能结构:附思维导图 ☆开发技术: &#x1f6e…

【Android】可折叠式标题栏

在 Android 应用开发中,精美的用户界面可以显著提升应用品质和用户体验。Material Design 组件中的 CollapsingToolbarLayout 能够为应用添加动态、流畅的折叠效果,让标题栏不再是静态的元素。本文将深入探讨如何使用 CollapsingToolbarLayout 创建令人惊…

Debian13下使用 Vim + Vimspector + ST-LINK v2.1 调试 STM32F103 指南

1. 硬件准备与连接 1.1 所需硬件 STM32F103C8T6 最小系统板ST-LINK v2.1 调试器连接线(杜邦线) 1.2 硬件连接 ST-LINK v2.1 ↔ STM32F103C8T6 连接方式:ST-LINK v2.1 引脚STM32F103C8T6 引脚功能说明SWDIOPA13数据线SWCLKPA14时钟线GNDGND共地…

第21课:成本优化与资源管理

第21课:成本优化与资源管理 课程目标 掌握计算资源优化 学习成本控制策略 了解资源调度算法 实践实现成本优化系统 课程内容 21.1 成本分析框架 成本分析系统 class CostAnalysisFramework {constructor(config) {this.config

SAP HANA Scale-out 04:CalculationView优化

CV执行过程计算视图激活时,生成Stored ModelSELECT查询时:首先将Stored Model实例化为runtime Model 计算引擎执行优化,将runtime Model转换为Optimized Runtime ModelOptimized Runtime Model通过SQL Optimizer进行优化计算引擎优化特性说明…

鸿蒙审核问题——Scroll中嵌套了List/Grid时滑动问题

文章目录背景原因解决办法1、借鉴Flutter中的解决方式,如下图2、鸿蒙Next中对应的解决方式,如下图3、官方文档回访背景 来源一次审核被拒的情况。也是出于粗心导致的。之前在flutter项目中也是遇到过这种问题的。其实就是滚动视图内嵌滚动视图造成的&am…

测试电商购物车功能,设计测试case

在电商场景中,购物车是连接商品浏览与下单支付的关键环节,需要从功能、性能、兼容性、安全性等多维度进行测试。以下是购物车功能的测试用例设计: 一、功能测试 1. 商品添加到购物车 - 未登录状态下,添加商品到购物车(…

Linux --- 常见的基本指令

一. 前言本篇博客使用的 Linux 操作系统是 centos ,用来学习Linux 的 Linux 系统的内核版本和系统架构信息版本如下所示:上图的主要结构为:主版本号-次版本号 修正次数,3.10.0 是操作系统的主版本号;当我们在维护一段L…

微信小程序 -开发邮箱注册验证功能

一、前端验证:正则表达式与插件结合正则表达式设计 使用通用邮箱格式校验正则,并允许中文域名(如.中国): const emailReg /^[a-zA-Z0-9._%-][a-zA-Z0-9-](?:\.[a-zA-Z0-9-])*\.[a-zA-Z]{2,}(?:\.[a-zA-Z]{2})?$/i;…

docker 部署 code-server

docker 部署 code-servercode-serverError response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headersdocker 配置正确步骤 阿里云源permission de…

网络编程专题:从源码解析网络编程常用方法(基于6.16.3内核)

前言 本文是因为作者在研究下面这个代码时发现的问题: int main() {// 1. 创建 IPv4 专用地址结构体 sockaddr_instruct sockaddr_in ipv4_addr;memset(&ipv4_addr, 0, sizeof(ipv4_addr)); // 初始化清零// 2. 填充 IPv4 专属信息ipv4_addr.sin_family AF_IN…

2025年数字公共治理专业重点学什么内容?(详细指南)

数字公共治理作为一个新兴的跨学科领域,近年来受到越来越多高校和学生的关注。这个专业融合了多个学科的知识体系,旨在培养掌握现代治理理念和技术应用能力的复合型人才。对于在校大学生而言,了解这一专业的学习内容和发展方向,有…

一招解决 win 下 终端打印中文乱码问题

适合所有终端 cmd powershell git bash, 原理:修改电脑的区域设置,勾选使用 UTF-8 1.电脑搜索 区域, 打开区域设置2. 打开相关设置3. 点击更改 日期、时间或数字格式4. 选则管理-点击更改系统区域设置,在弹出框中勾选 …