1. 先想清楚调度系统到底在解决什么问题
1.1 为什么说调度才是AGV项目的灵魂
AGV调度系统这四个字,在项目立项书里出现频率极高,但理解深度差别很大。我接触过的不少项目,前期预算和时间都砸在车体硬件和导航算法上,调度系统被当成“最后加一个软件模块”来处理,结果到了现场联调阶段,问题几乎全部集中在这个模块上:两辆车在交叉口互等、任务优先级混乱导致急单被反复插队、低电量车辆堵在通道正中间。这些都不属于单机导航的范畴,而是调度策略没有设计好。
调度系统解决的是“多车、多任务、复杂环境下的协同决策”问题。单台AGV只需要走到指定位置,多台AGV在同一张地图上运行,就要额外考虑路权分配、任务匹配、充电时机、异常接管。把这个系统比作城市交通指挥中心,单机导航相当于每辆车的司机,而调度系统就是红绿灯、交警、调度台和事故处理中心的综合体。没有调度系统,AGV数量一多,现场很快就会陷入“车多路堵、任务挤兑、互相死锁”的混乱状态。
这篇文章主要写给正在做AGV集成项目、准备选型或自研调度系统、以及刚接手AGV运维想摸清系统逻辑的同行。我会从整体设计讲到具体参数配置,把我在几个现场项目中踩过的坑和实际验证过的做法都写出来。文中涉及的具体项目案例,我会统一用代称描述,重点在于思路和方法,而不是特定产品。
提示:理解调度系统的第一件事,是把“调”和“度”分开看。“调”解决的是任务怎么分配,谁去干什么;“度”解决的是车在路上怎么走,谁先谁后。两者互相影响,但思维模型完全不同。
1.2 架构选型:集中式还是分布式
调度系统第一步要定的不是算法,而是架构。常见架构有两种:集中式和分布式。集中式调度由一台调度服务器统一维护全图车辆状态和任务队列,所有AGV通过无线通信上报位置、接收指令;分布式调度则把决策能力下沉到每台车或区域节点,节点之间协商路权和任务归属。
实际项目中,绝大多数场景我用的是集中式,核心原因在于状态一致性。调度系统涉及任务、路径、路权、车辆位置、站点占用等多个状态,如果这些状态分散在多节点,一致性问题会变得极其复杂。两辆车同时申请同一个路段时,分布式节点之间如果靠实时通信协商,时延和节点故障都会成为隐患。集中式系统虽然存在单点故障风险,但可以用主备热备加快速切换来兜底,这是工程上比较成熟的组合方式。
规模上我的判断是:单图车辆数在50台以内,集中式完全够用;超过50台,或者厂房跨区域、多个独立车间需要整体联动时,才值得认真考虑分层分布式——上层总控做任务分解和跨区协调,下层区域调度做本区车辆的路权与路径管理。盲目上分布式,只会增加调试成本,并不会带来效率提升。
1.3 五大核心模块与数据模型
拆开来看,一套AGV调度系统通常包含五个核心模块:任务管理、车辆管理、路径规划、交通管制、地图数据服务,再加通信协议和状态监控作为底层支撑。
- 任务管理:接收上层系统(如制造执行系统、仓库管理系统)下发的任务,做合并、拆分、优先级排序。
- 车辆管理:维护每台车的实时状态,包括位置、姿态、电量、当前任务、故障状态。
- 路径规划:根据起点和终点计算行进路线,并处理路径变更。
- 交通管制:负责路段锁、交叉口避让、死锁检测和恢复。
- 地图数据服务:给所有模块提供几何拓扑和站点信息。
模块之间流通的是三类数据:地图数据、任务数据、车辆状态数据。地图数据我建议用节点-边模型来建模,节点代表站点、交叉口、充电桩等关键位置,边代表可通行路径,每条边要带长度、限速、方向属性。任务数据至少要包含任务ID、优先级、起点、终点、预计完成时间、当前状态。车辆状态则要有精确位置、实时电量、速度、异常码、任务绑定关系。这三类数据缺一不可,数据结构设计好,后面写调度算法会省掉大量返工时间。
2. 核心机制拆解:任务、路径与通信链路
2.1 任务状态机与全生命周期管理
任务调度是我认为整个系统里最容易做乱的部分。一个任务从创建到结束,必须经历明确的状态流转。我在项目里常用的状态序列是:待分配、已分配、正在行驶、到达取货点、取货完成、正在运送、到达放货点、卸货完成、已完成。中间任何一个环节超时或执行失败,都要转入异常状态,并触发重试或告警。
为什么要这么精细化?因为任务状态是调度系统判断后续动作的依据。车辆行驶到取货点时,如果任务状态没有得到确认,调度器就可能重复分配同一任务,或者某台车卡在“正在行驶”却没有实际动作。我踩过的最典型的一个坑是:任务状态只分“执行中”和“完成”两种,某台车因为货物位置超差需要重新定位,系统仍然认为它在正常执行,结果后面的车在同一个站点排了一长队。后来所有任务都拆成细粒度状态机,每个状态变更都记录时间戳,这个问题才彻底解决。
任务分配策略上,最朴素的做法是“就近分配”,取货距离最短的车先接单。但实际运行中这个策略缺陷明显:如果一辆车电量低于返回充电桩的阈值,它近也跑不了;如果所有车都集中在同一片区域,远处任务的响应时间会被无限拖长。我比较推荐加一层加权评分,综合任务优先级、车辆距离、剩余电量、当前任务负载,得分最高的车接单。评分权重不是一成不变的,现场调试时可以根据瓶颈方向调整——追求吞吐量就加大距离权重,追求响应及时性就加大优先级权重。
2.2 路径规划与路权控制的协同逻辑
路径规划是调度系统都会涉及的模块,但工程实现和教科书差别很大。理论上讲,Dijkstra和A*都是经典寻路算法,实际项目中我更倾向于先基于地图拓扑做路由表预处理,把常用站点间的静态最优路径先算好存起来,运行时直接查询,再结合实时路况做局部微调,而不是每次任务都从头全图寻路。原因很简单:AGV地图规模通常不大,但任务并发量大,每次实时全图寻路在任务高峰期会成为明显瓶颈。
比路径规划更关键的是路权控制。路径算出来只是一条路线,车在实际行驶中能不能顺利走完,取决于交通管制模块怎么分配和释放路段锁。实际项目里我常用的做法是:把每条路段设计成互斥资源,一辆车进入前先申请锁,离开后才释放;交叉口和窄通道设置独立的临界区,车辆通过前必须获取该临界区的独占锁。这种机制的思路来自操作系统的资源管理,只不过资源从内存变量变成了物理路段。
这里要区分三种锁:路段锁管一段可通行路径,站点锁管取放货位的占用状态,充电桩锁管充电位预约。三种锁的粒度、超时时间和释放条件都不同,混在一起处理容易出逻辑漏洞。我建议在代码层面也分开建模,避免“一把锁通用所有场景”的偷懒设计。
2.3 通信链路与数据同步的工程细节
调度系统运行得稳不稳,通信链路的质量往往是被低估的因素。AGV常用的无线通信方式包括Wi-Fi和工业无线专网,核心指标是端到端时延和漫游切换时间。现场常有这种状况:车在A区运行正常,走到B区拐角时位置突然跳变,查看日志发现那一瞬间无线通信中断了几百毫秒,车辆位置没有及时上报,调度系统还在按旧位置做决策,指令发出去也收不到。
我的常规做法是三层保障。第一层,车辆端位置上报频率不低于10Hz,调度端对位置做缓存和插值,短时间丢包不影响位置连续性;第二层,所有关键指令采用请求-确认机制,车辆执行完指令必须回执,调度端没有收到回执就触发超时重发;第三层,车辆和调度端保持心跳,超过设定时间没有心跳就判定通信异常,车辆进入安全停车状态。这三层看起来简单,但确实解决了很多莫名其妙的调度错乱问题。
注意:时间同步很重要。车辆端事件日志和调度端日志如果时间基准不一致,排查问题时根本对不上号。我一般要求车辆端统一通过NTP与调度服务器同步,所有日志记录精确到毫秒级。
3. 落地实操:从地图标定到性能调参
3.1 地图制作与站点标定的经验
调度系统的地图和AGV导航用的地图不是同一个概念。导航地图关注的是环境几何特征,调度地图关注的是通行拓扑和逻辑位置。实操中我会先把现场CAD图纸转成基础坐标系,在图上标记出所有站点、交叉口、通道、充电桩,然后人工基于这些信息画节点和边。节点之间的距离和转弯半径必须和实际车辆的物理参数对齐,否则调度系统规划出来的路径看着合理,车实际走不过去。
站点标定是最容易被忽视的环节。每个站点的坐标直接决定任务执行准确性,现场实测坐标和图纸坐标之间往往存在偏差,必须在现场逐一核对。我的习惯是:地图初步制作完成后,逐站点派一辆车去实际定位,把实际到位坐标和地图坐标的偏差记录成一张校准表,再统一修正。某项目里曾出现取货偏差超过10厘米的情况,排查发现是一排站点在图纸上标注的位置和现场货架实际位置差了将近半米——货架被挪动过,图纸没更新。这种问题只有实地复核才能发现。
地图属性也要提前设计好:每条边要标识是否单向、是否允许双向、是否有速度限制、是否配置了避让点。窄通道上的边如果漏标单向属性,调度系统规划路径时把双向车都放进去,现场就会在通道中间顶牛。
3.2 多车协同通过窄通道的交通管制配置
窄通道场景是交通管制设计里最常见的需求。假设现场有一段单向通行通道,通道中段无法会车,高峰期七八辆车都要经过。如果只依赖路段锁,车辆会在通道两端排队,逻辑上没毛病,但整体通行效率很难看。我常用的配置是在通道两端各设一个等待点,调度系统只在确认通道另一端的出口路段空闲时,才放行下一辆车进入。
这里有一个参数必须认真调:通道占用超时时间。如果一台车进入通道后因为障碍物停车等待,占用超时一到,调度系统要生成告警,并切换通道放行模式。超时时间设太短,正常通行也可能误报;设太长,故障车会把通道堵死。我的经验值是按通道长度和车辆限速计算理论通行时间,再乘以1.5到2的系数作为超时阈值。比如通道长80米,车辆速度1米/秒,理论通行时间80秒,阈值设在120秒到160秒比较稳妥。
交叉口处理是另一个重点。多车道的交叉口,我会引入“交叉口控制器”概念:交叉口同一时间只允许一台车通过,车辆进入前必须申请交叉口控制器的独占权,完全驶离交叉口范围后才释放。逻辑上等价于给交叉口加了一把排他锁,简单有效。
3.3 调度性能调参与效果观测
调度系统上线后,真正的难点是性能调优。我习惯用三个核心指标衡量调度质量:任务平均完成时间、车辆平均利用率、任务按时完成率。这三个指标从吞吐、负载、时效三个维度刻画运行状态。调优不是拍脑袋,先看数据,定位瓶颈在任务分配、路径规划还是交通管制,再动手改参数。
举个例子,某项目现场任务是固定的搬运循环,车辆利用率数据显示所有车的利用率都在50%左右,但任务平均完成时间偏长。从日志里按车辆维度拆解,发现有一类任务需要跨越两个作业区,必须经过一段上下坡通道,而这段通道的通行优先级排得比较低,大量车在通道口等待。找到瓶颈后,我调整了通道请求的优先级加权,把跨区任务的路径请求权重提高,该场景下任务平均完成时间从约12分钟下降到了8分钟。
| 指标 | 计算方式 | 用途 | 建议观测频率 |
|---|---|---|---|
| 任务平均完成时间 | 所有已完成任务的耗时均值 | 判断整体响应水平 | 每日 |
| 车辆平均利用率 | 车辆执行任务时间 / 总运行时间 | 判断负载是否均衡 | 每周 |
| 任务按时完成率 | 按时完成数 / 总任务数 | 判断时效稳定性 | 每日 |
注意,利用率不是越高越好。利用率长期超过85%,说明车辆几乎没有冗余,一旦出现故障或充电需求,整个系统吞吐会断崖式下跌。我一般建议把利用率峰值控制在70%到80%之间,留出应对波动的余量。
4. 现场问题排查与避坑实录
4.1 两车死锁问题
两车死锁是AGV调度系统上线初期最高频的问题,表现是两辆车在交叉口或窄通道面对面互等,谁也不让。原因通常是路权分配逻辑里缺少统一的资源申请顺序。解决思路我总结为三步:
- 在交通管制层保证所有车辆申请路段锁的顺序一致,避免形成循环等待;
- 给每条路段的锁加超时,超过一定时间强制释放并触发重规划;
- 系统级增加死锁检测,定时扫描所有车辆状态,如果检测到循环等待环路,指定优先级低的一方后退到避让点。
实操时最需要注意的是:强行释放锁可能造成车辆位置状态和实际位置不一致。所以在执行“强制解锁”前,我会先要求车辆做一次到位确认,确认车辆确实停在安全位置,再做锁释放。跳过这一步,后续任务指派就会出现位置错乱。
4.2 任务饥饿与分配不均
任务饥饿的表现是某些低优先级任务长时间得不到执行,部分车辆空闲,部分车辆超负荷。常见原因是贪心式分配——调度系统总是把新任务派给距离最近或负载最轻的车,导致某些区域的任务一直被“忽略”。解决方案有两个策略:一是给任务增加“等待时间老化因子”,等待越久优先级越高,保证不会饿死;二是分配时机优化,不是有任务就立即分,而是攒一个小批次,每隔几秒统一做一次分配。
实际项目中我遇到过一种情况:某区域有5辆车,但任务点集中在地图边缘的同一站点,调度系统始终把任务派给离站点最近的那辆车,其他4台一直空闲。加装了老化因子后,等待超过3分钟的任务优先派发给空闲车辆,虽然单程距离远了一些,整体吞吐量反而明显提升。这类问题靠参数调整就能解决,但前提是任务表里要记录任务创建时间,并支持动态优先级修正。
4.3 位置跳变与任务中断
位置跳变是另一个高频问题。表现为车辆在实际运行途中,调度界面上的位置突然跳到另一个地方,随后任务中断或车辆停驶。原因通常是定位数据短暂丢失后的误差累积、轮子打滑或无线通信延迟。排查时先看车辆端和调度端的日志时间线:如果车辆端位置正常但调度端跳变,问题大概率在通信或数据上报链路;如果车辆端本身位置就跳变,问题在定位系统本身。
缓解手段包括:增加二维码或反光板等绝对定位校正点、对上报位置做滤波处理、设置位置跳变阈值,超过阈值判定为无效定位并要求车辆原地重新定位。工程上的一个实用细节是:位置上报数据里带一个“定位置信度”字段。车辆定位精度差时,调度端可以据此降低该车参与任务分配的评价权重,避免把关键任务派给正在定位漂移的车辆。
4.4 低电量充电调度与充电桩占用管理
AGV运行到低电量时怎么处理?如果只是简单让车辆停止运行,系统吞吐量会断崖式下降;如果同时让所有车都跑去充电,充电桩又会排长队。充电调度需要考虑两个问题:充电时机和充电位分配。
充电时机上,我给每台车设置了一个动态返航电量阈值,综合考虑当前任务剩余路径长度、当前位置到最近充电桩的距离、电量消耗速率三个因素计算,而不是等电量低于固定百分比才去充电。比如一辆车正在执行长距离搬运任务,即使当前电量还有30%,也可能触发返航充电,因为按剩余路径和空驶回充电路径计算,30%根本不够跑完。
充电桩占用管理同样重要。我会为每个充电桩加“状态锁”,充电桩一旦被预约,其他车辆只能排队等待。同时调度系统要区分“充电中”和“充电完成待离场”两种状态,避免充电完成后车辆一直占用充电位,影响后续排队车辆的充电节奏。
做AGV调度系统这几年,我最大的体会是:这类系统真正难的地方从来不是某个算法的先进性,而是对边界情况的处理是否足够周全。地图坐标偏差、通信抖动、任务状态流转遗漏、充电桩占用冲突,每一个单独看都是小问题,但叠在一起就会把系统压垮。调试阶段我坚持一个原则:先跑通所有常规流程,再用异常注入的方式,逐个测试系统对故障场景的反应。这个过程中会暴露很多正常联调时看不到的问题,改完之后系统的稳定性会有明显提升。
最后分享一个小技巧:无论是自研还是选型,一定要让系统具备完整的轨迹回放能力。任务时间戳、车辆位置点、指令记录、异常事件全部落盘,出了问题能够精确回放到某个时间点,看车辆当时在什么位置、收到了什么指令、为什么没有执行。这个能力在项目交付初期的价值,比任何花哨的算法都高。把它提前设计进系统,后续的调试、培训和运维都会省掉大量时间。