☰
机械臂DH建模完全指南:从坐标系搭建到正运动学Python实现
2026/10/15 2:43:23 网站建设 项目流程

做机械臂控制的人,十有八九都会在DH建模这一关卡一下。我最早接触这东西是在做某台六轴机械臂的运动控制时,当时想着无非就是算个正运动学,结果坐标系怎么摆、参数怎么填、矩阵怎么写,一串问题直接把我按在地上摩擦。后来花了一个多星期把DH建模捋顺之后回头看,发现这东西一旦理解透了,后面所有逆运动学、雅可比、轨迹规划都顺了。这篇就基于我的实际经验,把DH建模从头到尾拆开讲透,适合刚入门机器人学、准备写机械臂正运动学代码、或者做项目需要对接运动学模型的同学。

1. DH建模到底在干什么:它是给机械臂搭"坐标系骨架"

1.1 你不可能靠一堆角度和距离硬算末端位置

先想一个问题:一台六轴机械臂,给你六个关节角,让你算出手腕末端在空间里的坐标和姿态,你会怎么做?没有运动学模型的话,你得拿着CAD图量出每一段连杆的长度、每一个关节轴的方向,然后自己手推一套三维几何公式。臂短还行,六轴、八轴装在一起,角度一变,末端位置涉及几十上百个中间变量,式子多到根本没法维护。

DH建模解决的就是这件事。它用一套统一的规则,在每个关节处建立坐标系,然后只靠四个参数——a、alpha、d、theta——就能把相邻两个坐标系的变换关系完全确定下来。一串矩阵乘过去,末端位姿自然就出来了。这套规则不挑机械臂类型,串联机械臂、协作臂、直角坐标机器人、移动机器人关节臂,都能用。说白了,DH建模就是给机械臂的每段骨头都贴上一张标准化的"身份证",后续不管做正运动学还是逆运动学,都拿这张身份证说话。

1.2 四个参数的人话解释:骨头长度、拧角、错位量和关节转了多少

刚开始看DH参数表的人,最容易背了一堆定义还是不知道自己在填什么。我换个说法:

  • a(连杆长度):相邻两个关节轴线之间的公垂线距离,沿着X轴方向量。可以粗暴理解为"这段骨头的长度",单位用米或毫米。
  • alpha(连杆扭角):绕X轴从一条关节轴线扭到另一条关节轴线的角度。它决定了相邻两个关节轴是平行、垂直还是斜交。生活里可以类比成"骨头之间拧了多少度"。
  • d(关节偏置):沿当前Z轴方向,两条公垂线之间的距离。更直白一点,就是两个关节在轴线方向上"错开"了多少,像楼层之间的层高。
  • theta(关节角):绕当前Z轴,从上一条X轴转到当前X轴的角度。对旋转关节来说,它才是真正会变的量。

这里必须提醒一句:a和alpha这两个参数在标准DH(SDH)里带的下标是i-1,d和theta的下标是i。什么意思?就是a和alpha描述的是"上一段连杆"的几何特性,而d和theta描述的是"当前关节"的特性。这个下标错位问题,是我见过最多人栽跟头的地方。参数表第一行往往写着a=0、alpha=0,很多人以为是个巧合,其实是因为第一行确实没有上一段连杆可以描述。

1.3 用一个二连杆平面臂验证直觉

理论讲半天不如动手算。假设有一个两连杆平面机械臂,第一段长L1,第二段长L2,两个关节都在纸面内旋转。这个例子所有几何都摆在你眼前,最适合验证DH建模是不是算对了。

按SDH定义,Z0沿关节1轴线(垂直纸面),Z1沿关节2轴线(同样垂直纸面,与Z0平行),Z2沿末端工具方向。因为Z0和Z1平行,alpha0=0;Z0到Z1的公垂线距离就是L1,所以a0=L1;同理a1=L2。参数表就是:

ia(i-1)alpha(i-1)d(i)theta(i)
1000θ1
2L100θ2
3L2000

然后把变换矩阵乘起来,末端位置是:

X = L1·cosθ1 + L2·cos(θ1+θ2) Y = L1·sinθ1 + L2·sin(θ1+θ2)

这正是几何上直接算出来的结果:第一段端点绕基座转了θ1,第二段端点相对于第一段又转了θ2。我第一次算出这个结果的时候,心里那块石头才落了地——原来DH不是什么玄学,它就是一套严谨的几何规则。记住这种感觉,后面遇到再复杂的机械臂,你就是在重复这件事:建立坐标系、填参数、乘矩阵、验证结果。

2. SDH和MDH千万别混:同一台臂,两套参数能算出不同结果

2.1 两种模型的核心差别在坐标系原点放哪

DH建模有两大流派,标准DH(SDH,也叫经典DH)和修正DH(MDH)。这两套东西都能正确描述机械臂,但坐标系的摆放规则不一样,参数表的数值也不一样。很多人拿着A教材的公式去套B软件的参数,结果算出个莫名其妙的位置,还以为是矩阵乘错了。

SDH的关键特征是:坐标系{i}建立在连杆i的末端,Z轴沿第i+1个关节的轴线。也就是说,坐标系{i}的原点落在下一个关节的轴线上。MDH则反过来,坐标系{i}的Z轴沿第i个关节本身的轴线,原点就在当前关节轴线上。

差别最直观的体现就在二连杆例子里。用SDH时,第一个变换0T1只包含关节1的旋转,连杆长度L1作为a0出现在第一个和第二个坐标系之间的变换里。而MDH下,每个变换的几何参数直接跟当前关节挂钩,参数下标习惯也不一样。这个差异导致同一台机器人,SDH参数表和MDH参数表几乎不可能通用。

2.2 怎么快速判断手头的资料是哪套DH

我整理了一个快速判据,适合你在网上扒资料或者看开源代码时用:

判断点SDH标准DHMDH修正DH
坐标系{i}的Z轴沿关节i+1轴线沿关节i轴线
第一行参数通常a=0、alpha=0可能直接出现非零a、alpha
参数下标习惯a、alpha下标为i-1a、alpha下标为i
常见使用场景经典教材、传统多轴机器人树形结构、闭链结构、很多仿真SDK

但光看文字还是容易错。我自己的判断方法是看旋转关节的"转动轴"到底在哪。主动动一下关节i,看坐标系{i}的变化情况,就能分辨出是SDH还是MDH:SDH下,动关节i时,坐标系{i-1}到{i}的旋转体现在theta_i上;MDH下,也是类似,但坐标系的Z轴和变换挂接的关节不同,从结构上一眼能看出来。

2.3 我的实用建议:选定一套就不要换来换去

说实话,这两种模型没有高下之分,SDH在教材里讲得多,MDH在不少仿真项目里用得多。最怕的不是选错,而是选了一套又按另一套的规则去读参数。我自己习惯在这类项目里全程用SDH,因为在教学和正运动学推导上资料更多,出错时更容易找到对照。如果你是从某个开源驱动或者仿真插件起步,那就跟着那个项目用MDH,别自己擅自改。

还有一个防呆技巧:无论SDH还是MDH,参数表里都要写清楚"哪一列是可变的关节变量、哪一列是固定常量"。很多时候搞混不是流派的问题,而是把theta和d当作变量的地方整反了。

3. 六轴机械臂完整建模:从坐标系摆放到Python代码跑通

3.1 建模第一步不是填表,而是画草图和定零位

很多教程上来就给一张DH参数表,看起来好像凭空就有。实际建模时,第一步是画一张机械臂各关节轴线的简化草图,标清楚每一根轴线的方向,然后确定"数学零位"。

有个非常容易踩的概念混淆是"机械零位"和"数学零位"。机械臂示教器上显示的零点通常是每个关节都转到某个物理位置(比如对齐刻度线),但不一定等于你DH表里theta=0时的构型。比如你的机械臂在示教器上显示关节2为0度,但你的DH模型里关节2要填90度才能让坐标系的姿态对齐,那多出来的90度就是theta offset。这个偏移量必须单独记录,不要硬塞进公式里,否则后续标定、标零位的时候你会发疯。

3.2 逐关节定坐标系,填出这台臂的DH表

我用一台典型的六轴关节型机械臂举例。关节1绕基座垂直轴旋转,关节2和关节3做俯仰,关节4、5、6组成手腕。按SDH规则,各坐标系Z轴方向沿下一个关节轴线。经过一步步摆放,我得到如下参数表(这里是虚构的示例数据,不代表任何真实机型):

itheta_id_i (m)a_{i-1} (m)alpha_{i-1}
1θ10.3000
2θ200.05+90°
3θ300.350
4θ40.350.08+90°
5θ500-90°
6θ60.1000

怎么读这张表?theta列是可变的关节角;d1=0.30是基座到肩关节的高度,d4=0.35是肘部到手腕的轴向距离,d6=0.10是手腕末端到法兰面的距离;a2=0.35是大臂长度,a3=0.08是手腕前的一小段偏置。alpha的+90°和-90°表明相邻关节轴线互相垂直,正负号决定了Z轴的方向是朝上还是朝下。

这里要特别强调alpha正负号的判断。判断方法就是右手定则:右手大拇指指向X轴方向,其余四指从Z_{i-1}转向Z_i,能转过去就是正,反过来就是负。建模时宁可多花十分钟把每个alpha的正负号对着草图核一遍,也不要写完代码后一整晚排查方向问题。

3.3 齐次变换矩阵公式与乘法顺序

标准DH的单个变换矩阵长这样:

T(i-1→i) = [ cosθ_i -sinθ_i·cosα_{i-1} sinθ_i·sinα_{i-1} a_{i-1}·cosθ_i ] [ sinθ_i cosθ_i·cosα_{i-1} -cosθ_i·sinα_{i-1} a_{i-1}·sinθ_i ] [ 0 sinα_{i-1} cosα_{i-1} d_i ] [ 0 0 0 1 ]

这个矩阵看着复杂,但拆开就四个变换的复合:先沿X_{i-1}方向平移a_{i-1},再绕X_{i-1}扭转alpha_{i-1},然后沿Z_i方向平移d_i,最后绕Z_i旋转theta_i。写代码不需要手推这个矩阵,直接按公式填入即可。

整个机械臂的末端位姿,就是把这些矩阵按顺序乘起来:

T(0→6) = T(0→1) · T(1→2) · T(2→3) · T(3→4) · T(4→5) · T(5→6)

最后得到的4x4矩阵,其左上角3x3块是末端坐标系在基座坐标系中的姿态,第四列前三个元素就是末端位置。

3.4 用Python跑通正运动学

我把上面的例子写成了一段可运行的正运动学代码,用numpy矩阵相乘,逻辑非常清晰:

import numpy as np def dh_transform(theta, d, a, alpha): T = np.array([ [np.cos(theta), -np.sin(theta)*np.cos(alpha), np.sin(theta)*np.sin(alpha), a*np.cos(theta)], [np.sin(theta), np.cos(theta)*np.cos(alpha), -np.cos(theta)*np.sin(alpha), a*np.sin(theta)], [0, np.sin(alpha), np.cos(alpha), d], [0, 0, 0, 1] ]) return T def fkine(theta_vec): # 参数表:theta取当前值,d、a、alpha为固定参数 dh_table = [ [theta_vec[0], 0.30, 0, 0], [theta_vec[1], 0, 0.05, np.pi/2], [theta_vec[2], 0, 0.35, 0], [theta_vec[3], 0.35, 0.08, np.pi/2], [theta_vec[4], 0, 0, -np.pi/2], [theta_vec[5], 0.10, 0, 0], ] T = np.eye(4) for row in dh_table: T = T @ dh_transform(row[0], row[1], row[2], row[3]) return T print("全关节0度时的末端位姿:") print(fkine(np.zeros(6))) print("关节1转90度后的末端位置:") print(fkine([np.pi/2, 0, 0, 0, 0, 0]))

在我的示例参数下,全零位时末端位置大约是[0.91, -0.35, -0.15]米,姿态矩阵是[[1,0,0],[0,-1,0],[0,0,-1]],也就是说末端Z轴朝下。关节1转90度后,末端位置变成[0.35, 0.91, -0.15]米,可以看到它正好绕基座Z轴转了90度,位置规律完全符合预期。

这段代码你可以直接复制改参数。注意所有角度都用弧度,这是新手最容易忽略的。另外我把参数表写在函数内部是为了演示方便,实际项目里建议把它们放到配置文件里,方便换机型、做标定。

4. 验证模型对不对:四招让错误在仿真阶段就暴露

4.1 第一招:零位比对法

拿到任何一台机械臂,我做的第一件事永远是算一遍全零位。把theta全设成0(或者你定义的数学零位),用DH模型算出末端位置,然后跟机器人的CAD模型比对。如果没有CAD,就找一根直尺或激光测距,把机械臂摆在零位,直接量末端到基座坐标系三个轴方向的距离。差了几毫米内可以接受,差了几厘米甚至方向不对,那就是DH参数有误,不需要犹豫,回头查。

用我上面的例子,全零位的末端位置是[0.91, -0.35, -0.15]米。什么意思?就是末端法兰相对于基座,向X方向伸出0.91米,向Y方向偏了0.35米,比基座低0.15米。如果你在真实机械臂上看到的形状完全对不上这个感觉,那就要检查是不是坐标系的Z方向或者alpha符号搞反了。

4.2 第二招:单关节动起来看轨迹

验证运动学模型最直观的方法,是让某个关节单独动,看末端轨迹是否符合几何预期。比如只转动关节1,末端应该在基座Z轴周围画一个圆,圆的高度应该保持不变,半径等于末端到基座Z轴的横向距离。在代码里就是循环theta1从0到2π,其他theta保持0,记录末端位置,画出来是一个在水平面上的圆。

这个方法之所以好用,是因为它能快速暴露"坐标系方向定义错误"和"关节变量填错位置"这类问题。如果关节1动了,末端在Z方向上的高度也跟着变,那可能是你的Z0方向定义和矩阵里的符号不一致;如果末端轨迹不是圆,大概率是旋转轴搞错了。

4.3 第三招:锁定部分关节,把六轴降成二轴手算

当整体轨迹看着没什么毛病,但某个位置总觉得不对时,我常用的一招是把机械臂"锁"成平面机械臂。具体做法:选一组关节角度让大臂、小臂、手腕处在同一个平面内,比如让关节1等于0,这样整个手臂落在某个平面里,然后固定其他关节,只动关节2或关节3,此时末端轨迹应该落在X0Z平面或者X0Y平面内。

这种情况下,你可以直接用平面几何手算末端位置,跟DH模型的结果对比。比如关节2转90度、关节3转0度时,大臂指向正上方,小臂向前伸,末端位置距离基座的高度应该是几个连杆长度的代数和。一旦手算和模型能对上,整条链的a、d、alpha参数基本就都被你验证过了。

4.4 第四招:放到仿真环境或对准示教器数值

有些机械臂自带示教器,可以在里面看到每个关节角度对应的末端坐标。这是最省事的对标资源。把DH模型算出来的位置跟示教器显示的位置对比,如果单位统一、零位定义统一,数值应该几乎一致。很多厂家的标定精度在毫米级,DH模型算出来如果差了一两毫米主要是机械加工和零位标定误差,可以接受;但如果差了几厘米,别急着怪厂家,先回去查单位是不是米和毫米混了,theta是不是度数当成弧度用了。

说实话,我见过最多的一次性翻车现场,就是单位问题。DH表里的d和a用米,theta用弧度,三个一混,末端位置能偏得连方向都不对。建议从一开始就在注释里额外标注单位,配置文件也统一规定好。

5. 那些年我踩过的DH坑:高频问题与自查清单

5.1 alpha方向搞反:Z轴指向不统一

alpha的正负号问题太常见了。很多人在纸上画草图时,Z轴习惯性朝上,但DH建模里Z轴的方向是由下一个关节的轴线方向决定的,不一定是朝上。比如关节4和关节5之间的扭转角在示例里是-90度,如果填成+90度,坐标系的Z轴会翻转,末端姿态矩阵直接变化,位置计算也会随之偏移。所以每次填alpha,我都会在草图边上写一行"右手定则验证:从Z_{i-1}向Z_i绕X_{i-1}旋转",填完再审一遍。

5.2 参数下标错位:SDH的a、alpha是上一根连杆的

前面反复提到过,SDH里a_{i-1}和alpha_{i-1}描述的是上一段连杆。我在刚开始建模时,经常把第i行的a直接填成当前连杆的长度,结果整个模型错位。判断方法很简单:对照你的草图看,坐标系{i-1}到坐标系{i}的变换,跨过的是哪一段骨头?那根骨头就是a_{i-1}和alpha_{i-1}描述的。

5.3 零位偏移没处理:示教器显示0不等于数学0

真实机械臂的θ=0通常不是DH意义上的0。比如某台臂在机械零位时,关节2的大臂其实是水平前伸的,但在DH定义里可能需要θ2=90度才对应水平。这种偏移必须在模型里补上,否则全零位验证绝对对不上。我的做法是在代码里单独维护一个theta_offset数组,正运动学计算前先把offset加进去,而不是改DH参数表本身,这样标定或者重新调零位时只需要改配置文件。

5.4 平移关节的变量处理:d才是关节变量

如果是直角坐标机械臂或者有平移关节的结构,记得关节变量不是theta,而是d。平移关节那一行的theta通常固定为0度或90度,d根据位置变化。别把theta当变量使了,不然算出来的末端位置会靠近得莫名其妙。

5.5 DH模型自查清单

检查项检查方法常见错误
单位统一长度全部用同一单位,角度全部用弧度米、毫米混用,度、弧度混用
alpha符号右手定则对照草图正负号相反,Z轴翻转
参数下标确认SDH中a、alpha是i-1填成当前连杆长度
零位偏移数学零位和机械零位分离记录忽略offset,全零位对不上
变换顺序矩阵按关节顺序相乘顺序错误或漏乘
单关节验证只动一个关节,看轨迹轨迹不是圆或方向不符
单位换算验证末端位置量级在合理范围误差到厘米级仍没发现

拿这张清单去逐一核对,我相信至少能筛掉八成以上的低级错误。剩下两成,多半是机器人结构本身有奇怪的补偿或者耦合,那已经不是"基础DH建模"的范畴了。

最后说点个人经验。我现在的习惯是先写一个最小的二连杆平面臂作为自检工具,每次要换新算法、新机型时,先在这个简单模型上跑通框架,再换上真正的六轴参数表。这样能保证出问题的一定是参数或者机型适配,而不是正运动学代码本身。另外,强烈建议把DH参数做成外部配置文件,不要写死在代码里。我做过的项目里,DH参数至少被改过三回——换了机械装配、标定了零位、调整了工具长度,每次改参数都要重新编译排查,改成配置后只改几行数据,省下的时间够喝好几杯咖啡了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询