尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
曼哈顿距离在机器人路径规划中的原理与实战详解
前两天在调我们一台小型自动清扫机器人的任务调度时又看到有同事对着坐标嘀咕机器人停在(3,5)任务点在(7,2)两点间直线距离明明是5为什么程序最后算出的是7这个问题背后正是曼哈顿距离也叫 L1 距离、城市街区距离。很多刚接触路径规划的同学第一次看到 |x1-x2||y1-y2| 这个公式都会觉得太简单可真正用起来才发现它的适用场景、计算细节和常见坑比公式本身要复杂得多。这篇文章我就结合机器人坐标的例子从原理讲到代码再讲到我实际调试时踩过的那些雷。1. 曼哈顿距离到底解决机器人什么问题先看清它的使用场景1.1 为什么叫“曼哈顿”而不是“两点之间线段最短”曼哈顿距离这个名字来自城市街区的道路结构。在网格状路网里你想从街口 A 走到街口 B没法直接穿过一栋栋建筑只能沿着东西方向和南北方向的道路走。一个方向走 x 格另一个方向走 y 格总步数就是 |x1-x2||y1-y2|。把这个模型搬进机器人地图里就很直观了。当机器人只能在网格地图上做“前后左右”四方向移动时它走过的路径只能和坐标轴平行。从 (3,5) 到 (7,2)x 方向需要从 3 走到 7共 4 格y 方向需要从 5 走到 2共 3 格总步数就是 4 3 7。如果机器人能斜着走比如无人机那走直线距离才是最短可对我们这种在货架间穿行的清扫机器人斜线往往意味着撞到货架、越过障碍根本走不了。所以路径规划里算代价时曼哈顿距离比欧几里得距离更贴近真实运动成本。1.2 直线距离会低估机器人的实际“腿脚成本”欧几里得距离的公式是 sqrt((x1-x2)^2 (y1-y2)^2)代入(3,5)和(7,2)会得到 5。单纯看数值5 确实比 7 小如果你拿 5 当作两点的通行代价去调度机器人就会出现一个很微妙的偏差机器人明明要拐弯绕路程序却以为它几分钟就能到位结果任务超时、电量预估偏小甚至后续任务排队全乱掉。这不是代码 bug而是“距离模型”选错了。调度系统关心的是机器人实际执行任务的开销不是人类在地图上用尺子量的直线长度。问自己一个问题机器人到达目标点的方式是可斜穿还是必须沿网格走如果能斜穿用欧氏如果只能上下左右曼哈顿才是正确的那把尺子。这也是我强烈建议在写任何坐标距离函数之前先在地图上搞清楚“移动约束条件”的原因。2. 从 (3,5) 到 (7,2)把曼哈顿公式拆成两步减法2.1 先各算各轴再合起来顺序不重要很多初学者第一次写曼哈顿距离会纠结到底应该用 x1-x2 还是 x2-x1答案是随便因为公式外面有绝对值。我们以机器人坐标 (3,5)、任务点坐标 (7,2) 为例x 轴差值7 - 3 4取绝对值后还是 4y 轴差值2 - 5 -3取绝对值后是 3总距离4 3 7。就算你把坐标反过来写用 (7,2) 作为起点(3,5) 作为终点得到的是 |3-7| |5-2| 4 3 7一模一样。这是个很重要的性质曼哈顿距离是“对称”的它不关心谁先谁后只关心两个坐标点位置差的绝对值之和。实际写代码时你只要保证“两个点来自同一个坐标系”谁在前谁在后完全无所谓。不过我发现很多新手会在这里做个多余操作先判断两个数谁大谁小再相减。这没有必要abs() 函数已经把大小方向都处理好了多写if判断只是给代码增加无谓分支。2.2 为什么一定要绝对值负距离没有意义再往深一层想|x1-x2| 这个绝对值本质上是把“坐标差值”转换成了“距离代价”。坐标差可以是负数代表机器人需要往反方向走但走的步数不可能是负数。想象一下机器人从 y5 走到 y2y 方向差是 -3意思是从正方向往负方向移动 3 格如果丢掉绝对值把 -3 和 4 相加得到 1这个数字既不是直线距离也不是实际路径长度只是纯粹的数学残渣。所有距离度量都必须满足一条基本性质非负性。曼哈顿距离通过绝对值保证了这一点。这也是我排查问题时最爱用的一个信号如果程序算出来的“曼哈顿距离”是负数说明不是公式写错就是拿到的坐标数据本身有问题比如传感器传回了一个没初始化过的坐标占位值。负数距离几乎一定会让后续路径规划逻辑出现异常。3. 直接上代码从裸公式到函数封装再到批量计算3.1 先用一行代码确认结果跑通“最小可用版本”标题说了直接上代码那就先来最少的。Python 里几个内置函数就够用x1, y1 3, 5 x2, y2 7, 2 distance abs(x1 - x2) abs(y1 - y2) print(distance) # 7这段代码没什么好解释的abs() 取绝对值加号连接 x 轴和 y 轴的结果。放到任何支持绝对值和四则运算的语言里思路都一样C、C 用 std::absJava 用 Math.absJavaScript 用 Math.absGo 用 math.Abs。不过只写这么一段还谈不上“工程代码”。实际项目里坐标点通常来自传感器、地图解析器或任务下发模块直接裸写着两个变量是很脆弱的。所以我的习惯是先把坐标打包成元组或结构体再写一个专门的距离函数。3.2 封装成函数让调用方不用记公式我给团队里的项目封装过一个非常简单的 Python 函数def manhattan_distance(point_a, point_b): 计算二维平面上的曼哈顿距离。 point_a, point_b 格式: (x, y) x1, y1 point_a x2, y2 point_b return abs(x1 - x2) abs(y1 - y2) robot_pos (3, 5) target_pos (7, 2) print(manhattan_distance(robot_pos, target_pos)) # 输出 7这个封装的收益在于调用方不需要知道曼哈顿公式是绝对值相加只要传入两个同格式的坐标点就能得到距离。后续如果地图从二维网格升到三维比如楼层导航你只需要改函数内部所有调用点的行为都会同步更新。我再补充一个细节函数里用了解包x1, y1 point_a这要求外边传入的 point_a 必须严格是长度为 2 的可迭代对象。如果你传入的坐标是列表 [3, 5]一样可以解包但如果哪天传入一个字符串 35代码就会在你完全没意料到的地方报错。所以正式项目里最好再加一个类型检查或在文档字符串里写明坐标格式否则别人接手你的代码时很容易用错。3.3 批量计算面对一堆任务点的时候别写循环嵌套真实调度场景里机器人和任务点往往不止一组。比如扫地机器人需要知道它和当前楼层 20 个待清扫区域之间的距离这时候你当然可以一遍遍调用上面的函数但更推荐用列表推导式或循环一次性生成“距离清单”robot (3, 5) tasks [ (7, 2), (1, 4), (6, 8), ] for index, task in enumerate(tasks): dist manhattan_distance(robot, task) print(f任务点 {index 1}: 坐标 {task}, 曼哈顿距离 {dist})这段代码跑出来的结果会是任务点 1: 坐标 (7, 2), 曼哈顿距离 7 任务点 2: 坐标 (1, 4), 曼哈顿距离 3 任务点 3: 坐标 (6, 8), 曼哈顿距离 6批量计算的价值不只是省几行代码而是让任务分配逻辑可以直接基于这个距离清单排序“先安排最近的任务点再安排远的”。我项目里就是这么做的先把所有任务点按曼哈顿距离从小到大排序再配合机器人的电量阈值做过滤调度问题就被拆解成了一个排序问题。3.4 扩展到三维甚至更高维机器人在楼层之间移动如果机器人还能在楼层之间坐电梯移动比如从 1 层的某点跑到 3 层的某点就需要计算三维曼哈顿距离。公式是distance_3d abs(x1 - x2) abs(y1 - y2) abs(z1 - z2)更高维也可以写成一个支持任意维度数量的版本def manhattan_distance_md(point_a, point_b): return sum(abs(a - b) for a, b in zip(point_a, point_b)) # 二维 print(manhattan_distance_md((3, 5), (7, 2))) # 7 # 三维 print(manhattan_distance_md((3, 5, 1), (7, 2, 3))) # 4 3 2 9不过我要提醒一句不要盲目把“越高维越好”当成真理。在三维物理空间里如果机器人不是被限制在网格上移动那么曼哈顿距离会严重高估实际飞行或行驶距离。三维曼哈顿只适合“楼道电梯”“货架层垂直升降机”这类严格分轴运动的场景。用到三维时一定要先确认 z 轴是否真的有对应的物理移动成本否则算出来的数字会失真。4. 距离算对不等于规划做好顺序、坐标系与边界三种坑4.1 距离值相同实际路线却可能完全不同这是我踩过比较有意思的一个坑。曼哈顿距离只告诉你“至少需要 7 步”但并不会告诉你“具体怎么走这 7 步”。从 (3,5) 到 (7,2)总共有 35 种不同的“先右再下”组合顺序下面只是其中三条路径一先向右走 4 格到 (7,5)再向下走 3 格到 (7,2)长度是 437路径二先向下走 3 格到 (3,2)再向右走 4 格到 (7,2)长度也是 347路径三向右 2 格、向下 1 格、再向右 2 格、再向下 2 格每一步都算上长度依然是 7。同样是 7这三条路径经过的网格完全不一样。如果地图上有障碍物某条长度最短的路可能会被墙挡住机器人就得绕更远但距离公式本身不会告诉你任何障碍信息。所以我后来在项目里都会强调曼哈顿距离适合作为“代价估算”或“启发式”而不能替代真正的寻路算法。它只是一个下界或参考值实际的可行路径还需要靠 A*、Dijkstra 这类算法去栅格地图里搜索。4.2 坐标系方向反了、单位不一致距离照样算错绝对值能解决“谁减谁”的问题但解决不了“坐标系不对齐”的问题。举个例子在屏幕或图像坐标里y 轴通常向下为正在我们常用的笛卡尔平面直角坐标系里y 轴向上为正。同一个点在不同坐标系里坐标值完全不同。如果你把机器人坐标用 A 地图读出来任务点坐标用 B 地图读出来哪怕两边都是“正坐标”得到的曼哈顿距离也可能跟真实运动距离毫无关系。更隐蔽的问题还有单位一格到底代表 1 米还是 1 厘米地图缩放倍数不同坐标数值相差很大但距离公式永远只会机械地做绝对值相加。我在实际项目里习惯写一个简单自检函数把机器人的当前位置和任务点坐标从同一个地图接口读取打印出原始坐标和差值人工看一眼方向是否合理。比如任务点在机器人的右下方那期望看到 dx 为正、dy 为负如果打印出来 dy 也是正说明两个点的坐标系来源很可能混了。距离数值会骗人但坐标差的方向不会。4.3 大数值坐标、浮点误差和“零距离”的特殊情况还有一个容易忽略的问题坐标值很大时整数溢出。在 C 里如果坐标是 32 位 int两个大数相减后绝对值理论上可能超过 2^31-1比如一个坐标在(2_000_000_000, 0)另一个在(-2_000_000_000, 0)差值绝对就是 4_000_000_000直接用 int 存就会溢出。解决方案很简单计算差值时用 long long、double 或任意精度整数。如果坐标是浮点数曼哈顿距离也可能有浮点误差虽然绝对值相加只涉及加减法误差很小但累计多次距离后还是可能漂移。我建议在比较两个距离是否相等时别用而是用一个小阈值比如abs(d1 - d2) 0.001。最后还有一种特殊情况两点坐标完全相同。此时曼哈顿距离是 0代码没问题但业务逻辑要小心比如机器人和目标点重合还继续下发“前往该任务点”的指令就属于逻辑冗余了。我在调度代码里碰到 dist 0 时会直接跳过任务省电也省时间。5. 用一个完整示例验证从起点到多个任务点的距离清单5.1 手算一遍建立对数字的直觉纸上谈兵再多不如拿个真实小例子验证。假设我们机器人起点是 (3,5)要评估三个任务点我通常会先手算一张表再去对程序输出任务点x 轴差值y 轴差值曼哈顿距离(7,2)7-342-5-3绝对值 3437(1,4)1-3-2绝对值 24-5-1绝对值 1213(6,8)6-338-53336手算表的价值在于你可以快速判断哪个任务点离起点最近。这里明显是 (1,4) 距离最近只有 3。但要注意最近的未必是“最优完成顺序”因为实际路径还要考虑障碍物、机器人朝向、任务优先级。距离排序只是一个很好用的初筛维度。5.2 用代码输出同样的表比对两边结果我平时会写一段验证脚本把表里的每个字段都打印出来而不是只打印最终距离。打印差值能让你一眼看到符号是不是正常robot (3, 5) tasks [(7, 2), (1, 4), (6, 8)] print(起点:, robot) print(任务点 | dx | dy | 距离) for task in tasks: dx task[0] - robot[0] dy task[1] - robot[1] dist abs(dx) abs(dy) print(f{task} | {dx} | {dy} | {dist})输出起点: (3, 5) 任务点 | dx | dy | 距离 (7, 2) | 4 | -3 | 7 (1, 4) | -2 | -1 | 3 (6, 8) | 3 | 3 | 6对表里每个点dx、dy 的符号代表了机器人该往哪两个方向走。比如 (1,4) 的 dx 是 -2说明任务点在机器人左边dy 是 -1说明任务点在机器人下方或 y 轴负方向。看到这种钉子符号你才能确认坐标读进来之后没有发生轴翻转。5.3 验证时最有用的调试方法打印原始输入和中间差值很多调试不顺的时候问题根本不在曼哈顿计算公式而在数据源头。传感器或地图接口偶尔会返回 null、NaN 或者颠倒好的坐标而公式照样能算出一个数字。比如 y 坐标被传成 null在某些语言里会被强制转成 0距离结果看起来“合理”实际上完全错误。所以我调试时有一个死习惯任何距离计算前先把两个点的原始坐标打出来再看 dx、dy然后才看最终距离。不要怕日志刷屏这种信息在排查“机器人为什么突然把自己规划到地图外面”的时候能救你一命。加日志的成本极低而跑一遍完整路径模拟的时间成本高得多。6. 实战中什么时候选曼哈顿什么时候换成欧氏或切比雪夫6.1 四方向网格、轴对齐运动曼哈顿是默认选择如果地图被抽象成方格机器人只能上下左右移动那么曼哈顿距离几乎就是“最准确的最短路径下界”。在 A* 寻路算法里它之所以广受欢迎是因为它满足“可采纳性”任何情况下估算值都不会大于真实最短路径长度从而保证 A* 找到的最终路径是最优的。这类场景我见过很多仓储机器人沿货架通道移动、扫地机器人沿瓷砖缝走、电路板布线避开斜线等。曼哈顿距离在这些领域表现极稳代码又轻性能开销只有几次减法和绝对值比开平方快得多。在几百个任务点的实时调度里这种性能差距是能感知到的。6.2 八方向移动、斜穿无阻挡区域曼哈顿会高估距离一旦机器人允许斜向移动比如八方向网格或者开阔平地上可以自由转弯曼哈顿距离就会高估真实距离。此时欧几里得距离更接近实际但如果你只想在网格里快速估算也可以使用切比雪夫距离或者给曼哈顿公式加一个系数def octile_distance(point_a, point_b, diagonal_cost1.414): dx abs(point_a[0] - point_b[0]) dy abs(point_a[1] - point_b[1]) return max(dx, dy) (diagonal_cost - 1) * min(dx, dy)但这个函数已经算不上“纯曼哈顿距离”了而是混合距离。如果你用 A* 做八方向寻路启发式也必须跟着换否则估算法过高算法可能会绕过真正最优路径。我见过有人做了八方向地图却继续用纯曼哈顿结果规划出来的路径总是多绕一步调了一整天才发现是启发式函数和移动成本不匹配。6.3 机器人的朝向、加速度也会影响距离选择我最后一次想聊的实战坑是机器人运动模型不只看“能不能斜走”还要看“转个弯要花多少代价”。差速驱动机器人可以原地转方向转向代价相对小车式机器人则需要更大的转弯半径曼哈顿距离和实际路径就差得更多。此时单纯的曼哈顿距离只适合做粗略估价还需要额外考虑转向惩罚。我在做清扫机器人调度时最终采用的做法是两层距离并用第一层用曼哈顿距离快速筛选出候选任务点把范围从 30 个缩到 5 个第二层再对这 5 个候选做带障碍和转向代价的路径搜索找出真正可行的执行顺序。这样既保住了曼哈顿距离的性能优势又避免了它“不考虑障碍”的天然短板。如果你也在做类似调度不妨试一试这种“粗筛 精排”的组合思路。
RELATED

相关推荐

Vite打包常见报错与解决方案:从内存溢出到体积优化全记录

Vite打包常见报错与解决方案:从内存溢出到体积优化全记录

Vite用久了你会发现一个规律:开发环境(dev server)跑得飞起,一旦执行npm run build,各种奇奇怪怪的问题就冒出来了。不是内存溢出,就是资源路径不对,再不然就是打包体积大得离谱,警告…

📅 2026/10/19 5:55:43
diagram-design:从随手画图到系统性图表设计,告别技术债

diagram-design:从随手画图到系统性图表设计,告别技术债

1. 从一张草图到一套系统:diagram-design 到底在解决什么问题很多人第一次听到 diagram-design 这个词,会下意识觉得它只是“画图”的另一种说法。但真正在项目里被图表折磨过的人知道,画图本身从来不是难点,难点在于图表的可维护…

📅 2026/10/19 5:50:43
百度地图API批量地址转坐标:Excel处理与坐标系避坑指南

百度地图API批量地址转坐标:Excel处理与坐标系避坑指南

简介:面向Web开发与GIS数据处理场景的百度地图API地址批量转换工具,基于前端页面实现Excel表格上传、地理编码批量解析与经纬度回填,同时涉及GCJ-02、BD-09等坐标系转换与地图撒点展示,适合需要处理大量地址数据的产品、运营或开发…

📅 2026/10/19 5:50:43
MORE NEWS

更多资讯

📰

YOLO26人脸检测门禁系统:从数据到部署的完整实践指南

1. 项目核心:为什么门禁系统偏偏选YOLO26做门禁人脸识别,市面上方案很多,从最传统的指纹刷卡,到基于人脸关键点定位的经典方法,再到端到端的深度学习方案。但这几年真正能在“精度、速度、部署成本”三者之间取得平衡的…

📰

S7-200 SMART自由口通讯全解析:从接线到轮询例程

做设备调试这几年,我经常碰到一个有点尴尬的局面:现场设备只给了一个RS485口、一份几十页写着“自定义协议”的文档,要么是仪表、扫码枪、LED屏,要么是某个老款变频器,厂家只肯说“我们走串口,支持读写寄存…

📰

多传感器融合智能小车实战:从串口协议到PID闭环设计

做智能小车这个项目之前,我一直觉得堆硬件是件很"爽"的事——超声波买三个、循迹买八路、陀螺仪也安排上,仿佛传感器越多车就越聪明。真到了联调那天才发现,传感器越多,打架的机会越多,数据越乱,…

📰

LabVIEW中CRC-16校验码计算VI的实现与排查指南

做LabVIEW上位机联调的工程师,大概率都经历过这样一个下午:下位机明明把数据发回来了,串口助手也显示得清清楚楚,可程序里的VI就是报校验失败。我最近就陪A同学排查过一晚上这种问题——温度采集仪用的Modbus RTU协议,…

📰

三维弹性问题PINN实战:从网络结构到优化器调试全记录

做三维固体力学问题的物理信息神经网络(PINN),如果上手试过,大概率会碰到这样几个现象:训练几百轮loss卡在某个下不去的值、边界上位移很准但域内应力乱跳、一算二阶导数计算图和梯度双双失控。这些坑我都踩过&#xf…

📰

多功能表单源码系统:打通信息收集、预约与收款闭环

我现在做的这个“多功能表单源码系统”,说白了就是把信息收集、客户预约和线上收款这三件事,塞进一套统一的后台里,用一个表单搞定从“用户填单”到“客户付钱”再到“商家收款”的完整链路。如果你经营的是咨询工作室、兴趣培训班、家政服务…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬