From 35ad214e6c080d40d0501df8e40a4bce3f28b933 Mon Sep 17 00:00:00 2001 From: luoyifan Date: Mon, 23 Jun 2025 01:28:50 +0800 Subject: [PATCH] EnvController.runDemo --- servo/src/main/java/com/galaxis/rcs/RCS.java | 76 +++++++++- .../com/galaxis/rcs/common/entity/RcsTaskPlan.java | 15 +- .../galaxis/rcs/common/entity/StoreLocation.java | 9 +- .../galaxis/rcs/common/enums/PlanTaskStatus.java | 23 ++++ .../com/galaxis/rcs/common/enums/PlanTaskType.java | 12 ++ .../com/galaxis/rcs/common/query/QRcsTaskPlan.java | 37 +++-- .../galaxis/rcs/connector/ConnectorConsumer.java | 9 ++ .../galaxis/rcs/connector/ConnectorFactory.java | 40 ++++++ .../galaxis/rcs/connector/cl2/Cl2Connector.java | 99 +++++++++---- .../galaxis/rcs/connector/cl2/Cl2ConnectorImp.java | 29 ---- .../rcs/connector/cl2/Cl2DeviceConnector.java | 59 ++++++++ .../rcs/connector/cl2/VirtualCl2Connector.java | 34 +++-- .../java/com/galaxis/rcs/plan/PTRTaskPlanner.java | 153 --------------------- .../com/galaxis/rcs/plan/PlanTaskSequence.java | 97 +++++++++++++ .../main/java/com/galaxis/rcs/plan/Planner.java | 20 --- .../com/galaxis/rcs/plan/TaskPlannerFactory.java | 3 + .../galaxis/rcs/plan/planner/PTRTaskPlanner.java | 151 ++++++++++++++++++++ .../java/com/galaxis/rcs/plan/planner/Planner.java | 48 +++++++ .../main/java/com/galaxis/rcs/task/RcsBizTask.java | 4 - .../java/com/galaxis/rcs/task/RcsDeviceTask.java | 4 - .../java/com/galaxis/rcs/task/RcsPlanTask.java | 4 - .../com/galaxis/rcs/task/TaskDispatchFactory.java | 3 + .../java/com/galaxis/rcs/task/TaskService.java | 36 +++-- .../rcs/task/dispatcher/TaiWanDispatcher.java | 4 +- .../java/com/yvan/logisticsEnv/LogisticsEnv.java | 56 ++++++-- .../java/com/yvan/logisticsModel/BaseItem.java | 38 ++++- .../logisticsModel/ExecutorConnectorThread.java | 66 +++++++++ .../java/com/yvan/logisticsModel/ExecutorItem.java | 105 ++++++++++++-- .../main/java/com/yvan/logisticsModel/Floor.java | 7 +- .../java/com/yvan/logisticsModel/FlowItem.java | 5 + .../com/yvan/logisticsModel/LogisticsRuntime.java | 88 +++++++++++- .../logisticsModel/LogisticsRuntimeService.java | 28 +++- .../java/com/yvan/logisticsModel/StaticItem.java | 13 +- .../dashboard/DashboardManager.java | 29 +--- .../yvan/workbench/controller/EnvController.java | 13 +- .../com/yvan/workbench/model/entity/Vector2.java | 13 ++ servo/src/main/resources/application-dev.yml | 3 + .../test/java/com/yvan/workbench/CodegenTest.java | 2 +- 38 files changed, 1072 insertions(+), 363 deletions(-) create mode 100644 servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskStatus.java create mode 100644 servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskType.java create mode 100644 servo/src/main/java/com/galaxis/rcs/connector/ConnectorConsumer.java create mode 100644 servo/src/main/java/com/galaxis/rcs/connector/ConnectorFactory.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java create mode 100644 servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java create mode 100644 servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/plan/Planner.java create mode 100644 servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java create mode 100644 servo/src/main/java/com/galaxis/rcs/plan/planner/Planner.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java create mode 100644 servo/src/main/java/com/yvan/logisticsModel/ExecutorConnectorThread.java create mode 100644 servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java diff --git a/servo/src/main/java/com/galaxis/rcs/RCS.java b/servo/src/main/java/com/galaxis/rcs/RCS.java index 2768bc9..cffe036 100644 --- a/servo/src/main/java/com/galaxis/rcs/RCS.java +++ b/servo/src/main/java/com/galaxis/rcs/RCS.java @@ -2,16 +2,44 @@ package com.galaxis.rcs; import com.galaxis.rcs.common.entity.AddTaskRequest; import com.galaxis.rcs.common.entity.AddTaskResult; -import com.galaxis.rcs.task.TaskService; +import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.galaxis.rcs.common.entity.StoreLocation; +import com.galaxis.rcs.common.enums.BizTaskType; +import com.galaxis.rcs.plan.planner.Planner; +import com.galaxis.rcs.plan.TaskPlannerFactory; +import com.galaxis.rcs.plan.PlanTaskSequence; +import com.google.common.base.Joiner; +import com.yvan.logisticsEnv.LogisticsEnv; import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntimeService; +import com.yvan.logisticsMonitor.task.BizTask; +import com.yvan.workbench.model.entity.Model; +import lombok.SneakyThrows; +import org.apache.commons.io.FileUtils; +import org.clever.core.json.JsonWrapper; + +import java.io.File; +import java.nio.charset.StandardCharsets; /** * RCS 对外API调用类 */ public class RCS { + static { + init(); + } - static final LogisticsRuntimeService logisticsRuntimeService = new LogisticsRuntimeService(); + @SneakyThrows + static void init() { + String fs = Joiner.on("\n").join(FileUtils.readLines(new File("./yvan-lcc/src/example/example1.json"), StandardCharsets.UTF_8)); + JsonWrapper jw = new JsonWrapper(fs); + + LogisticsRuntimeService.createEnv(1); + LogisticsRuntime runtime = LogisticsRuntimeService.findByEnvCode(1); + runtime.loadMap(jw); + + runtime.start(); + } /** * 添加任务, 示例 @@ -31,15 +59,55 @@ public class RCS { * } * */ - public static AddTaskResult addTask(String envCode, AddTaskRequest request) { + public static AddTaskResult addTask(long envId, AddTaskRequest request) { AddTaskResult result = new AddTaskResult(); - LogisticsRuntime logisticsRuntime = logisticsRuntimeService.findByEnvCode(envCode); + LogisticsRuntime logisticsRuntime = LogisticsRuntimeService.findByEnvCode(envId); String bizTaskId = logisticsRuntime.taskService.addBizTask(request); result.bizTaskId = bizTaskId; return result; } + public static void runDemo() { + String executorId = "10"; // 执行器ID + String lpn = "pallet1124"; + long envId = 1; + + AddTaskRequest request = new AddTaskRequest(); + request.setType(BizTaskType.CARRY); + request.setTaskExecutorId(executorId); + request.setLpn(lpn); + request.setPriority(1); + request.setFrom(new StoreLocation("rack1", 0, 1, 0)); + request.setTo(new StoreLocation("54", 0, 0, 0)); + request.setDescription("从rack1的0/1/0, 取货到地堆54"); + request.setCreateBy("runDemo"); + + AddTaskResult result = RCS.addTask(envId, request); + LogisticsRuntime logisticsRuntime = LogisticsRuntimeService.findByEnvCode(envId); + RcsTaskBiz bizTask = logisticsRuntime.taskService.waitingTaskList.get(logisticsRuntime.taskService.waitingTaskList.size() - 1); + + + Planner planner = TaskPlannerFactory.getPlanner("cl2"); + + // 规划任务序列 + PlanTaskSequence planSequence = new PlanTaskSequence(executorId, logisticsRuntime, bizTask, "demo"); + planSequence.addMoveTo("23"); + planSequence.addRotationTo(90); + planSequence.addMoveTo("27"); + planSequence.addLoad(lpn, "rack1", 0, 1, 0); + planSequence.addMoveTo("23"); + planSequence.addRotationTo(-90); + planSequence.addMoveTo("20"); + planSequence.addUnload("gst_01", 0, 0, 0); + planSequence.addFinish(); + + planner.appendSequence(planSequence); + } + + public static LogisticsRuntime getDemo() { + return LogisticsRuntimeService.findByEnvCode(1L); + } } diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java index 7fa08c9..2b8dce2 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java @@ -2,6 +2,7 @@ package com.galaxis.rcs.common.entity; import lombok.Data; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Date; /** @@ -21,9 +22,21 @@ public class RcsTaskPlan implements Serializable { private String executorId; /** 规划序号 */ private Integer seq; + /** 目标点ID */ + private String targetId; + /** 目标点货架列 */ + private Integer targetBay; + /** 目标点货架层 */ + private Integer targetLevel; + /** 目标点货架格 */ + private Integer targetCell; + /** 目标点货架旋转角度 */ + private BigDecimal targetRotation; + /** 背负托盘ID */ + private String loadLpn; /** 任务负载信息 */ private String planTaskPayload; - /** 规划状态 */ + /** 规划执行状态 */ private String planTaskStatus; /** 异常提示信息 */ private String planTaskErrorInfo; diff --git a/servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java b/servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java index 2c5ad2e..a301f1f 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java +++ b/servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java @@ -12,18 +12,13 @@ package com.galaxis.rcs.common.entity; * */ public record StoreLocation( - String item, // 货架ID + String rackId, // 货架ID int bay, // 列 int level, // 层 int cell // 格 ) { @Override public String toString() { - return "StoreLocation{" + - "item='" + item + '\'' + - ", bay=" + bay + - ", level=" + level + - ", cell=" + cell + - '}'; + return rackId + "_" + bay + "_" + level + "_" + cell; } } diff --git a/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskStatus.java b/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskStatus.java new file mode 100644 index 0000000..2799ae4 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskStatus.java @@ -0,0 +1,23 @@ +package com.galaxis.rcs.common.enums; + +/** + * 任务规划状态枚举 + */ +public enum PlanTaskStatus { + /** + * 等待执行 + */ + PENDING, + /** + * 执行中 + */ + EXECUTING, + /** + * 执行成功 + */ + FINISHED, + /** + * 执行失败 + */ + ERROR; +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskType.java b/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskType.java new file mode 100644 index 0000000..a0f0f14 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskType.java @@ -0,0 +1,12 @@ +package com.galaxis.rcs.common.enums; + +/** + * 任务规划状态枚举 + */ +public enum PlanTaskType { + MOVE, // 移动任务 + ROTATION, // 旋转任务 + LOAD, // 取货任务 + UNLOAD, // 装载任务 + CHARGE // 充电任务 +} diff --git a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java index 581ed4c..4551655 100644 --- a/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java +++ b/servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java @@ -6,6 +6,7 @@ import com.querydsl.core.types.*; import com.querydsl.sql.*; import java.sql.Types; import com.galaxis.rcs.common.entity.RcsTaskPlan; +import java.math.BigDecimal; import java.util.Date; /** @@ -28,9 +29,21 @@ public class QRcsTaskPlan extends RelationalPathBase { public final StringPath executorId = createString("executorId"); /** 规划序号 */ public final NumberPath seq = createNumber("seq", Integer.class); + /** 目标点ID */ + public final StringPath targetId = createString("targetId"); + /** 目标点货架列 */ + public final NumberPath targetBay = createNumber("targetBay", Integer.class); + /** 目标点货架层 */ + public final NumberPath targetLevel = createNumber("targetLevel", Integer.class); + /** 目标点货架格 */ + public final NumberPath targetCell = createNumber("targetCell", Integer.class); + /** 目标点货架旋转角度 */ + public final NumberPath targetRotation = createNumber("targetRotation", BigDecimal.class); + /** 背负托盘ID */ + public final StringPath loadLpn = createString("loadLpn"); /** 任务负载信息 */ public final StringPath planTaskPayload = createString("planTaskPayload"); - /** 规划状态 */ + /** 规划执行状态 */ public final StringPath planTaskStatus = createString("planTaskStatus"); /** 异常提示信息 */ public final StringPath planTaskErrorInfo = createString("planTaskErrorInfo"); @@ -77,13 +90,19 @@ public class QRcsTaskPlan extends RelationalPathBase { 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)); + addMetadata(targetId, ColumnMetadata.named("target_id").withIndex(7).ofType(Types.VARCHAR).withSize(50)); + addMetadata(targetBay, ColumnMetadata.named("target_bay").withIndex(8).ofType(Types.INTEGER).withSize(10)); + addMetadata(targetLevel, ColumnMetadata.named("target_level").withIndex(9).ofType(Types.INTEGER).withSize(10)); + addMetadata(targetCell, ColumnMetadata.named("target_cell").withIndex(10).ofType(Types.INTEGER).withSize(10)); + addMetadata(targetRotation, ColumnMetadata.named("target_rotation").withIndex(11).ofType(Types.REAL).withSize(7).withDigits(3)); + addMetadata(loadLpn, ColumnMetadata.named("load_lpn").withIndex(12).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(planTaskPayload, ColumnMetadata.named("plan_task_payload").withIndex(13).ofType(Types.VARCHAR).withSize(3000)); + addMetadata(planTaskStatus, ColumnMetadata.named("plan_task_status").withIndex(14).ofType(Types.VARCHAR).withSize(10)); + addMetadata(planTaskErrorInfo, ColumnMetadata.named("plan_task_error_info").withIndex(15).ofType(Types.VARCHAR).withSize(500)); + addMetadata(planTaskDescription, ColumnMetadata.named("plan_task_description").withIndex(16).ofType(Types.VARCHAR).withSize(500)); + addMetadata(createAt, ColumnMetadata.named("create_at").withIndex(17).ofType(Types.TIMESTAMP)); + addMetadata(createBy, ColumnMetadata.named("create_by").withIndex(18).ofType(Types.VARCHAR).withSize(50)); + addMetadata(updateAt, ColumnMetadata.named("update_at").withIndex(19).ofType(Types.TIMESTAMP)); + addMetadata(updateBy, ColumnMetadata.named("update_by").withIndex(20).ofType(Types.VARCHAR).withSize(50)); } } diff --git a/servo/src/main/java/com/galaxis/rcs/connector/ConnectorConsumer.java b/servo/src/main/java/com/galaxis/rcs/connector/ConnectorConsumer.java new file mode 100644 index 0000000..fdae98d --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/connector/ConnectorConsumer.java @@ -0,0 +1,9 @@ +package com.galaxis.rcs.connector; + +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.LogisticsRuntime; + +public interface ConnectorConsumer { + void consume(ExecutorItem executorItem, LogisticsRuntime logisticsRuntime, RcsTaskPlan task); +} diff --git a/servo/src/main/java/com/galaxis/rcs/connector/ConnectorFactory.java b/servo/src/main/java/com/galaxis/rcs/connector/ConnectorFactory.java new file mode 100644 index 0000000..9d09cc4 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/connector/ConnectorFactory.java @@ -0,0 +1,40 @@ +package com.galaxis.rcs.connector; + +import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; +import com.galaxis.rcs.connector.cl2.VirtualCl2Connector; +import com.google.common.collect.Maps; + +import java.util.Map; + +public class ConnectorFactory { + /** + * 设备连接器映射 + */ + private static final Map connectorMap = Maps.newHashMap(); + + /** + * 虚拟连接器映射 + */ + private static final Map virtualConnectorMap = Maps.newHashMap(); + + static { + connectorMap.put("cl2", new Cl2DeviceConnector()); + virtualConnectorMap.put("cl2", new VirtualCl2Connector()); + } + + public static ConnectorConsumer getConnector(String type) { + ConnectorConsumer connector = connectorMap.get(type); + if (connector == null) { + throw new IllegalArgumentException("No connector found for type: " + type); + } + return connector; + } + + public static ConnectorConsumer getVirtualConnector(String type) { + ConnectorConsumer connector = connectorMap.get(type); + if (connector == null) { + throw new IllegalArgumentException("No connector found for type: " + type); + } + return connector; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Connector.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Connector.java index 64edd48..080bcf6 100644 --- a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Connector.java +++ b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Connector.java @@ -1,52 +1,99 @@ package com.galaxis.rcs.connector.cl2; -public interface Cl2Connector { +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.PlanTaskType; +import com.galaxis.rcs.connector.ConnectorConsumer; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.LogisticsRuntime; + +public abstract class Cl2Connector implements ConnectorConsumer { // RCS发往CL2的指令 + + /** + * 消费任务计划 + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 + */ + @Override + public void consume(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task) { + switch (PlanTaskType.valueOf(task.getPlanType())) { + case MOVE: + robotMove(executorItem, runtime, task, task.getTargetId()); + break; + case ROTATION: + robotRotation(executorItem, runtime, task, task.getTargetRotation().floatValue()); + break; + case LOAD: + robotLoad(executorItem, runtime, task, task.getTargetId(), task.getTargetBay(), task.getTargetLevel(), task.getTargetCell()); + break; + case UNLOAD: + robotUnload(executorItem, runtime, task, task.getTargetId(), task.getTargetBay(), task.getTargetLevel(), task.getTargetCell()); + break; + case CHARGE: + robotCharger(executorItem, runtime, task, task.getTargetId()); + break; + default: + throw new IllegalArgumentException("Unknown plan type: " + task.getPlanType()); + } + } + /** * 移动 robotMove - * @param executorId 机器人设备ID - * @param startWayPoint 起点Id, WayPointId - * @param endWayPoint 终点ID, WayPointId - * @param armRotation number类型,货叉/机械臂,相对于头的角度, 逆时针为正 + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 + * @param endWayPoint 终点ID, WayPointId */ - void robotMove(String executorId, String startWayPoint, String endWayPoint, double armRotation); + public abstract void robotMove(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String endWayPoint); /** * 旋转 robotRotate - * @param executorId 机器人编号 + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 * @param worldRotation 转动身体到世界角度 90 度 */ - void robotRotation(String executorId, double worldRotation); + public abstract void robotRotation(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, float worldRotation); /** * 取货 robotLoad - * @param executorId 机器人编号 - * @param rackItem 货架ID - * @param bay 列 - * @param level 层 - * @param cell 格 - * @param storeBarCode 地标二维码编号 - * @param boxItem 容器ID + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 + * @param rackItem 货架ID + * @param bay 列 + * @param level 层 + * @param cell 格 */ - void robotLoad(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode, String boxItem); + public abstract void robotLoad(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell); /** * 放货 robotUnload - * @param executorId 机器人编号 - * @param rackItem 货架ID - * @param bay 列 - * @param level 层 - * @param cell 格 - * @param storeBarCode 地标二维码编号 + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 + * @param rackItem 货架ID + * @param bay 列 + * @param level 层 + * @param cell 格 */ - void robotUnload(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode); + public abstract void robotUnload(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell); /** * 充电 robotCharge - * @param executorId 机器人编号 - * @param chargerItem 充电桩ID + * + * @param executorItem 机器人执行器 + * @param runtime 物流运行时环境 + * @param task 任务计划 + * @param chargerItem 充电桩ID */ - void robotCharger(String executorId, String chargerItem); + public abstract void robotCharger(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String chargerItem); } diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java deleted file mode 100644 index 7a674d0..0000000 --- a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.galaxis.rcs.connector.cl2; - -public class Cl2ConnectorImp implements Cl2Connector { - @Override - public void robotMove(String executorId, String startWayPoint, String endWayPoint, double armRotation) { - // 获取车当前位置 - - } - - @Override - public void robotRotation(String executorId, double worldRotation) { - - } - - @Override - public void robotLoad(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode, String boxItem) { - - } - - @Override - public void robotUnload(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode) { - - } - - @Override - public void robotCharger(String executorId, String chargerItem) { - - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java new file mode 100644 index 0000000..6af2217 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java @@ -0,0 +1,59 @@ +package com.galaxis.rcs.connector.cl2; + +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.FlowItem; +import com.yvan.logisticsModel.LogisticsRuntime; +import com.yvan.logisticsModel.StaticItem; +import lombok.extern.slf4j.Slf4j; + +/** + * CL2 车型报文推送 + */ +@Slf4j +public class Cl2DeviceConnector extends Cl2Connector { + + @Override + public void robotMove(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String endPointId) { + log.info("Cl2DeviceConnector robotMove: executorItem={}, task={}, endPointId={}", + executorItem.getId(), task.getPlanTaskId(), endPointId); + + // 获取静态数据(货架、地标等) + StaticItem pointItem = runtime.getStaticItemById(endPointId); + log.info("{}", pointItem); + + // 获取车的数据 + ExecutorItem agv = runtime.executorItemMap.get(executorItem.getId()); + log.info("{}", agv); + + // 获取箱子的数据 + FlowItem box = runtime.flowItemMap.get("pallet1122"); + log.info("{}", box); + + log.info("车的当前位置是不可知的,要从实际情况中获取, 移动的路径一定是可以到达的,不用考虑转向问题。但 Speed 是正还是负,需要从当前车的角度情况下决定。"); + } + + @Override + public void robotRotation(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, float worldRotation) { + log.info("Cl2DeviceConnector robotRotation: executorItem={}, task={}, worldRotation={}", + executorItem.getId(), task.getPlanTaskId(), worldRotation); + } + + @Override + public void robotLoad(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell) { + log.info("Cl2DeviceConnector robotLoad: executorItem={}, task={}, rackItem={}, bay={}, level={}, cell={}", + executorItem.getId(), task.getPlanTaskId(), rackItem, bay, level, cell); + } + + @Override + public void robotUnload(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell) { + log.info("Cl2DeviceConnector robotUnload: executorItem={}, task={}, rackItem={}, bay={}, level={}, cell={}", + executorItem.getId(), task.getPlanTaskId(), rackItem, bay, level, cell); + } + + @Override + public void robotCharger(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String chargerItem) { + log.info("Cl2DeviceConnector robotCharger: executorItem={}, task={}, chargerItem={}", + executorItem.getId(), task.getPlanTaskId(), chargerItem); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/VirtualCl2Connector.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/VirtualCl2Connector.java index 28177cc..60a5fe0 100644 --- a/servo/src/main/java/com/galaxis/rcs/connector/cl2/VirtualCl2Connector.java +++ b/servo/src/main/java/com/galaxis/rcs/connector/cl2/VirtualCl2Connector.java @@ -1,33 +1,43 @@ package com.galaxis.rcs.connector.cl2; +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.LogisticsRuntime; +import lombok.extern.slf4j.Slf4j; + /** * @author cwj * @since 2023/7/30 */ -public class VirtualCl2Connector implements Cl2Connector { - +@Slf4j +public class VirtualCl2Connector extends Cl2Connector { @Override - public void robotMove(String executorId, String startWayPoint, String endWayPoint, double armRotation) { - + public void robotMove(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String endWayPoint) { + log.info("VirtualCl2Connector robotMove: executorItem={}, task={}, endWayPoint={}", + executorItem.getId(), task.getPlanTaskId(), endWayPoint); } @Override - public void robotRotation(String executorId, double worldRotation) { - + public void robotRotation(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, float worldRotation) { + log.info("VirtualCl2Connector robotRotation: executorItem={}, task={}, worldRotation={}", + executorItem.getId(), task.getPlanTaskId(), worldRotation); } @Override - public void robotLoad(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode, String boxItem) { - + public void robotLoad(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell) { + log.info("VirtualCl2Connector robotLoad: executorItem={}, task={}, rackItem={}, bay={}, level={}, cell={}", + executorItem.getId(), task.getPlanTaskId(), rackItem, bay, level, cell); } @Override - public void robotUnload(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode) { - + public void robotUnload(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String rackItem, int bay, int level, int cell) { + log.info("VirtualCl2Connector robotUnload: executorItem={}, task={}, rackItem={}, bay={}, level={}, cell={}", + executorItem.getId(), task.getPlanTaskId(), rackItem, bay, level, cell); } @Override - public void robotCharger(String executorId, String chargerItem) { - + public void robotCharger(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, String chargerItem) { + log.info("VirtualCl2Connector robotCharger: executorItem={}, task={}, chargerItem={}", + executorItem.getId(), task.getPlanTaskId(), chargerItem); } } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java b/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java deleted file mode 100644 index 6bb7195..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java +++ /dev/null @@ -1,153 +0,0 @@ -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 agv AGV - */ - @Override - public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, ExecutorItem agv) { - - - // 绑定任务执行器 - 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 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" 号储位 - - -地图路由 -```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() -``` - */ - - agv.executeTaskPlanList(runtime, task, planList); - } - -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java new file mode 100644 index 0000000..658e109 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java @@ -0,0 +1,97 @@ +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.PlanTaskStatus; +import com.galaxis.rcs.common.enums.PlanTaskType; +import com.google.common.collect.Lists; +import com.yvan.logisticsModel.LogisticsRuntime; +import org.clever.core.id.SnowFlake; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +public class PlanTaskSequence { + public static final SnowFlake snowFlake = new SnowFlake(); + public final String executorId; + public final LogisticsRuntime logisticsRuntime; + public final List taskList = Lists.newArrayList(); + public final RcsTaskBiz bizTask; + public final String createBy; + + public String lastWayPointId; + public Float lastRotationAngle = null; + public boolean isFinished = false; + public String lastLoadLpn = ""; + + public PlanTaskSequence(String executorId, LogisticsRuntime logisticsRuntime, RcsTaskBiz bizTask, String createBy) { + this.executorId = executorId; + this.logisticsRuntime = logisticsRuntime; + this.bizTask = bizTask; + this.createBy = createBy; + } + + private RcsTaskPlan createTaskPlanEntity(String planType) { + RcsTaskPlan planTask = new RcsTaskPlan(); + planTask.setPlanTaskId(snowFlake.nextId()); + planTask.setBizTaskId(this.bizTask.getBizTaskId()); + planTask.setEnvId(logisticsRuntime.logisticsEnv.getEnvId()); + planTask.setPlanType(planType); + planTask.setExecutorId(this.executorId); + planTask.setSeq(taskList.size()); + planTask.setPlanTaskStatus(PlanTaskStatus.PENDING.toString()); + planTask.setPlanTaskErrorInfo("N/A"); + planTask.setPlanTaskDescription("N/A"); + planTask.setCreateBy(createBy); + planTask.setCreateAt(new Date()); + + taskList.add(planTask); + return planTask; + } + + // 添加移动到指定路标点的动作 + public RcsTaskPlan addMoveTo(String waypointId) { + RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.MOVE.toString()); + task.setTargetId(waypointId); + this.lastWayPointId = waypointId; + return task; + } + + // 添加旋转动作 + public RcsTaskPlan addRotationTo(float rotationAngle) { + RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.ROTATION.toString()); + task.setTargetRotation(new BigDecimal(rotationAngle)); + this.lastRotationAngle = rotationAngle; + return task; + } + + // 添加取货动作 + public RcsTaskPlan addLoad(String lpn, String rackId, int bay, int level, int cell) { + RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.LOAD.toString()); + task.setTargetId(rackId); + task.setTargetBay(bay); + task.setTargetLevel(level); + task.setTargetCell(cell); + this.lastLoadLpn = lpn; + return task; + } + + // 添加放货动作 + public RcsTaskPlan addUnload(String item, int level, int bay, int cell) { + RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.UNLOAD.toString()); + task.setTargetId(item); + task.setTargetBay(bay); + task.setTargetLevel(level); + task.setTargetCell(cell); + this.lastLoadLpn = ""; + return task; + } + + // 添加完成动作 + public RcsTaskPlan addFinish() { + RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.ROTATION.toString()); + this.isFinished = true; + return task; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/Planner.java b/servo/src/main/java/com/galaxis/rcs/plan/Planner.java deleted file mode 100644 index 3707c94..0000000 --- a/servo/src/main/java/com/galaxis/rcs/plan/Planner.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.galaxis.rcs.plan; - -import com.galaxis.rcs.common.entity.RcsTaskBiz; -import com.yvan.logisticsModel.ExecutorItem; -import com.yvan.logisticsModel.LogisticsRuntime; - -/** - * 任务执行器的计划接口 - * 用于定义如何执行任务计划 - */ -public interface Planner { - /** - * 执行任务计划 - * - * @param runtime 物流运行时环境 - * @param tasks 任务对象,包含任务的详细信息 - * @param executorId 执行器ID - */ - void executePlan(LogisticsRuntime runtime, RcsTaskBiz tasks, ExecutorItem executorId); -} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/TaskPlannerFactory.java b/servo/src/main/java/com/galaxis/rcs/plan/TaskPlannerFactory.java index 57be144..09fa445 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/TaskPlannerFactory.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/TaskPlannerFactory.java @@ -1,5 +1,8 @@ package com.galaxis.rcs.plan; +import com.galaxis.rcs.plan.planner.PTRTaskPlanner; +import com.galaxis.rcs.plan.planner.Planner; + import java.util.Map; /** diff --git a/servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java b/servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java new file mode 100644 index 0000000..2bf1c6a --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java @@ -0,0 +1,151 @@ +package com.galaxis.rcs.plan.planner; + +import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.BizTaskStatus; +import com.galaxis.rcs.plan.PlanTaskSequence; +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 extends Planner { + + static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); + + /** + * 执行任务规划 + * + * @param runtime 物流运行时环境 + * @param task 任务对象,包含任务的详细信息 + * @param agv AGV + */ + @Override + public void executePlan(LogisticsRuntime runtime, RcsTaskBiz task, ExecutorItem agv) { + + // 绑定任务执行器 + task.setAllocatedExecutorId(agv.getId()); + task.setBizTaskStatus(BizTaskStatus.DEVICE_EXECUTING.toString()); + queryDSL.update(rcsTaskBiz) + .populate(task) + .set(rcsTaskBiz.updateAt, runtime.logisticsEnv.getCurrentDate()) + .set(rcsTaskBiz.updateBy, PTRTaskPlanner.class.getName()) + .where(rcsTaskBiz.bizTaskId.eq(task.getBizTaskId())) + .execute(); + runtime.taskService.removeFromWaitingTaskList(task.getBizTaskId()); + + PlanTaskSequence planSequence = new PlanTaskSequence(agv.getId(), runtime, task, "demo"); + + + /* +用 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" 号储位 + + +地图路由 +```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=当前机器人编号; + +按照这个示例,他输出结果为 + +// 规划任务序列 +PlanTaskSequence planSequence = new PlanTaskSequence(executorId, logisticsRuntime, bizTask, "demo"); +planSequence.addMoveTo("23"); +planSequence.addRotationTo(90); +planSequence.addMoveTo("27"); +planSequence.addLoad(lpn, "rack1", 0, 1, 0); +planSequence.addMoveTo("23"); +planSequence.addRotationTo(-90); +planSequence.addMoveTo("20"); +planSequence.addUnload("gst_01", 0, 0, 0); +planSequence.addFinish(); +``` + */ + + this.appendSequence(planSequence); + } + +} diff --git a/servo/src/main/java/com/galaxis/rcs/plan/planner/Planner.java b/servo/src/main/java/com/galaxis/rcs/plan/planner/Planner.java new file mode 100644 index 0000000..f16a3b7 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/plan/planner/Planner.java @@ -0,0 +1,48 @@ +package com.galaxis.rcs.plan.planner; + +import com.galaxis.rcs.common.entity.RcsTaskBiz; +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.query.QRcsTaskPlan; +import com.galaxis.rcs.plan.PlanTaskSequence; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.LogisticsRuntime; +import org.clever.data.jdbc.DaoFactory; +import org.clever.data.jdbc.QueryDSL; + +import static com.galaxis.rcs.common.query.QRcsTaskPlan.rcsTaskPlan; + +/** + * 任务执行器的计划接口 + * 用于定义如何执行任务计划 + */ +public abstract class Planner { + /** + * 执行任务计划 + * + * @param runtime 物流运行时环境 + * @param bizTask 业务任务 + * @param executor 执行器 + */ + public abstract void executePlan(LogisticsRuntime runtime, RcsTaskBiz bizTask, ExecutorItem executor); + + /** + * 追加任务序列到当前计划中 + */ + public void appendSequence(PlanTaskSequence sequence) { + final QueryDSL queryDSL = DaoFactory.getQueryDSL(); + + LogisticsRuntime runtime = sequence.logisticsRuntime; + ExecutorItem agv = runtime.executorItemMap.get(sequence.executorId); + agv.appendSequence(sequence); + + var batchAction = queryDSL.insert(rcsTaskPlan); + for (RcsTaskPlan task : sequence.taskList) { + batchAction.populate(task) + .addBatch(); + } + + if (batchAction.getBatchCount() > 0) { + batchAction.execute(); + } + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java b/servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java deleted file mode 100644 index 4895e66..0000000 --- a/servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.task; - -public class RcsBizTask { -} diff --git a/servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java b/servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java deleted file mode 100644 index 230d70f..0000000 --- a/servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.task; - -public class RcsDeviceTask { -} diff --git a/servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java b/servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java deleted file mode 100644 index b97b9fc..0000000 --- a/servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.galaxis.rcs.task; - -public class RcsPlanTask { -} diff --git a/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java b/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java index fcbbede..b6cabcb 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java +++ b/servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java @@ -7,6 +7,9 @@ import com.yvan.logisticsModel.LogisticsRuntime; import java.util.List; +/** + * 任务指派器, 将任务指派给车 + */ public class TaskDispatchFactory { public final LogisticsRuntime logisticsRuntime; private TaiWanDispatcher dispatcher = new TaiWanDispatcher(); diff --git a/servo/src/main/java/com/galaxis/rcs/task/TaskService.java b/servo/src/main/java/com/galaxis/rcs/task/TaskService.java index 9590345..3a2947d 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/TaskService.java +++ b/servo/src/main/java/com/galaxis/rcs/task/TaskService.java @@ -5,6 +5,7 @@ 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.google.common.collect.Lists; import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; import org.clever.core.Conv; @@ -26,7 +27,7 @@ public class TaskService { static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); public final LogisticsRuntime logisticsRuntime; - public List waitingTaskList; + public List waitingTaskList = Lists.newArrayList(); public TaskService(LogisticsRuntime logisticsRuntime) { this.logisticsRuntime = logisticsRuntime; @@ -79,24 +80,29 @@ public class TaskService { String payload = JsonWrapper.toJson(request); Long taskId = DaoFactory.getJdbc().nextId("rcs_task_biz"); + + RcsTaskBiz task = new RcsTaskBiz(); + task.setBizTaskId(taskId); + task.setEnvId(logisticsRuntime.logisticsEnv.getEnvId()); + task.setBizType(request.type.toString()); + task.setLpn(request.lpn); + task.setPriority(request.priority); + task.setTaskFrom(request.from.toString()); + task.setTaskTo(request.to.toString()); + task.setAllocatedExecutorId(request.taskExecutorId); + task.setBizTaskPayload(payload); + task.setBizTaskErrorInfo("N/A"); + task.setBizTaskDescription(request.description); + task.setBizTaskStatus(BizTaskStatus.WAITING_FOR_DISPATCH.toString()); + task.setCreateAt(logisticsRuntime.logisticsEnv.getCurrentDate()); + task.setCreateBy(request.createBy); + 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) + .populate(task) .execute(); logisticsRuntime.taskDispatchFactory.checkAll(); + this.waitingTaskList.add(task); return taskId.toString(); } diff --git a/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java b/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java index 1cb9e9d..8d745c9 100644 --- a/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java +++ b/servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java @@ -1,7 +1,7 @@ package com.galaxis.rcs.task.dispatcher; import com.galaxis.rcs.common.entity.RcsTaskBiz; -import com.galaxis.rcs.plan.Planner; +import com.galaxis.rcs.plan.planner.Planner; import com.galaxis.rcs.plan.TaskPlannerFactory; import com.galaxis.rcs.task.TaskDispatchFactory; import com.yvan.logisticsModel.ExecutorItem; @@ -14,8 +14,6 @@ public class TaiWanDispatcher { public void dispatchTask(TaskDispatchFactory factory, List executorList, List tasks) { // 台湾展会的任务分配逻辑 for (ExecutorItem agv : executorList) { - String agvType = agv.getT(); - for (RcsTaskBiz task : tasks) { if (Objects.equals(agv.getId(), task.getAllocatedExecutorId())) { // 按车 ID 分配任务 diff --git a/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java b/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java index 373262f..61f75fd 100644 --- a/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java +++ b/servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java @@ -1,9 +1,14 @@ package com.yvan.logisticsEnv; import com.galaxis.rcs.common.enums.EnvStatus; +import com.google.common.collect.Lists; +import com.yvan.logisticsModel.ExecutorItem; import lombok.Getter; import lombok.Setter; +import java.util.Date; +import java.util.List; + /** * 物流仓储环境上下文 */ @@ -13,30 +18,57 @@ public class LogisticsEnv { private EnvStartParam startParam; - // 环境ID - private Long envId; + /** + * 环境ID + */ + private long envId; - // 环境状态 - private EnvStatus state; + /** + * 是否为虚拟环境 + */ + private boolean isVirtual; /** - * 获取AGV车列表 + * 是否正在运行 */ - void getTasks() { + private boolean isRunning; - } + /** + * 环境开始时间 + */ + private long startTime; /** - * 载入地图 + * 环境停止时间 */ - void loadMap() { + private long stopTime; - } + /** + * 时间流速倍率 + */ + private int timeRate; /** - * 获取库存分布状态 + * 获取AGV车列表 */ - void loadInv() { + List getExecutorList() { + return Lists.newArrayList(); + } + + public long currentTimeMillis() { + if (!this.isVirtual) { + // 正式环境,返回系统当前时间 + return System.currentTimeMillis(); + } + if (!this.isRunning) { + return this.stopTime; + } + + long realCost = System.currentTimeMillis() - this.startTime; + return this.startTime + (realCost * this.timeRate); + } + public Date getCurrentDate() { + return new Date(this.currentTimeMillis()); } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/BaseItem.java b/servo/src/main/java/com/yvan/logisticsModel/BaseItem.java index cc59d8b..b9da893 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/BaseItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/BaseItem.java @@ -1,25 +1,53 @@ package com.yvan.logisticsModel; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import lombok.Getter; +import org.clever.core.Conv; +import java.util.List; import java.util.Map; /** * 物流单元基类 */ @Data -public class BaseItem { - String id; - String t; +public abstract class BaseItem { + final String id; + final String t; /** * 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 */ - float[][] tf; + final float[][] tf; /** * 物品的自定义数据 */ - Map dt; + @JsonIgnore + final Map dt; + + @JsonIgnore + final Map raw; + + public BaseItem(Map map) { + this.raw = map; + this.id = Conv.asString(map.get("id")); + this.t = Conv.asString(map.get("t")); + + List tfRaw = (List) map.get("tf"); + + this.tf = new float[3][3]; + this.tf[0][0] = Conv.asFloat(((List) tfRaw.get(0)).get(0)); + this.tf[0][1] = Conv.asFloat(((List) tfRaw.get(0)).get(1)); + this.tf[0][2] = Conv.asFloat(((List) tfRaw.get(0)).get(2)); + this.tf[1][0] = Conv.asFloat(((List) tfRaw.get(1)).get(0)); + this.tf[1][1] = Conv.asFloat(((List) tfRaw.get(1)).get(1)); + this.tf[1][2] = Conv.asFloat(((List) tfRaw.get(1)).get(2)); + this.tf[2][0] = Conv.asFloat(((List) tfRaw.get(2)).get(0)); + this.tf[2][1] = Conv.asFloat(((List) tfRaw.get(2)).get(1)); + this.tf[2][2] = Conv.asFloat(((List) tfRaw.get(2)).get(2)); + + this.dt = (Map) map.get("dt"); + } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/ExecutorConnectorThread.java b/servo/src/main/java/com/yvan/logisticsModel/ExecutorConnectorThread.java new file mode 100644 index 0000000..ac77af8 --- /dev/null +++ b/servo/src/main/java/com/yvan/logisticsModel/ExecutorConnectorThread.java @@ -0,0 +1,66 @@ +package com.yvan.logisticsModel; + +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.PlanTaskStatus; +import com.galaxis.rcs.connector.ConnectorFactory; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.atomic.AtomicBoolean; + +@Slf4j +public class ExecutorConnectorThread extends Thread { + private final AtomicBoolean running = new AtomicBoolean(false); + + private final ExecutorItem executorItem; + private final LogisticsRuntime logisticsRuntime; + + public ExecutorConnectorThread(ExecutorItem executorItem, LogisticsRuntime logisticsRuntime) { + super("ExecutorConnector-" + executorItem.getId()); + this.executorItem = executorItem; + this.logisticsRuntime = logisticsRuntime; + } + + @Override + public void run() { + running.set(true); + log.info("Connector thread started for executor: {}", this.executorItem.getId()); + + try { + while (running.get()) { + // 从队列中获取任务,如果队列为空则阻塞等待 + RcsTaskPlan task = this.executorItem.planQueue.take(); + + try { + // 处理任务 + ConnectorFactory.getConnector(this.executorItem.getT()) + .consume(this.executorItem, this.logisticsRuntime, task); + + } catch (Exception e) { + log.error("Error processing task: " + task, e); + task.setPlanTaskErrorInfo(e.getMessage()); + task.setPlanTaskStatus(PlanTaskStatus.ERROR.toString()); + } + } + } catch (InterruptedException e) { + System.out.println("Connector thread interrupted for executor: " + this.executorItem.getId()); + } finally { + System.out.println("Connector thread stopped for executor: " + this.executorItem.getId()); + } + } + + /** + * 停止连接器线程 + */ + public void stopConnector() { + running.set(false); + this.interrupt(); // 中断阻塞状态 + } + + /** + * 检查连接器是否在运行 + */ + public boolean isRunning() { + return running.get(); + } +} diff --git a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java index deb67a0..33deee7 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java @@ -1,31 +1,116 @@ package com.yvan.logisticsModel; -import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.common.entity.RcsTaskPlan; -import com.google.common.collect.Lists; +import com.galaxis.rcs.plan.PlanTaskSequence; +import com.google.common.collect.Queues; +import com.yvan.workbench.model.entity.Vector2; -import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.BlockingQueue; /** * 物流任务执行单元(如拣货台、小车、AGV、堆垛机、人等) + * 每个物流任务执行器都会有一个 Connector 线程,专门用来消费 currentPlanList 队列,变成实际的设备指令 */ public class ExecutorItem extends BaseItem { + private final int BLOCKING_QUEUE_CAPACITY = 100; + private final LogisticsRuntime logisticsRuntime; + + /** + * 当前执行的任务规划列表 + */ + final BlockingQueue planQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY); + + /** + * 车执行完所有任务之后,停留在什么坐标点位实体上 + */ + public StaticItem planTargetItem; + + /** + * 车当前旋转角度 + */ + public Float currentRotationAngle; + + /** + * 车当前逻辑坐标位 + */ + public Vector2 currentLogicPosition; + + /** + * 车当前世界坐标位 + */ + public Vector2 currentWorldPosition; + + /** + * 计划目标坐标位, 执行完所有任务之后,车会停留在什么是世界角度 + */ + public Float planRotationAngle; + + /** + * 连接器线程 + */ + private final ExecutorConnectorThread connectorThread; - private final List currentPlanList = Lists.newArrayList(); /** - * 执行规划任务 + * 启动连接器线程 */ - public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, List planList) { - if (this.currentPlanList.size() > 0) { - throw new RuntimeException("has plans, please wait for the current plans to finish"); + public void startConnector() { + if (!connectorThread.isRunning()) { + connectorThread.start(); + System.out.println("Connector started for executor: " + this.getId()); + } + } + + /** + * 停止连接器线程 + */ + public void stopConnector() { + connectorThread.stop(); + System.out.println("Connector stopped for executor: " + this.getId()); + } + + public ExecutorItem(LogisticsRuntime logisticsRuntime, Map raw) { + super(raw); + this.logisticsRuntime = logisticsRuntime; + this.connectorThread = new ExecutorConnectorThread(this, logisticsRuntime); + } + + /** + * 添加任务序列到当前执行器 + */ + public void appendSequence(PlanTaskSequence sequence) { + if (sequence == null || sequence.taskList.isEmpty()) { + return; } + // 检查 planList 是不是全都是我的任务 + for (RcsTaskPlan plan : sequence.taskList) { + if (!plan.getExecutorId().equals(this.getId())) { + throw new RuntimeException("plan not belong executor:" + this.getId() + ", " + plan.getExecutorId()); + } + } + + LogisticsRuntime runtime = sequence.logisticsRuntime; + + if (sequence.lastWayPointId != null) { + this.planTargetItem = runtime.getStaticItemById(sequence.lastWayPointId); + } + if (sequence.lastRotationAngle != null) { + this.planRotationAngle = sequence.lastRotationAngle; + } + + planQueue.addAll(sequence.taskList); + // TODO: 开启轮询线程,等待下一个待执行任务 - // 找到对应类型的 connector,进行报文的发送 } + /** + * 执行器是否空闲 + */ public boolean isFree() { - throw new RuntimeException("not implemented yet, please implement isFree method in ExecutorItem"); + return (this.planQueue.isEmpty() && this.connectorThread.isRunning()); } + } diff --git a/servo/src/main/java/com/yvan/logisticsModel/Floor.java b/servo/src/main/java/com/yvan/logisticsModel/Floor.java index c112aa9..60708b5 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/Floor.java +++ b/servo/src/main/java/com/yvan/logisticsModel/Floor.java @@ -9,9 +9,14 @@ import java.util.Map; */ public class Floor { + public final String id; + /** * 物流固定单元(非箱子容器/非执行器的单元),比如输送线、货架、地标、路线等 */ - public final Map itemMap = Maps.newConcurrentMap(); + public final Map itemMap = Maps.newHashMap(); + public Floor(String id) { + this.id = id; + } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/FlowItem.java b/servo/src/main/java/com/yvan/logisticsModel/FlowItem.java index bc82ccc..15c1fa5 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/FlowItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/FlowItem.java @@ -1,7 +1,12 @@ package com.yvan.logisticsModel; +import java.util.Map; + /** * 物流流动单元(周转箱、托盘等) */ public class FlowItem extends BaseItem { + public FlowItem(Map map) { + super(map); + } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java index 89d927a..3bd0d06 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java @@ -1,5 +1,6 @@ package com.yvan.logisticsModel; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.plan.path.NavigationGraph; import com.galaxis.rcs.task.TaskDispatchFactory; @@ -7,13 +8,18 @@ import com.galaxis.rcs.task.TaskService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.yvan.logisticsEnv.LogisticsEnv; +import com.yvan.workbench.model.entity.Vector2; +import lombok.extern.slf4j.Slf4j; +import org.clever.core.Conv; +import org.clever.core.json.JsonWrapper; import java.util.List; import java.util.Map; /** - * 物流 + * 物流上下文运行时 */ +@Slf4j public class LogisticsRuntime { /** @@ -24,27 +30,30 @@ public class LogisticsRuntime { /** * 任务服务 */ + @JsonIgnore public TaskService taskService = new TaskService(this); /** * 任务分配服务 */ + @JsonIgnore public TaskDispatchFactory taskDispatchFactory = new TaskDispatchFactory(this); /** * 物流流动单元(周转箱、托盘、纸箱等) */ - public final Map flowItemMap = Maps.newConcurrentMap(); + public final Map flowItemMap = Maps.newHashMap(); /** * 物流任务执行单元(如拣货台、小车、AGV、堆垛机、人等) */ - public final Map executorItemMap = Maps.newConcurrentMap(); + public final Map executorItemMap = Maps.newHashMap(); /** * AGV导航地图 车类型 t -> NavigationGraph */ - public final Map executorGraphMap = Maps.newConcurrentMap(); + @JsonIgnore + public final Map executorGraphMap = Maps.newHashMap(); /** * 楼层目录 catalogCode -> Floor @@ -69,4 +78,75 @@ public class LogisticsRuntime { } + /** + * 根据 ID 获取静态物品(如路标点、货架等) + */ + public StaticItem getStaticItemById(String itemId) { + // 到所有楼层寻找这个物品 + for (Floor floor : this.floorMap.values()) { + StaticItem item = floor.itemMap.get(itemId); + if (item != null) { + return item; + } + } + return null; + } + + /** + * 读取某个楼层的地图数据 + * 格式必须是如下模式: + *
+     * {
+     *     "catalogCode": "f2",
+     *     "t": "floor",
+     *     "items": []
+     * }
+     * 
+ * + * @param jw 原始 Json 读取器 + */ + public void loadMap(JsonWrapper jw) { + if (!"floor".equals(jw.asStr("t"))) { + throw new RuntimeException("loadMap error, not floor type: " + jw.asStr("t")); + } + List> items = (List>) jw.getInnerMap().get("items"); + + Floor floor = new Floor(jw.asStr("catalogCode")); + this.floorMap.put(floor.id, floor); + + for (Map itemObject : items) { + String t = Conv.asString(itemObject.get("t")); + BaseItem item; + switch (t) { + case "way": + case "gstore": + case "rack": + item = new StaticItem(itemObject); + floor.itemMap.put(item.getId(), (StaticItem) item); + break; + + case "pallet": + case "carton": + item = new FlowItem(itemObject); + this.flowItemMap.put(item.getId(), (FlowItem) item); + break; + + case "cl2": + case "clx": + item = new ExecutorItem(this, itemObject); + this.executorItemMap.put(item.getId(), (ExecutorItem) item); + break; + } + } + } + + public void start() { + // 开启所有机器人的任务调度 + for (ExecutorItem executorItem : executorItemMap.values()) { + executorItem.startConnector(); + log.info("Executor {} started", executorItem.getId()); + } + + this.taskDispatchFactory.startPolling(); + } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java index 4affcad..6dca652 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java @@ -1,6 +1,7 @@ package com.yvan.logisticsModel; import com.google.common.collect.Maps; +import com.yvan.logisticsEnv.LogisticsEnv; import java.util.Map; @@ -8,17 +9,30 @@ import java.util.Map; * 物流运行时服务类 */ public class LogisticsRuntimeService { - - private final Map runtimeMap = Maps.newConcurrentMap(); + private static final Object LOCK = new Object(); + private static final Map runtimeMap = Maps.newHashMap(); /** * 根据 EnvCode 查找物流运行时实例 */ - public LogisticsRuntime findByEnvCode(String envCode) { - LogisticsRuntime runtime = runtimeMap.get(envCode); - if (runtime != null) { - return runtime; + public static LogisticsRuntime findByEnvCode(long envId) { + synchronized (LOCK) { + LogisticsRuntime runtime = runtimeMap.get(envId); + if (runtime != null) { + return runtime; + } + throw new RuntimeException("LogisticsRuntime not found for envCode: " + envId); + } + } + + public static void createEnv(int envId) { + synchronized (LOCK) { + LogisticsEnv env = new LogisticsEnv(); + env.setEnvId(envId); + env.setVirtual(envId != 1); + + LogisticsRuntime runtime = new LogisticsRuntime(env); + runtimeMap.put(env.getEnvId(), runtime); } - throw new RuntimeException("LogisticsRuntime not found for envCode: " + envCode); } } diff --git a/servo/src/main/java/com/yvan/logisticsModel/StaticItem.java b/servo/src/main/java/com/yvan/logisticsModel/StaticItem.java index 90b4445..dc12554 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/StaticItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/StaticItem.java @@ -1,10 +1,21 @@ package com.yvan.logisticsModel; +import org.clever.core.Conv; + import java.util.Map; /** * 物流固定单元(非箱子容器/非执行器的单元),比如输送线、货架、地标、路线等 */ -public class StaticItem extends BaseItem { +public class StaticItem extends BaseItem { + public int logicX; + public int logicY; + public int logicZ; + public StaticItem(Map map) { + super(map); + this.logicX = Conv.asInteger(map.get("logicX")); + this.logicY = Conv.asInteger(map.get("logicY")); + this.logicZ = Conv.asInteger(map.get("logicZ")); + } } diff --git a/servo/src/main/java/com/yvan/logisticsMonitor/dashboard/DashboardManager.java b/servo/src/main/java/com/yvan/logisticsMonitor/dashboard/DashboardManager.java index 62321a6..75dc1b0 100644 --- a/servo/src/main/java/com/yvan/logisticsMonitor/dashboard/DashboardManager.java +++ b/servo/src/main/java/com/yvan/logisticsMonitor/dashboard/DashboardManager.java @@ -1,31 +1,4 @@ package com.yvan.logisticsMonitor.dashboard; -import com.galaxis.rcs.connector.cl2.Cl2Connector; - -public class DashboardManager implements Cl2Connector { - - @Override - public void robotMove(String executorId, String startWayPoint, String endWayPoint, double armRotation) { - - } - - @Override - public void robotRotation(String executorId, double worldRotation) { - - } - - @Override - public void robotLoad(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode, String boxItem) { - - } - - @Override - public void robotUnload(String executorId, String rackItem, int bay, int level, int cell, String storeBarCode) { - - } - - @Override - public void robotCharger(String executorId, String chargerItem) { - - } +public class DashboardManager { } diff --git a/servo/src/main/java/com/yvan/workbench/controller/EnvController.java b/servo/src/main/java/com/yvan/workbench/controller/EnvController.java index 4aafc31..c7f09df 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/EnvController.java +++ b/servo/src/main/java/com/yvan/workbench/controller/EnvController.java @@ -1,13 +1,12 @@ package com.yvan.workbench.controller; +import com.galaxis.rcs.RCS; import com.yvan.workbench.model.entity.Model; 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.clever.data.jdbc.querydsl.utils.QueryDslUtils; import org.clever.web.mvc.annotation.RequestBody; -import org.springframework.data.redis.core.query.QueryUtils; import org.springframework.web.bind.annotation.ResponseBody; import java.util.LinkedHashMap; @@ -19,7 +18,6 @@ import static com.galaxis.rcs.common.query.QLccEnvInfo.lccEnvInfo; public class EnvController { static final QueryDSL queryDSL = DaoFactory.getQueryDSL(); - @ResponseBody public static Model>> getAllEnv(@RequestBody Map params) { var list = queryDSL.select(QueryDslUtils.linkedMap(lccEnvInfo)) .from(lccEnvInfo) @@ -28,4 +26,13 @@ public class EnvController { return Model.newSuccess(list); } + + public static Model runDemo() { + RCS.runDemo(); + return Model.newSuccess(true); + } + + public static Model getDemo() { + return Model.newSuccess(RCS.getDemo()); + } } diff --git a/servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java b/servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java new file mode 100644 index 0000000..c81c29a --- /dev/null +++ b/servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java @@ -0,0 +1,13 @@ +package com.yvan.workbench.model.entity; + +public record Vector2( + /** + * X坐标 + */ + float x, + /** + * Y坐标 + */ + float y) { + +} diff --git a/servo/src/main/resources/application-dev.yml b/servo/src/main/resources/application-dev.yml index 5f132a8..d87f517 100644 --- a/servo/src/main/resources/application-dev.yml +++ b/servo/src/main/resources/application-dev.yml @@ -1,3 +1,6 @@ +server: + port: 7779 + app: root-path: './' diff --git a/servo/src/test/java/com/yvan/workbench/CodegenTest.java b/servo/src/test/java/com/yvan/workbench/CodegenTest.java index 519e9ae..9a1845e 100644 --- a/servo/src/test/java/com/yvan/workbench/CodegenTest.java +++ b/servo/src/test/java/com/yvan/workbench/CodegenTest.java @@ -29,7 +29,7 @@ public class CodegenTest { // .addTable("rcs_task_biz") // .addTable("rcs_task_device") // .addTable("rcs_task_plan"); - .addTable("lcc_env_info"); + .addTable("rcs_task_plan"); CodegenUtils.genCode(jdbc, config); log.info("-->"); jdbc.close();