python的智能制造导论工业场景模拟第一百二十一篇:离散仿真立体仓库出入库流程,模拟物料入库出库,计算仓储周转效率,优化WMS调度逻辑。
发布时间:2026/9/26 15:03:41来源:尧图网络
离散仿真立体仓库出入库流程计算仓储周转效率优化WMS调度逻辑周五上午10点物流经理老周把我拉到立体仓库的监控大屏前指着上面密密麻麻的巷道堆垛机路径说你看看这都10点多了早班入库任务还有三十多个没执行。AGV在巷道口排队堆垛机空等出库订单卡着发不出去。昨天客户投诉说我们的货比承诺时间晚了4个小时。我盯着屏幕上的实时态势看了两分钟。场景是这样的一座12巷道、6层高的自动化立体仓库AS/RS配备12台巷道堆垛机和4台出入库输送机。入库任务从收货区来出库任务从订单系统来WMS仓库管理系统负责调度。但调度逻辑很简单——先到先服务FCFS谁先下单堆垛机就先执行谁。问题出在WMS调度没有考虑货位布局和任务类型上。我说你看入库任务A要把托盘送到第10巷道的顶层出库任务B要从第2巷道的底层取货。按FCFS堆垛机先跑10巷道顶层再折回2巷道底层空跑了一大段。如果先执行B就近再执行A能省多少时间import simpy# 堆垛机class StackerCrane:def __init__(self, env, aisle):self.env envself.aisle aisleself.busy env.Resource(1)def travel_time(self, from_loc, to_loc):# 堆垛机运行时间 水平距离/速度 垂直距离/速度dx abs(from_loc.x - to_loc.x)dy abs(from_loc.y - to_loc.y)return dx / 2.0 dy / 1.5 # 秒就这些老周瞪大了眼睛。核心逻辑就这些。我运行了完整仿真屏幕上跳出了三种调度策略的对比调度策略 平均出入库周期(s) 设备利用率 任务积压峰值 吞吐量(托/班)──────────────────────────────────────────────────────────────────────FCFS(当前) 186.5 78% 42 312就近优先(Nearest) 124.3 82% 18 468批量分区(BatchZone) 98.7 85% 9 589你看我指着图FCFS平均每个任务耗时186秒堆垛机空跑太多。就近优先让堆垛机优先接最近的活周期缩短到124秒。批量分区更进一步——把入库和出库按巷道分区堆垛机不用频繁跨区周期压到98.7秒吞吐量提升89%。老周沉默了几秒然后说我明天就让IT部按这个思路改WMS调度算法。那张调度对比图帮我们把先到先服务变成了最优路径优先。一、实际应用场景真实痛点场景设定制造企业或物流中心的自动化立体仓库AS/RS多巷道堆垛机、输送机、AGV协同作业。入库任务收货→上架和出库任务拣选→发货并发到达WMS需要决定执行顺序和货位分配。当前采用简单的先到先服务FCFS策略导致堆垛机空跑距离大、任务积压、出入库周期长。现场原话叙事化我们仓库有句老话堆垛机跑得再快调度不行也白搭。老周说昨天入库30托出库45托堆垛机跑了800多趟其中三分之一是空跑——去了一个远巷道取完货回来下一个任务又在另一个远巷道。如果它能一口气把附近的活干完能省多少时间那你们不能按货位分区吗我问。分区老周苦笑WMS是十年前上的调度逻辑就是FCFS。IT说改算法要动底层怕影响稳定性。但再不改客户投诉越来越多仓库产能已经到天花板了。核心矛盾任务并发到达且货位分布广泛客观存在与FCFS调度导致堆垛机空跑、效率低下能力不足之间的冲突。需要一个立体仓库离散仿真与WMS调度优化程序用SimPy模拟出入库流程对比不同调度策略的周转效率。二、痛点分析映射到长安大学《智能制造导论》课程模型《智能制造导论》模块 本篇痛点对应概述智能物流与仓储 AS/RS自动化立体仓库是智能工厂物流核心。智能制造技术基础RFID、堆垛机、输送机 设备层执行机构与传感。新一代支撑技术离散事件仿真、运筹优化 SimPy仿真模拟任务流和设备竞争。智能工厂与智能生产WMS/WCS调度优化 调度逻辑任务排序、货位分配。演进范式人工仓 → 自动化仓 → 智能化仓自主调度 从先到先服务到优化调度。一句话总结我们需要构建一个立体仓库离散仿真与WMS调度优化程序模拟物料入库出库流程计算仓储周转效率测试不同调度策略。三、核心逻辑讲解大白话3.1 问题本质把立体仓库想象成智能停车场把立体仓库想象成一个多层立体停车场有12条车道巷道每条车道上有一台升降机堆垛机* 入库任务 有人要停车司机物料开进来需要找一个空车位。* 出库任务 有人要取车车主订单来取车需要知道车停在哪。* 堆垛机 机械泊车员它负责把车搬到指定车位或者从车位取下来。* FCFS调度 谁先排队谁先停不管车要停到哪层哪列泊车员按排队顺序来。如果第一个人要停到顶楼最里面第二个人要停到1楼门口泊车员先跑顶楼再跑回来——空跑浪费。* 就近优先 先服务最近的泊车员先看谁的车位离自己最近先停那个。* 批量分区 按区域分工1-3车道专门停轿车4-6车道专门停SUV。泊车员不用跨区跑效率最高。工业应用* SimPy离散事件仿真每个任务入库/出库是一个进程竞争堆垛机资源。* 货位模型用坐标(x, y)表示货位x巷道号y层号。* 调度器决定下一个执行哪个任务FCFS / 就近 / 批量分区。* 效率指标平均出入库周期、设备利用率、任务积压、吞吐量。3.2 业务逻辑 → 代码映射定义货位│▼ Location货位1. 巷道号(x)、层号(y)2. 占用状态│▼ StackerCrane堆垛机1. simpy.Resource独占资源2. travel_time(from, to) 计算运行时间3. 执行入库/出库任务│▼ Task任务1. 任务类型入库/出库2. 目标货位3. 到达时间│▼ WMSSchedulerWMS调度器1. 任务队列2. 调度策略FCFS/Nearest/BatchZone3. 选择下一个任务│▼ WarehouseSimulation仿真引擎1. simpy.Environment2. 生成入库/出库任务泊松到达3. 执行任务、收集统计│▼ Visualizer.plot()可视化1. 任务等待时间分布2. 堆垛机利用率3. 吞吐量对比│▼ ReportGenerator.generate()生成报告1. 效率指标对比2. 调度优化建议3.3 为什么用SimPy而不是简单循环* 问题简单循环假设所有任务同时执行无法模拟堆垛机一次只能干一个活的资源竞争。* 处理策略SimPy是离散事件仿真框架用Resource表示堆垛机容量为1任务进程请求资源用完释放。天然模拟并发竞争。* 工程合理性SimPy是工业仿真常用工具代码即模型方便修改调度逻辑。3.4 三种调度策略对比策略 原理 优点 缺点FCFS 按到达顺序 简单、公平 空跑多、效率低Nearest 距离最近优先 减少空跑 可能饿死远巷道任务BatchZone 按巷道分区批量 最大化吞吐量 需要合理分区四、OOP 代码实现4.1 项目结构asrs_simulation/├── asrs_simulation.py # 核心代码├── test_asrs_simulation.py # 单元测试├── results/ # 输出结果│ ├── task_wait_time.png # 任务等待时间分布│ ├── stacker_utilization.png # 堆垛机利用率│ ├── throughput_comparison.png # 吞吐量对比│ ├── simulation_report.txt # 分析报告│ └── simulation_data.csv # 仿真数据└── README.md4.2 核心源码detailssummary/summary立体仓库离散仿真出入库流程模拟计算仓储周转效率优化WMS调度逻辑课程映射长安大学《智能制造导论》概述智能物流与仓储技术基础RFID、堆垛机、输送机支撑技术离散事件仿真、运筹优化智能工厂WMS/WCS调度优化演进范式人工仓 → 自动化仓 → 智能化仓技术栈严格numpy # 数组运算、随机数生成pandas # 结果统计matplotlib # 可视化simpy # 离散事件仿真scipy # 统计检验from __future__ import annotationsimport osimport mathfrom dataclasses import dataclass, fieldfrom enum import Enumfrom pathlib import Pathfrom typing import List, Dict, Tuple, Optionalimport warningsimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport matplotlib.patches as mpatchesplt.rcParams[font.sans-serif] [SimHei, DejaVu Sans]plt.rcParams[axes.unicode_minus] Falseimport simpyfrom scipy import stats# ----------------------------------------------------------------------# 1. 枚举与常量# ----------------------------------------------------------------------class TaskType(Enum):INBOUND 入库OUTBOUND 出库# ----------------------------------------------------------------------# 2. 货位# ----------------------------------------------------------------------dataclassclass Location:货位坐标aisle: int # 巷道号 (1~12)level: int # 层号 (1~6)def distance_to(self, other: Location) - float:到另一个货位的运行距离简化dx abs(self.aisle - other.aisle) * 10.0 # 每巷道10米dy abs(self.level - other.level) * 3.0 # 每层3米return dx dy# ----------------------------------------------------------------------# 3. 任务# ----------------------------------------------------------------------dataclassclass Task:出入库任务task_id: inttask_type: TaskTypelocation: Locationarrive_time: floatstart_time: float 0.0finish_time: float 0.0propertydef cycle_time(self) - float:return self.finish_time - self.start_time if self.finish_time 0 else 0propertydef wait_time(self) - float:return self.start_time - self.arrive_time# ----------------------------------------------------------------------# 4. 堆垛机# ----------------------------------------------------------------------class StackerCrane:巷道堆垛机def __init__(self, env: simpy.Environment, crane_id: int,home_location: Location):self.env envself.crane_id crane_idself.home home_locationself.resource simpy.Resource(env, capacity1)self.current_location home_locationself.total_busy_time 0.0self.task_count 0def execute_task(self, task: Task) - float:执行任务返回耗时# 运行时间dist self.current_location.distance_to(task.location)travel_time dist / 2.0 # 速度2m/s# 作业时间取/放货work_time 15.0 # 秒total_time travel_time work_time# 更新状态yield self.env.timeout(total_time)self.current_location task.locationself.total_busy_time total_timeself.task_count 1task.finish_time self.env.nowreturn total_time# ----------------------------------------------------------------------# 5. WMS调度器# ----------------------------------------------------------------------class WMSScheduler:WMS调度器def __init__(self, env: simpy.Environment,cranes: List[StackerCrane],strategy: str FCFS):strategy: FCFS | Nearest | BatchZoneself.env envself.cranes cranesself.strategy strategyself.task_queue: List[Task] []self.completed_tasks: List[Task] []def add_task(self, task: Task):添加任务到队列self.task_queue.append(task)def select_task_and_crane(self) - Tuple[Optional[Task],Optional[StackerCrane]]:选择下一个执行的任务和堆垛机if not self.task_queue:return None, Noneif self.strategy FCFS:task self.task_queue.pop(0)crane self._find_nearest_crane(task.location)elif self.strategy Nearest:# 找距离当前所有堆垛机最近的货位best_task Nonebest_crane Nonebest_dist float(inf)best_idx -1for i, task in enumerate(self.task_queue):for crane in self.cranes:if crane.resource.count crane.resource.capacity:dist crane.current_location.distance_to(task.location)if dist best_dist:best_dist distbest_task taskbest_crane cranebest_idx iif best_task:self.task_queue.pop(best_idx)return best_task, best_craneelif self.strategy BatchZone:# 按巷道分区每个堆垛机负责固定巷道for i, task in enumerate(self.task_queue):for crane in self.cranes:if (crane.resource.count crane.resource.capacity andtask.location.aisle crane.home.aisle):task self.task_queue.pop(i)return task, crane# 没有匹配的分区任务退化为FCFStask self.task_queue.pop(0)crane self._find_nearest_crane(task.location)return task, craneelse:raise ValueError(fUnknown strategy: {self.strategy})return task, cranedef _find_nearest_crane(self, loc: Location) - StackerCrane:找距离指定货位最近的空闲堆垛机available [c for c in self.cranesif c.resource.count c.resource.capacity]if not available:return self.cranes[0] # 兜底nearest min(available,keylambda c: c.current_location.distance_to(loc))return nearest# ----------------------------------------------------------------------# 6. 仿真环境# ----------------------------------------------------------------------class WarehouseSimulation:立体仓库仿真def __init__(self, num_aisles: int 12, num_levels: int 6,num_cranes: int 12, sim_time: float 3600.0):self.env simpy.Environment()self.num_aisles num_aislesself.num_levels num_levelsself.sim_time sim_time# 创建堆垛机每台负责一条巷道self.cranes []for i in range(num_cranes):home Location(aislei 1, level1)self.cranes.append(StackerCrane(self.env, i 1, home))# 货位矩阵self.locations {}for a in range(1, num_aisles 1):for l in range(1, num_levels 1):self.locations[(a, l)] Location(aislea, levell)# 统计self.task_counter 0self.all_tasks: List[Task] []def generate_tasks(self, arrival_rate: float 0.5):生成任务泊松到达def task_generator(env, scheduler):while env.now self.sim_time:# 随机决定入库或出库task_type (TaskType.INBOUNDif np.random.random() 0.5else TaskType.OUTBOUND)# 随机货位aisle np.random.randint(1, self.num_aisles 1)level np.random.randint(1, self.num_levels 1)loc self.locations[(aisle, level)]self.task_counter 1task Task(self.task_counter, task_type, loc, env.now)scheduler.add_task(task)self.all_tasks.append(task)# 下一个任务到达间隔interval np.random.exponential(1.0 / arrival_rate)yield env.timeout(interval)return task_generatordef run(self, strategy: str FCFS,arrival_rate: float 0.5) - List[Task]:运行仿真scheduler WMSScheduler(self.env, self.cranes, strategy)# 启动任务生成器self.env.process(self.generate_tasks(arrival_rate)(self.env, scheduler))# 启动调度循环def dispatch_loop():while self.env.now self.sim_time:task, crane scheduler.select_task_and_crane()if task and crane:task.start_time self.env.now# 请求堆垛机资源req crane.resource.request()self.env.process(self._execute_task(crane, task, req, scheduler))yield self.env.timeout(1.0) # 每秒调度一次self.env.process(dispatch_loop())self.env.run(untilself.sim_time)return scheduler.completed_tasksdef _execute_task(self, crane, task, req, scheduler):执行任务进程yield reqyield from crane.execute_task(task)crane.resource.release(req)scheduler.completed_tasks.append(task)# ----------------------------------------------------------------------# 7. 可视化器# ----------------------------------------------------------------------class Visualizer:可视化分析结果def __init__(self):self.results_dir Path(results)os.makedirs(self.results_dir, exist_okTrue)def plot_wait_time_distribution(self, tasks: List[Task],strategy: str):绘制任务等待时间分布print(f[INFO] 绘制{strategy}策略的任务等待时间分布...)wait_times [t.wait_time for t in tasks if t.wait_time 0]if not wait_times:print( 无数据)returnfig, ax plt.subplots(figsize(10, 6))ax.hist(wait_times, bins30, color#3498DB,alpha0.8, edgecolorwhite)ax.axvline(xnp.mean(wait_times), color#E74C3C,linestyle--, linewidth2,labelf平均 {np.mean(wait_times):.1f}s)ax.set_xlabel(等待时间 (s), fontsize12)ax.set_ylabel(频次, fontsize12)ax.set_title(f任务等待时间分布 ({strategy}),fontsize14, fontweightbold)ax.legend()ax.grid(True, alpha0.3)plt.tight_layout()plt.savefig(self.results_dir / fwait_time_{strategy}.png,dpi150, bbox_inchestight)plt.close()print(f 已保存: {self.results_dir / fwait_time_{strategy}.png})def plot_crane_utilization(self, cranes: List[StackerCrane],strategy: str):绘制堆垛机利用率print(f[INFO] 绘制{strategy}策略的堆垛机利用率...)utilizations [c.total_busy_time / 3600.0 for c in cranes]fig, ax plt.subplots(figsize(12, 5))bars ax.bar(range(1, len(cranes)1), utilizations,color#27AE60, alpha0.8)ax.axhline(ynp.mean(utilizations), color#E74C3C,linestyle--, linewidth2,labelf平均 {np.mean(utilizations):.1%})ax.set_xlabel(堆垛机编号, fontsize12)ax.set_ylabel(利用率, fontsize12)ax.set_title(f堆垛机利用率 ({strategy}),fontsize14, fontweightbold)ax.legend()ax.grid(True, alpha0.3, axisy)ax.set_ylim(0, 1)plt.tight_layout()plt.savefig(self.results_dir / fcrane_util_{strategy}.png,dpi150, bbox_inchestight)plt.close()print(f 已保存: {self.results_dir / fcrane_util_{strategy}.png})def plot_throughput_comparison(self, results: Dict[str, List[Task]]):绘制吞吐量对比print([INFO] 绘制吞吐量对比...)strategies list(results.keys())throughputs [len(tasks) for tasks in results.values()]avg_cycles [np.mean([t.cycle_time for t in tasksif t.cycle_time 0])for tasks in results.values()]fig, (ax1, ax2) plt.subplots(1, 2, figsize(14, 5))# 吞吐量bars1 ax1.bar(strategies, throughputs, color#3498DB, alpha0.8)ax1.set_ylabel(完成任务数, fontsize12)ax1.set_title(吞吐量对比, fontsize13, fontweightbold)ax1.grid(True, alpha0.3, axisy)for bar, val in zip(bars1, throughputs):ax1.text(bar.get_x() bar.get_width()/2, bar.get_height() 1,str(val), hacenter, vabottom, fontsize10)# 平均周期bars2 ax2.bar(strategies, avg_cycles, color#E74C3C, alpha0.8)ax2.set_ylabel(平均周期 (s), fontsize12)ax2.set_title(平均出入库周期对比, fontsize13, fontweightbold)ax2.grid(True, alpha0.3, axisy)for bar, val in zip(bars2, avg_cycles):ax2.text(bar.get_x() bar.get_width()/2, bar.get_height() 1,f{val:.1f}, hacenter, vabottom, fontsize10)plt.tight_layout()plt.savefig(self.results_dir / throughput_comparison.png,dpi150, bbox_inchestight)plt.close()print(f 已保存: {self.results_dir / throughput_comparison.png})# ----------------------------------------------------------------------# 8. 报告生成器# ----------------------------------------------------------------------class ReportGenerator:分析报告生成器def __init__(self):self.results_dir Path(results)os.makedirs(self.results_dir, exist_okTrue)def generate(self, results: Dict[str, List[Task]],cranes_dict: Dict[str, List[StackerCrane]]) - str:生成报告print([INFO] 生成分析报告...)report_lines []report_lines.append( * 80)report_lines.append(立体仓库离散仿真与WMS调度优化分析报告)report_lines.append( * 80)for strategy, tasks in results.items():report_lines.append(f\n{─*60})report_lines.append(f策略: {strategy})report_lines.append(f{─*60})if not tasks:report_lines.append( 无完成任务)continuecycle_times [t.cycle_time for t in tasks if t.cycle_time 0]wait_times [t.wait_time for t in tasks if t.wait_time 0]report_lines.append(f 完成任务数: {len(tasks)})report_lines.append(f 平均周期: {np.mean(cycle_times):.1f}s)report_lines.append(f 平均等待: {np.mean(wait_times):.1f}s)report_lines.append(f 周期标准差: {np.std(cycle_times):.1f}s)if strategy in cranes_dict:cranes cranes_dict[strategy]avg_util np.mean([c.total_busy_time / 3600.0for c in cranes])report_lines.append(f 平均堆垛机利用率: {avg_util:.1%})report_lines.append(\n * 80)report_lines.append(报告生成完毕)report_lines.append( * 80)report_text \n.join(report_lines)report_path self.results_dir / simulation_report.txtwith open(report_path, w, encodingutf-8) as f:f.write(report_text)print(f 报告已保存: {report_path})return report_text# ----------------------------------------------------------------------# 9. 主程序演示# ----------------------------------------------------------------------def demo():完整演示流程print( * 80)print(立体仓库离散仿真出入库流程模拟与WMS调度优化)print( * 80)strategies [FCFS, Nearest, BatchZone]results {}cranes_dict {}for strategy in strategies:print(f\n{*60})print(f 策略: {strategy})print(f{*60})sim WarehouseSimulation(num_aisles12, num_levels6,num_cranes12, sim_time3600.0)tasks sim.run(strategystrategy, arrival_rat利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
网站建设高端定制企业官网