Python 机器人运动学与轨迹规划代码解释

1. 概述

该 Python 脚本旨在实现一个特定类型并联机器人(基于提供的运动学公式推测)的正向和逆向运动学计算,并根据给定的 MATLAB 代码逻辑,生成一个圆形轨迹,并规划沿该轨迹的 S 曲线速度轮廓。最终,它会计算轨迹上每个点的关节变量,并提供可视化结果,包括运动曲线图和机器人姿态动画。

该脚本的主要目的是将一个 MATLAB 实现的轨迹规划任务转换为 Python 代码。

2. 导入库

脚本首先导入了必要的 Python 库:

  • NumPy (np): 用于高效的数值计算,特别是数组和矩阵操作。

  • SymPy (sp): 用于符号数学计算,主要在正向运动学中定义和求解方程组。

  • math: 提供基本的数学函数。

  • Matplotlib (plt): 用于数据可视化,包括绘制 2D 曲线图和 3D 机器人模型及轨迹。

  • time: 用于在动画中添加暂停。

import numpy as np
import sympy as sp
import math
import matplotlib.pyplot as plt
import time
sp.init_printing(use_unicode=True) # 启用 SymPy 的美观打印

3. 机器人参数 (get_robot_params)

这个函数定义并返回一个包含机器人几何尺寸参数的字典。这些参数是运动学计算的基础。

  • \(a_{11}, a_{22}, a_{33}\): 移动平台上连接点到平台中心的距离。

  • \(b_{11}, b_{22}, b_{33}\): 固定平台上连接点到平台中心的距离。

  • \(e\): 中心柱的固定(不可伸缩)部分的长度。

def get_robot_params():
    return {
        'a11': 135.0, 'a22': 135.0, 'a33': 135.0,
        'b11': 570.0, 'b22': 320.0, 'b33': 320.0,
        'e': 345.0
    }

4. 位置逆解 (inverse_kinematics)

逆运动学(IK)解决的问题是:给定末端执行器(移动平台中心)期望的笛卡尔坐标 \(x_p, y_p, z_p\),计算出机器人需要达到的关节变量。

输入:

  • \(x_p, y_p, z_p\): 目标位置 (float)。

  • params: 包含机器人尺寸的字典。

输出: 一个包含计算结果的字典:

  • \(q_1, q_2, q_3\): 计算得到的驱动杆“长度”(float)。注意: 根据代码中的公式,这可能不是物理连杆 \(B_i\)\(A'_i\) 的直线距离,而是基于特定投影或定义的长度。

  • \(q_4\): 中心柱的可变长度 (float),即 \(||r_p|| - e\)

  • \(\theta_1, \theta_2\): 描述移动平台姿态的角度 (rad)。

  • \(r_p\): 末端位置向量 \(\begin{bmatrix} x_p \\ y_p \\ z_p \end{bmatrix}\) (NumPy 数组)。

  • \(R_4\): 移动平台的旋转矩阵 (3x3 NumPy 数组),描述了平台坐标系相对于固定坐标系的姿态。

  • \(w_4\): 中心柱方向的单位向量 (3x1 NumPy 数组),即 \(r_p / ||r_p||\)

  • error: 错误信息字符串,如果无法求解则非空。

计算步骤:

  1. 计算 \(r_p\) 及其模长 \(||r_p||\)

  2. 检查目标点是否在固定中心柱长度 \(e\) 范围内,如果是则不可达。

  3. 计算中心柱可变长度 \(q_4 = ||r_p|| - e\)

  4. 根据 \(x_p\)\(||r_p||\) 计算 \(\theta_2 = \arcsin(x_p / ||r_p||)\)

  5. 根据 \(y_p, z_p, ||r_p||, \theta_2\) 计算 \(\theta_1 = \operatorname{arctan2}(-y_p / (||r_p||\cos\theta_2), z_p / (||r_p||\cos\theta_2))\),并处理 \(\cos\theta_2 \approx 0\) 的情况。

  6. 使用 \(\theta_1, \theta_2\) 构建旋转矩阵 \(R_4\)

  7. 计算固定平台和移动平台的连接点向量 (\(b_i\)\(a_i = R_4 a_{i0}\))。

  8. 计算中心柱方向向量 \(w_4\)

  9. 根据代码中给出的特定公式计算 \(q_1, q_2, q_3\): $\( q_i = || r_p - b_i + a_i - e w_4 || \)\( 这对应于从 \)B_i\( 指向 \)A’_i\((移动平台连接点在固定坐标系中的绝对位置)的向量,再减去固定中心柱向量 \)e w_4$ 后的模长。

5. 位置正解 (Forward Kinematics - FK)

正运动学解决的问题是:给定驱动关节的输入值 \(q_1, q_2, q_3\)(根据 IK 中的定义),计算末端执行器的位置 \(x_p, y_p, z_p\) 和姿态 \(\theta_1, \theta_2\)。这通常比逆解更复杂,因为它涉及到求解非线性方程组。

5.1 符号设置与数值函数生成 (define_symbolic_fk)

此函数使用 SymPy 库来建立正解所需的数学模型。

输入:

  • params: 机器人参数。

  • \(q_{1,in}, q_{2,in}, q_{3,in}\): 输入的驱动杆计算长度。

输出:

  • Func_sym: 包含三个符号约束方程 \(F, G, H\) 的 SymPy 矩阵。这些方程基于机器人的闭环几何约束,将已知的 \(q_{1,in}, q_{2,in}, q_{3,in}\) 与未知的 \(q_4, \theta_1, \theta_2\) 联系起来。其形式为 \(|| L_i ||^2 - q_{i,in}^2 = 0\),其中 \(L_i = q_4 w_4 + a_i - b_i\)。代码中直接使用了展开后的简化形式(经验证与 \(||L_i||^2\) 定义一致)。

  • J_sym: \(F, G, H\) 相对于未知变量 \(X = [q_4, \theta_1, \theta_2]^T\) 的符号雅可比矩阵 \(J = \frac{\partial(F,G,H)}{\partial X}\)

  • num_func, num_jac: 通过 sp.lambdify 将符号方程和雅可比矩阵转换为快速求值的 NumPy 函数。

  • X_sym: 包含符号变量 \([q_4, \theta_1, \theta_2]^T\) 的 SymPy 矩阵。

5.2 牛顿迭代求解器 (forward_kinematics)

此函数使用牛顿-拉弗森(Newton-Raphson)迭代法来数值求解由 define_symbolic_fk 建立的非线性方程组 \(Func(X) = 0\)

输入:

  • \(q_{1,in}, q_{2,in}, q_{3,in}\): 输入的驱动杆计算长度。

  • params: 机器人参数。

  • initial_guess: 对未知变量 \([q_4, \theta_1, \theta_2]\) 的初始猜测值。

  • max_iter, tolerance: 最大迭代次数和收敛容差。

输出: 一个包含结果的字典:

  • \(x_{p,fk}, y_{p,fk}, z_{p,fk}\): 计算得到的末端位置。

  • \(q_{4,k}, \theta_{1,k}, \theta_{2,k}\): 计算得到的最终 \(q_4, \theta_1, \theta_2\) 值。

  • iterations: 实际迭代次数。

  • final_error_norm: 最终的方程误差范数 \(||Func(X_k)||\)

  • converged: 是否收敛 (bool)。

  • error: 错误信息。

计算步骤:

  1. 获取数值计算函数 num_funcnum_jac

  2. 从初始猜测 \(X_0\) 开始迭代。

  3. 在第 \(k\) 次迭代: a. 计算当前 \(X_k\) 下的函数值 \(F_k = Func(X_k)\)。 b. 检查误差 \(||F_k||\) 是否小于容差,如果是则停止迭代。 c. 计算当前 \(X_k\) 下的雅可比矩阵 \(J_k = J(X_k)\)。 d. 求解线性方程组 \(J_k \Delta X = -F_k\) 得到步长 \(\Delta X\)。如果 \(J_k\) 奇异则报错。 e. 更新解:\(X_{k+1} = X_k + \Delta X\)

  4. 如果达到最大迭代次数仍未收敛,则报告失败。

  5. 如果收敛,使用最终得到的 \(q_4, \theta_1, \theta_2\) 计算末端位置:\(r_p = (e + q_4) w_4\),其中 \(w_4\)\(\theta_1, \theta_2\) 确定。

6. 可视化函数 (plot_robot)

该函数使用 Matplotlib 在 3D 坐标系中绘制机器人的当前姿态。

输入:

  • ax: Matplotlib 的 3D 坐标轴对象。

  • \(r_p\): 当前末端位置向量。

  • \(R_4\): 当前移动平台的旋转矩阵。

  • params: 机器人参数。

  • title: 图表标题。

绘制内容:

  • 计算所有关键点(原点 O, 固定平台连接点 \(B_i\), 移动平台连接点 \(A'_i\), 末端点 P, 中心柱顶端 E)在固定坐标系中的坐标。

  • 绘制固定平台(灰色虚线三角形 \(B_1B_2B_3\))。

  • 绘制移动平台(蓝色实线三角形 \(A'_1A'_2A'_3\))。

  • 绘制物理驱动杆(红色实线 \(B_iA'_i\))。

  • 绘制中心柱(绿色线段 OE 和 EP,分别代表固定部分和可变部分)。

  • 标记原点 O 和末端点 P。

  • 设置坐标轴标签、标题、图例和大致范围,并尝试设置等比例轴。

7. S 曲线速度轮廓生成 (s_velocity_motion)

此函数用于生成沿路径的运动轮廓,即规划位移 \(s(t)\)、速度 \(v(t)\) 和加速度 \(a(t)\)

重要: 这个函数的实现严格复制了提供的 MATLAB 代码 Svelocity_motion 的逻辑,包括其独特的(可能非标准的)参数计算方法和分段函数公式。

输入:

  • vmax: 路径上的最大速度。

  • TA: 加速(或减速)阶段的总时间(用于推导 \(a_{max}\)\(j_e\))。

  • sall: 要移动的总路径长度。

  • ts: 时间步长。

输出:

  • ac, vc, sc: 包含加速度、速度、位移值的 NumPy 数组。

  • time_vec: 对应的时间点数组。

  • params: 包含中间计算参数(如 \(T_1..T_5, j_e, a_{max}, t_1..t_5\) 等)的字典。

计算逻辑:

  1. 根据 vmaxTA 计算 \(a_{max} = vmax / TA\)

  2. 根据 MATLAB 代码逻辑设置 \(T_1 = T_2 = T_4 = T_5 = TA\)

  3. 计算加加速度(Jerk) \(j_e = a_{max} / T_1\)

  4. 根据 MATLAB 代码中的特定公式计算匀速阶段时间 \(T_3 = (sall - 2 j_e T_1^3) / vmax\)。如果 \(T_3 < 0\),则打印警告并将 \(T_3\) 设为 0。

  5. 计算各阶段的时间边界 \(t_1, t_2, t_3, t_4, t_5\)

  6. 生成时间向量 time_vec

  7. 初始化 ac, vc, sc 数组。

  8. 遍历时间向量中的每个时间点 \(t\),根据 \(t\) 所处的阶段(由 \(t_1..t_5\) 界定),应用 MATLAB 代码片段中给出的分段公式计算瞬时的 \(a(t), v(t), s(t)\)

  9. 函数结束时会检查最终位移是否接近 sall,并报告最终速度(根据 MATLAB 代码,最终速度可能不为零)。

8. 主程序 (if __name__ == "__main__":)

这是脚本的执行入口。

流程:

  1. 参数设置: 获取机器人参数,并设置轨迹参数(圆半径 \(r\), \(v_{max}\), \(T_A\), \(t_s\), 总路径长度 \(s_{all}\), Z 高度 z_level, Y 偏移 y_offset)。这些参数与 MATLAB 代码中的注释/值一致。

  2. 生成运动轮廓: 调用 s_velocity_motion 函数得到 \(s(t), v(t), a(t)\) 曲线,并绘制这些曲线。

  3. 计算轨迹点和关节值 (IK 循环): a. 遍历由运动轮廓生成的时间点。 b. 对每个时间点 ntt: i. 计算当前沿圆弧的位移 \(s_{current} = sc[ntt]\)。 ii. 计算对应的圆弧角度 \(\alpha = s_{current} / r - \pi/2\)。 iii. 计算目标笛卡尔位置 \((x_p, y_p, z_p) = (r\cos\alpha, r\sin\alpha + y_{offset}, z_{level})\)。 iv. 计算目标笛卡尔速度 \((v_{xp}, v_{yp}, v_{zp})\),使用链式法则,基于 \(v(t)\)。 v. 计算目标笛卡尔加速度 \((a_{xp}, a_{yp}, a_{zp})\),考虑切向加速度 \(a(t)\) 和向心加速度 \(v(t)^2 / r\)。 vi. 调用 inverse_kinematics 函数计算该笛卡尔点对应的关节变量 \((q_1..q_4, \theta_1, \theta_2)\) 和机器人姿态 \((R_4, r_p)\)。 vii. 存储计算结果,并处理可能的 IK 错误。

  4. 计算关节速度: 使用有限差分法(中心差分、前向/后向差分)根据计算出的关节位置序列 \(q_1(t), q_2(t), q_3(t)\) 估算关节速度 \(v_{q1}(t), v_{q2}(t), v_{q3}(t)\)

  5. 绘图: a. 绘制期望的 3D 笛卡尔轨迹(圆形)。 b. 绘制关节空间轨迹(关节位置 \(q_i\) vs 时间,关节速度 \(v_{qi}\) vs 时间)。

  6. 动画: a. 创建一个 3D 绘图窗口。 b. 遍历计算出的机器人姿态序列。 c. 在每一帧,调用 plot_robot 绘制机器人在该时刻的姿态。 d. 绘制已经过的轨迹路径。 e. 暂停一小段时间,然后更新到下一帧,形成动画效果。

9. 总结

该脚本成功地将 MATLAB 中的特定机器人运动学模型和轨迹规划逻辑转换为了 Python 实现。它利用 NumPy 进行数值计算,SymPy 处理正解中的符号方程,Matplotlib 进行结果可视化。核心在于 inverse_kinematicsforward_kinematicss_velocity_motion 函数,以及将它们串联起来计算并展示圆形轨迹的主程序逻辑。需要注意的是 s_velocity_motion 函数是为了精确复制源 MATLAB 代码的行为而编写的,其内部参数推导可能与标准的运动规划理论有所不同。