python的工业过程控制场景模拟第一百篇:多机器人任务分配算法,根据距离,剩余电量分配设备巡检任务。
多机器人任务分配算法 —— 基于距离-能耗均衡的巡检任务调度“那年厂里上了 8 台巡检机器人本以为能减负结果调度靠喊、任务靠猜。有的机器人电量耗尽瘫在管廊有的却在空地上兜圈。后来我们写了这套距离-能耗均衡分配算法让每台机器人像有了‘全局大脑’就近接单、量力而行再也没出现过‘有的累死、有的闲死’。”—— 哈尔滨工程大学《工业过程控制》课程核心思想延伸一、实际应用场景描述在大型化工园区、电力管廊、仓储物流中心多台移动机器人协同执行巡检任务已成常态┌──────────────────────────────────────────────┐│ 多机器人任务分配与调度系统 ││ ││ [上位机中央调度器] ││ │ 全局状态感知 / 任务分解 / 分配决策 ││ ▼ ││ ┌────────────────────────────┐ ││ │ 任务池管理器 │ ││ │ ┌──────────────────────┐ │ ││ │ │ 1. 任务队列管理 │ │ ││ │ │ (FIFO/Priority) │ │ ││ │ └──────────────────────┘ │ ││ │ ┌──────────────────────┐ │ ││ │ │ 2. 任务属性标注 │ │ ││ │ │ (位置/类型/紧急度) │ │ ││ │ └──────────────────────┘ │ ││ │ ┌──────────────────────┐ │ ││ │ │ 3. 任务超时处理 │ │ ││ │ │ (重分配/告警) │ │ ││ └────────────┬───────────────┘ ││ │ 任务分配指令 ││ ┌───────┴───────┐ ││ ▼ ▼ ││ ┌─────────┐ ┌─────────┐ ││ │ 机器人01 │ │ 机器人02 │ ││ │ (电量78%) │ │ (电量45%) │ ││ │ 位置:A3 │ │ 位置:C7 │ ││ │ 状态:空闲 │ │ 状态:巡检 │ ││ └────┬────┘ └────┬────┘ ││ │ 状态上报 │ 状态上报 ││ ▼ ▼ ││ ┌────────────────────────────┐ ││ │ 代价评估引擎 │ ││ │ • 距离代价: d(i,j) │ ││ │ • 能耗代价: E f(d, θ) │ ││ │ • 电量约束: SOC ≥ 20% │ ││ │ • 任务优先级: P ∈ [0,1] │ ││ └────────────┬───────────────┘ ││ │ 综合代价矩阵 ││ ▼ ││ ┌────────────────────────────┐ ││ │ 分配算法核心 │ ││ │ • 匈牙利算法 (KM优化) │ ││ │ • 贪心回溯 (小规模) │ ││ │ • 一致性协商 (分布式) │ ││ └────────────┬───────────────┘ ││ │ 最优分配方案 ││ ▼ ││ ┌────────────────────────────┐ ││ │ 物理世界 (巡检目标) │ ││ │ 阀门组A (紧急) │ ││ │ 泵房B (常规) │ ││ │ 储罐C (高危) │ ││ │ 管道D (预警) │ ││ └───────────────────────────┘ ││ ││ 核心: 距离-能耗多目标优化 约束满足 │└──────────────────────────────────────────────┘传统人工调度 vs 智能分配算法维度 人工/固定调度 智能分配算法分配依据 ❌ 凭经验、轮流制 ✅ 距离电量优先级负载均衡 ❌ 易出现忙闲不均 ✅ 全局最优应急响应 ❌ 反应迟缓 ✅ 毫秒级重分配能耗管理 ❌ 常出现中途断电 ✅ 电量预判扩展性 ❌ 难以增加新机器人 ✅ 动态增删节点二、引入痛点2.1 现场的真实困境场景 现场发生了什么 根因“瘫在半路” “机器人巡检到一半没电了” 未考虑剩余电量“远水救近火” “派最远的机器人去处理紧急故障” 未考虑距离代价“扎堆围观” “3台机器人挤在同一个阀门旁” 缺乏冲突消解“闲死忙死” “有的机器人跑了50km有的只跑5km” 无负载均衡机制“任务积压” “紧急任务排在队列末尾” 无优先级调度2.2 核心矛盾多机器人系统的本质是“分布式资源约束下的多目标优化问题”。 任务分配不仅要考虑距离最短时间最优还要考虑能耗可行电量约束更要兼顾负载均衡系统寿命。单纯的贪心算法容易导致局部最优而暴力枚举又无法实时响应。解决方案是基于匈牙利算法Kuhn-Munkres的任务-机器人最优匹配结合电量可行性剪枝与距离-能耗加权代价函数。2.3 我们要解决什么用一段精简的 Python 程序构建一个多机器人任务分配仿真系统实现1. 多目标代价函数 —— 综合距离、能耗、电量、优先级2. 匈牙利算法 —— 求解最优分配矩阵3. 电量约束剪枝 —— 剔除不可行分配方案4. 动态重分配 —— 机器人故障或电量不足的应急处理5. 可视化 —— 展示分配结果、路径、负载分布三、核心逻辑讲解3.1 理论基础匈牙利算法与多目标优化本工具基于哈工程《工业过程控制》第十三章“最优控制”和第四章“线性规划”① 任务分配的数学模型设机器人集合 R \{r_1, r_2, ..., r_m\} 任务集合 T \{t_1, t_2, ..., t_n\} 。构造代价矩阵 C \in \mathbb{R}^{m \times n} 其中 c_{ij} 表示机器人 r_i 执行任务 t_j 的综合代价。目标函数\min \sum_{i1}^{m} \sum_{j1}^{n} c_{ij} x_{ij}约束条件\sum_{j1}^{n} x_{ij} \le 1 \quad \forall i \in R \quad \text{(一台机器人最多执行一个任务)}\sum_{i1}^{m} x_{ij} 1 \quad \forall j \in T \quad \text{(一个任务必须被分配)}x_{ij} \in \{0, 1\}② 综合代价函数设计c_{ij} \alpha \cdot \frac{d_{ij}}{d_{max}} \beta \cdot \frac{e_{ij}}{e_{max}} - \gamma \cdot p_j \delta \cdot (1 - \frac{soc_i}{soc_{max}})其中- d_{ij} 机器人 i 到任务 j 的欧氏距离- e_{ij} 预估能耗与距离、地形相关- p_j 任务 j 的优先级0~1越高越紧急- soc_i 机器人 i 的剩余电量- \alpha, \beta, \gamma, \delta 权重系数③ 匈牙利算法Kuhn-Munkres通过行列规约将代价矩阵转化为含有足够多零元素的矩阵然后寻找最优指派。3.2 分配架构┌─────────────┐│ 任务生成器 ││ (定时/事件) │└──────┬──────┘│ 新任务┌─────────▼─────────┐│ 任务池管理器 ││ • 优先级排序 ││ • 超时检测 │└─────────┬─────────┘│ 待分配任务┌─────────▼─────────┐│ 状态感知模块 ││ • 机器人位置 ││ • 剩余电量 ││ • 当前状态 │└─────────┬─────────┘│ 机器人状态┌─────────▼─────────┐│ 代价矩阵生成器 ││ C[i][j] f(dist, ││ energy, ││ soc, ││ priority│└─────────┬─────────┘│ 代价矩阵┌─────────▼─────────┐│ 匈牙利算法核心 ││ • 行列规约 ││ • 试指派 ││ • 调整优化 │└─────────┬─────────┘│ 分配方案┌─────────▼─────────┐│ 可行性校验 ││ • 电量充足? ││ • 路径可达? │└─────────┬─────────┘│ 最终指令▼┌─────────────┐│ 机器人执行层 │└─────────────┘四、代码讲解面向对象设计4.1 类结构总览类名 职责 设计模式TaskPriority 任务优先级枚举 枚举RobotState 机器人状态枚举 枚举Task 巡检任务dataclass 值对象Robot 巡检机器人实体 实体对象CostMatrix 代价矩阵生成器 策略模式HungarianAlgorithm 匈牙利算法实现 模板方法TaskAllocator 任务分配器聚合根 聚合根VisualizationEngine 可视化引擎 封装4.2 核心代码实现from dataclasses import dataclass, fieldfrom typing import List, Dict, Tuple, Optional, Setfrom enum import Enum, autoimport numpy as npimport matplotlib.pyplot as pltfrom collections import defaultdict, dequeimport mathimport heapq# # 1. 基础枚举与数据结构# class TaskPriority(Enum):任务优先级EMERGENCY 0 # 紧急秒级响应HIGH 1 # 高分钟级NORMAL 2 # 正常小时级LOW 3 # 低可延后class RobotState(Enum):机器人状态IDLE auto() # 空闲ASSIGNED auto() # 已分配任务MOVING auto() # 移动中EXECUTING auto() # 执行任务CHARGING auto() # 充电中ERROR auto() # 故障dataclassclass Task:巡检任务 —— 值对象id: strposition: Tuple[float, float]priority: TaskPriority TaskPriority.NORMALestimated_duration: float 60.0 # 预估执行时间秒required_soc: float 20.0 # 所需最低电量%created_at: float field(default_factorylambda: time.time())def __lt__(self, other):用于优先级队列排序return self.priority.value other.priority.valuedataclassclass Robot:巡检机器人 —— 实体对象id: strposition: Tuple[float, float]battery_capacity: float 100.0 # 电池容量Ah简化current_soc: float 100.0 # 当前电量%max_speed: float 1.0 # 最大速度m/senergy_consumption_rate: float 0.1 # 能耗率%/米state: RobotState RobotState.IDLEcurrent_task: Optional[Task] Nonepath_history: List[Tuple[float, float]] field(default_factorylist)def can_execute(self, task: Task, distance: float) - bool:判断是否能执行任务# 1. 电量检查required_soc distance * self.energy_consumption_rate \task.estimated_duration * 0.01 # 执行任务消耗if self.current_soc max(task.required_soc, required_soc):return False# 2. 状态检查if self.state in [RobotState.ERROR, RobotState.CHARGING]:return Falsereturn Truedef estimate_energy_cost(self, distance: float, task: Task) - float:估算任务能耗travel_cost distance * self.energy_consumption_rateexecution_cost task.estimated_duration * 0.01return travel_cost execution_costdef move_towards(self, target: Tuple[float, float], dt: float 1.0) - bool:向目标移动一步返回是否到达dx target[0] - self.position[0]dy target[1] - self.position[1]dist math.sqrt(dx*dx dy*dy)if dist 0.1: # 到达阈值self.position targetreturn True# 移动step min(self.max_speed * dt, dist)ratio step / distself.position (self.position[0] dx * ratio,self.position[1] dy * ratio)# 消耗电量self.current_soc - step * self.energy_consumption_rate# 记录路径self.path_history.append(self.position)return False# # 2. 代价矩阵生成器策略模式# class CostMatrixGenerator:代价矩阵生成器 —— 策略模式根据距离、电量、优先级计算综合代价def __init__(self,distance_weight: float 1.0,energy_weight: float 0.5,priority_weight: float 2.0,soc_weight: float 1.5):self.w_dist distance_weightself.w_energy energy_weightself.w_prio priority_weightself.w_soc soc_weightdef calculate_distance(self, robot: Robot, task: Task) - float:计算欧氏距离return math.sqrt((robot.position[0] - task.position[0])**2 (robot.position[1] - task.position[1])**2)def calculate_energy_cost(self, robot: Robot, task: Task, distance: float) - float:计算能耗代价return robot.estimate_energy_cost(distance, task)def normalize(self, value: float, min_val: float, max_val: float) - float:归一化到 [0, 1]if max_val - min_val 0:return 0.0return (value - min_val) / (max_val - min_val)def generate(self, robots: List[Robot], tasks: List[Task]) - np.ndarray:生成代价矩阵 C[m x n]m: 机器人数量n: 任务数量m, n len(robots), len(tasks)cost_matrix np.full((m, n), np.inf) # 初始化为无穷大# 预计算所有距离和能耗distances np.zeros((m, n))energies np.zeros((m, n))for i, robot in enumerate(robots):for j, task in enumerate(tasks):distances[i, j] self.calculate_distance(robot, task)energies[i, j] self.calculate_energy_cost(robot, task, distances[i, j])# 归一化参数max_dist np.max(distances) if n 0 else 1.0max_energy np.max(energies) if n 0 else 1.0max_prio max(p.value for p in TaskPriority)# 计算综合代价for i, robot in enumerate(robots):for j, task in enumerate(tasks):# 可行性检查if not robot.can_execute(task, distances[i, j]):cost_matrix[i, j] np.infcontinue# 归一化各项指标norm_dist self.normalize(distances[i, j], 0, max_dist)norm_energy self.normalize(energies[i, j], 0, max_energy)norm_prio task.priority.value / max_prionorm_soc 1.0 - (robot.current_soc / 100.0) # 电量越低代价越高# 综合代价cost (self.w_dist * norm_dist self.w_energy * norm_energy self.w_prio * (1.0 - norm_prio) # 优先级越高代价越低self.w_soc * norm_soc)cost_matrix[i, j] costreturn cost_matrix# # 3. 匈牙利算法实现Kuhn-Munkres# class HungarianAlgorithm:匈牙利算法Kuhn-Munkres实现用于求解指派问题的最优解def __init__(self):self.debug Falsedef solve(self, cost_matrix: np.ndarray) - List[Tuple[int, int]]:求解最优分配返回: [(robot_idx, task_idx), ...]if cost_matrix.size 0:return []# 确保矩阵是方阵通过填充无穷大m, n cost_matrix.shapesize max(m, n)square_matrix np.full((size, size), np.inf)square_matrix[:m, :n] cost_matrix# 步骤1: 每行减去最小值for i in range(size):min_val np.min(square_matrix[i, :])if min_val ! np.inf:square_matrix[i, :] - min_val# 步骤2: 每列减去最小值for j in range(size):min_val np.min(square_matrix[:, j])if min_val ! np.inf:square_matrix[:, j] - min_val# 步骤3: 寻找独立零元素简化版贪心回溯assignment self._find_assignment(square_matrix, m, n)return assignmentdef _find_assignment(self, matrix: np.ndarray, m: int, n: int) - List[Tuple[int, int]]:寻找最优指派简化贪心算法assignments []used_rows set()used_cols set()# 创建候选列表代价行列candidates []for i in range(m):for j in range(n):if matrix[i, j] ! np.inf:heapq.heappush(candidates, (matrix[i, j], i, j))# 贪心分配while candidates and len(assignments) min(m, n):cost, i, j heapq.heappop(candidates)if i not in used_rows and j not in used_cols:assignments.append((i, j))used_rows.add(i)used_cols.add(j)return assignments# # 4. 任务分配器聚合根# class TaskAllocator:任务分配器 —— 聚合根协调任务分配全流程def __init__(self):self.robots: Dict[str, Robot] {}self.task_queue: List[Task] []self.cost_generator CostMatrixGenerator()self.hungarian HungarianAlgorithm()self.assignment_history: List[Dict] []self.current_time: float 0.0def register_robot(self, robot: Robot):注册机器人self.robots[robot.id] robotdef add_task(self, task: Task):添加任务到队列按优先级排序# 使用插入排序保持优先级顺序inserted Falsefor i, existing_task in enumerate(self.task_queue):if task.priority.value existing_task.priority.value:self.task_queue.insert(i, task)inserted Truebreakif not inserted:self.task_queue.append(task)def allocate_tasks(self) - Dict[str, Task]:执行任务分配返回: {robot_id: task}if not self.task_queue or not self.robots:return {}# 筛选可用机器人available_robots [r for r in self.robots.values()if r.state RobotState.IDLE]if not available_robots:return {}# 生成代价矩阵cost_matrix self.cost_generator.generate(available_robots, self.task_queue)# 使用匈牙利算法求解assignments self.hungarian.solve(cost_matrix)# 应用分配结果allocation {}assigned_task_indices set()for robot_idx, task_idx in assignments:if task_idx len(self.task_queue):continuerobot available_robots[robot_idx]task self.task_queue[task_idx]# 再次确认可行性distance self.cost_generator.calculate_distance(robot, task)if robot.can_execute(task, distance):allocation[robot.id] taskrobot.state RobotState.ASSIGNEDrobot.current_task taskassigned_task_indices.add(task_idx)# 记录历史self.assignment_history.append({time: self.current_time,robot: robot.id,task: task.id,cost: cost_matrix[robot_idx, task_idx]})# 从队列中移除已分配的任务self.task_queue [task for i, task in enumerate(self.task_queue)if i not in assigned_task_indices]return allocationdef reallocate_on_failure(self, failed_robot_id: str):机器人故障时的重分配robot self.robots.get(failed_robot_id)if robot and robot.current_task:print(f 机器人 {failed_robot_id} 故障重分配任务 {robot.current_task.id})robot.state RobotState.ERRORrobot.current_task Noneself.add_task(robot.current_task) # 重新加入队列def update(self, dt: float 1.0):更新系统状态self.current_time dt# 更新机器人状态for robot in self.robots.values():if robot.state RobotState.ASSIGNED and robot.current_task:# 开始移动robot.state RobotState.MOVINGelif robot.state RobotState.MOVING and robot.current_task:# 移动中target robot.current_task.positionarrived robot.move_towards(target, dt)if arrived:robot.state RobotState.EXECUTINGprint(f 机器人 {robot.id} 到达任务 {robot.current_task.id})elif robot.state RobotState.EXECUTING and robot.current_task:# 执行任务简化立即完成robot.current_task.estimated_duration - dtif robot.current_task.estimated_duration 0:print(f✅ 机器人 {robot.id} 完成任务 {robot.current_task.id})robot.state RobotState.IDLErobot.current_task None# 周期性重新分配if int(self.current_time) % 10 0: # 每10秒尝试分配allocation self.allocate_tasks()if allocation:print(f\n 新分配 {len(allocation)} 个任务:)for robot_id, task in allocation.items():print(f • {robot_id} → {task.id} (优先级:{task.priority.name}))# # 5. 可视化引擎# class VisualizationEngine:可视化引擎 —— 封装def __init__(self, allocator: TaskAllocator):self.allocator allocatordef plot_scene(self, save_path: str multi_robot_allocation.png):绘制分配场景fig, axes plt.subplots(2, 2, figsize(14, 12))# 1. 机器人位置与任务分布ax axes[0, 0]self._plot_distribution(ax)# 2. 代价矩阵热力图ax axes[0, 1]self._plot_cost_matrix(ax)# 3. 机器人电量与负载ax axes[1, 0]self._plot_robot_status(ax)# 4. 任务队列状态ax axes[1, 1]self._plot_task_queue(ax)plt.suptitle(Multi-Robot Task Allocation System,fontsize16, fontweightbold)plt.tight_layout()plt.savefig(save_path, dpi150, bbox_inchestight)plt.close()print(f 可视化已保存至: {save_path})def _plot_distribution(self, ax):绘制机器人与任务分布# 机器人robot_x [r.position[0] for r in self.allocator.robots.values()]robot_y [r.position[1利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛

相关新闻

鸿蒙应用开发:组件生命周期详解与优化实践

鸿蒙应用开发:组件生命周期详解与优化实践

1. 鸿蒙应用开发中的组件生命周期解析 在鸿蒙应用开发中,理解组件和页面的生命周期是构建稳定应用的基础。作为一名长期从事鸿蒙开发的工程师,我发现很多初学者在自定义组件时经常遇到状态管理混乱、资源释放不及时等问题,究其根源往往是对生…

2026/11/4 15:32:37 阅读更多 →
SSM框架教学质量管理系统开发实践

SSM框架教学质量管理系统开发实践

1. 项目概述这个基于SSM框架的教学质量管理系统是一个典型的Java Web应用开发项目,主要面向高校或培训机构的教学质量监控需求。系统采用SpringSpringMVCMyBatis的主流技术栈,实现了从数据采集、分析到可视化展示的全流程教学质量管控。我在实际开发中发…

2026/10/25 4:38:53 阅读更多 →
Ralph Loop:让AI编程助手实现自动化任务拆解与验证循环

Ralph Loop:让AI编程助手实现自动化任务拆解与验证循环

1. 项目概述:当AI编程助手学会了“坚持”如果你用过Claude Code,或者任何类似的AI编程助手,大概率都经历过这种“挫败感”:你让它写一个功能,它噼里啪啦给你生成了一大段看起来不错的代码,你满怀期待地运行…

2026/11/2 14:32:16 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/5 12:28:00 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/5 1:08:50 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/5 12:28:01 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/5 12:28:02 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/6 8:08:42 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/5 19:38:59 阅读更多 →

日新闻

周新闻

月新闻