前两天跟人聊到机械臂选型,对方第一句话就是“先看它能不能够到那个点”,第二句话是“够到了能不能干细活”。这其实就是机器人学里最基础但最容易被跳过的预分析:可达空间,以及可操作性。很多项目都是直接上运动规划,等到轨迹在某处反复报奇异、或者末端在某片区域怎么调姿态都别扭,才回头补工作空间的功课。我个人的习惯恰恰相反,拿到一条机械臂的模型,先花二十分钟把可达空间和可操作性的可视化跑出来,再决定后续的布局、选型和轨迹策略。
这篇文章是Matlab机器人工具箱系列的第二篇,上一篇讲过建模和正逆运动学基础,这次专门聊预分析阶段怎么把“机械臂到底能干什么”用图形化方式呈现出来。内容围绕两个核心展开:一是用随机采样法画可达空间,二是把雅可比矩阵的可操作性映射到工作空间上做成热力图。适合正在做机械臂选型、工作站布局、或者写运动规划前想确认任务可执行性的工程师和研究者。
1. 为什么动手规划前,先要回答两个问题
1.1 可达空间与可操作性,解决的是两类完全不同的事
可达空间和可操作性,这两个概念经常被混淆,但它们在工程上回答的问题完全不一样。
可达空间(reachable workspace)回答的是“能不能碰到”的问题。它定义成末端参考点能到达的所有位置集合,本质上是关节空间通过正运动学映射到笛卡尔空间的像。关节空间里的每个关节角组合,经过正运动学变换,得到末端的一个位置;把所有可能的关节角组合都跑一遍,末端所有位置的并集就是可达空间。这里只关心位置,不关心末端在那个点上拿着什么姿态、动作有多灵活。换句话说,只要末端能“伸到”那个点,不管姿势多别扭,这个点都算可达空间里的点。
可操作性(manipulability)回答的则是“碰到了之后干不干得动细活”的问题。它反映的是机械臂在某个关节构型下,末端执行器在各个方向上改变位置和姿态的能力。数学上,这个概念来自雅可比矩阵:末端速度与关节速度之间是线性映射,即v = J(q)·q̇。给定关节速度有一个单位球约束,末端速度能取到的集合就是一个椭球,这个椭球的体积和形状就由雅可比矩阵的奇异值决定。椭球越“胖”,说明末端在各个方向上运动能力越均衡;椭球越扁,说明某些方向上几乎动不了,也就是接近奇异。
这两个概念经常被拿出来放到一起做预分析,原因是它们构成了“机械臂能力画像”的两个侧面:可达空间告诉你范围,可操作性告诉你质量。范围够大但可操作性差,机械臂在那个位置就是个“跛脚”状态;可操作性好但根本够不到,那一切免谈。
1.2 预分析在工程流程中的落位
预分析这件事,听上去像是研发阶段才需要做的仿真工作,但实际在工程流程里它的用处非常直接。我自己经历过至少三类场景,都是靠这两幅图解决的:
一是选型对比。手上有两三条候选机械臂,规格书上都有最大工作半径,但规格书给的是理想最大半径,实际安装底座高度、关节限位不同,可达空间的形状差异很大。把各自模型跑一遍可达空间,装在同一个坐标系里对比,谁覆盖的区域更大、谁在重点区域内有更高的可操作性,一眼就看明白了。
二是工作站布局。机械臂安装在什么高度、工作台放在哪个位置、料盘摆在哪个象限,这些都属于布局问题。布局不合理,可能出现“位置能到但姿态不够”、“姿态够了但位置差一点点”这种尴尬情况。提前把预分析结果叠加到布局图上,就能在设计阶段把这些问题消掉,而不是到了调试现场再搬来搬去。
三是任务可行性判断。比如一条打磨轨迹,机械臂末端的运动方向需要沿着曲面法向走,如果这条轨迹落在可操作性很差的区域,执行时就会频繁逼近奇异,导致速度突变甚至报错。预分析阶段在可操作性云图上核对一下轨迹是否经过低分区域,能避免后面大量的规划调试时间。
2. 模型准备:DH参数、关节限位与工具箱版本差异
2.1 用SerialLink快速建一个可分析的六轴模型
要做预分析,第一步当然是有一个可靠的机械臂模型。Matlab机器人工具箱(Robotics Toolbox)里最常用的建模方式是SerialLink加Link对象。这个系列第一篇应该已经讲过怎么建模,这里再快速给一个可以直接跑通的六自由度模型示例,方便后面接可视化的代码。
% 一个通用6自由度串联机械臂的DH参数模型 % 采用标准DH约定,单位为米、弧度 L1 = Link('d', 0.15, 'a', 0, 'alpha', pi/2, 'qlim', [-pi pi]); L2 = Link('d', 0, 'a', 0.30, 'alpha', 0, 'qlim', [-2.5 2.5]); L3 = Link('d', 0, 'a', 0.10, 'alpha', pi/2, 'qlim', [-pi pi]); L4 = Link('d', 0.25, 'a', 0, 'alpha', -pi/2, 'qlim', [-pi pi]); L5 = Link('d', 0, 'a', 0, 'alpha', pi/2, 'qlim', [-pi pi]); L6 = Link('d', 0.08, 'a', 0, 'alpha', 0, 'qlim', [-pi pi]); robot = SerialLink([L1 L2 L3 L4 L5 L6], 'name', 'demo6');这里有几个点值得强调。一个是DH参数约定,工具箱默认走的是标准DH,如果你的模型是从URDF之类的地方导出的,要注意标准DH和改进DH的差异,两者d和a的位置、以及相邻坐标系变换的顺序都不一样,搞混了画出来的模型姿态会很怪。另一个是qlim这个属性,也就是每个关节的运动范围,这个在后面做蒙特卡洛采样时非常关键,因为随机采样要在qlim范围内取关节值,如果qlim没设置或者设置得太宽,画出来的可达空间就和真实机械臂完全对不上。
2.2 版本差异:fkine、ikine、jacob0在不同版本的调用变化
Matlab机器人工具箱经历过比较大的API变化,网上很多老教程里的代码在新版本上直接跑会报错,这个坑我踩过不止一次。最大的一个变化是fkine的返回值:在较老的版本(比如9.x)里,robot.fkine(q)返回的是4×4的齐次变换矩阵;从10.x开始,返回值变成了SE3类对象,直接取位置的话要用对象的t属性。
这个差异会直接影响代码的兼容性。我在做预分析时习惯写一个兼容提取函数,这样同一个脚本在不同版本上都能跑:
function p = getPosition(T) % 兼容不同版本工具箱的位姿位置提取 if isa(T, 'SE3') p = T.t; else p = T(1:3,4); end endikine的调用也需要注意,新版中推荐用mask参数指定需要约束的维度,比如只约束位置不约束姿态,就写成'mask', [1 1 1 0 0 0]。jacob0函数倒是相对稳定,一直用来计算基坐标系下的几何雅可比矩阵,6自由度机械臂返回6×6矩阵。这些版本差异不是什么大难题,但知道的话能省很多排查时间。
3. 可达空间可视化:从随机点云到可决策的边界切片
3.1 Monte Carlo采样的内在逻辑与首版散点图
可达空间的可视化,最常规的做法是蒙特卡洛采样法,也叫随机采样法。核心逻辑很简单:在关节空间的qlim范围内让每个关节取随机值,组合成一组关节角,然后通过正运动学算出末端位置;重复大量次数,把所有末端位置画成散点图,点云的覆盖范围就近似等于可达空间。
这个方法为什么有效?从概率角度看,关节空间里每个关节角都在限位内均匀随机取值,正运动学是一个确定性的连续映射。大量采样点落在某个区域的密度,近似等于该区域在关节空间里对应的“体积比例”。采样数足够多时,点云的边界会收敛到真实的可达空间边界。它不需要求解逆运动学,所以完全绕开了可达性判断这个麻烦问题,这在工程上非常实用。
% 可达空间蒙特卡洛采样 N = 50000; rng(42); % 固定随机种子,保证结果可复现 q = rand(N, 6); for i = 1:6 q(:, i) = robot.qlim(i,1) + q(:, i) * (robot.qlim(i,2) - robot.qlim(i,1)); end Ts = robot.fkine(q); % 批量正运动学 pos = zeros(N, 3); for i = 1:N if isa(Ts, 'SE3') pos(i, :) = Ts(i).t; % 新版工具箱 else pos(i, :) = Ts(1:3, 4, i)'; % 旧版工具箱 end end figure; plot3(pos(:,1), pos(:,2), pos(:,3), '.', 'MarkerSize', 2); axis equal; grid on; xlabel('x (m)'); ylabel('y (m)'); zlabel('z (m)'); title('可达空间散点图(50000次采样)');这段代码跑完,你会得到一张点云图。如果机械臂模型没问题,一般能看到一个球壳状的立体点云,内部会有一片空白区域。球壳对应机械臂伸直时的极限半径,内部空白则是关节构型限制导致末端无法到达的位置。
但散点图有个非常实际的问题:它对边界刻画不够清晰。你能看到一个大概轮廓,但很难回答“边界到底在哪里”“某个高度截面上可达范围是什么形状”这类问题。所以散点图只是起点,工程决策需要进一步做边界提取和切片分析。
3.2 用alphaShape把点云变成实体边界
点云要变成可用的几何信息,我通常会用MATLAB自带的alphaShape函数。它可以对三维点集构建一个可变精细度的包络形状,alpha值小了形状会破碎成很多小块,alpha值大了会过度平滑,把真实的凹陷和孔洞吞掉。选alpha的经验做法是:先画散点图,目测点云的平均间距,alpha取平均间距的3到5倍左右。针对上面那个模型,我一般取0.05到0.08之间。
% 用alphaShape提取可达空间边界 alphaVal = 0.06; shp = alphaShape(pos(:,1), pos(:,2), pos(:,3), alphaVal); V = volume(shp); % 可达空间体积 fprintf('可达空间体积:%.4f m^3\n', V); figure; plot(shp, 'FaceAlpha', 0.3, 'EdgeColor', 'none'); axis equal; grid on; xlabel('x (m)'); ylabel('y (m)'); zlabel('z (m)'); title('alphaShape 边界可视化');得到shp对象之后还能做两件事。一是直接算体积,这个数值可以用于候选机械臂的容量比较,比单纯看最大工作半径要靠谱得多。二是后续切片分析时用inShape函数判断某个空间点是否在可达范围内,这一步非常关键,因为可操作性云图遍历网格点时,需要先判断这个点是否可达,避免对不可达点做无意义的逆解计算。
3.3 平面切片:直接回答“这个高度能覆盖多大范围”
散点图给了直观感受,alphaShape给了边界实体,但真正做布局决策时,我依赖最多的是平面切片。比如工作站台面的高度是0.2米,那我就想知道在z=0.2这个平面上,机械臂末端能覆盖哪些区域。用inShape配合meshgrid,把平面细分成网格点,逐个判断是否在可达空间内,然后画出二维掩码图:
% 在指定高度截面判断可达性 z0 = 0.20; % 工作台面高度,单位m gx = linspace(-0.6, 0.6, 200); gy = gx; [Xg, Yg] = meshgrid(gx, gy); Zg = z0 * ones(size(Xg)); in = inShape(shp, Xg, Yg, Zg); figure; imagesc(gx, gy, in); axis xy; axis equal; colormap(gca, [0.85 0.85 0.85; 0.2 0.4 0.8]); colorbar; xlabel('x (m)'); ylabel('y (m)'); title(sprintf('z=%.2f m 处的可达截面', z0));这张图的价值在于它把三维问题降维成二维平面,直接在布局图上叠加就能规划工位。一个很常见的例子:机械臂装在工作台正后方,台面高度0.2米,你从切片图里发现前方0.4米左右有一条可达性很好的带状区域,那料盘和治具就尽量放在这个带状区里。如果要分析多个高度,可以循环跑上面这段代码,把不同高度截面的可达面积算出来,画成一条“高度-可达面积”曲线,直接看这条臂在哪一层工作面最好用。
三种可视化形态各有用途,我常用的组合是:先看散点图确认模型对不对,再用alphaShape看整体边界和体积,最后用切片图做具体的布局判断。
4. 可操作性可视化:雅可比矩阵到工作空间热力图
4.1 可操作性椭球与奇异值:理解“灵活性”的数学含义
如果说可达空间可视化依赖的是正运动学,那可操作性可视化依赖的就是雅可比矩阵。先把这个概念拆开讲清楚。
雅可比矩阵J(q)描述的是末端速度与关节速度的线性关系。每个关节速度都有个自然约束,通常可以看作关节速度矢量的范数不超过1。那末端速度能取到什么范围呢?把满足‖q̇‖≤1的关节速度集合通过线性映射v=Jq̇作用到末端速度空间,得到的就不是一个圆或者球了,而是一个椭球。这个椭球叫可操作性椭球。椭球的半轴长度就是雅可比矩阵的奇异值σi,半轴方向是奇异值分解里左奇异向量对应的方向。
这个名字本身就已经把物理含义说清楚了:奇异值衡量的是“末端在这个方向上每单位的关节速度能换来多少末端速度”。奇异值大,说明这个方向上末端很“有力”,一点关节转速就能产生很大的末端速度;奇异值接近0,说明这个方向上有运动“死区”,很可能接近奇异位形。
于是就有了两个常用指标。一个是可操作性度量(manipulability measure),定义成w = sqrt(det(J·Jᵀ)),对于方阵来说就等于所有奇异值的乘积σ1·σ2·…·σn。它正比于椭球体积,衡量“整体运动能力大小”。另一个是各向同性指标,σ_min / σ_max,衡量椭球有多接近球,1表示各方向能力完全一致,0表示某个方向已经退化。这两个指标一个看大小一个看形状,配合使用才完整。
多说一句,很多资料直接给w的数值,但要注意雅可比矩阵前3行是线速度相关的量纲,后3行是角速度相关的量纲,这导致w的量纲是混合的,绝对数值没有明确物理单位。所以实际操作中我不太关注w的绝对值,而是关注它在工作空间里的相对分布。为了让色标更平滑,我习惯对w开n次方取几何平均,也就是sigma_mean = w^(1/n),这个值相当于“平均每个方向的速度放大系数”,数值从0到几,画热力图更直观。
4.2 网格遍历加数值逆解:给每个工作点打分
有了可操作性指标,接下来就是把整个可达空间里每个点都打一个分。做法是:在可达空间内取一批空间网格点,对每个点反解机械臂能到达该点的关节角,然后用雅可比矩阵算该构型下的可操作性。注意这里有个细节,同一个末端位置通常对应多个逆解,肘上肘下之类的不同构型可操作性差异很大。我的简化处理是:对目标位置设置位置约束,不约束姿态,用几组随机初值做数值逆解,取第一个收敛的解来算分。这样做得到的是“不关心姿态约束的情况下,这一点能达到的某种灵活性”,如果后续任务有特殊姿态要求,需要把目标姿态也放进逆解条件里。
% 在z=0.20平面上的可操作性云图 step = 0.04; [xt, yt] = meshgrid(-0.5:step:0.5, -0.5:step:0.5); zt = z0 * ones(size(xt)); wm = nan(size(xt)); wIso = nan(size(xt)); for i = 1:numel(xt) % 先判断可达性,不可达直接跳过 if ~inShape(shp, xt(i), yt(i), zt(i)) continue; end T_target = SE3(eye(3), [xt(i), yt(i), zt(i)]); % 只关心位置 for k = 1:3 q_init = robot.qlim(:,1)' + rand(1,6) .* (robot.qlim(:,2) - robot.qlim(:,1))'; try q_sol = robot.ikine(T_target, q_init, ... 'mask', [1 1 1 0 0 0], 'tol', 1e-6, 'ilimit', 500); if ~isempty(q_sol) J = robot.jacob0(q_sol); s = svd(J); wm(i) = prod(s)^(1/6); % 可操作性,几何平均 wIso(i) = min(s) / max(s); % 各向同性 break; % 找到一组解即可 end catch end end end figure; imagesc(xt(1,:), yt(:,1), wm); axis xy; axis equal; colormap(jet); colorbar; xlabel('x (m)'); ylabel('y (m)'); title(sprintf('z=%.2f m 可操作性分布', z0));这段代码跑起来需要一点耐心,网格点数量大约26×26=676个,每个点最多三次逆解,一次逆解是几十毫秒级,整体下来大概十几秒到几十秒,属于可以接受的预分析范畴。如果网格步长进一步加密到0.02,点数会接近2500个,时间会暴涨到几分钟,所以预分析阶段不必追求过细,先看趋势再局部加密。
4.3 各向同性指标:找“关键灵活区”和“奇异死角”
可操作性云图跑出来之后,通常能看到工作空间内部偏中心区域有一个明亮的高分带,越靠近可达空间边界颜色越暗。这也符合直觉:机械臂在中间区域各关节角度余量大,运动灵活;在边界附近关节几乎伸直,末端能动的方向非常有限,很容易接近奇异。
各向同性指标wIso这张图则更严格地反映方向均衡性。如果某个点位w很大,但wIso很小,说明这个点虽然“整体能力大”,却是扁椭球,在某些方向上一动就容易奇异。这对精密加工类任务特别关键,打磨、铣削、装配这类任务都要求末端在作业方向上有充分的调配空间,我一般会在预分析阶段圈出wIso大于0.3的区域作为“精作业区”,再把关键作业轨迹尽量放在这个区域里。搬运、码垛这类粗任务则可以放宽,w的绝对大小更重要。
如果还想看得更细,可以在某个关键点把可操作性椭球本身画出来。方法是对该构型做奇异值分解,得到左奇异向量U和奇异值σ,然后以该点为原点,沿U的列方向画出半轴长度为σ的椭球。这个图能直接告诉你末端在这个点“哪个方向灵活、哪个方向僵硬”,比单看一个数字要直观得多。
5. 实测中必须注意的四个坑
5.1 采样数不是越大越好,还和随机种子有关
蒙特卡洛采样有一个很常见的误区:觉得采样数越多越好,一上来就采50万甚至100万次。实际效果上,5万次和20万次的边界差别非常小,但alphaShape处理20万点时的计算时间明显变长,绘制3D图形也会变得卡顿。我的经验是预分析阶段5万次足够,如果想得到更平滑的边界,优先调alpha值而不是盲目加采样数。
另一个容易被忽略的是随机种子。如果不固定rng,两次运行得到的点云会略有不同,边界的毛刺位置也不一样。这会导致你对比两个方案时,误把随机噪声当成真实差异。所以我在所有预分析脚本里都会写rng(42),保证结果可复现。
5.2 关节限位没设对,画出来的空间是假的
这个坑我见过太多次。建模的时候只写了DH参数,没写qlim,或者qlim设置得过于宽松,然后蒙特卡洛采样的范围就错了。关节限位不仅影响采样范围,也影响后面的逆解和雅可比分析。一个真实的机械臂,哪怕前三个大臂关节范围都接近±180°,第四五六关节的实际运动范围也往往受到线缆、机械限位等因素约束。如果模型里没设限位,可达空间会多出一大块“理论上能到、实际到不了”的区域,这在实际工程中很致命。
验证限位是否正确的方法也很简单:在散点图画出来之后,手动teach一下机械臂,把每个关节打到极限,看末端实际位置是否落在点云边界附近。如果差得多,优先检查qlim。
5.3 逆解失败要容错,别让NaN污染云图
工作空间网格遍历时,最烦的就是某些不可达点或者接近奇异的点导致ikine失败。ikine是一个数值迭代算法,迭代不收敛时会返回空数组或者直接报错。如果不加处理,程序会在中途炸掉,或者图上出现一片NaN空洞,很难判断到底是算法失败还是真不可达。
我的处理方式是在循环里包一层try-catch,并且给每个点尝试几组随机初值。数值逆解对初值敏感,特别是在接近工作空间边界的区域,一组初值不收敛很正常,换一组可能就收敛了。如果三组初值都失败,就把这个点标记为不可达,在图上保留空白,这在工程上是有意义的——这个位置要么真不可达,要么逆解困难,无论哪种都说明这里不适合放任务点。
5.4 别只看形状,还要看密度与方向
最后一个是方法论层面的提醒。很多人画完可达空间点云,觉得“哎这个形状挺规整”,就结束了。但点云内部点的疏密其实非常重要。关节空间均匀采样映射到笛卡尔空间后,点密度不是均匀的。工作空间中心区域往往点更密集,而边界区域点稀疏。这个密度分布反映了“关节空间体积在笛卡尔空间的膨胀程度”,密度大的区域意味着机械臂在这一带对关节角度变化不敏感,换个角度末端位置变化很小,往往是运动学性能比较好的地方;密度特别稀疏的边界区域,则是运动学放大效应强的地方,稍动一下关节末端就飞出去,非常不适合精细操作。真正完整的预分析,应该是可达空间的形状加上内部的密度或可操作性云图叠加来看,只看外轮廓而不看内部质量,等于只看房子外形不看户型。
6. 完整示例脚本:一次跑完可达空间与可操作性预分析
6.1 可直接复制的整合脚本
把前面各部分拼成一个完整的预分析脚本。这个脚本会完成:建立模型、生成可达空间点云、提取alphaShape边界、做高度切片、计算该平面上的可操作性云图。如果你只是想做选型对比,跑一遍这个脚本就够了。
%% 机械臂预分析:可达空间 + 可操作性可视化 clear; clc; close all; rng(42); % ---------- 1. 建模 ---------- L1 = Link('d', 0.15, 'a', 0, 'alpha', pi/2, 'qlim', [-pi pi]); L2 = Link('d', 0, 'a', 0.30, 'alpha', 0, 'qlim', [-2.5 2.5]); L3 = Link('d', 0, 'a', 0.10, 'alpha', pi/2, 'qlim', [-pi pi]); L4 = Link('d', 0.25, 'a', 0, 'alpha', -pi/2, 'qlim', [-pi pi]); L5 = Link('d', 0, 'a', 0, 'alpha', pi/2, 'qlim', [-pi pi]); L6 = Link('d', 0.08, 'a', 0, 'alpha', 0, 'qlim', [-pi pi]); robot = SerialLink([L1 L2 L3 L4 L5 L6], 'name', 'demo6'); % ---------- 2. 蒙特卡洛采样 ---------- N = 50000; q = rand(N, 6); for i = 1:6 q(:, i) = robot.qlim(i,1) + q(:, i) * (robot.qlim(i,2) - robot.qlim(i,1)); end Ts = robot.fkine(q); pos = zeros(N, 3); for i = 1:N if isa(Ts, 'SE3') pos(i, :) = Ts(i).t; else pos(i, :) = Ts(1:3, 4, i)'; end end % ---------- 3. 边界与体积 ---------- alphaVal = 0.06; shp = alphaShape(pos(:,1), pos(:,2), pos(:,3), alphaVal); fprintf('可达空间体积:%.4f m^3\n', volume(shp)); figure; plot(shp, 'FaceAlpha', 0.3, 'EdgeColor', 'none'); axis equal; grid on; xlabel('x (m)'); ylabel('y (m)'); zlabel('z (m)'); title('可达空间边界'); % ---------- 4. 高度切片 ---------- z0 = 0.20; gx = linspace(-0.6, 0.6, 200); gy = gx; [Xg, Yg] = meshgrid(gx, gy); Zg = z0 * ones(size(Xg)); in = inShape(shp, Xg, Yg, Zg); figure; imagesc(gx, gy, in); axis xy; axis equal; colormap(gca, [0.85 0.85 0.85; 0.2 0.4 0.8]); colorbar; xlabel('x (m)'); ylabel('y (m)'); title(sprintf('z=%.2f m 可达截面', z0)); % ---------- 5. 可操作性云图 ---------- step = 0.04; [xt, yt] = meshgrid(-0.5:step:0.5, -0.5:step:0.5); zt = z0 * ones(size(xt)); wm = nan(size(xt)); for i = 1:numel(xt) if ~inShape(shp, xt(i), yt(i), zt(i)) continue; end T_target = SE3(eye(3), [xt(i), yt(i), zt(i)]); for k = 1:3 q_init = robot.qlim(:,1)' + rand(1,6) .* (robot.qlim(:,2) - robot.qlim(:,1))'; try q_sol = robot.ikine(T_target, q_init, ... 'mask', [1 1 1 0 0 0], 'tol', 1e-6, 'ilimit', 500); if ~isempty(q_sol) J = robot.jacob0(q_sol); s = svd(J); wm(i) = prod(s)^(1/6); break; end catch end end end figure; imagesc(xt(1,:), yt(:,1), wm); axis xy; axis equal; colormap(jet); colorbar; xlabel('x (m)'); ylabel('y (m)'); title(sprintf('z=%.2f m 可操作性分布', z0));6.2 输出解读:怎么用这三张图做判断
脚本跑完,正常情况下你会得到三张图:三维边界图、高度切片图、可操作性云图。我的判读顺序是这样的。
先看三维边界图,确认机械臂模型整体形状是否合理。对于六轴串联机械臂,典型特征是基座附近有一个比较空的区域,因为第一二关节的组合限位决定了末端不可能贴近基座轴心。再看切片图,z=0.2这个高度上可达区域应该是连续的一片,通常在机械臂正前方有一个近似扇形的区域,左右对称(前提是前三个关节限位对称)。最后看重头戏可操作性云图,云图上偏亮的区域就是这台机械臂在台面高度上干活最顺手的范围。
把这套脚本固化成自己的预分析工具后,每次拿到新机械臂参数,我基本是这么一套动作跑下来。最后再分享一个我在实际项目里反复验证的经验:凡是预分析阶段发现可操作性特别低的区域,后面写轨迹规划时几乎一定会在那里出问题,要么奇异报警,要么速度波动明显。所以别小看这二十分钟的预分析,它把很多问题提前挡在了前面,省下的调试时间远不止二十分钟。