Browse Source

A* 路径规划器

master
修宁 6 months ago
parent
commit
e63b18df97
  1. 10
      servo/src/main/java/com/galaxis/rcs/RCS.java
  2. 10
      servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java
  3. 2
      servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java
  4. 2
      servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java
  5. 2
      servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java
  6. 46
      servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskStatus.java
  7. 15
      servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java
  8. 26
      servo/src/main/java/com/galaxis/rcs/common/enums/OperationSide.java
  9. 31
      servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java
  10. 31
      servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java
  11. 25
      servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java
  12. 170
      servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java
  13. 3
      servo/src/main/java/com/galaxis/rcs/plan/Planner.java
  14. 29
      servo/src/main/java/com/galaxis/rcs/plan/path/AStarNodeState.java
  15. 122
      servo/src/main/java/com/galaxis/rcs/plan/path/AStarPathPlanner.java
  16. 4
      servo/src/main/java/com/galaxis/rcs/plan/path/ChargerPoint.java
  17. 95
      servo/src/main/java/com/galaxis/rcs/plan/path/GraphInitializer.java
  18. 69
      servo/src/main/java/com/galaxis/rcs/plan/path/NavigationGraph.java
  19. 23
      servo/src/main/java/com/galaxis/rcs/plan/path/NavigationNode.java
  20. 33
      servo/src/main/java/com/galaxis/rcs/plan/path/OperationPoint.java
  21. 7
      servo/src/main/java/com/galaxis/rcs/plan/path/PathInfoManager.java
  22. 15
      servo/src/main/java/com/galaxis/rcs/plan/path/PathSegment.java
  23. 4
      servo/src/main/java/com/galaxis/rcs/plan/path/Point.java
  24. 4
      servo/src/main/java/com/galaxis/rcs/plan/path/StorePoint.java
  25. 4
      servo/src/main/java/com/galaxis/rcs/plan/path/WayPoint.java
  26. 56
      servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java
  27. 99
      servo/src/main/java/com/galaxis/rcs/task/TaskService.java
  28. 31
      servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java
  29. 2
      servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java
  30. 6
      servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java
  31. 24
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java

10
servo/src/main/java/com/galaxis/rcs/RCS.java

@ -35,19 +35,11 @@ public class RCS {
AddTaskResult result = new AddTaskResult();
LogisticsRuntime logisticsRuntime = logisticsRuntimeService.findByEnvCode(envCode);
String bizTaskId = logisticsRuntime.taskService.addBizTask(request);
logisticsRuntime.taskDispatchFactory.checkAll();
result.bizTaskId = bizTaskId;
return result;
}
/**
* 地图信息2
* 1<->2, 2<->3, 3<->4, 4<->5, 5<->6, 6<->7, 7<->8, 8<->9,9<->10
* 1 <-> 38, 1 <-> 36
*/
}

10
servo/src/main/java/com/galaxis/rcs/common/entity/AddTaskRequest.java

@ -51,4 +51,14 @@ public class AddTaskRequest {
* 目标位置
*/
public StoreLocation to;
/**
* 任务描述
*/
public String description;
/**
* 创建者
*/
public String createBy;
}

2
servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskBiz.java

@ -11,6 +11,8 @@ import java.util.Date;
public class RcsTaskBiz implements Serializable {
/** */
private Long bizTaskId;
/** 环境ID */
private Long envId;
/** 任务类型 */
private String bizType;
/** 托盘ID */

2
servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskDevice.java

@ -15,6 +15,8 @@ public class RcsTaskDevice implements Serializable {
private Long planTaskId;
/** 业务任务ID */
private Long bizTaskId;
/** 环境ID */
private Long envId;
/** 设备类型 */
private String deviceType;
/** 执行器ID */

2
servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java

@ -13,6 +13,8 @@ public class RcsTaskPlan implements Serializable {
private Long planTaskId;
/** 业务任务ID */
private Long bizTaskId;
/** 环境ID */
private Long envId;
/** 规划类型 */
private String planType;
/** 执行器ID */

46
servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskStatus.java

@ -0,0 +1,46 @@
package com.galaxis.rcs.common.enums;
public enum BizTaskStatus {
/**
* 待调度
*/
WAITING_FOR_DISPATCH,
/**
* 设备执行中
*/
DEVICE_EXECUTING,
/**
* 暂停执行
*/
PAUSED,
/**
* 调度异常
*/
DISPATCH_ERROR,
/**
* 规划异常
*/
PLANNING_ERROR,
/**
* 设备执行异常
*/
DEVICE_ERROR;
public static BizTaskStatus fromString(String value) {
if (value == null)
throw new IllegalArgumentException("Value cannot be null");
for (BizTaskStatus type : BizTaskStatus.values()) {
if (type.toString().equalsIgnoreCase(value.trim())) {
return type;
}
}
throw new IllegalArgumentException("No constant with name: " + value);
}
}

15
servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java

@ -1,5 +1,18 @@
package com.galaxis.rcs.common.enums;
public enum BizTaskType {
CARRY, // 搬运任务
CARRY; // 搬运任务
public static BizTaskType fromString(String value) {
if (value == null)
throw new IllegalArgumentException("Value cannot be null");
for (BizTaskType type : BizTaskType.values()) {
if (type.toString().equalsIgnoreCase(value.trim())) {
return type;
}
}
throw new IllegalArgumentException("No constant with name: " + value);
}
}

26
servo/src/main/java/com/galaxis/rcs/common/enums/OperationSide.java

@ -0,0 +1,26 @@
package com.galaxis.rcs.common.enums;
/**
* 表示货位 路标点, 在世界坐标中的相对位置关系
*/
public enum OperationSide {
/**
* 货位在路标点的上方
*/
TOP,
/**
* 货位在路标点的下方
*/
BOTTOM,
/**
* 货位在路标点的左侧
*/
LEFT,
/**
* 货位在路标点的右侧
*/
RIGHT
}

31
servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskBiz.java

@ -18,6 +18,8 @@ public class QRcsTaskBiz extends RelationalPathBase<RcsTaskBiz> {
/** */
public final NumberPath<Long> bizTaskId = createNumber("bizTaskId", Long.class);
/** 环境ID */
public final NumberPath<Long> envId = createNumber("envId", Long.class);
/** 任务类型 */
public final StringPath bizType = createString("bizType");
/** 托盘ID */
@ -74,19 +76,20 @@ public class QRcsTaskBiz extends RelationalPathBase<RcsTaskBiz> {
private void addMetadata() {
addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19));
addMetadata(bizType, ColumnMetadata.named("biz_type").withIndex(2).ofType(Types.VARCHAR).withSize(10));
addMetadata(lpn, ColumnMetadata.named("lpn").withIndex(3).ofType(Types.VARCHAR).withSize(50));
addMetadata(priority, ColumnMetadata.named("priority").withIndex(4).ofType(Types.INTEGER).withSize(10));
addMetadata(taskFrom, ColumnMetadata.named("task_from").withIndex(5).ofType(Types.VARCHAR).withSize(50));
addMetadata(taskTo, ColumnMetadata.named("task_to").withIndex(6).ofType(Types.VARCHAR).withSize(50));
addMetadata(allocatedExecutorId, ColumnMetadata.named("allocated_executor_id").withIndex(7).ofType(Types.VARCHAR).withSize(50));
addMetadata(bizTaskPayload, ColumnMetadata.named("biz_task_payload").withIndex(8).ofType(Types.VARCHAR).withSize(3000));
addMetadata(bizTaskErrorInfo, ColumnMetadata.named("biz_task_error_info").withIndex(9).ofType(Types.VARCHAR).withSize(500));
addMetadata(bizTaskDescription, ColumnMetadata.named("biz_task_description").withIndex(10).ofType(Types.VARCHAR).withSize(500));
addMetadata(bizTaskStatus, ColumnMetadata.named("biz_task_status").withIndex(11).ofType(Types.VARCHAR).withSize(10));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(12).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(13).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(14).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(15).ofType(Types.VARCHAR).withSize(50));
addMetadata(envId, ColumnMetadata.named("env_id").withIndex(2).ofType(Types.BIGINT).withSize(19));
addMetadata(bizType, ColumnMetadata.named("biz_type").withIndex(3).ofType(Types.VARCHAR).withSize(10));
addMetadata(lpn, ColumnMetadata.named("lpn").withIndex(4).ofType(Types.VARCHAR).withSize(50));
addMetadata(priority, ColumnMetadata.named("priority").withIndex(5).ofType(Types.INTEGER).withSize(10));
addMetadata(taskFrom, ColumnMetadata.named("task_from").withIndex(6).ofType(Types.VARCHAR).withSize(50));
addMetadata(taskTo, ColumnMetadata.named("task_to").withIndex(7).ofType(Types.VARCHAR).withSize(50));
addMetadata(allocatedExecutorId, ColumnMetadata.named("allocated_executor_id").withIndex(8).ofType(Types.VARCHAR).withSize(50));
addMetadata(bizTaskPayload, ColumnMetadata.named("biz_task_payload").withIndex(9).ofType(Types.VARCHAR).withSize(3000));
addMetadata(bizTaskErrorInfo, ColumnMetadata.named("biz_task_error_info").withIndex(10).ofType(Types.VARCHAR).withSize(500));
addMetadata(bizTaskDescription, ColumnMetadata.named("biz_task_description").withIndex(11).ofType(Types.VARCHAR).withSize(500));
addMetadata(bizTaskStatus, ColumnMetadata.named("biz_task_status").withIndex(12).ofType(Types.VARCHAR).withSize(10));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(13).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(14).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(15).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(16).ofType(Types.VARCHAR).withSize(50));
}
}

31
servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskDevice.java

@ -22,6 +22,8 @@ public class QRcsTaskDevice extends RelationalPathBase<RcsTaskDevice> {
public final NumberPath<Long> planTaskId = createNumber("planTaskId", Long.class);
/** 业务任务ID */
public final NumberPath<Long> bizTaskId = createNumber("bizTaskId", Long.class);
/** 环境ID */
public final NumberPath<Long> envId = createNumber("envId", Long.class);
/** 设备类型 */
public final StringPath deviceType = createString("deviceType");
/** 执行器ID */
@ -80,19 +82,20 @@ public class QRcsTaskDevice extends RelationalPathBase<RcsTaskDevice> {
addMetadata(deviceTaskId, ColumnMetadata.named("device_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19));
addMetadata(planTaskId, ColumnMetadata.named("plan_task_id").withIndex(2).ofType(Types.BIGINT).withSize(19));
addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(3).ofType(Types.BIGINT).withSize(19));
addMetadata(deviceType, ColumnMetadata.named("device_type").withIndex(4).ofType(Types.VARCHAR).withSize(50));
addMetadata(deviceItemId, ColumnMetadata.named("device_item_id").withIndex(5).ofType(Types.VARCHAR).withSize(50));
addMetadata(seq, ColumnMetadata.named("seq").withIndex(6).ofType(Types.INTEGER).withSize(10));
addMetadata(packetType, ColumnMetadata.named("packet_type").withIndex(7).ofType(Types.VARCHAR).withSize(10));
addMetadata(packetEndPoint, ColumnMetadata.named("packet_end_point").withIndex(8).ofType(Types.VARCHAR).withSize(50));
addMetadata(packetPayload, ColumnMetadata.named("packet_payload").withIndex(9).ofType(Types.VARCHAR).withSize(50));
addMetadata(deviceTaskPayload, ColumnMetadata.named("device_task_payload").withIndex(10).ofType(Types.VARCHAR).withSize(3000));
addMetadata(deviceTaskStatus, ColumnMetadata.named("device_task_status").withIndex(11).ofType(Types.VARCHAR).withSize(10));
addMetadata(deviceTaskErrorInfo, ColumnMetadata.named("device_task_error_info").withIndex(12).ofType(Types.VARCHAR).withSize(500));
addMetadata(deviceTaskDescription, ColumnMetadata.named("device_task_description").withIndex(13).ofType(Types.VARCHAR).withSize(500));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(14).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(15).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(16).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(17).ofType(Types.VARCHAR).withSize(50));
addMetadata(envId, ColumnMetadata.named("env_id").withIndex(4).ofType(Types.BIGINT).withSize(19));
addMetadata(deviceType, ColumnMetadata.named("device_type").withIndex(5).ofType(Types.VARCHAR).withSize(50));
addMetadata(deviceItemId, ColumnMetadata.named("device_item_id").withIndex(6).ofType(Types.VARCHAR).withSize(50));
addMetadata(seq, ColumnMetadata.named("seq").withIndex(7).ofType(Types.INTEGER).withSize(10));
addMetadata(packetType, ColumnMetadata.named("packet_type").withIndex(8).ofType(Types.VARCHAR).withSize(10));
addMetadata(packetEndPoint, ColumnMetadata.named("packet_end_point").withIndex(9).ofType(Types.VARCHAR).withSize(50));
addMetadata(packetPayload, ColumnMetadata.named("packet_payload").withIndex(10).ofType(Types.VARCHAR).withSize(50));
addMetadata(deviceTaskPayload, ColumnMetadata.named("device_task_payload").withIndex(11).ofType(Types.VARCHAR).withSize(3000));
addMetadata(deviceTaskStatus, ColumnMetadata.named("device_task_status").withIndex(12).ofType(Types.VARCHAR).withSize(10));
addMetadata(deviceTaskErrorInfo, ColumnMetadata.named("device_task_error_info").withIndex(13).ofType(Types.VARCHAR).withSize(500));
addMetadata(deviceTaskDescription, ColumnMetadata.named("device_task_description").withIndex(14).ofType(Types.VARCHAR).withSize(500));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(15).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(16).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(17).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(18).ofType(Types.VARCHAR).withSize(50));
}
}

25
servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java

@ -20,6 +20,8 @@ public class QRcsTaskPlan extends RelationalPathBase<RcsTaskPlan> {
public final NumberPath<Long> planTaskId = createNumber("planTaskId", Long.class);
/** 业务任务ID */
public final NumberPath<Long> bizTaskId = createNumber("bizTaskId", Long.class);
/** 环境ID */
public final NumberPath<Long> envId = createNumber("envId", Long.class);
/** 规划类型 */
public final StringPath planType = createString("planType");
/** 执行器ID */
@ -71,16 +73,17 @@ public class QRcsTaskPlan extends RelationalPathBase<RcsTaskPlan> {
private void addMetadata() {
addMetadata(planTaskId, ColumnMetadata.named("plan_task_id").withIndex(1).ofType(Types.BIGINT).withSize(19));
addMetadata(bizTaskId, ColumnMetadata.named("biz_task_id").withIndex(2).ofType(Types.BIGINT).withSize(19));
addMetadata(planType, ColumnMetadata.named("plan_type").withIndex(3).ofType(Types.VARCHAR).withSize(10));
addMetadata(executorId, ColumnMetadata.named("executor_id").withIndex(4).ofType(Types.VARCHAR).withSize(50));
addMetadata(seq, ColumnMetadata.named("seq").withIndex(5).ofType(Types.INTEGER).withSize(10));
addMetadata(planTaskPayload, ColumnMetadata.named("plan_task_payload").withIndex(6).ofType(Types.VARCHAR).withSize(3000));
addMetadata(planTaskStatus, ColumnMetadata.named("plan_task_status").withIndex(7).ofType(Types.VARCHAR).withSize(10));
addMetadata(planTaskErrorInfo, ColumnMetadata.named("plan_task_error_info").withIndex(8).ofType(Types.VARCHAR).withSize(500));
addMetadata(planTaskDescription, ColumnMetadata.named("plan_task_description").withIndex(9).ofType(Types.VARCHAR).withSize(500));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(10).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(11).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(12).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(13).ofType(Types.VARCHAR).withSize(50));
addMetadata(envId, ColumnMetadata.named("env_id").withIndex(3).ofType(Types.BIGINT).withSize(19));
addMetadata(planType, ColumnMetadata.named("plan_type").withIndex(4).ofType(Types.VARCHAR).withSize(10));
addMetadata(executorId, ColumnMetadata.named("executor_id").withIndex(5).ofType(Types.VARCHAR).withSize(50));
addMetadata(seq, ColumnMetadata.named("seq").withIndex(6).ofType(Types.INTEGER).withSize(10));
addMetadata(planTaskPayload, ColumnMetadata.named("plan_task_payload").withIndex(7).ofType(Types.VARCHAR).withSize(3000));
addMetadata(planTaskStatus, ColumnMetadata.named("plan_task_status").withIndex(8).ofType(Types.VARCHAR).withSize(10));
addMetadata(planTaskErrorInfo, ColumnMetadata.named("plan_task_error_info").withIndex(9).ofType(Types.VARCHAR).withSize(500));
addMetadata(planTaskDescription, ColumnMetadata.named("plan_task_description").withIndex(10).ofType(Types.VARCHAR).withSize(500));
addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(11).ofType(Types.TIMESTAMP));
addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(12).ofType(Types.VARCHAR).withSize(50));
addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(13).ofType(Types.TIMESTAMP));
addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(14).ofType(Types.VARCHAR).withSize(50));
}
}

170
servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java

@ -2,64 +2,152 @@ package com.galaxis.rcs.plan;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.common.entity.RcsTaskPlan;
import com.galaxis.rcs.common.enums.BizTaskStatus;
import com.google.common.collect.Lists;
import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime;
import org.clever.data.jdbc.DaoFactory;
import org.clever.data.jdbc.QueryDSL;
import java.util.Date;
import java.util.List;
import static com.galaxis.rcs.common.query.QRcsTaskBiz.rcsTaskBiz;
/**
* PTR 任务规划器
* 用于处理 CL2 / CLX 等车型的任务规划
*/
public class PTRTaskPlanner implements Planner {
static final QueryDSL queryDSL = DaoFactory.getQueryDSL();
/**
* 执行任务规划
*
* @param runtime 物流运行时环境
* @param task 任务对象包含任务的详细信息
* @param executorId 执行器ID
* @param runtime 物流运行时环境
* @param task 任务对象包含任务的详细信息
* @param agv AGV
*/
@Override
public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, String executorId) {
/**
* 示例数据
* {
* type: 'carry', // 任务类型
* agv: 'cl2', // 指定车辆
* lpn: 'pallet1124', // 托盘ID, 用于校验
* priority: 1, // 优先级
* // 起始点位的详细信息
* from: {
* item: '27', // 货架编号
* bay: 0, // 货架列
* level: 1, // 货架层
* cell: 0 // 货架格
* },
* // 目标点位的详细信息
* to: {
* item: '20' // 地堆货位号
* }
* }
*/
public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, ExecutorItem agv) {
/**
* 地图路由示例1
* 17<->20, 20<->21, 21<->22, 22<->23, 23<->24, 24<->25, 25<->26, 26<->27, 27<->charger2,
*
* 地图货位信息
* 21 左侧 rack1 / 3
* 22 右侧 56
* 23 左侧 rack1 / 2
* 24 旋转位
* 25 左侧 rack1 / 1
* 26 右侧 58
* 27 左侧 rack1 / 0
*/
// 绑定任务执行器
task.setAllocatedExecutorId(executorId);
task.setAllocatedExecutorId(agv.getId());
task.setBizTaskStatus(BizTaskStatus.DEVICE_EXECUTING.toString());
queryDSL.update(rcsTaskBiz)
.populate(task)
.set(rcsTaskBiz.updateAt, new Date())
.set(rcsTaskBiz.updateBy, PTRTaskPlanner.class.getName())
.where(rcsTaskBiz.bizTaskId.eq(task.getBizTaskId()))
.execute();
runtime.taskService.removeFromWaitingTaskList(task.getBizTaskId());
List<RcsTaskPlan> planList = Lists.newArrayList();
/*
Java 编写任务规划逻辑.
例如, 需求给出的是
示例数据
需求报文:
```json5
{
type: 'carry', // 任务类型
agv: 'cl2', // 指定车辆
lpn: 'pallet1124', // 托盘ID, 用于校验
priority: 1, // 优先级
// 起始点位的详细信息
from: {
item: 'rack1',// 货架编号
bay: 0, // 货架列
level: 1, // 货架层
cell: 0 // 货架格
},
// 目标点位的详细信息
to: {
item: '54' // 地堆货位号
}
}
```
from 是一个组合数据, 他需要取出 "rack1"货架的"3", 取出 "pallet1124" 托盘
to 是一个对象数据他需要搬运到 "54" 号储位
// TODO: 写入 rcs_task_biz 表, 写入 rcs_task_plan 表, 并安排规划方案的顺序执行, 并将全部规划通知给 MQTT
RcsTaskPlan[] planList = new RcsTaskPlan[0];
地图路由
```text
路标点位信息
17<->20, 20<->21, 21<->22, 22<->23, 23<->24, 24<->25, 25<->26, 26<->27, 27<->charger2,
1<->2, 2<->3, 3<->4, 4<->5, 5<->6, 6<->7, 7<->8
36<->1, 38<->1, 8<->charger1
地图货位信息
```text
20 右侧 54
21 左侧 rack1 / 3
22 右侧 56
23 左侧 rack1 / 2
24 可旋转位
25 左侧 rack1 / 1
26 右侧 58
27 左侧 rack1 / 0
38 上方 49
36 上方 47
1 可旋转位
3 右侧 rack1 / 3
5 右侧 rack1 / 2
7 右侧 rack1 / 1
8 右侧 rack1 / 0
```
"地图货位信息"中看到"rack1"货架的"3" "27" 号路标点的左侧
他需要查询目前执行器所在的位置和执行器当前的姿态货叉朝向
如果方向不对他需要运行到最近的"可旋转位"进行方位姿态的调整
然后引导到取货点进行取货
取货完毕之后再查看目标位置
"地图货位信息"中看到目的地 "54" 号储位 位于 "20" 号路标点的右侧
他要查询取货之后的车的姿态货叉朝向
如果方向不对他需要运行到最近的"可旋转位"进行方位姿态的调整
然后引导到目的点进行放货
算法输出小车的行动规划序列, 行动的类型有:
移动: RcsTaskPlan move = new RcsTaskPlan()
move.type = "robotMove"; .executorId=当前机器人编号; .startWayPoint=""; .endWayPoint=""; .armRotiation=90;
转动 RcsTaskPlan rotation = new RcsTaskPlan()
rotation.type = "robotRotation"; .executorId=当前机器人编号; .worldRotation=90;
取货 RcsTaskPlan load = new RcsTaskPlan()
load.type = "robotLoad"; .executorId=当前机器人编号; .rackItem="货架ID"; .bay="列"; .level="层"; .cell="格"
放货 RcsTaskPlan unload = new RcsTaskPlan()
unload.type = "robotUnload"; .executorId=当前机器人编号; .rackItem="货架ID"; .bay="列"; .level="层"; .cell="格"
完成 RcsTaskPlan finish = new RcsTaskPlan()
finish.type = "robotFinish"; .executorId=当前机器人编号;
按照这个示例他输出结果为
const cl2 = Model.getCl2('ptr1')
const palletId = 'pallet1124'
const yy = Model.getPositionByEntityId(palletId).y
move('23')
rotation(90)
move('27')
load(level=1, cell=0)
move('23')
rotation(-90)
move('20')
unload(level=0)
finish()
```
*/
runtime.executorItemMap.get(executorId).executeTaskPlanList(runtime, task, planList);
agv.executeTaskPlanList(runtime, task, planList);
}
}

3
servo/src/main/java/com/galaxis/rcs/plan/Planner.java

@ -1,6 +1,7 @@
package com.galaxis.rcs.plan;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime;
/**
@ -15,5 +16,5 @@ public interface Planner {
* @param tasks 任务对象包含任务的详细信息
* @param executorId 执行器ID
*/
void executePlan(LogisticsRuntime runtime, RcsTaskBiz tasks, String executorId);
void executePlan(LogisticsRuntime runtime, RcsTaskBiz tasks, ExecutorItem executorId);
}

29
servo/src/main/java/com/galaxis/rcs/plan/path/AStarNodeState.java

@ -0,0 +1,29 @@
package com.galaxis.rcs.plan.path;
/**
* A*路径节点状态
*/
public record AStarNodeState(
String nodeId, // 当前节点ID
int direction, // 当前方向 (0,90,180,270)
double gCost, // 实际代价
double hCost, // 启发式代价
AStarNodeState parent // 父节点
) implements Comparable<AStarNodeState> {
// 状态唯一标识
public String stateKey() {
return nodeId + ":" + direction;
}
// 总代价
public double fCost() {
return gCost + hCost;
}
@Override
public int compareTo(AStarNodeState other) {
return Double.compare(this.fCost(), other.fCost());
}
}

122
servo/src/main/java/com/galaxis/rcs/plan/path/AStarPathPlanner.java

@ -0,0 +1,122 @@
package com.galaxis.rcs.plan.path;
import java.util.*;
/**
* A*路径规划器
*/
public class AStarPathPlanner {
private final NavigationGraph graph;
public AStarPathPlanner(NavigationGraph graph) {
this.graph = graph;
}
/**
* 规划路径
*
* @param startNodeId 起始节点ID
* @param startDirection 起始方向
* @param endNodeId 目标节点ID
* @param endDirection 目标方向
* @return 路径节点序列 (包含方向信息)
*/
public List<AStarNodeState> planPath(String startNodeId, int startDirection, String endNodeId, int endDirection) {
// 开放集 (优先队列)
PriorityQueue<AStarNodeState> openSet = new PriorityQueue<>();
// 状态管理
Map<String, Double> gScoreMap = new HashMap<>();
Map<String, AStarNodeState> cameFrom = new HashMap<>();
// 初始化起点
AStarNodeState start = new AStarNodeState(
startNodeId,
startDirection,
0,
graph.heuristicCost(startNodeId, endNodeId),
null
);
openSet.add(start);
gScoreMap.put(start.stateKey(), 0.0);
while (!openSet.isEmpty()) {
AStarNodeState current = openSet.poll();
// 到达目标状态
if (current.nodeId().equals(endNodeId) &&
current.direction() == endDirection) {
return reconstructPath(cameFrom, current);
}
// 处理移动操作 (到相邻节点)
for (NavigationNode neighbor : graph.getAdjacentNodes(current.nodeId())) {
PathSegment segment = graph.getPathSegment(current.nodeId(), neighbor.id());
if (segment == null) continue;
double moveCost = segment.distance();
double tentativeGCost = current.gCost() + moveCost;
String neighborKey = neighbor.id() + ":" + current.direction();
// 发现更好路径
if (tentativeGCost < gScoreMap.getOrDefault(neighborKey, Double.MAX_VALUE)) {
AStarNodeState neighborState = new AStarNodeState(
neighbor.id(),
current.direction(),
tentativeGCost,
graph.heuristicCost(neighbor.id(), endNodeId),
current
);
cameFrom.put(neighborKey, current);
gScoreMap.put(neighborKey, tentativeGCost);
openSet.add(neighborState);
}
}
// 处理旋转操作 (当前节点可旋转时)
NavigationNode currentNode = graph.nodes.get(current.nodeId());
if (currentNode != null && currentNode.rotatable()) {
for (int rotation : new int[]{90, -90}) {
int newDirection = (current.direction() + rotation + 360) % 360;
double rotateCost = 1.0; // 旋转代价
double tentativeGCost = current.gCost() + rotateCost;
String rotatedKey = current.nodeId() + ":" + newDirection;
// 发现更好路径
if (tentativeGCost < gScoreMap.getOrDefault(rotatedKey, Double.MAX_VALUE)) {
AStarNodeState rotatedState = new AStarNodeState(
current.nodeId(),
newDirection,
tentativeGCost,
current.hCost(), // 旋转不改变位置,启发值不变
current
);
cameFrom.put(rotatedKey, current);
gScoreMap.put(rotatedKey, tentativeGCost);
openSet.add(rotatedState);
}
}
}
}
return Collections.emptyList(); // 未找到路径
}
private List<AStarNodeState> reconstructPath(
Map<String, AStarNodeState> cameFrom,
AStarNodeState endState
) {
LinkedList<AStarNodeState> path = new LinkedList<>();
AStarNodeState current = endState;
while (current != null) {
path.addFirst(current);
current = cameFrom.get(current.stateKey());
}
return path;
}
}

4
servo/src/main/java/com/galaxis/rcs/plan/path/ChargerPoint.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.plan.path;
public class ChargerPoint {
}

95
servo/src/main/java/com/galaxis/rcs/plan/path/GraphInitializer.java

@ -0,0 +1,95 @@
package com.galaxis.rcs.plan.path;
import com.galaxis.rcs.common.enums.OperationSide;
import com.yvan.logisticsModel.LogisticsRuntime;
import org.clever.core.Conv;
import java.util.List;
import java.util.Map;
public class GraphInitializer {
public NavigationGraph initializeGraph(LogisticsRuntime runtime, String agvType, List<Map<String, Object>> jsonData) {
if (runtime.executorGraphMap.containsKey(agvType)) {
return runtime.executorGraphMap.get(agvType);
}
NavigationGraph graph = new NavigationGraph();
runtime.executorGraphMap.put(agvType, graph);
// 第一步:创建所有节点
for (Map<String, Object> nodeData : jsonData) {
String id = (String) nodeData.get("id");
// 判断是否是 way 类型才创建 NavigationNode
if (!"way".equals(nodeData.get("t"))) {
continue;
}
List<List<Double>> tf = (List<List<Double>>) nodeData.get("tf");
double x = tf.get(0).get(0);
double z = tf.get(0).get(2);
// 检查是否为可旋转点
Map<String, Object> dt = (Map<String, Object>) nodeData.get("dt");
boolean rotatable = false;
if (dt.containsKey("agvRotation")) {
rotatable = true;
}
// 添加节点
graph.addNode(new NavigationNode(id, x, z, rotatable));
}
// 第二步:添加路径连接
for (Map<String, Object> nodeData : jsonData) {
if (!"way".equals(nodeData.get("t"))) continue;
String id = (String) nodeData.get("id");
Map<String, Object> dt = (Map<String, Object>) nodeData.get("dt");
List<String> outEdges = (List<String>) dt.get("out");
if (outEdges != null) {
for (String neighborId : outEdges) {
if (graph.nodes.containsKey(id) && graph.nodes.containsKey(neighborId)) {
NavigationNode from = graph.nodes.get(id);
NavigationNode to = graph.nodes.get(neighborId);
graph.addBidirectionalPath(from, to);
}
}
}
}
// 第三步:添加操作点 OperationPoint
for (Map<String, Object> nodeData : jsonData) {
if (!"way".equals(nodeData.get("t"))) continue;
String nodeId = (String) nodeData.get("id");
Map<String, Object> dt = (Map<String, Object>) nodeData.get("dt");
if (dt.containsKey("linkStore")) {
List<Map<String, Object>> linkStores = (List<Map<String, Object>>) dt.get("linkStore");
for (Map<String, Object> store : linkStores) {
String targetId = (String) store.get("item");
Integer bay = Conv.asInteger(store.get("bay"));
Integer level = Conv.asInteger(store.get("level"));
Integer cell = Conv.asInteger(store.get("cell"));
// 根据位置确定方位(这里假设固定为 TOP,可根据 tf 中的方向判断更精确)
OperationSide side = OperationSide.TOP;
OperationPoint point = new OperationPoint(
graph.nodes.get(nodeId),
targetId,
side,
bay,
level,
cell
);
graph.addOperationPoint(point);
}
}
}
return graph;
}
}

69
servo/src/main/java/com/galaxis/rcs/plan/path/NavigationGraph.java

@ -0,0 +1,69 @@
package com.galaxis.rcs.plan.path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 导航图管理器
*/
public class NavigationGraph {
final Map<String, NavigationNode> nodes = new ConcurrentHashMap<>();
final Map<String, OperationPoint> operationPoints = new ConcurrentHashMap<>();
final Map<String, PathSegment> pathSegments = new ConcurrentHashMap<>();
final Map<String, List<NavigationNode>> adjacencyList = new ConcurrentHashMap<>();
// 添加节点
public void addNode(NavigationNode node) {
nodes.put(node.id(), node);
adjacencyList.put(node.id(), new ArrayList<>());
}
// 添加双向路径
public void addBidirectionalPath(NavigationNode a, NavigationNode b) {
double distance = a.distanceTo(b);
pathSegments.put(a.id() + "->" + b.id(), new PathSegment(a, b, distance));
pathSegments.put(b.id() + "->" + a.id(), new PathSegment(b, a, distance));
adjacencyList.get(a.id()).add(b);
adjacencyList.get(b.id()).add(a);
}
// 添加操作点
public void addOperationPoint(OperationPoint point) {
operationPoints.put(point.locationKey(), point);
}
// 查找操作点
public OperationPoint findOperationPoint(String locationKey) {
return operationPoints.get(locationKey);
}
// 获取路径段
public PathSegment getPathSegment(String startId, String endId) {
return pathSegments.get(startId + "->" + endId);
}
// 获取相邻节点
public List<NavigationNode> getAdjacentNodes(String nodeId) {
return adjacencyList.getOrDefault(nodeId, Collections.emptyList());
}
// 获取最近的旋转点
public NavigationNode findNearestRotationPoint(String startId) {
NavigationNode start = nodes.get(startId);
if (start == null) return null;
return nodes.values().parallelStream()
.filter(NavigationNode::rotatable)
.min(Comparator.comparingDouble(start::distanceTo))
.orElse(null);
}
// 计算启发式代价 (使用欧几里得距离)
public double heuristicCost(String fromId, String toId) {
NavigationNode from = nodes.get(fromId);
NavigationNode to = nodes.get(toId);
if (from == null || to == null) return Double.MAX_VALUE;
return from.distanceTo(to);
}
}

23
servo/src/main/java/com/galaxis/rcs/plan/path/NavigationNode.java

@ -0,0 +1,23 @@
package com.galaxis.rcs.plan.path;
/**
* 路标节点地图中的顶点
*/
public record NavigationNode(
String id, // 节点ID (如 "20", "charger1")
double x, // 向右增长
double z, // 向下增长 (y无效)
boolean rotatable // 是否为可旋转位
) implements Comparable<NavigationNode> {
// 计算到另一个节点的欧几里得距离
public double distanceTo(NavigationNode other) {
double dx = this.x - other.x;
double dz = this.z - other.z;
return Math.sqrt(dx * dx + dz * dz);
}
@Override
public int compareTo(NavigationNode other) {
return this.id.compareTo(other.id);
}
}

33
servo/src/main/java/com/galaxis/rcs/plan/path/OperationPoint.java

@ -0,0 +1,33 @@
package com.galaxis.rcs.plan.path;
import com.galaxis.rcs.common.enums.OperationSide;
/**
* 操作位置取货/放货/充电点
*/
public record OperationPoint(
NavigationNode node, // 关联的路标节点
String targetId, // 货位ID (如 "54") 或货架ID (如 "rack1")
OperationSide side, // 方位
Integer bay, // 列 (货架时非空)
Integer level, // 层 (货架时非空)
Integer cell // 格 (货架时非空)
) {
// 计算操作所需方向
public int requiredDirection() {
return switch (side) {
case LEFT -> 90;
case RIGHT -> 270;
case TOP -> 0;
case BOTTOM -> 180;
};
}
// 位置唯一标识
public String locationKey() {
if (bay == null || level == null || cell == null) {
return targetId; // 地堆货位
}
return targetId + "-" + bay + "-" + level + "-" + cell;
}
}

7
servo/src/main/java/com/galaxis/rcs/plan/path/PathInfoManager.java

@ -1,7 +0,0 @@
package com.galaxis.rcs.plan.path;
/**
* 物流任务路径信息管理类
*/
public class PathInfoManager {
}

15
servo/src/main/java/com/galaxis/rcs/plan/path/PathSegment.java

@ -0,0 +1,15 @@
package com.galaxis.rcs.plan.path;
/**
* 路径段节点之间的连接
*/
public record PathSegment(
NavigationNode start, // 起点节点
NavigationNode end, // 终点节点
double distance // 路径距离
) {
// 路径唯一标识
public String key() {
return start.id() + "->" + end.id();
}
}

4
servo/src/main/java/com/galaxis/rcs/plan/path/Point.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.plan.path;
public class Point {
}

4
servo/src/main/java/com/galaxis/rcs/plan/path/StorePoint.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.plan.path;
public class StorePoint {
}

4
servo/src/main/java/com/galaxis/rcs/plan/path/WayPoint.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.plan.path;
public class WayPoint {
}

56
servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java

@ -2,11 +2,15 @@ package com.galaxis.rcs.task;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.task.dispatcher.TaiWanDispatcher;
import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime;
import java.util.List;
public class TaskDispatchFactory {
public final LogisticsRuntime logisticsRuntime;
private TaiWanDispatcher dispatcher = new TaiWanDispatcher();
private WorkThread workThread;
public TaskDispatchFactory(LogisticsRuntime logisticsRuntime) {
this.logisticsRuntime = logisticsRuntime;
@ -16,16 +20,60 @@ public class TaskDispatchFactory {
* 开启轮询线程定时检查有没有空执行器可以用于执行选定任务
*/
public void startPolling() {
// TODO: 启动一个线程,定时检查是否有空闲的执行器
RcsTaskBiz taskBiz = new RcsTaskBiz();
dispatcher.dispatchTask(this, taskBiz);
if (workThread != null && workThread.isAlive()) {
return; // 如果线程已经在运行,则不再启动
}
workThread = new WorkThread(this);
workThread.setName("RCS-TaskDispatchFactory-WorkThread");
workThread.setDaemon(true); // 设置为守护线程
workThread.start();
}
/**
* 停止轮询线程
*/
public void stopPolling() {
// TODO: 停止轮询线程
if (workThread != null) {
workThread.running = false; // 设置线程停止标志
try {
workThread.join(); // 等待线程结束
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
workThread = null; // 清理引用
}
}
static class WorkThread extends Thread {
private final TaskDispatchFactory factory;
private boolean running = true;
public WorkThread(TaskDispatchFactory factory) {
this.factory = factory;
}
@Override
public void run() {
while (this.running) {
List<ExecutorItem> executorList = this.factory.logisticsRuntime.getFreeExecutorList();
// 获取空车
if (!executorList.isEmpty()) {
// 获取任务
List<RcsTaskBiz> tasks = this.factory.logisticsRuntime.taskService.getWaitingTaskList(executorList);
if (!tasks.isEmpty()) {
// 分配任务
this.factory.dispatcher.dispatchTask(this.factory, executorList, tasks);
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
/**

99
servo/src/main/java/com/galaxis/rcs/task/TaskService.java

@ -1,9 +1,22 @@
package com.galaxis.rcs.task;
import com.galaxis.rcs.common.entity.AddTaskRequest;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.common.enums.BizTaskStatus;
import com.galaxis.rcs.common.query.QRcsTaskBiz;
import com.google.common.base.Strings;
import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime;
import org.clever.core.Conv;
import org.clever.core.json.JsonWrapper;
import org.clever.data.jdbc.DaoFactory;
import org.clever.data.jdbc.QueryDSL;
import org.joda.time.DateTime;
import java.util.Date;
import java.util.List;
import static com.galaxis.rcs.common.query.QRcsTaskBiz.rcsTaskBiz;
/**
* 任务服务
@ -11,13 +24,48 @@ import org.clever.data.jdbc.DaoFactory;
*/
public class TaskService {
static final QueryDSL queryDSL = DaoFactory.getQueryDSL();
public final LogisticsRuntime logisticsRuntime;
public List<RcsTaskBiz> waitingTaskList;
public TaskService(LogisticsRuntime logisticsRuntime) {
this.logisticsRuntime = logisticsRuntime;
}
/**
* 从数据库中加载当前等待执行的任务列表
*/
public void reload() {
this.waitingTaskList = queryDSL.select(rcsTaskBiz)
.from(rcsTaskBiz)
.where(rcsTaskBiz.bizTaskStatus.eq(BizTaskStatus.WAITING_FOR_DISPATCH.toString()))
.where(rcsTaskBiz.envId.eq(logisticsRuntime.logisticsEnv.getEnvId()))
.orderBy(rcsTaskBiz.priority.desc())
.orderBy(rcsTaskBiz.bizTaskId.asc())
.fetch();
}
/**
* 获取当前等待执行的任务列表
*/
public List<RcsTaskBiz> getWaitingTaskList(List<ExecutorItem> executorList) {
return waitingTaskList;
}
/**
* 从等待任务列表中移除指定的业务任务
*/
public boolean removeFromWaitingTaskList(Long bizTaskId) {
for (RcsTaskBiz task : waitingTaskList) {
if (task.getBizTaskId().equals(bizTaskId)) {
waitingTaskList.remove(task);
return true;
}
}
return false;
}
/**
* 添加业务任务
*
* @param request 任务请求
@ -28,40 +76,27 @@ public class TaskService {
throw new RuntimeException("TaskExecutorId cannot be null or empty");
}
String payload = JsonWrapper.toJson(request);
Long taskId = DaoFactory.getJdbc().nextId("rcs_task_biz");
queryDSL.insert(rcsTaskBiz)
.set(rcsTaskBiz.bizTaskId, taskId)
.set(rcsTaskBiz.envId, logisticsRuntime.logisticsEnv.getEnvId())
.set(rcsTaskBiz.bizType, request.type.toString())
.set(rcsTaskBiz.lpn, request.lpn)
.set(rcsTaskBiz.priority, request.priority)
.set(rcsTaskBiz.taskFrom, request.from.toString())
.set(rcsTaskBiz.taskTo, request.to.toString())
.set(rcsTaskBiz.allocatedExecutorId, request.taskExecutorId)
.set(rcsTaskBiz.bizTaskPayload, payload)
.set(rcsTaskBiz.bizTaskErrorInfo, "N/A")
.set(rcsTaskBiz.bizTaskDescription, request.description)
.set(rcsTaskBiz.bizTaskStatus, BizTaskStatus.WAITING_FOR_DISPATCH.toString())
.set(rcsTaskBiz.createAt, new Date())
.set(rcsTaskBiz.createBy, request.createBy)
.execute();
/**
* TODO: 插入 rcs_task_biz , 结构为
* biz_task_id bigint not null,
* task_executor_id varchar(50) not null,
* task_type varchar(10)
* lpn varchar(50)
* priority integer
* task_from varchar(100)
* task_to varchar(100)
* biz_task_status varchar(10) default 'pending'
* create_at timestamp
* create_by varchar(50)
* update_at timestamp
* update_by varchar(50)
*
* create table rcs_task_biz (
* biz_task_id bigint not null,
* task_executor_id varchar(50) not null comment '任务执行器ID' default 'N/A',
* task_type varchar(10) not null comment '任务类型' default 'carry',
* lpn varchar(50) not null comment '托盘ID',
* priority integer not null comment '任务优先级',
* task_from varchar(50) not null comment '任务起始点',
* task_to varchar(50) not null comment '任务目标点',
* biz_task_status varchar(10) default 'pending' comment '任务状态',
* create_at datetime not null comment '创建时间',
* create_by varchar(50) not null comment '创建人',
* update_at datetime not null comment '更新时间',
* update_by varchar(50) not null comment '更新人',
*
* primary key (biz_task_id)
* }
*/
logisticsRuntime.taskDispatchFactory.checkAll();
return taskId.toString();
}

31
servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java

@ -4,24 +4,35 @@ import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.plan.Planner;
import com.galaxis.rcs.plan.TaskPlannerFactory;
import com.galaxis.rcs.task.TaskDispatchFactory;
import com.yvan.logisticsModel.ExecutorItem;
import java.util.List;
import java.util.Objects;
public class TaiWanDispatcher {
public void dispatchTask(TaskDispatchFactory factory, RcsTaskBiz tasks) {
// TODO: 台湾展会的任务分配逻辑
public void dispatchTask(TaskDispatchFactory factory, List<ExecutorItem> executorList, List<RcsTaskBiz> tasks) {
// 台湾展会的任务分配逻辑
for (ExecutorItem agv : executorList) {
String agvType = agv.getT();
for (RcsTaskBiz task : tasks) {
if (Objects.equals(agv.getId(), task.getAllocatedExecutorId())) {
// 按车 ID 分配任务
this.allocateExecutorBizTask(factory, task, agv);
}
}
}
}
/**
* TODO: 分配任务给指定的执行器
*
* @param tasks 任务对象包含任务的详细信息
* @param executorId 执行器ID
* @param task 任务对象包含任务的详细信息
* @param agv 执行器
*/
public void allocateExecutorBizTask(TaskDispatchFactory factory, RcsTaskBiz tasks, String executorId) {
// 选定了一个执行器,分配任务给它
String executorType = executorId.substring(0, 3); // 假设执行器ID的前3位是车型标识
Planner planner = TaskPlannerFactory.getPlanner(executorType);
planner.executePlan(factory.logisticsRuntime, tasks, executorId);
public void allocateExecutorBizTask(TaskDispatchFactory factory, RcsTaskBiz task, ExecutorItem agv) {
Planner planner = TaskPlannerFactory.getPlanner(agv.getT());
planner.executePlan(factory.logisticsRuntime, task, agv);
}
}

2
servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java

@ -14,7 +14,7 @@ public class LogisticsEnv {
private EnvStartParam startParam;
// 环境ID
private String envId;
private Long envId;
// 环境状态
private EnvStatus state;

6
servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java

@ -16,7 +16,7 @@ public class ExecutorItem extends BaseItem {
/**
* 执行规划任务
*/
public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, RcsTaskPlan[] planList) {
public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, List<RcsTaskPlan> planList) {
if (this.currentPlanList.size() > 0) {
throw new RuntimeException("has plans, please wait for the current plans to finish");
}
@ -24,4 +24,8 @@ public class ExecutorItem extends BaseItem {
// TODO: 开启轮询线程,等待下一个待执行任务
// 找到对应类型的 connector,进行报文的发送
}
public boolean isFree() {
throw new RuntimeException("not implemented yet, please implement isFree method in ExecutorItem");
}
}

24
servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java

@ -1,10 +1,14 @@
package com.yvan.logisticsModel;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.plan.path.NavigationGraph;
import com.galaxis.rcs.task.TaskDispatchFactory;
import com.galaxis.rcs.task.TaskService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yvan.logisticsEnv.LogisticsEnv;
import java.util.List;
import java.util.Map;
/**
@ -38,6 +42,11 @@ public class LogisticsRuntime {
public final Map<String, ExecutorItem> executorItemMap = Maps.newConcurrentMap();
/**
* AGV导航地图 车类型 t -> NavigationGraph
*/
public final Map<String, NavigationGraph> executorGraphMap = Maps.newConcurrentMap();
/**
* 楼层目录 catalogCode -> Floor
*/
public final Map<String, Floor> floorMap = Maps.newHashMap();
@ -45,4 +54,19 @@ public class LogisticsRuntime {
public LogisticsRuntime(LogisticsEnv logisticsEnv) {
this.logisticsEnv = logisticsEnv;
}
/**
* 获取当前空闲的执行器列表
*/
public List<ExecutorItem> getFreeExecutorList() {
List<ExecutorItem> freeExecutorList = Lists.newArrayList();
for (ExecutorItem executorItem : executorItemMap.values()) {
if (executorItem.isFree()) {
freeExecutorList.add(executorItem);
}
}
return freeExecutorList;
}
}

Loading…
Cancel
Save