别再死记公式了!用Python+SymPy从零推导两连杆机械臂动力学方程(保姆级教程)

张开发
2026/4/16 17:46:51 15 分钟阅读

分享文章

别再死记公式了!用Python+SymPy从零推导两连杆机械臂动力学方程(保姆级教程)
用PythonSymPy从零推导两连杆机械臂动力学方程让数学推导自动化在机器人动力学建模领域两连杆机械臂是最基础的模型之一也是理解更复杂机械系统的重要起点。传统教材中推导其动力学方程往往需要大量繁琐的手工计算从位置、速度到动能、势能再到拉格朗日方程的展开每一步都可能因为符号运算的复杂性而引入错误。而现代符号计算工具如SymPy可以让我们摆脱这些重复性劳动专注于物理本质和工程应用。1. 环境准备与基础概念1.1 安装必要的Python库开始之前确保你的Python环境已安装以下库pip install sympy numpy matplotlibSymPy是核心的符号计算库NumPy用于后续可能的数值计算Matplotlib则可用于可视化结果。1.2 机械臂模型的基本假设我们考虑一个典型的平面两连杆机械臂模型做出以下简化假设连杆为刚性杆件质量集中在末端点质量模型关节处无摩擦运动完全由驱动力矩控制所有运动发生在二维平面内模型参数定义符号含义l₁第一连杆长度l₂第二连杆长度m₁第一连杆末端质量m₂第二连杆末端质量q₁第一关节角度q₂第二关节相对角度g重力加速度2. 建立符号系统与运动学关系2.1 初始化符号变量首先导入SymPy并定义所有需要的符号变量from sympy import symbols, Function, Matrix, sin, cos, diff, simplify # 定义常数和符号变量 l1, l2, m1, m2, g, t symbols(l1 l2 m1 m2 g t) q1 Function(q1)(t) # 关节角度是时间的函数 q2 Function(q2)(t) # 角速度定义 q1_dot diff(q1, t) q2_dot diff(q2, t)2.2 计算末端位置坐标根据几何关系可以写出两个连杆末端的位置坐标# 第一连杆末端位置 x1 l1 * cos(q1) y1 l1 * sin(q1) # 第二连杆末端位置 x2 x1 l2 * cos(q1 q2) y2 y1 l2 * sin(q1 q2)注意这里q₂是第二连杆相对于第一连杆的角度因此总角度为q₁q₂2.3 计算末端速度通过对位置求时间导数得到速度# 第一连杆末端速度 v1x diff(x1, t) v1y diff(y1, t) # 第二连杆末端速度 v2x diff(x2, t) v2y diff(y2, t) # 速度平方用于动能计算 v1_sq v1x**2 v1y**2 v2_sq v2x**2 v2y**23. 能量计算与拉格朗日函数3.1 动能计算根据物理学定义动能T½mv²# 动能计算 T1 m1 * v1_sq / 2 T2 m2 * v2_sq / 2 T T1 T2 # 系统总动能3.2 势能计算以基座为势能零点势能Vmgh# 势能计算 V1 m1 * g * y1 V2 m2 * g * y2 V V1 V2 # 系统总势能3.3 构建拉格朗日函数拉格朗日函数L定义为动能减去势能L T - V4. 推导动力学方程4.1 拉格朗日方程形式对于每个广义坐标qᵢ拉格朗日方程为d/dt(∂L/∂q̇ᵢ) - ∂L/∂qᵢ τᵢ其中τᵢ是对应关节的广义力力矩。4.2 自动求导实现使用SymPy自动计算各项导数# 对第一个关节的方程 tau1 symbols(tau1) # 第一个关节的力矩 # 计算各项导数 dL_dq1dot diff(L, q1_dot) term1 diff(dL_dq1dot, t) term2 diff(L, q1) eq1 simplify(term1 - term2 - tau1) # 对第二个关节的方程 tau2 symbols(tau2) # 第二个关节的力矩 dL_dq2dot diff(L, q2_dot) term3 diff(dL_dq2dot, t) term4 diff(L, q2) eq2 simplify(term3 - term4 - tau2)4.3 整理矩阵形式机械臂动力学通常表示为矩阵形式M(q)q̈ C(q,q̇)q̇ G(q) τ我们可以将前面得到的方程整理成这种形式# 定义角加速度符号 q1_ddot symbols(q1_ddot) q2_ddot symbols(q2_ddot) # 提取惯性矩阵M M Matrix([[eq1.coeff(q1_ddot), eq1.coeff(q2_ddot)], [eq2.coeff(q1_ddot), eq2.coeff(q2_ddot)]]) # 提取科氏力和离心力项 C Matrix([[simplify(eq1 - M[0,0]*q1_ddot - M[0,1]*q2_ddot).subs({q1_dot:0, q2_dot:0})], [simplify(eq2 - M[1,0]*q1_ddot - M[1,1]*q2_ddot).subs({q1_dot:0, q2_dot:0})]]) # 提取重力项 G Matrix([[simplify(eq1 - M[0,0]*q1_ddot - M[0,1]*q2_ddot - C[0]).subs({q1_dot:0, q2_dot:0, q1_ddot:0, q2_ddot:0})], [simplify(eq2 - M[1,0]*q1_ddot - M[1,1]*q2_ddot - C[1]).subs({q1_dot:0, q2_dot:0, q1_ddot:0, q2_ddot:0})]])5. 结果验证与应用5.1 与理论结果对比将SymPy推导结果与经典教材中的两连杆机械臂动力学方程对比惯性矩阵M应具有对称性当q₂0时系统应退化为单摆当g0时重力项G应为零5.2 数值模拟准备为了验证推导的正确性可以将符号表达式转换为数值计算函数from sympy.utilities.lambdify import lambdify import numpy as np # 创建数值计算函数 params {l1: 1.0, l2: 0.8, m1: 1.0, m2: 0.5, g: 9.81} M_func lambdify((q1, q2), M.subs(params), numpy) C_func lambdify((q1, q2, q1_dot, q2_dot), C.subs(params), numpy) G_func lambdify((q1, q2), G.subs(params), numpy)5.3 控制仿真中的应用这些动力学方程可直接用于计算前馈控制力矩设计基于模型的控制器系统动力学特性分析在实际项目中我发现将符号推导结果转换为C代码可以显著提高实时控制性能。SymPy提供了ccode函数可以直接生成C代码from sympy.printing import ccode # 生成M矩阵的C代码 print(// 惯性矩阵M) for i in range(2): for j in range(2): print(fdouble M{i}{j} {ccode(M[i,j].subs(params))};)

更多文章