向量与矩阵基础:点积、叉积、矩阵乘法与逆矩阵

好,咱们接着聊。上一章我们把坐标变换的「世界观」搭好了,这一章得把「工具箱」备齐。

向量和矩阵,说白了就是机器人控制里的加减乘除。你想想看,机械臂要抓一个杯子,它得知道杯子在哪儿(向量),还得知道怎么转过去(矩阵)。这些运算搞不明白,后面的变换公式就是空中楼阁。

我个人习惯,先讲向量,再讲矩阵。因为矩阵本质上就是一堆向量排排坐。

2.1 向量的点积:投影的度量

点积,也叫内积。公式很简单:a · b = |a| |b| cosθ。

但别被公式吓到。我换个说法:点积就是向量 a 在向量 b 方向上的投影长度,再乘以 b 的长度。

在机器人里,点积最常见的用处是判断两个方向是否「对齐」。

  • 如果点积 > 0,夹角小于 90°,方向大致相同。
  • 如果点积 = 0,垂直,正交。
  • 如果点积 < 0,夹角大于 90°,方向相反。

实际案例:我在做移动机器人导航时,经常用点积判断机器人当前朝向和目标方向是否一致。如果点积接近 1,说明方向对了,可以直走;如果接近 -1,说明方向反了,得掉头。

代码实现也很简单:

// 二维向量点积
float dotProduct(float ax, float ay, float bx, float by) {
    return ax * bx + ay * by;
}

// 三维向量点积
float dotProduct3D(float a[3], float b[3]) {
    return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}

小技巧:点积的结果是一个标量,不是向量。很多新手会搞混,记住:点积「点」出一个数。

2.2 向量的叉积:法向量的生成器

叉积就更有意思了。它只存在于三维空间(严格来说二维也有,但结果是个标量)。

公式:a × b = |a| |b| sinθ · n,其中 n 是垂直于 a 和 b 的单位向量。

说白了,叉积生成一个垂直于两个输入向量的新向量。方向由右手定则决定。

我在项目中遇到过什么场景呢?机械臂的逆运动学求解。你要计算关节轴的旋转方向,就得用叉积。比如已知两个不共线的向量,想找到垂直于它们的方向,叉积就是最直接的工具。

// 三维向量叉积
void crossProduct(float a[3], float b[3], float result[3]) {
    result[0] = a[1]*b[2] - a[2]*b[1];
    result[1] = a[2]*b[0] - a[0]*b[2];
    result[2] = a[0]*b[1] - a[1]*b[0];
}

注意:叉积不满足交换律!a × b = - (b × a)。方向搞反了,机械臂可能就往反方向转了。我曾经因为这个 bug 调试了一整天……

2.3 矩阵乘法:变换的串联

矩阵乘法,是坐标变换的核心操作。为什么?因为一个旋转矩阵乘以一个向量,就等于把这个向量旋转了。

多个变换叠加呢?比如先旋转再平移,那就是多个矩阵相乘。

矩阵乘法的规则:C = A × B,其中 C 的第 i 行第 j 列等于 A 的第 i 行与 B 的第 j 列的点积。

嗯,这里要注意:矩阵乘法不满足交换律。A × B 一般不等于 B × A。这在实际中意味着什么?先旋转再平移,和先平移再旋转,结果完全不同。

操作顺序 矩阵表达式 结果
先旋转后平移 T × R × v 物体绕原点旋转后再移动
先平移后旋转 R × T × v 物体移动后再绕原点旋转

代码示例:

// 3x3 矩阵乘法
void matrixMultiply(float A[3][3], float B[3][3], float C[3][3]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            C[i][j] = 0;
            for (int k = 0; k < 3; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

2.4 逆矩阵:回到原点

逆矩阵,说白了就是「撤销」操作。你做了一个变换,想回到原来的状态,就用逆矩阵。

定义:如果 A × A⁻¹ = I(单位矩阵),那么 A⁻¹ 就是 A 的逆矩阵。

在机器人控制里,逆矩阵太常用了。比如你知道了末端执行器的位姿,想反推各个关节的角度,这就是逆运动学问题,里面大量用到逆矩阵。

计算逆矩阵的方法有很多:

  • 2x2 矩阵:直接用公式,简单快速。
  • 3x3 矩阵:用伴随矩阵法,或者高斯消元。
  • 更大矩阵:一般用数值方法,比如 LU 分解。
// 2x2 矩阵求逆
void inverse2x2(float A[2][2], float invA[2][2]) {
    float det = A[0][0]*A[1][1] - A[0][1]*A[1][0];
    if (fabs(det) < 1e-6) {
        printf("矩阵不可逆!\n");
        return;
    }
    float invDet = 1.0 / det;
    invA[0][0] = A[1][1] * invDet;
    invA[0][1] = -A[0][1] * invDet;
    invA[1][0] = -A[1][0] * invDet;
    invA[1][1] = A[0][0] * invDet;
}

避坑指南:我曾经在写运动学解算时,忘记检查矩阵的行列式是否为零。结果程序跑着跑着就崩了。后来我养成了习惯:每次求逆之前,先算行列式,如果接近零就做特殊处理。

2.5 知识体系总览

这一章的内容比较多,我画了张图帮你理清关系:

向量与矩阵基础 向量运算 • 点积:投影度量,判断方向一致性 • 叉积:生成法向量,右手定则 • 应用:导航方向判断、运动学求解 矩阵运算 • 乘法:变换的串联,顺序不可交换 • 逆矩阵:撤销变换,回到原点 • 应用:位姿变换、逆运动学 共同支撑:坐标变换公式 • 旋转矩阵 = 三个正交基向量组成的矩阵 • 齐次变换矩阵 = 旋转矩阵 + 平移向量

你看,向量和矩阵不是孤立的。点积和叉积是向量的基本操作,矩阵乘法是这些操作的推广和组合,逆矩阵则让我们有了「后悔药」。把这些基础打牢,后面的变换公式就是水到渠成的事。

我的建议:别光看,动手算一算。拿个 2x2 矩阵手动求个逆,或者算两个三维向量的叉积。手算一遍,比看十遍都管用。

好了,这一章就到这里。记住:向量是点,矩阵是变换。点积看方向,叉积找法线,乘法做串联,逆矩阵能还原。这些工具备齐了,下一章我们就可以开始搭建真正的坐标变换体系了。

可可精品资料库