Browse Source

EnvController.runDemo

master
修宁 6 months ago
parent
commit
35ad214e6c
  1. 76
      servo/src/main/java/com/galaxis/rcs/RCS.java
  2. 15
      servo/src/main/java/com/galaxis/rcs/common/entity/RcsTaskPlan.java
  3. 9
      servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java
  4. 23
      servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskStatus.java
  5. 12
      servo/src/main/java/com/galaxis/rcs/common/enums/PlanTaskType.java
  6. 37
      servo/src/main/java/com/galaxis/rcs/common/query/QRcsTaskPlan.java
  7. 9
      servo/src/main/java/com/galaxis/rcs/connector/ConnectorConsumer.java
  8. 40
      servo/src/main/java/com/galaxis/rcs/connector/ConnectorFactory.java
  9. 79
      servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Connector.java
  10. 29
      servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java
  11. 59
      servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java
  12. 34
      servo/src/main/java/com/galaxis/rcs/connector/cl2/VirtualCl2Connector.java
  13. 97
      servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java
  14. 20
      servo/src/main/java/com/galaxis/rcs/plan/Planner.java
  15. 3
      servo/src/main/java/com/galaxis/rcs/plan/TaskPlannerFactory.java
  16. 36
      servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java
  17. 48
      servo/src/main/java/com/galaxis/rcs/plan/planner/Planner.java
  18. 4
      servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java
  19. 4
      servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java
  20. 4
      servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java
  21. 3
      servo/src/main/java/com/galaxis/rcs/task/TaskDispatchFactory.java
  22. 36
      servo/src/main/java/com/galaxis/rcs/task/TaskService.java
  23. 4
      servo/src/main/java/com/galaxis/rcs/task/dispatcher/TaiWanDispatcher.java
  24. 56
      servo/src/main/java/com/yvan/logisticsEnv/LogisticsEnv.java
  25. 38
      servo/src/main/java/com/yvan/logisticsModel/BaseItem.java
  26. 66
      servo/src/main/java/com/yvan/logisticsModel/ExecutorConnectorThread.java
  27. 105
      servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java
  28. 7
      servo/src/main/java/com/yvan/logisticsModel/Floor.java
  29. 5
      servo/src/main/java/com/yvan/logisticsModel/FlowItem.java
  30. 88
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java
  31. 24
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java
  32. 11
      servo/src/main/java/com/yvan/logisticsModel/StaticItem.java
  33. 29
      servo/src/main/java/com/yvan/logisticsMonitor/dashboard/DashboardManager.java
  34. 13
      servo/src/main/java/com/yvan/workbench/controller/EnvController.java
  35. 13
      servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java
  36. 3
      servo/src/main/resources/application-dev.yml
  37. 2
      servo/src/test/java/com/yvan/workbench/CodegenTest.java

76
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 {
* }
* </pre>
*/
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);
}
}

15
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;

9
servo/src/main/java/com/galaxis/rcs/common/entity/StoreLocation.java

@ -12,18 +12,13 @@ package com.galaxis.rcs.common.entity;
* </pre>
*/
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;
}
}

23
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;
}

12
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 // 充电任务
}

37
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<RcsTaskPlan> {
public final StringPath executorId = createString("executorId");
/** 规划序号 */
public final NumberPath<Integer> seq = createNumber("seq", Integer.class);
/** 目标点ID */
public final StringPath targetId = createString("targetId");
/** 目标点货架列 */
public final NumberPath<Integer> targetBay = createNumber("targetBay", Integer.class);
/** 目标点货架层 */
public final NumberPath<Integer> targetLevel = createNumber("targetLevel", Integer.class);
/** 目标点货架格 */
public final NumberPath<Integer> targetCell = createNumber("targetCell", Integer.class);
/** 目标点货架旋转角度 */
public final NumberPath<BigDecimal> 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<RcsTaskPlan> {
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));
}
}

9
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);
}

40
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<String, ConnectorConsumer> connectorMap = Maps.newHashMap();
/**
* 虚拟连接器映射
*/
private static final Map<String, ConnectorConsumer> 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;
}
}

79
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 executorItem 机器人执行器
* @param runtime 物流运行时环境
* @param task 任务计划
* @param endWayPoint 终点ID, WayPointId
* @param armRotation number类型货叉/机械臂相对于头的角度, 逆时针为正
*/
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 executorItem 机器人执行器
* @param runtime 物流运行时环境
* @param task 任务计划
* @param rackItem 货架ID
* @param bay
* @param level
* @param cell
* @param storeBarCode 地标二维码编号
* @param boxItem 容器ID
*/
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 executorItem 机器人执行器
* @param runtime 物流运行时环境
* @param task 任务计划
* @param rackItem 货架ID
* @param bay
* @param level
* @param cell
* @param storeBarCode 地标二维码编号
*/
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 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);
}

29
servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2ConnectorImp.java

@ -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) {
}
}

59
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);
}
}

34
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);
}
}

97
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<RcsTaskPlan> 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;
}
}

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

@ -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);
}

3
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;
/**

36
servo/src/main/java/com/galaxis/rcs/plan/PTRTaskPlanner.java → servo/src/main/java/com/galaxis/rcs/plan/planner/PTRTaskPlanner.java

@ -1,8 +1,9 @@
package com.galaxis.rcs.plan;
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;
@ -18,7 +19,7 @@ import static com.galaxis.rcs.common.query.QRcsTaskBiz.rcsTaskBiz;
* PTR 任务规划器
* 用于处理 CL2 / CLX 等车型的任务规划
*/
public class PTRTaskPlanner implements Planner {
public class PTRTaskPlanner extends Planner {
static final QueryDSL queryDSL = DaoFactory.getQueryDSL();
@ -32,19 +33,18 @@ public class PTRTaskPlanner implements Planner {
@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.updateAt, runtime.logisticsEnv.getCurrentDate())
.set(rcsTaskBiz.updateBy, PTRTaskPlanner.class.getName())
.where(rcsTaskBiz.bizTaskId.eq(task.getBizTaskId()))
.execute();
runtime.taskService.removeFromWaitingTaskList(task.getBizTaskId());
List<RcsTaskPlan> planList = Lists.newArrayList();
PlanTaskSequence planSequence = new PlanTaskSequence(agv.getId(), runtime, task, "demo");
/*
@ -131,23 +131,21 @@ 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()
// 规划任务序列
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();
```
*/
agv.executeTaskPlanList(runtime, task, planList);
this.appendSequence(planSequence);
}
}

48
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();
}
}
}

4
servo/src/main/java/com/galaxis/rcs/task/RcsBizTask.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.task;
public class RcsBizTask {
}

4
servo/src/main/java/com/galaxis/rcs/task/RcsDeviceTask.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.task;
public class RcsDeviceTask {
}

4
servo/src/main/java/com/galaxis/rcs/task/RcsPlanTask.java

@ -1,4 +0,0 @@
package com.galaxis.rcs.task;
public class RcsPlanTask {
}

3
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();

36
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<RcsTaskBiz> waitingTaskList;
public List<RcsTaskBiz> 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();
}

4
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<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 分配任务

56
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<ExecutorItem> 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());
}
}

38
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<String, Object> dt;
@JsonIgnore
final Map<String, Object> dt;
@JsonIgnore
final Map<String, Object> raw;
public BaseItem(Map<String, Object> 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<String, Object>) map.get("dt");
}
}

66
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();
}
}

105
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;
private final List<RcsTaskPlan> currentPlanList = Lists.newArrayList();
/**
* 当前执行的任务规划列表
*/
final BlockingQueue<RcsTaskPlan> planQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY);
/**
* 车执行完所有任务之后停留在什么坐标点位实体上
*/
public StaticItem planTargetItem;
/**
* 车当前旋转角度
*/
public Float currentRotationAngle;
/**
* 车当前逻辑坐标位
*/
public Vector2 currentLogicPosition;
/**
* 执行规划任务
* 车当前世界坐标位
*/
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");
public Vector2 currentWorldPosition;
/**
* 计划目标坐标位, 执行完所有任务之后车会停留在什么是世界角度
*/
public Float planRotationAngle;
/**
* 连接器线程
*/
private final ExecutorConnectorThread connectorThread;
/**
* 启动连接器线程
*/
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<String, Object> 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());
}
}

7
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<String, StaticItem> itemMap = Maps.newConcurrentMap();
public final Map<String, StaticItem> itemMap = Maps.newHashMap();
public Floor(String id) {
this.id = id;
}
}

5
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<String, Object> map) {
super(map);
}
}

88
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<String, FlowItem> flowItemMap = Maps.newConcurrentMap();
public final Map<String, FlowItem> flowItemMap = Maps.newHashMap();
/**
* 物流任务执行单元(如拣货台小车AGV堆垛机人等)
*/
public final Map<String, ExecutorItem> executorItemMap = Maps.newConcurrentMap();
public final Map<String, ExecutorItem> executorItemMap = Maps.newHashMap();
/**
* AGV导航地图 车类型 t -> NavigationGraph
*/
public final Map<String, NavigationGraph> executorGraphMap = Maps.newConcurrentMap();
@JsonIgnore
public final Map<String, NavigationGraph> 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;
}
/**
* 读取某个楼层的地图数据
* 格式必须是如下模式:
* <pre>
* {
* "catalogCode": "f2",
* "t": "floor",
* "items": []
* }
* </pre>
*
* @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<Map<String, Object>> items = (List<Map<String, Object>>) jw.getInnerMap().get("items");
Floor floor = new Floor(jw.asStr("catalogCode"));
this.floorMap.put(floor.id, floor);
for (Map<String, Object> 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();
}
}

24
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<String, LogisticsRuntime> runtimeMap = Maps.newConcurrentMap();
private static final Object LOCK = new Object();
private static final Map<Long, LogisticsRuntime> runtimeMap = Maps.newHashMap();
/**
* 根据 EnvCode 查找物流运行时实例
*/
public LogisticsRuntime findByEnvCode(String envCode) {
LogisticsRuntime runtime = runtimeMap.get(envCode);
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: " + envCode);
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);
}
}
}

11
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 int logicX;
public int logicY;
public int logicZ;
public StaticItem(Map<String, Object> map) {
super(map);
this.logicX = Conv.asInteger(map.get("logicX"));
this.logicY = Conv.asInteger(map.get("logicY"));
this.logicZ = Conv.asInteger(map.get("logicZ"));
}
}

29
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 {
}

13
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<List<LinkedHashMap<String, Object>>> getAllEnv(@RequestBody Map<String, Object> 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());
}
}

13
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) {
}

3
servo/src/main/resources/application-dev.yml

@ -1,3 +1,6 @@
server:
port: 7779
app:
root-path: './'

2
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();

Loading…
Cancel
Save