Skip to content

Commit bb9edd7

Browse files
committed
feat(simulation): 新增定时仿真任务,每5分钟自动循环运行测试
- 新增 SimulationScheduledTask:每5分钟自动启动一轮仿真(车辆+订单), 运行270s后统计完成/超时订单数并记录日志,支持跨轮次累计统计 - 新增 SimulationEngine.clearModules():防止每轮 start 重复注册模块 - 修复 SimulationController.startSimulation():调用 clearModules() 后再注册 - OpentcsApplication 添加 @EnableScheduling 开启定时任务支持 - application.yml 添加 simulation.schedule.* 配置段,支持灵活调整 间隔(interval-ms)、运行时长(run-duration-seconds)、车辆数(vehicle-count)等
1 parent a321978 commit bb9edd7

5 files changed

Lines changed: 154 additions & 5 deletions

File tree

opentcs-admin/src/main/java/org/opentcs/OpentcsApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
77
import org.springframework.context.annotation.ComponentScan;
88
import org.springframework.context.annotation.FilterType;
9+
import org.springframework.scheduling.annotation.EnableScheduling;
910

1011
/**
1112
* 启动程序
@@ -14,6 +15,7 @@
1415
*/
1516

1617
@SpringBootApplication
18+
@EnableScheduling
1719
@MapperScan("org.opentcs.**.mapper")
1820
@ComponentScan(
1921
basePackages = {

opentcs-admin/src/main/resources/application.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,17 @@ opentcs:
284284
dispatch-interval-ms: 1000
285285
scheduling:
286286
deadlock-prevention: true
287-
conflict-check-interval-ms: 100
287+
conflict-check-interval-ms: 100
288+
--- # 仿真定时任务配置
289+
simulation:
290+
schedule:
291+
# 每轮间隔(毫秒),默认 5 分钟
292+
interval-ms: 300000
293+
# 启动延迟(毫秒),等待 Spring 完全启动后再执行第一轮
294+
initial-delay-ms: 60000
295+
# 每轮仿真运行时长(秒),留 30s 给下一轮准备
296+
run-duration-seconds: 270
297+
# 每轮测试车辆数
298+
vehicle-count: 2
299+
# 车辆最大速度(m/s)
300+
vehicle-max-speed: 2.0

opentcs-applications/opentcs-simulation/src/main/java/org/opentcs/simulation/controller/SimulationController.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,17 @@ public Map<String, Object> startSimulation() {
5050
vehicleSimulator.initialize();
5151
orderSimulator.initialize();
5252
trafficSimulator.initialize();
53-
53+
5454
// 设置模拟器之间的依赖
5555
orderSimulator.setVehicleSimulator(vehicleSimulator);
5656
trafficSimulator.setVehicleSimulator(vehicleSimulator);
57-
58-
// 添加模拟器到仿真引擎
57+
58+
// 清除旧模块后重新注册,防止重复 addModule
59+
simulationEngine.clearModules();
5960
simulationEngine.addModule(vehicleSimulator);
6061
simulationEngine.addModule(orderSimulator);
6162
simulationEngine.addModule(trafficSimulator);
62-
63+
6364
// 启动仿真
6465
simulationEngine.start();
6566

opentcs-applications/opentcs-simulation/src/main/java/org/opentcs/simulation/core/SimulationEngine.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ public void addModule(SimulationModule module) {
171171
public void removeModule(SimulationModule module) {
172172
modules.remove(module);
173173
}
174+
175+
/**
176+
* 清除所有已注册模块(重新启动前调用,防止重复注册)
177+
*/
178+
public void clearModules() {
179+
modules.clear();
180+
}
174181

175182
/**
176183
* 添加仿真监听器
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package org.opentcs.simulation.task;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.opentcs.simulation.core.SimulationEngine;
5+
import org.opentcs.simulation.order.OrderSimulator;
6+
import org.opentcs.simulation.order.SimulatedOrder;
7+
import org.opentcs.simulation.traffic.TrafficSimulator;
8+
import org.opentcs.simulation.vehicle.VehicleSimulator;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.beans.factory.annotation.Value;
11+
import org.springframework.scheduling.annotation.Scheduled;
12+
import org.springframework.stereotype.Component;
13+
14+
import java.util.List;
15+
import java.util.Map;
16+
import java.util.concurrent.atomic.AtomicLong;
17+
import java.util.stream.Collectors;
18+
19+
/**
20+
* 仿真定时任务:每隔固定周期自动启动一轮仿真测试(地图 + 车辆 + 订单),
21+
* 运行指定时长后统计结果并记录日志。
22+
*/
23+
@Slf4j
24+
@Component
25+
public class SimulationScheduledTask {
26+
27+
/** 每轮仿真运行时长(秒),默认 270s,留 30s 给下一轮准备 */
28+
@Value("${simulation.schedule.run-duration-seconds:270}")
29+
private int runDurationSeconds;
30+
31+
/** 每轮添加的测试车辆数 */
32+
@Value("${simulation.schedule.vehicle-count:2}")
33+
private int vehicleCount;
34+
35+
/** 车辆最大速度(m/s) */
36+
@Value("${simulation.schedule.vehicle-max-speed:2.0}")
37+
private double vehicleMaxSpeed;
38+
39+
@Autowired
40+
private SimulationEngine simulationEngine;
41+
42+
@Autowired
43+
private VehicleSimulator vehicleSimulator;
44+
45+
@Autowired
46+
private OrderSimulator orderSimulator;
47+
48+
@Autowired
49+
private TrafficSimulator trafficSimulator;
50+
51+
/** 累计完成订单总数(跨轮次) */
52+
private final AtomicLong totalCompleted = new AtomicLong(0);
53+
54+
/** 已执行轮次 */
55+
private final AtomicLong cycleCount = new AtomicLong(0);
56+
57+
/**
58+
* 每 5 分钟自动执行一轮仿真测试。
59+
* fixedDelay 保证上一轮完全结束后再计时,避免并发执行。
60+
*/
61+
@Scheduled(fixedDelayString = "${simulation.schedule.interval-ms:300000}",
62+
initialDelayString = "${simulation.schedule.initial-delay-ms:60000}")
63+
public void runCycle() {
64+
long cycle = cycleCount.incrementAndGet();
65+
log.info("===== 仿真定时任务 第 {} 轮 开始 =====", cycle);
66+
67+
try {
68+
// 1. 停止上一轮(如果还在跑)
69+
if (simulationEngine.getStatus() != SimulationEngine.SimulationStatus.STOPPED) {
70+
simulationEngine.stop();
71+
vehicleSimulator.stop();
72+
orderSimulator.stop();
73+
trafficSimulator.stop();
74+
Thread.sleep(500);
75+
}
76+
77+
// 2. 初始化 & 注册模块
78+
vehicleSimulator.initialize();
79+
orderSimulator.initialize();
80+
trafficSimulator.initialize();
81+
82+
orderSimulator.setVehicleSimulator(vehicleSimulator);
83+
trafficSimulator.setVehicleSimulator(vehicleSimulator);
84+
85+
simulationEngine.clearModules();
86+
simulationEngine.addModule(vehicleSimulator);
87+
simulationEngine.addModule(orderSimulator);
88+
simulationEngine.addModule(trafficSimulator);
89+
90+
simulationEngine.start();
91+
92+
// 3. 添加测试车辆
93+
for (int i = 1; i <= vehicleCount; i++) {
94+
vehicleSimulator.createVehicle(
95+
"scheduled-v" + i,
96+
"TestVehicle-" + i,
97+
vehicleMaxSpeed, 0.5, 0.5, 100.0
98+
);
99+
}
100+
log.info("已添加 {} 辆测试车辆,仿真运行中({}s)...", vehicleCount, runDurationSeconds);
101+
102+
// 4. 运行指定时长
103+
Thread.sleep(runDurationSeconds * 1000L);
104+
105+
// 5. 统计本轮结果
106+
List<SimulatedOrder> orders = orderSimulator.getOrders();
107+
Map<SimulatedOrder.OrderState, Long> stats = orders.stream()
108+
.collect(Collectors.groupingBy(SimulatedOrder::getState, Collectors.counting()));
109+
110+
long completed = stats.getOrDefault(SimulatedOrder.OrderState.COMPLETED, 0L);
111+
long timedOut = stats.getOrDefault(SimulatedOrder.OrderState.TIMED_OUT, 0L);
112+
long total = orders.size();
113+
114+
totalCompleted.addAndGet(completed);
115+
116+
log.info("===== 仿真定时任务 第 {} 轮 完成 | 本轮:总={} 完成={} 超时={} | 累计完成={} =====",
117+
cycle, total, completed, timedOut, totalCompleted.get());
118+
119+
} catch (InterruptedException e) {
120+
Thread.currentThread().interrupt();
121+
log.warn("仿真定时任务第 {} 轮被中断", cycle);
122+
} catch (Exception e) {
123+
log.error("仿真定时任务第 {} 轮执行异常: {}", cycle, e.getMessage(), e);
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)