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; |
|||
|
|||
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); |
|||
|
|||
} |
|||
|
|||
@ -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; |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
@ -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; |
|||
|
|||
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"); |
|||
} |
|||
} |
|||
|
|||
@ -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; |
|||
|
|||
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()); |
|||
} |
|||
|
|||
} |
|||
|
|||
@ -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); |
|||
} |
|||
} |
|||
|
|||
@ -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")); |
|||
} |
|||
} |
|||
|
|||
@ -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 { |
|||
} |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
package com.yvan.workbench.model.entity; |
|||
|
|||
public record Vector2( |
|||
/** |
|||
* X坐标 |
|||
*/ |
|||
float x, |
|||
/** |
|||
* Y坐标 |
|||
*/ |
|||
float y) { |
|||
|
|||
} |
|||
Loading…
Reference in new issue