38 changed files with 1072 additions and 363 deletions
@ -0,0 +1,23 @@ |
|||||
|
package com.galaxis.rcs.common.enums; |
||||
|
|
||||
|
/** |
||||
|
* 任务规划状态枚举 |
||||
|
*/ |
||||
|
public enum PlanTaskStatus { |
||||
|
/** |
||||
|
* 等待执行 |
||||
|
*/ |
||||
|
PENDING, |
||||
|
/** |
||||
|
* 执行中 |
||||
|
*/ |
||||
|
EXECUTING, |
||||
|
/** |
||||
|
* 执行成功 |
||||
|
*/ |
||||
|
FINISHED, |
||||
|
/** |
||||
|
* 执行失败 |
||||
|
*/ |
||||
|
ERROR; |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
package com.galaxis.rcs.common.enums; |
||||
|
|
||||
|
/** |
||||
|
* 任务规划状态枚举 |
||||
|
*/ |
||||
|
public enum PlanTaskType { |
||||
|
MOVE, // 移动任务
|
||||
|
ROTATION, // 旋转任务
|
||||
|
LOAD, // 取货任务
|
||||
|
UNLOAD, // 装载任务
|
||||
|
CHARGE // 充电任务
|
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -1,52 +1,99 @@ |
|||||
package com.galaxis.rcs.connector.cl2; |
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的指令
|
// 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 |
* 移动 robotMove |
||||
* @param executorId 机器人设备ID |
* |
||||
* @param startWayPoint 起点Id, WayPointId |
* @param executorItem 机器人执行器 |
||||
* @param endWayPoint 终点ID, WayPointId |
* @param runtime 物流运行时环境 |
||||
* @param armRotation number类型,货叉/机械臂,相对于头的角度, 逆时针为正 |
* @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 |
* 旋转 robotRotate |
||||
* @param executorId 机器人编号 |
* |
||||
|
* @param executorItem 机器人执行器 |
||||
|
* @param runtime 物流运行时环境 |
||||
|
* @param task 任务计划 |
||||
* @param worldRotation 转动身体到世界角度 90 度 |
* @param worldRotation 转动身体到世界角度 90 度 |
||||
*/ |
*/ |
||||
void robotRotation(String executorId, double worldRotation); |
public abstract void robotRotation(ExecutorItem executorItem, LogisticsRuntime runtime, RcsTaskPlan task, float worldRotation); |
||||
|
|
||||
/** |
/** |
||||
* 取货 robotLoad |
* 取货 robotLoad |
||||
* @param executorId 机器人编号 |
* |
||||
* @param rackItem 货架ID |
* @param executorItem 机器人执行器 |
||||
* @param bay 列 |
* @param runtime 物流运行时环境 |
||||
* @param level 层 |
* @param task 任务计划 |
||||
* @param cell 格 |
* @param rackItem 货架ID |
||||
* @param storeBarCode 地标二维码编号 |
* @param bay 列 |
||||
* @param boxItem 容器ID |
* @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 |
* 放货 robotUnload |
||||
* @param executorId 机器人编号 |
* |
||||
* @param rackItem 货架ID |
* @param executorItem 机器人执行器 |
||||
* @param bay 列 |
* @param runtime 物流运行时环境 |
||||
* @param level 层 |
* @param task 任务计划 |
||||
* @param cell 格 |
* @param rackItem 货架ID |
||||
* @param storeBarCode 地标二维码编号 |
* @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 |
* 充电 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); |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -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) { |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -1,33 +1,43 @@ |
|||||
package com.galaxis.rcs.connector.cl2; |
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 |
* @author cwj |
||||
* @since 2023/7/30 |
* @since 2023/7/30 |
||||
*/ |
*/ |
||||
public class VirtualCl2Connector implements Cl2Connector { |
@Slf4j |
||||
|
public class VirtualCl2Connector extends Cl2Connector { |
||||
@Override |
@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 |
@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 |
@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 |
@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 |
@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); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -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; |
||||
|
} |
||||
|
} |
||||
@ -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); |
|
||||
} |
|
||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,4 +0,0 @@ |
|||||
package com.galaxis.rcs.task; |
|
||||
|
|
||||
public class RcsBizTask { |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
package com.galaxis.rcs.task; |
|
||||
|
|
||||
public class RcsDeviceTask { |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
package com.galaxis.rcs.task; |
|
||||
|
|
||||
public class RcsPlanTask { |
|
||||
} |
|
||||
@ -1,25 +1,53 @@ |
|||||
package com.yvan.logisticsModel; |
package com.yvan.logisticsModel; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
import lombok.Data; |
import lombok.Data; |
||||
import lombok.Getter; |
import lombok.Getter; |
||||
|
import org.clever.core.Conv; |
||||
|
|
||||
|
import java.util.List; |
||||
import java.util.Map; |
import java.util.Map; |
||||
|
|
||||
/** |
/** |
||||
* 物流单元基类 |
* 物流单元基类 |
||||
*/ |
*/ |
||||
@Data |
@Data |
||||
public class BaseItem { |
public abstract class BaseItem { |
||||
String id; |
final String id; |
||||
String t; |
final String t; |
||||
|
|
||||
/** |
/** |
||||
* 变换矩阵, 3x3矩阵, 采用Y轴向上为正, X轴向右, Z轴向前的右手坐标系 |
* 变换矩阵, 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"); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
@ -1,31 +1,116 @@ |
|||||
package com.yvan.logisticsModel; |
package com.yvan.logisticsModel; |
||||
|
|
||||
import com.galaxis.rcs.common.entity.RcsTaskBiz; |
|
||||
import com.galaxis.rcs.common.entity.RcsTaskPlan; |
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、堆垛机、人等) |
* 物流任务执行单元(如拣货台、小车、AGV、堆垛机、人等) |
||||
|
* 每个物流任务执行器都会有一个 Connector 线程,专门用来消费 currentPlanList 队列,变成实际的设备指令 |
||||
*/ |
*/ |
||||
public class ExecutorItem extends BaseItem { |
public class ExecutorItem extends BaseItem { |
||||
|
private final int BLOCKING_QUEUE_CAPACITY = 100; |
||||
|
private final LogisticsRuntime logisticsRuntime; |
||||
|
|
||||
|
/** |
||||
|
* 当前执行的任务规划列表 |
||||
|
*/ |
||||
|
final BlockingQueue<RcsTaskPlan> 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<RcsTaskPlan> currentPlanList = Lists.newArrayList(); |
|
||||
|
|
||||
/** |
/** |
||||
* 执行规划任务 |
* 启动连接器线程 |
||||
*/ |
*/ |
||||
public void executeTaskPlanList(LogisticsRuntime runtime, RcsTaskBiz task, List<RcsTaskPlan> planList) { |
public void startConnector() { |
||||
if (this.currentPlanList.size() > 0) { |
if (!connectorThread.isRunning()) { |
||||
throw new RuntimeException("has plans, please wait for the current plans to finish"); |
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: 开启轮询线程,等待下一个待执行任务
|
// TODO: 开启轮询线程,等待下一个待执行任务
|
||||
// 找到对应类型的 connector,进行报文的发送
|
|
||||
} |
} |
||||
|
|
||||
|
/** |
||||
|
* 执行器是否空闲 |
||||
|
*/ |
||||
public boolean isFree() { |
public boolean isFree() { |
||||
throw new RuntimeException("not implemented yet, please implement isFree method in ExecutorItem"); |
return (this.planQueue.isEmpty() && this.connectorThread.isRunning()); |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,7 +1,12 @@ |
|||||
package com.yvan.logisticsModel; |
package com.yvan.logisticsModel; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
/** |
/** |
||||
* 物流流动单元(周转箱、托盘等) |
* 物流流动单元(周转箱、托盘等) |
||||
*/ |
*/ |
||||
public class FlowItem extends BaseItem { |
public class FlowItem extends BaseItem { |
||||
|
public FlowItem(Map<String, Object> map) { |
||||
|
super(map); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -1,10 +1,21 @@ |
|||||
package com.yvan.logisticsModel; |
package com.yvan.logisticsModel; |
||||
|
|
||||
|
import org.clever.core.Conv; |
||||
|
|
||||
import java.util.Map; |
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<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")); |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -1,31 +1,4 @@ |
|||||
package com.yvan.logisticsMonitor.dashboard; |
package com.yvan.logisticsMonitor.dashboard; |
||||
|
|
||||
import com.galaxis.rcs.connector.cl2.Cl2Connector; |
public class DashboardManager { |
||||
|
|
||||
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) { |
|
||||
|
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,13 @@ |
|||||
|
package com.yvan.workbench.model.entity; |
||||
|
|
||||
|
public record Vector2( |
||||
|
/** |
||||
|
* X坐标 |
||||
|
*/ |
||||
|
float x, |
||||
|
/** |
||||
|
* Y坐标 |
||||
|
*/ |
||||
|
float y) { |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue