简介:这份文档面向电子设计竞赛参赛者、自动化与物流工程专业学生及AGV研发入门人员,系统讲解基于自动导向车的自动化物流系统设计。内容围绕省TI杯大学生电子设计竞赛赛题展开,涵盖设计任务与要求、中央处理器选型、动力与转向系统、引导方式、装卸货点检测、障碍物探测等方案比较与论证,并给出硬件电路、黑白线信息采集与停车标识识别、自动循迹控制、智能充电、声光报警等模块设计,以及主程序、装卸货和充电模块的软件流程与系统测试方法。资源包共1个doc文件,约889KB,结构完整、目录清晰,便于按章节查阅。已有95人学习。读者可借此掌握AGV自动装载、搬运、卸载与智能充电的完整实现思路,获得可直接参考的竞赛方案与工程化设计框架。
1. 从一台 AGV 趴窝说起:自动化物流系统设计说明到底要写清什么
车间里三台 AGV 同时停在交叉路口,调度屏上三条任务链全部卡死,现场工程师拿着对讲机喊「谁把 3 号车手动开走了」——这是我见过最典型的自动化物流系统翻车现场。问题不在单车,而在系统设计说明里根本没写清路权分配和异常接管流程。所谓「基于 AGV 的自动化物流系统设计说明」,本质是一份把自动导向车、调度系统、路径规划、任务分配、异常处理串成闭环的工程文档,它要回答的不是「AGV 怎么跑」,而是「多台 AGV 在同一个场地里怎么不打架、怎么在故障时优雅降级」。这份文档面向的是产线物流改造的落地工程师、系统集成商和厂内物流负责人,核心价值在于让调度算法、通信协议、安全逻辑在纸面上先跑通一遍,避免现场调试时才发现路径冲突、任务死锁、充电桩排队这些血泪坑。热搜里常出现的「agv调度系统」「agv协同」「三条agv基本a*算法」,其实都指向同一个诉求:用可复现的规则把多车协同讲明白,而不是堆一堆参数表就交差。
2. 设计说明的第一块硬骨头:AGV 选型与场地约束怎么落到纸面
2.1 从载重和巷道宽度反推车型,而不是先选车再改场地
很多设计说明一上来就写「选用潜伏顶升式 AGV 若干台」,这是典型的倒果为因。我一般会先拉三组数据:最大载重单元重量、托盘/料车尺寸、巷道最小净宽。载重决定驱动轮功率和电池容量,料车尺寸决定顶升盘或牵引机构的适配方式,巷道净宽决定 AGV 本体宽度加上安全余量后的最小转弯半径。常见做法是留出单侧 150mm、双侧 300mm 的安全间隙,如果巷道宽度小于 AGV 对角线长度的 1.2 倍,就必须考虑单向行驶或错车岛设计。
设计说明里要落一张约束表,而不是一段文字描述。下面这张表是我在多个项目里反复用到的模板,参数需要根据现场实测填写:
| 约束项 | 符号 | 典型取值 | 对系统的影响 |
|---|---|---|---|
| 最大载重 | W | 500kg / 1000kg / 1500kg | 决定驱动功率与电池规格 |
| 巷道净宽 | L | 实测值,单位 mm | 决定是否单向行驶 |
| 最小转弯半径 | R | 车型手册值 | 决定路口设计 |
| 充电桩数量 | N | 按 AGV 数量 1:3 配置 | 决定排队策略 |
| 通信周期 | T | 100ms~500ms | 决定调度实时性 |
这张表填完,车型基本就锁定了。如果载重 1000kg、巷道净宽 1800mm、转弯半径 1200mm,那基本只能选潜伏顶升式,且路口必须做圆角处理。设计说明里要把这些推导过程写出来,而不是只给结论,否则施工方改一个参数,整个系统就要重算。
2.2 用 A* 算法做单车路径规划,但设计说明要写清栅格粒度
热搜里「三条agv基本a算法」这个说法很实在,A确实是 AGV 路径规划最常用的基础算法。但设计说明里不能只写「采用 A* 算法」,必须写清栅格地图的粒度、启发函数的选择、以及拐点平滑策略。栅格太大,路径贴墙走,安全余量不够;栅格太小,计算量爆炸,调度周期跟不上。我一般按 AGV 本体宽度的 1/2 到 1/3 来设栅格边长,比如车宽 600mm,栅格取 200mm~300mm。
下面是一个最小可复现的 A* 路径规划代码片段,用于在设计说明里验证单车路径是否合理:
import heapq def a_star(grid, start, goal): # grid: 0 可通行, 1 障碍物 # start/goal: (row, col) rows, cols = len(grid), len(grid[0]) open_set = [(0, start)] came_from = {} g_score = {start: 0} f_score = {start: heuristic(start, goal)} while open_set: _, current = heapq.heappop(open_set) if current == goal: return reconstruct(came_from, current) for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]: neighbor = (current[0]+dr, current[1]+dc) if not (0 <= neighbor[0] < rows and 0 <= neighbor[1] < cols): continue if grid[neighbor[0]][neighbor[1]] == 1: continue tentative_g = g_score[current] + 1 if tentative_g < g_score.get(neighbor, float('inf')): came_from[neighbor] = current g_score[neighbor] = tentative_g f_score[neighbor] = tentative_g + heuristic(neighbor, goal) heapq.heappush(open_set, (f_score[neighbor], neighbor)) return None def heuristic(a, b): # 曼哈顿距离,适合四向移动 return abs(a[0]-b[0]) + abs(a[1]-b[1]) def reconstruct(came_from, current): path = [current] while current in came_from: current = came_from[current] path.append(current) return path[::-1]这段代码的逻辑说明:grid是二维栅格地图,0 表示可通行,1 表示障碍物;heuristic用曼哈顿距离,因为 AGV 通常只做四向移动,如果用八向移动就要换成对角距离。参数说明:栅格边长直接决定grid的尺寸,200mm 栅格下 100m×50m 的场地就是 500×250 的矩阵,A* 单次搜索在普通工控机上大约 10ms~50ms,完全能满足 100ms 调度周期。设计说明里要写清这个换算关系,否则调度周期和栅格粒度对不上,现场就会出现「路径算不完,车已经到路口」的尴尬。
2.3 多车协同不是把 A* 跑三遍,而是做时空联合约束
三条 AGV 各自跑 A* 没问题,但三台车同时跑就会在交叉路口撞上。设计说明里必须引入时间窗或预约机制。常见做法有两种:一是把路径按时间切片,每个栅格在特定时间段内只允许一台车占用;二是用交通管制规则,路口设虚拟信号灯,AGV 到达路口前先申请路权。前者适合路径固定的场景,后者适合路径动态变化的场景。
我一般会在设计说明里画一张时空占用表,而不是流程图。比如三台车在 t=0 到 t=10s 内,各自占用哪些栅格,冲突点在哪里,怎么错开。这张表比任何文字描述都管用,施工方一看就知道路口该怎么布传感器。
3. 调度系统设计说明的核心:任务分配、通信协议与异常降级
3.1 任务分配用「最近空闲车 + 负载均衡」双因子,别只写最近
很多设计说明里任务分配只写「选择距离最近的空闲 AGV」,这在三台车场景下就会出问题:三台车都往同一个取货点跑,结果两台空跑。我一般用双因子评分:距离因子占 70%,负载因子占 30%。负载因子可以是当前任务队列长度,也可以是电池电量。电量低于 30% 的车直接不参与新任务分配,优先去充电。
设计说明里要给出评分公式和权重,而不是一句「智能分配」。下面是一个可落地的评分逻辑:
def score_agv(agv, task): # distance_score: 距离越近分越高,归一化到 0-1 max_dist = 100.0 # 场地最大对角线距离,单位米 dist = manhattan_distance(agv.position, task.pickup) distance_score = 1 - min(dist / max_dist, 1.0) # load_score: 队列越短分越高 max_queue = 5 load_score = 1 - min(len(agv.task_queue) / max_queue, 1.0) # battery_score: 电量低于 30% 直接淘汰 if agv.battery < 0.3: return -1 return 0.7 * distance_score + 0.3 * load_score逻辑说明:manhattan_distance用曼哈顿距离而不是欧氏距离,因为 AGV 走的是直角路径;max_dist和max_queue要根据场地和任务量调整,不能照搬。参数说明:权重 0.7 和 0.3 不是固定的,如果任务量波动大,负载因子权重可以提到 0.4;如果场地特别大,距离因子权重可以提到 0.8。设计说明里要写清调整依据,否则现场一改参数就乱。
3.2 通信协议选 MQTT 还是 TCP 长连接,设计说明要写清心跳和重连
AGV 调度系统最怕通信断连。设计说明里必须写清通信周期、心跳间隔、重连策略、断连后的降级行为。常见做法是调度系统与 AGV 之间用 MQTT,因为 MQTT 支持 QoS 和遗嘱消息,AGV 断连后调度系统能立刻知道。但 MQTT 的 broker 要单独部署,增加一个故障点。如果场地不大、AGV 数量少于 10 台,直接用 TCP 长连接也够用,但必须自己实现心跳和重连。
我一般会在设计说明里写清三组参数:心跳间隔 1s,重连超时 3s,断连后 AGV 原地停车并亮黄灯。调度系统在 5s 内收不到心跳,就把该车标记为离线,任务重新分配。这些参数要写进文档,不能靠现场调试时拍脑袋。
3.3 异常降级:设计说明里最容易被忽略但最值钱的部分
AGV 系统跑起来之后,最常出的不是算法问题,而是异常场景:AGV 被手动挪走、货物掉落、充电桩被占用、网络抖动。设计说明里必须有一章专门写异常降级,而不是只写正常流程。我一般会列一张异常场景表,每个场景对应检测方式、降级动作、恢复条件。
| 异常场景 | 检测方式 | 降级动作 | 恢复条件 |
|---|---|---|---|
| AGV 离线 | 心跳超时 5s | 任务重新分配,该车标记离线 | 心跳恢复且自检通过 |
| 货物掉落 | 顶升盘压力传感器 | 原地停车,呼叫人工 | 人工确认后手动复位 |
| 充电桩占用 | 充电桩状态查询 | 排队等待或换桩 | 充电桩空闲 |
| 网络抖动 | 心跳延迟 > 1s | 降速运行,任务暂停下发 | 心跳恢复正常 |
这张表要写进设计说明,并且每个场景都要有对应的日志记录和告警推送。现场工程师最怕的就是「车停了但不知道为什么停」,有了这张表,排查时间能从半小时降到五分钟。
4. 避坑与排查:AGV 自动化物流系统设计说明里最容易翻车的五件事
4.1 路径规划没留安全余量,AGV 贴墙走导致频繁急停
现象:AGV 在巷道里跑着跑着突然急停,日志显示「障碍物检测触发」,但现场看并没有障碍物。原因:A* 路径贴墙走,AGV 本体与墙面的安全余量小于激光雷达的最小检测距离,雷达把墙面当成障碍物。解决:在设计说明里明确栅格地图要做「膨胀」处理,障碍物栅格向外膨胀 AGV 半径加 100mm,路径只能走膨胀后的可通行区域。这个膨胀参数要写进文档,不能靠现场调。
4.2 充电桩数量按 1:1 配置,结果一半时间在排队
现象:五台 AGV 配五个充电桩,但 AGV 还是经常没电趴窝。原因:AGV 充电不是「一车一桩」就够,还要考虑充电时长和任务间隙。一台 AGV 充电 1 小时,一天工作 20 小时,实际需要 1.5 个充电桩才能轮转开。解决:设计说明里按 AGV 数量的 1:3 配置充电桩,并且写清充电策略——电量低于 30% 强制充电,低于 50% 且任务队列为空时机会充电。这个比例和阈值要写进文档。
4.3 调度周期设成 1s,结果路口还是撞车
现象:调度周期 1s,三台 AGV 还是在路口撞了。原因:调度周期不等于控制周期。调度系统 1s 下发一次路径,但 AGV 底层控制周期是 100ms,两台车在 1s 内可能同时进入路口。解决:设计说明里要区分调度周期和控制周期,路口区域必须做「路权预约」,AGV 到达路口前 2s 申请,调度系统锁定该区域,其他车收到等待指令。这个预约逻辑要写进设计说明,不能只靠调度周期。
4.4 通信断连后 AGV 继续跑,撞上货架
现象:网络抖动,调度系统与 AGV 断连 3s,AGV 继续按最后一条路径跑,撞上货架。原因:设计说明里没写断连降级行为,AGV 默认「保持最后指令」。解决:设计说明里明确写「心跳超时 1s 降速,超时 3s 原地停车」,并且 AGV 本地要有安全逻辑,断连后不能继续执行新动作。这个降级策略要写进通信协议章节。
4.5 设计说明没写日志格式,现场排查靠猜
现象:AGV 异常停车,现场工程师查日志发现只有「error」两个字,不知道是雷达触发还是调度指令超时。原因:设计说明里没规定日志格式和日志级别。解决:设计说明里明确日志要包含时间戳、AGV 编号、事件类型、事件参数、当前任务 ID。日志级别分 DEBUG、INFO、WARN、ERROR,现场默认开 INFO,排查时临时开 DEBUG。这个规范要写进文档,否则后期维护成本极高。
5. 从设计说明到现场落地:三个验证技巧和一份参数检查习惯
设计说明写完不是终点,现场落地才是真正的考试。我一般会在施工前做三件事:第一,用仿真工具把 A* 路径和多车调度跑一遍,重点看路口冲突和充电排队;第二,用真实 AGV 在空场地跑单车路径,验证栅格粒度和安全余量;第三,模拟断网和手动挪车,验证降级逻辑是否按设计说明执行。这三步做完,现场调试时间能压缩一半以上。
仿真验证时,我习惯把设计说明里的参数直接导入仿真脚本,而不是重新填一遍。下面是一个简单的多车冲突检测片段,用于验证时空占用表是否合理:
def check_conflict(paths, time_windows): # paths: {agv_id: [(row, col), ...]} # time_windows: {agv_id: [(start_time, end_time), ...]} conflict_points = [] agv_ids = list(paths.keys()) for i in range(len(agv_ids)): for j in range(i+1, len(agv_ids)): a, b = agv_ids[i], agv_ids[j] for idx_a, pos_a in enumerate(paths[a]): for idx_b, pos_b in enumerate(paths[b]): if pos_a == pos_b: # 检查时间窗是否重叠 ta = time_windows[a][idx_a] tb = time_windows[b][idx_b] if not (ta[1] < tb[0] or tb[1] < ta[0]): conflict_points.append((a, b, pos_a, ta, tb)) return conflict_points逻辑说明:这段代码遍历所有 AGV 的路径点,如果两个 AGV 在同一栅格且时间窗重叠,就记录为冲突点。参数说明:time_windows要和路径点一一对应,每个点的时间窗由 AGV 速度和调度周期推算。设计说明里要写清这个推算过程,否则仿真和实际对不上。我一般会在设计说明附录里放一张「参数检查清单」,列出所有需要现场实测的参数,比如巷道净宽、充电桩位置、WiFi 信号强度,施工前逐项打勾,避免遗漏。
现场调试时,我还有一个习惯:每天收工前把当天所有 AGV 的日志导出来,用脚本统计急停次数、任务超时次数、充电排队时长。这三个指标如果连续三天上升,说明设计说明里的某个参数需要调整。这个习惯帮我提前发现过好几次充电桩配置不足的问题,比等 AGV 趴窝再排查省事得多。希望帮到你。
本文还有配套的精品资源,点击获取