# 三. 入门

对于入门部分，实际上就是了解如何让一个工业机器人动起来。这方面其实已经研究非常成熟了，大家看上个世纪的教材就行，个人推荐的是 John Craig 的教材 《Introduction to Robotics: Mechanics and Control》\[1]，在 [Youtube](https://www.youtube.com/watch?v=0yD3uBshJB0\&list=PL64324A3B147B5578) 和[网易公开课](http://open.163.com/special/opencourse/robotics.html)都可以找到斯坦福 Oussama Khatib 大神的视频，基本与 Craig 的教材内容相匹配。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3SF3UKnu89fiAs%2FCraigBook.jpg?generation=1551198228425671\&alt=media)

建议从 Craig 的教材开始就看英文版本，Google 一下，很容易找到 PDF 版本。作为一本入门教材，Craig 的教材是相当深入浅出的，配合着 Khatib 的视频，可以快速掌握机器人学的基础。

我常对刚入学的师弟们说，「如果你把这本书的内容掌握了，就已经超过实验室绝大多数师兄师姐了。」

然而，真正把教材啃下来的并不多。

所以，我在这里要换个说法了，「如果你把这本书的内容掌握了，就可以胜任国内绝大多数机器人公司的开发工作了。」

这里，我会大概把基础的知识列一下，时间有限，暂时不会过多展开。顺序可能不完全与 Craig 教材相同。

## 3.1 空间变换

对于这部分内容，如果理论力学学得好的小伙伴，基本是没有太大问题的。问题是，有些小伙伴没有学好。

当然，其中齐次变换什么的是机器人学中非常基础和重要的内容。其中需要注意的地方有：

* 熟悉坐标表示方式：坐标系 {B} 在坐标系 {A} 下的位姿为 $${^A_B}T$$ 等；
* 左乘与右乘矩阵的区别；
* 了解旋转矩阵每一列的含义，学会如何通过「目测」写出两个坐标系之间的旋转矩阵；
* 姿态的表示方式：RPY 角、各种欧拉角、轴角（Angle-Axis）表示、旋转矩阵，除了书上的内容，可以顺便看看四元数（Quaternion）表示,了解欧拉角的 Gimbal lock （知道三参数表示的问题，才能更容易接受四元数这样的新事物）；
* 如果有可能，试着了解一下角速度。

## 3.2 运动学

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3UlOKnqX6WuEdS%2FRobotKinematics.jpg?generation=1551198226598681\&alt=media)

对于机器人来说，一个基本工作就是计算运动学：

* 正运动学：根据关节角度，计算机器人工具坐标系（末端）在机器人基座坐标系（底座）下的位姿；
* 逆运动学：给定一个末端位姿，计算达到这个位姿的关节角度。

前面，你知道了可以用一个 4x4 矩阵来描述两个坐标系之间的关系。对于机器人正运动学，如果我们知道每个连杆两两之间的坐标变换，就可以通过矩阵乘法计算出最后的末端位姿了。

为了方便计算两个连杆之间的相对位姿，你就需要学习一个叫做 DH 的建模方法，简而言之，就是按照一定规则建立每个关节坐标系，然后每个坐标系可以用四个参数（DH参数）来确定。

当然，你网上一搜，就会发现 DH 也有好几种，什么 Standard DH， Modified DH 之类的。

这不重要，你只要知道它是帮你确定两个连杆之间的相对关系就行。不妨掌握 Craig 书上的那种就行（Wikipedia上称为 Modified DH)：

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3W5hFUAA4OJNLL%2FModifiedDH.jpg?generation=1551198226587355\&alt=media)

1）建立坐标系：

* $$z_i$$ 轴与第 $$i$$ 个关节重合，关节转动方向遵照右手定律；
* $$x_i$$ 平行于 $$z_i$$ 和 $$z_{i+1}$$ 的公垂线：$$x_i = z_i \times z_{i+1}$$。如果两 $$z$$ 轴平行，则让 $$x_i$$ 从 $$z_{i}$$ 指向 $$z_{i+1}$$；
* 有了 $$x$$、 $$z$$ 轴后，就可以用右手定律定义 $$y$$ 轴方向。
* 除了与每个关节固连的坐标系外，还有可能额外在机器人基座 {B} 与末端工具 {E} 上固连两个坐标系。

2）计算 DH 参数:

* $$a_i$$ 是沿着 $$x_i$$，从 $$z_i$$ 到 $$z_{i+1}$$ 的距离；
* $$\alpha_i$$ 是绕着 $$x_i$$，从 $$z_i$$ 到 $$z_{i+1}$$ 的角度；
* $$d_i$$ 是沿着 $$z_i$$，从 $$x_{i-1}$$ 到 $$x_i$$ 的距离；
* $$\theta_i$$ 是绕着 $$z_i$$，从 $$x_{i-1}$$ 到 $$x_i$$ 的角度。

3）计算变换矩阵：

$${^i_{i-1}}T = Rot(x_{i-1}, \alpha_{i-1}) \cdot Trans(x_{i-1},a_{i-1}) \cdot Rot(z_i, \theta_i) \cdot Trans(z_i, d_i)$$

$${^i_{i-1}}T=\begin{bmatrix}cos(\theta_i)&-sin(\theta_i)&0&a_{i-1}\\sin(\theta_i)cos(\alpha_{i-1})&cos(\theta_i)cos(\alpha_{i-1})&-sin(\alpha_{i-1})&-d_isin(\alpha_{i-1})\\sin(\theta_i)sin(\alpha_{i-1})&cos(\theta_i)sin(\alpha_{i-1})&cos(\alpha_{i-1})&d_icos(\alpha_{i-1})\\0&0&0&1\end{bmatrix}$$

4）正解：

$${^b_e}{T}={^b_1}T\cdot{^1_2}T\cdot{...}\cdot{^n_e}T$$

5）逆解：

就是通过不断调整（左乘与右乘）上面几个矩阵的位置，尝试找到可以单独求解的未知数即可。虽然有些繁琐，但是各位初学者一定要亲手推一遍六轴机械臂的运动学逆解公式，并**编程实现**。

## 3.3 雅可比矩阵

雅可比矩阵 $$J$$ 是机器人学中一个非常重要的东西。它表示机器人关节速度 $$\dot{q}$$ 与末端速度 $$\dot{x}$$ 之间的关系:

$$\dot{x}=J\cdot \dot{q}$$

* 如果你前面没有弄清楚角速度，建议在这章仔细思考。例如，「为什么不能直接对欧拉角求导获得速度？」；
* 了解教材中的雅可比计算方式，并思考「是否可以直接对运动学正解的结果求偏导？」
* 这边需要掌握的就是它的计算方法了，**一定要**编程计算机器人的雅可比矩阵；
* 如果你用 Matlab 或 Python，你可以利用他们的符号运算工具来验证我上面几个问题。从而加深对角速度的理解。
* （PS：姿态和角速度无法直观理解很正常，因为它们不是在笛卡尔空间内，等后面学到更多数学，你们才能真正理解它。）；
* 如果你了解虚功原理，那么你又会知道雅可比也可以表示末端力与关节力矩的关系（这在以后力控等方面很有用）。

这时候，你有了雅可比矩阵，你就会发现，你知道怎么通过调节角度来控制末端运动了。这时候我们再回头看运动学逆解的问题。你会发现：「让机器人末端朝着目标位姿运动不就可以了？」。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3_PnZ28fFnhelU%2FJacobianIK.jpg?generation=1551198226292660\&alt=media)

是的，这就是机器人运动学的数值计算方式，你可以利用这个方法写一个机器人运动学的通用求解算法。具体可以看我在知乎上的回答 [MATLAB机器人工具箱中机器人逆解是如何求出来的](https://www.zhihu.com/question/41673569/answer/129670927)。

各位初学者**务必**亲手实现一遍这种算法，还是有些坑需要踩的。

当然，这个方法很简洁，但是也有它本身的问题：

* 计算速度慢，需要多次迭代；
* 一次只能返回一组解；
* 可能会遇到奇异点等，结果无法收敛。

这时候，你可以顺便去了解一些奇异（Singularity）的问题，理解奇异性是机器人构形相关的属性，无法通过建模方式来消除。

## 3.4 动力学

我相信，80% 的小伙伴是在这一章放弃的。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LaicO7_eQAW93sOesqQ%2F-LZebc3bZiTvVH6eDaIv%2FNewtonEulerDynamics.jpg?generation=1553413029566217\&alt=media)

对于多轴机器人的动力学，不论是采用牛顿欧拉还是拉格朗日法，都会**显得**异常复杂。再加上如果之前没学好理论力学，那么基本上是举步维艰了。

所以，我个人认为，先对这个部分有个基本概念就行，暂时不需要直接去碰六轴机器人的动力学：

* 会用拉格朗日法计算三轴机械臂的动力学模型（三轴的求解还是在可接受范围内的）；
* 用牛顿欧拉法计算三轴机械臂的动力学模型，一定要**编程实现**（因为在高自由度情况下，牛顿法更容易通过编程实现，未来如果要做动力学，更可能是用牛顿欧拉、而非拉格朗日）；
* 了解转动惯量之类的物理意义，（在上面编程实现过程中，肯定会有相应的问题发生，如角速度与转动惯量的参考坐标系问题）；
* 大概知道机器人动力学都包含哪些部分（公式的形式、连杆动力学、关节动力学、重力影响、关节摩擦力、电机动力学等）。

## 3.5 控制

这时候，我们有了各种工具来求解机器人的运动学问题了，我们知道要让机器人到达任意状态的关节角度值。但是，如何让这些关节动起来？

首先，我们要知道，日常生活中的世界还是受牛顿力学统治的。

$$F = m \cdot a$$

要让一个东西动起来，就要给它施力。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3dbOL64vhJIaKi%2FSlider.jpg?generation=1551198228327686\&alt=media)

如果我们给定一个滑块的运动轨迹 $$s(t)$$，我们就可以计算出它整个轨迹的加速度 $$\ddot{s}(t)$$，进而计算出让滑块按照我们设想运动所需的力 $$F(t) = m \cdot \ddot{s}(t)$$。

换句话说，我们可以通过动力学计算出让机器人运动所需的每个关节力矩。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3fRRwuZP3yNEOK%2FDCMotor.jpg?generation=1551198226653992\&alt=media)

而关节力矩，可以通过电机提供，对于直流电机，输出力矩与电流成正比。

但是，有几个问题：

* 动力学好难算；
* 动力学参数好不准（转动惯量不好测、关节摩擦力不好算）；
* 还可能有各种外力（抓持的物体，关节动力学属性变化等）。

这就是控制算法的工作了。于是，大家会接触到传说的 PID 控制。

但是，又有问题：如果我们直接把关节目标位置发给 PID 控制器，那么每次都是一次阶跃响应。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3hVW6xTR0OUegc%2FStepAndTraj.jpg?generation=1551198228687471\&alt=media)

在这里，建议有条件的小伙伴用单片机弄一个单轴伺服控制系统，有伺服电机（你可以控制电流、力矩、或者 PWM 占空比；步进电机、舵机就算了）、有编码器（可以反馈电机的角度）、有驱动器（能将数字指令转换成电机控制信号）、有控制器（STM32等单片机，可以给驱动器提供控制指令）。顺便可以了解一些通讯、中断、实时性的内容。

但是，感觉好像还是有什么不对，机器人运动好像是有加减速过程（右）的，而非一次阶跃（左）。

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3jPpjLVdWx4KnM%2FTrajPlanning.jpg?generation=1551198229048151\&alt=media)

这就是轨迹规划（Trajectory Planning），给定一些轨迹点，利用不同的函数来拟合这些轨迹。

这时候你又想到，既然 PID 和动力学都可以计算让机器人运动所需的力，只是动力学稍微有一些不准，那么有没有可能把它们结合在一起，先用动力学算一个基本准确的力矩，然后用 PID 消除不准确性造成的微小误差？

![](https://3783115390-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LZebJCau3Ase_hVFMCI%2F-LZebZ50mEr9txMbqI7B%2F-LZebc3lG16qlwUJ9E5x%2FFeedforwardPID.jpg?generation=1551198228834791\&alt=media)

是的，于是你发现了基于动力学前馈的 PID 控制算法。

Craig 书上剩下的其他一些部分，可以大概浏览一下，因为有不少内容已经比较旧了。
