Browse Source

Load / Unload 记库存

master
修宁 6 months ago
parent
commit
a751106535
  1. 2
      servo/src/main/java/com/galaxis/rcs/RCSService.java
  2. 179
      servo/src/main/java/com/galaxis/rcs/inv/InvManager.java
  3. 15
      servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java
  4. 4
      servo/src/main/java/com/galaxis/rcs/plan/path/PtrPathPlanner.java
  5. 1
      servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java
  6. 13
      servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java
  7. 60
      servo/src/main/java/com/yvan/entity/BasLocationVo.java
  8. 2
      servo/src/main/java/com/yvan/entity/LccProject.java
  9. 2
      servo/src/main/java/com/yvan/entity/LccProjectEnv.java
  10. 2
      servo/src/main/java/com/yvan/entity/Vector2.java
  11. 6
      servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java
  12. 60
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java
  13. 4
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java
  14. 17
      servo/src/main/java/com/yvan/pusher/FrontendMessagePushService.java
  15. 2
      servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java
  16. 222
      servo/src/main/java/com/yvan/workbench/controller/RcsController.java
  17. 7
      servo/src/main/java/com/yvan/workbench/service/LccMapService.java

2
servo/src/main/java/com/galaxis/rcs/RCSService.java

@ -10,7 +10,7 @@ import com.yvan.logisticsModel.LogisticsRuntime;
import com.yvan.logisticsModel.LogisticsRuntimeService; import com.yvan.logisticsModel.LogisticsRuntimeService;
import com.yvan.logisticsModel.StaticItem; import com.yvan.logisticsModel.StaticItem;
import com.yvan.workbench.SpringContext; import com.yvan.workbench.SpringContext;
import com.yvan.workbench.model.entity.LccProject; import com.yvan.entity.LccProject;
import com.yvan.workbench.service.LccMapService; import com.yvan.workbench.service.LccMapService;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;

179
servo/src/main/java/com/galaxis/rcs/inv/InvManager.java

@ -2,6 +2,7 @@ package com.galaxis.rcs.inv;
import com.galaxis.rcs.common.entity.LccInvLpn; import com.galaxis.rcs.common.entity.LccInvLpn;
import com.querydsl.core.util.StringUtils; import com.querydsl.core.util.StringUtils;
import org.clever.core.id.SnowFlake;
import org.clever.data.jdbc.DaoFactory; import org.clever.data.jdbc.DaoFactory;
import org.clever.data.jdbc.QueryDSL; import org.clever.data.jdbc.QueryDSL;
@ -15,15 +16,16 @@ public class InvManager {
/** /**
* 记录库存 * 记录库存
* @param envId 环境ID *
* @param lpn 容器号 * @param envId 环境ID
* @param locCode 库位号 * @param lpn 容器号
* @param locCode 库位号
* @param layerIndex 堆叠层 * @param layerIndex 堆叠层
* @param qty 数量 >0 增加数量 <0 减数量 * @param qty 数量 >0 增加数量 <0 减数量
* @param qtyIn 入库数量 >0 减数量 <0 减数量 * @param qtyIn 入库数量 >0 减数量 <0 减数量
* @param qtyOut 出库数量 >0 减数量 <0 减数量 * @param qtyOut 出库数量 >0 减数量 <0 减数量
*/ */
public static void invSave(Long envId, String lpn, String locCode, Integer layerIndex, int qty, int qtyIn, int qtyOut) { public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, Integer layerIndex, int qty, int qtyIn, int qtyOut) {
if (envId == null || envId <= 0 if (envId == null || envId <= 0
|| lpn == null || StringUtils.isNullOrEmpty(lpn) || lpn.equals("N/A") || lpn == null || StringUtils.isNullOrEmpty(lpn) || lpn.equals("N/A")
|| locCode == null || StringUtils.isNullOrEmpty(locCode) || locCode.equals("N/A") || locCode == null || StringUtils.isNullOrEmpty(locCode) || locCode.equals("N/A")
@ -73,98 +75,117 @@ public class InvManager {
} }
} }
queryDSL.beginTX(status -> {
if (lccInvLpnData != null) { if (lccInvLpnData != null) {
queryDSL.update(lccInvLpn) queryDSL.update(lccInvLpn)
.set(lccInvLpn.qty, lccInvLpn.qty.add(qty)) .set(lccInvLpn.qty, lccInvLpn.qty.add(qty))
.set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn)) .set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn))
.set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut)) .set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut))
.set(lccInvLpn.layerIndex, layerIndex) .set(lccInvLpn.layerIndex, layerIndex)
// .set(lccInvLpn.updateAt, ) .set(lccInvLpn.updateAt, new Date(System.currentTimeMillis()))
.where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn))) .set(lccInvLpn.updateBy, "system")
.execute(); .where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn)))
// 记录账页 .execute();
queryDSL.insert(lccInvLedger) // 记录账页
.set(lccInvLedger.envId, envId) queryDSL.insert(lccInvLedger)
.set(lccInvLedger.lpn, lpn) .set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId())
.set(lccInvLedger.locCode, locCode) .set(lccInvLedger.envId, envId)
.set(lccInvLedger.layerIndex, layerIndex) .set(lccInvLedger.lpn, lpn)
.set(lccInvLedger.qtyChange, qty) .set(lccInvLedger.bizTaskId, bizTaskId)
.set(lccInvLedger.qtyInChange, qtyIn) .set(lccInvLedger.locCode, locCode)
.set(lccInvLedger.qtyOutChange, qtyOut) .set(lccInvLedger.layerIndex, layerIndex)
.set(lccInvLedger.qty, lccInvLpnData.getQty() + qty) .set(lccInvLedger.qtyChange, qty)
.set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn) .set(lccInvLedger.qtyInChange, qtyIn)
.set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + qtyOut) .set(lccInvLedger.qtyOutChange, qtyOut)
.set(lccInvLedger.ledgerType, "记账") .set(lccInvLedger.qty, lccInvLpnData.getQty() + qty)
.set(lccInvLedger.ledgerRemark, "N/A") .set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn)
.execute(); .set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + qtyOut)
} else { .set(lccInvLedger.ledgerType, "记账")
queryDSL.insert(lccInvLpn) .set(lccInvLedger.ledgerRemark, "N/A")
.set(lccInvLpn.envId, envId) .set(lccInvLedger.createAt, new Date(System.currentTimeMillis()))
.set(lccInvLpn.lpn, lpn) .set(lccInvLedger.createBy, "system")
.set(lccInvLpn.locCode, locCode) .set(lccInvLedger.updateAt, new Date(System.currentTimeMillis()))
.set(lccInvLpn.layerIndex, layerIndex) .set(lccInvLedger.updateBy, "system")
.set(lccInvLpn.qty, qty) .execute();
.set(lccInvLpn.qtyIn, qtyIn) } else {
.set(lccInvLpn.qtyOut, qtyOut) queryDSL.insert(lccInvLpn)
.execute(); .set(lccInvLpn.envId, envId)
// 记录账页 .set(lccInvLpn.lpn, lpn)
queryDSL.insert(lccInvLedger) .set(lccInvLpn.locCode, locCode)
.set(lccInvLedger.envId, envId) .set(lccInvLpn.layerIndex, layerIndex)
.set(lccInvLedger.lpn, lpn) .set(lccInvLpn.qty, qty)
.set(lccInvLedger.locCode, locCode) .set(lccInvLpn.qtyIn, qtyIn)
.set(lccInvLedger.layerIndex, layerIndex) .set(lccInvLpn.qtyOut, qtyOut)
.set(lccInvLedger.qtyChange, qty) .set(lccInvLpn.createAt, new Date(System.currentTimeMillis()))
.set(lccInvLedger.qtyInChange, qtyIn) .set(lccInvLpn.createBy, "system")
.set(lccInvLedger.qtyOutChange, qtyOut) .set(lccInvLpn.updateAt, new Date(System.currentTimeMillis()))
.set(lccInvLedger.qty, qty) .set(lccInvLpn.updateBy, "system")
.set(lccInvLedger.qtyIn, qtyIn) .execute();
.set(lccInvLedger.qtyOut, qtyOut) // 记录账页
.set(lccInvLedger.ledgerType, "记账") queryDSL.insert(lccInvLedger)
.set(lccInvLedger.ledgerRemark, "N/A") .set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId())
.execute(); .set(lccInvLedger.envId, envId)
} .set(lccInvLedger.lpn, lpn)
// 删除所有数量预占预扣都为0的库存 .set(lccInvLedger.bizTaskId, bizTaskId)
queryDSL.delete(lccInvLpn).where(lccInvLpn.qty.eq(0).and(lccInvLpn.qtyIn.eq(0)).and(lccInvLpn.qtyOut.eq(0))).execute(); .set(lccInvLedger.locCode, locCode)
}); .set(lccInvLedger.layerIndex, layerIndex)
.set(lccInvLedger.qtyChange, qty)
.set(lccInvLedger.qtyInChange, qtyIn)
.set(lccInvLedger.qtyOutChange, qtyOut)
.set(lccInvLedger.qty, qty)
.set(lccInvLedger.qtyIn, qtyIn)
.set(lccInvLedger.qtyOut, qtyOut)
.set(lccInvLedger.ledgerType, "记账")
.set(lccInvLedger.ledgerRemark, "N/A")
.set(lccInvLedger.createAt, new Date(System.currentTimeMillis()))
.set(lccInvLedger.createBy, "system")
.set(lccInvLedger.updateAt, new Date(System.currentTimeMillis()))
.set(lccInvLedger.updateBy, "system")
.execute();
}
// 删除所有数量预占预扣都为0的库存
queryDSL.delete(lccInvLpn).where(lccInvLpn.qty.eq(0).and(lccInvLpn.qtyIn.eq(0)).and(lccInvLpn.qtyOut.eq(0))).execute();
} }
/** /**
* 记录库存 * 记录库存
* @param envId 环境ID *
* @param lpn 容器号 * @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号 * @param locCode 库位号
* @param qty 数量 >0 减数量 <0 减数量 * @param qty 数量 >0 减数量 <0 减数量
* @param qtyIn 入库数量 >0 减数量 <0 减数量 * @param qtyIn 入库数量 >0 减数量 <0 减数量
* @param qtyOut 出库数量 >0 减数量 <0 减数量 * @param qtyOut 出库数量 >0 减数量 <0 减数量
*/ */
public static void invSave(Long envId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) { public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) {
invSave(envId, lpn, locCode, 0, qty, qtyIn, qtyOut); invSave(envId, bizTaskId, lpn, locCode, 0, qty, qtyIn, qtyOut);
} }
/** /**
* 保存库存 * 保存库存
* @param envId 环境ID *
* @param lpn 容器号 * @param envId 环境ID
* @param locCode 库位号 * @param lpn 容器号
* @param locCode 库位号
* @param layerIndex 堆叠层 * @param layerIndex 堆叠层
* @param qty 数量 >0 减数量 <0 减数量 * @param qty 数量 >0 减数量 <0 减数量
*/ */
public static void invSave(Long envId, String lpn, String locCode, int layerIndex, int qty) { public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int layerIndex, int qty) {
invSave(envId, lpn, locCode, layerIndex, qty, 0, 0); invSave(envId, bizTaskId, lpn, locCode, layerIndex, qty, 0, 0);
} }
/** /**
* 保存库存 * 保存库存
* @param envId 环境ID *
* @param lpn 容器号 * @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号 * @param locCode 库位号
* @param qty 数量 >0 减数量 <0 减数量 * @param qty 数量 >0 减数量 <0 减数量
*/ */
public static void invSave(Long envId, String lpn, String locCode, int qty) { public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty) {
invSave(envId, lpn, locCode, 0, qty, 0, 0); invSave(envId, bizTaskId, lpn, locCode, 0, qty, 0, 0);
} }
} }

15
servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java

@ -6,12 +6,10 @@ import com.galaxis.rcs.common.entity.RcsTaskPlan;
import com.galaxis.rcs.common.enums.PlanTaskStatus; import com.galaxis.rcs.common.enums.PlanTaskStatus;
import com.galaxis.rcs.common.enums.PlanTaskType; import com.galaxis.rcs.common.enums.PlanTaskType;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.yvan.entity.BasLocationVo;
import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntime;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.clever.core.BannerUtils;
import org.clever.core.id.SnowFlake; import org.clever.core.id.SnowFlake;
import org.clever.core.json.JsonWrapper; import org.clever.core.json.JsonWrapper;
@ -33,7 +31,12 @@ public class PlanTaskSequence {
public String lastWayPointId; public String lastWayPointId;
public Float lastRotationAngle = null; public Float lastRotationAngle = null;
public String lastLoadLpn = "";
public String carryLpn;
public BasLocationVo loadBasLocationVo;
public BasLocationVo unloadBasLocationVo;
public BasLocationVo executorVo;
public int carryQty;
public PlanTaskSequence(String executorId, LogisticsRuntime logisticsRuntime, RcsTaskBiz bizTask, String createBy) { public PlanTaskSequence(String executorId, LogisticsRuntime logisticsRuntime, RcsTaskBiz bizTask, String createBy) {
this.executorId = executorId; this.executorId = executorId;
@ -90,13 +93,12 @@ public class PlanTaskSequence {
} }
// 添加取货动作 // 添加取货动作
public RcsTaskPlan addLoad(String lpn, String rackId, int bay, int level, int cell) { public RcsTaskPlan addLoad( String rackId, int bay, int level, int cell) {
RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.LOAD.toString()); RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.LOAD.toString());
task.setTargetId(rackId); task.setTargetId(rackId);
task.setTargetBay(bay); task.setTargetBay(bay);
task.setTargetLevel(level); task.setTargetLevel(level);
task.setTargetCell(cell); task.setTargetCell(cell);
this.lastLoadLpn = lpn;
return task; return task;
} }
@ -107,7 +109,6 @@ public class PlanTaskSequence {
task.setTargetBay(bay); task.setTargetBay(bay);
task.setTargetLevel(level); task.setTargetLevel(level);
task.setTargetCell(cell); task.setTargetCell(cell);
this.lastLoadLpn = "";
return task; return task;
} }

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

@ -123,7 +123,7 @@ public class PtrPathPlanner {
// 生成指令序列 // 生成指令序列
generateMoves(plan, toLoadPath); generateMoves(plan, toLoadPath);
plan.addLoad(task.lpn(), loadRackId, pickupBay, task.from().level(), task.from().cell()); plan.addLoad(loadRackId, pickupBay, task.from().level(), task.from().cell());
generateMoves(plan, toUnloadPath); generateMoves(plan, toUnloadPath);
plan.addUnload(unloadRackId, task.to().level(), task.to().bay(), task.to().cell()); plan.addUnload(unloadRackId, task.to().level(), task.to().bay(), task.to().cell());
@ -218,7 +218,7 @@ public class PtrPathPlanner {
// 生成指令序列 // 生成指令序列
generateMoves(plan, toLoadPath); generateMoves(plan, toLoadPath);
plan.addLoad("N/A", loadRackId, task.to().level(), task.to().bay(), task.to().cell()); plan.addLoad(loadRackId, task.to().level(), task.to().bay(), task.to().cell());
plan.addFinish(); plan.addFinish();
} }

1
servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java

@ -26,7 +26,6 @@ import com.galaxis.rcs.common.entity.StoreLocation;
*/ */
public record CarryTask( public record CarryTask(
String agv, String agv,
String lpn,
int priority, int priority,
StoreLocation from, StoreLocation from,
StoreLocation to StoreLocation to

13
servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java

@ -136,6 +136,19 @@ public abstract class PtrAgvItem extends ExecutorItem {
public synchronized void dispatchTask(PlanTaskSequence taskSequence) { public synchronized void dispatchTask(PlanTaskSequence taskSequence) {
if (!isFree()) { if (!isFree()) {
if (!this.runtime.isRunning()) {
throw new IllegalStateException("runtime is not running!");
}
if (planTaskSequence != null && !planTaskSequence.isAllCompleted()) {
throw new IllegalStateException("AGV is busy with an existing task sequence");
}
if (!deviceTaskQueue.isEmpty()) {
throw new IllegalStateException("AGV has pending device tasks in the queue");
}
if (!isOnline) {
throw new IllegalStateException("AGV is not online and cannot accept new tasks");
}
throw new IllegalStateException("AGV is not free to accept new tasks"); throw new IllegalStateException("AGV is not free to accept new tasks");
} }

60
servo/src/main/java/com/yvan/entity/BasLocationVo.java

@ -0,0 +1,60 @@
package com.yvan.entity;
import com.galaxis.rcs.common.entity.LccBasLocation;
import com.yvan.logisticsModel.ExecutorItem;
import lombok.Data;
/**
* 用于表示货位的值对象
*/
@Data
public class BasLocationVo {
/**
* 位置编码
*/
String locCode;
/**
* 货位类型
*/
String locType;
/**
* 货位
*/
String rack;
/**
*
*/
int bay;
/**
*
*/
int level;
/**
*
*/
int cell;
public BasLocationVo(LccBasLocation basLocation) {
this.locCode = basLocation.getLocCode();
this.locType = basLocation.getLocType();
this.rack = basLocation.getRack();
this.bay = basLocation.getBay();
this.level = basLocation.getLevel();
this.cell = basLocation.getCell();
}
public BasLocationVo(ExecutorItem executorItem) {
// 从 ExecutorItem 中提取信息并赋值给 BasLocationVo
this.locCode = "AGV_" + executorItem.getId();
this.locType = executorItem.getT();
this.rack = "N/A";
this.bay = 0;
this.level = 0;
this.cell = 0;
}
}

2
servo/src/main/java/com/yvan/workbench/model/entity/LccProject.java → servo/src/main/java/com/yvan/entity/LccProject.java

@ -1,4 +1,4 @@
package com.yvan.workbench.model.entity; package com.yvan.entity;
import lombok.Data; import lombok.Data;

2
servo/src/main/java/com/yvan/workbench/model/entity/LccProjectEnv.java → servo/src/main/java/com/yvan/entity/LccProjectEnv.java

@ -1,4 +1,4 @@
package com.yvan.workbench.model.entity; package com.yvan.entity;
import com.yvan.logisticsEnv.EnvConfig; import com.yvan.logisticsEnv.EnvConfig;
import lombok.Data; import lombok.Data;

2
servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java → servo/src/main/java/com/yvan/entity/Vector2.java

@ -1,4 +1,4 @@
package com.yvan.workbench.model.entity; package com.yvan.entity;
public record Vector2( public record Vector2(
/** /**

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

@ -1,14 +1,8 @@
package com.yvan.logisticsModel; package com.yvan.logisticsModel;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.galaxis.rcs.common.entity.RcsTaskPlan;
import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.PlanTaskSequence;
import com.google.common.collect.Queues;
import com.yvan.workbench.model.entity.Vector2;
import java.util.Map; import java.util.Map;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
/** /**
* 物流任务执行单元(如拣货台小车AGV堆垛机人等) * 物流任务执行单元(如拣货台小车AGV堆垛机人等)

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

@ -1,6 +1,10 @@
package com.yvan.logisticsModel; package com.yvan.logisticsModel;
import com.galaxis.rcs.common.entity.RcsTaskPlan;
import com.galaxis.rcs.common.enums.PlanTaskType;
import com.galaxis.rcs.connector.cl2.Cl2Item; import com.galaxis.rcs.connector.cl2.Cl2Item;
import com.galaxis.rcs.inv.InvManager;
import com.galaxis.rcs.plan.PlanTaskSequence;
import com.galaxis.rcs.plan.path.NavigationGraph; import com.galaxis.rcs.plan.path.NavigationGraph;
import com.galaxis.rcs.plan.path.PtrPathPlanner; import com.galaxis.rcs.plan.path.PtrPathPlanner;
import com.galaxis.rcs.ptr.AmrMessageHandler; import com.galaxis.rcs.ptr.AmrMessageHandler;
@ -12,26 +16,27 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.yvan.event.AgvEventManager; import com.yvan.event.AgvEventManager;
import com.yvan.event.AgvEventType; import com.yvan.event.AgvEventType;
import com.yvan.mqtt.FrontendMessagePushService; import com.yvan.pusher.FrontendMessagePushService;
import com.yvan.redis.LccRedisService; import com.yvan.redis.LccRedisService;
import com.yvan.workbench.model.entity.LccProject; import com.yvan.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv; import com.yvan.entity.LccProjectEnv;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.clever.core.BannerUtils; import org.clever.core.BannerUtils;
import org.clever.core.Conv; import org.clever.core.Conv;
import org.clever.data.jdbc.DaoFactory;
import org.clever.data.jdbc.QueryDSL;
import org.clever.data.redis.Redis; import org.clever.data.redis.Redis;
import org.clever.data.redis.RedisAdmin; import org.clever.data.redis.RedisAdmin;
import java.util.Date; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* 物流运行时 * 物流运行时
*/ */
@Slf4j @Slf4j
public class LogisticsRuntime { public class LogisticsRuntime {
public final QueryDSL queryDSL = DaoFactory.getQueryDSL();
/** /**
* 项目UUID * 项目UUID
*/ */
@ -134,12 +139,53 @@ public class LogisticsRuntime {
for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
eventArgs[i - 1] = Conv.asString(args[i]); eventArgs[i - 1] = Conv.asString(args[i]);
} }
if (type == AgvEventType.PLAN_TASK_COMPLETE) {
PlanTaskSequence taskSequence = (PlanTaskSequence) args[1];
RcsTaskPlan taskPlan = (RcsTaskPlan) args[2];
PlanTaskType planType = PlanTaskType.valueOf(taskPlan.getPlanType());
if (planType == PlanTaskType.LOAD) {
// 处理库存变化 rack-> agv
changeInvOfLoad(taskSequence, taskPlan);
} else if (planType == PlanTaskType.UNLOAD) {
// 处理库存变化 agv -> rack
changeInvOfUnload(taskSequence, taskPlan);
}
}
BannerUtils.printConfig(log, this.projectUuid + "(" + this.envId + ") " + type + " AGV:" + sender.getId(), eventArgs); BannerUtils.printConfig(log, this.projectUuid + "(" + this.envId + ") " + type + " AGV:" + sender.getId(), eventArgs);
}); });
} }
/** /**
* 库存转移 AGV->货架
*/
private void changeInvOfUnload(PlanTaskSequence taskSequence, RcsTaskPlan taskPlan) {
queryDSL.beginTX(status -> {
String lpn = taskSequence.carryLpn;
InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.executorVo.getLocCode(), -taskSequence.carryQty);
InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.unloadBasLocationVo.getLocCode(), taskSequence.carryQty);
this.frontendMessagePushService.pushInventoryUpdate(lpn, taskSequence.executorVo, taskSequence.unloadBasLocationVo, taskSequence.carryQty);
});
}
/**
* 库存转移 货架->AGV
*/
private void changeInvOfLoad(PlanTaskSequence taskSequence, RcsTaskPlan taskPlan) {
queryDSL.beginTX(status -> {
String lpn = taskSequence.carryLpn;
InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.loadBasLocationVo.getLocCode(), -taskSequence.carryQty);
InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.executorVo.getLocCode(), taskSequence.carryQty);
this.frontendMessagePushService.pushInventoryUpdate(lpn, taskSequence.loadBasLocationVo, taskSequence.executorVo, taskSequence.carryQty);
});
}
/**
* 获取当前空闲的执行器列表 * 获取当前空闲的执行器列表
*/ */
public List<ExecutorItem> getFreeExecutorList() { public List<ExecutorItem> getFreeExecutorList() {

4
servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java

@ -1,8 +1,8 @@
package com.yvan.logisticsModel; package com.yvan.logisticsModel;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.yvan.workbench.model.entity.LccProject; import com.yvan.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv; import com.yvan.entity.LccProjectEnv;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.net.InetAddress; import java.net.InetAddress;

17
servo/src/main/java/com/yvan/mqtt/FrontendMessagePushService.java → servo/src/main/java/com/yvan/pusher/FrontendMessagePushService.java

@ -1,5 +1,6 @@
package com.yvan.mqtt; package com.yvan.pusher;
import com.yvan.entity.BasLocationVo;
import com.yvan.logisticsEnv.EnvConfig; import com.yvan.logisticsEnv.EnvConfig;
import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntime;
import lombok.Getter; import lombok.Getter;
@ -165,18 +166,20 @@ public class FrontendMessagePushService implements MqttCallback {
/** /**
* 推送库存更新 * 推送库存更新
* /lcc/{proj_id}/{env_id}/inv/{catalogCode} * /lcc/{proj_id}/{env_id}/inv
* *
* @param catalogCode 货位目录编码 * @param lpn 容器号
* @param before 更新前库存 * @param before 更新前库存
* @param after 更新后库存 * @param after 更新后库存
*/ */
public void pushInventoryUpdate(String catalogCode, Object before, Object after) { public void pushInventoryUpdate(String lpn, BasLocationVo before, BasLocationVo after, int qty) {
String topic = buildTopic("inv/" + catalogCode); String topic = buildTopic("inv");
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("lpn", lpn);
data.put("before", before); data.put("before", before);
data.put("after", after); data.put("after", after);
data.put("qty", qty);
publishJson(topic, data); publishJson(topic, data);
} }

2
servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java

@ -4,7 +4,7 @@ import com.galaxis.rcs.common.entity.LccBasLocation;
import com.galaxis.rcs.common.entity.StoreLocation; import com.galaxis.rcs.common.entity.StoreLocation;
import com.galaxis.rcs.ptr.JacksonUtils; import com.galaxis.rcs.ptr.JacksonUtils;
import com.yvan.workbench.SpringContext; import com.yvan.workbench.SpringContext;
import com.yvan.workbench.model.entity.LccProject; import com.yvan.entity.LccProject;
import com.yvan.workbench.service.LccMapService; import com.yvan.workbench.service.LccMapService;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows; import lombok.SneakyThrows;

222
servo/src/main/java/com/yvan/workbench/controller/RcsController.java

@ -1,6 +1,6 @@
package com.yvan.workbench.controller; package com.yvan.workbench.controller;
import com.galaxis.rcs.RCSService; import com.galaxis.rcs.common.entity.LccBasLocation;
import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.common.entity.StoreLocation; import com.galaxis.rcs.common.entity.StoreLocation;
import com.galaxis.rcs.common.enums.BizTaskStatus; import com.galaxis.rcs.common.enums.BizTaskStatus;
@ -11,6 +11,7 @@ import com.galaxis.rcs.plan.task.*;
import com.galaxis.rcs.ptr.PtrAgvItem; import com.galaxis.rcs.ptr.PtrAgvItem;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.yvan.entity.BasLocationVo;
import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntime;
import com.yvan.logisticsModel.LogisticsRuntimeService; import com.yvan.logisticsModel.LogisticsRuntimeService;
@ -22,6 +23,9 @@ import org.clever.web.mvc.annotation.RequestBody;
import java.util.Map; import java.util.Map;
import static com.galaxis.rcs.common.query.QLccBasLocation.lccBasLocation;
import static com.galaxis.rcs.common.query.QLccInvLpn.lccInvLpn;
public class RcsController { public class RcsController {
static final SnowFlake snowFlake = new SnowFlake(); static final SnowFlake snowFlake = new SnowFlake();
@ -130,6 +134,101 @@ public class RcsController {
return R.success(executorItem); return R.success(executorItem);
} }
public static R<?> agvCarry(@RequestBody Map<String, Object> params) {
Object ret = getCommonParamAndCreateBizTask(params);
if (ret instanceof R) {
// 异常
return (R<?>) ret;
}
RcsCommonParam ps = (RcsCommonParam) ret;
// ==================== 查找来源货位 ====================
String fromStoreLoc = Conv.asString(params.get("fromStoreLoc"));
if (Strings.isNullOrEmpty(fromStoreLoc)) {
return R.fail("fromStoreLoc Must not be empty");
}
StoreLocation sourceLocation = StoreLocation.of(fromStoreLoc, "/");
StaticItem sourceItem = ps.runtime.getStaticItemById(sourceLocation.rackId());
if (sourceItem == null) {
return R.fail("fromStoreLoc storePoint not found!");
}
// 查找货位基础资料
LccBasLocation loadBasLocation = ps.runtime.queryDSL.selectFrom(
lccBasLocation
)
.where(lccBasLocation.envId.eq(ps.envId))
.where(lccBasLocation.rack.eq(sourceLocation.rackId()))
.where(lccBasLocation.bay.eq(sourceLocation.bay()))
.where(lccBasLocation.level.eq(sourceLocation.level()))
.where(lccBasLocation.cell.eq(sourceLocation.cell()))
.fetchFirst();
if (loadBasLocation == null) {
return R.fail("fromStoreLoc location not found!");
}
// ==================== 查找卸货货位 ====================
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty");
}
StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/");
StaticItem targetItem = ps.runtime.getStaticItemById(targetLocation.rackId());
if (targetItem == null) {
return R.fail("targetStoreLoc storePoint not found!");
}
// 查找货位基础资料
LccBasLocation unloadBasLocation = ps.runtime.queryDSL.selectFrom(
lccBasLocation
)
.where(lccBasLocation.envId.eq(ps.envId))
.where(lccBasLocation.rack.eq(targetLocation.rackId()))
.where(lccBasLocation.bay.eq(targetLocation.bay()))
.where(lccBasLocation.level.eq(targetLocation.level()))
.where(lccBasLocation.cell.eq(targetLocation.cell()))
.fetchFirst();
if (unloadBasLocation == null) {
return R.fail("targetStoreLoc location not found!");
}
// ==================== 找到托盘号 ====================
String lpn = ps.runtime.queryDSL
.select(lccInvLpn.lpn)
.from(lccInvLpn)
.where(lccInvLpn.envId.eq(ps.envId))
.where(lccInvLpn.locCode.eq(loadBasLocation.getLocCode()))
.fetchFirst();
if (Strings.isNullOrEmpty(lpn)) {
return R.fail("LPN not found at fromStoreLoc: " + fromStoreLoc);
}
// ==================== 布置任务 ====================
ps.bizTask.setLpn(lpn);
ps.bizTask.setTaskFrom(loadBasLocation.getCatalogCode());
ps.bizTask.setTaskTo(unloadBasLocation.getLocCode());
CarryTask carryTask = new CarryTask(
ps.agvId, ps.bizTask.getPriority(),
sourceLocation,
targetLocation
);
ps.planSequence.executorVo = new BasLocationVo(ps.agv);
ps.planSequence.loadBasLocationVo = new BasLocationVo(loadBasLocation);
ps.planSequence.unloadBasLocationVo = new BasLocationVo(unloadBasLocation);
ps.planSequence.carryLpn = lpn;
ps.planSequence.carryQty = 1;
ps.runtime.pathPlannerMap.get(ps.agv.getT())
.planCarryTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, carryTask);
ps.agv.logicX = ps.fromItem.logicX;
ps.agv.logicY = ps.fromItem.logicY;
ps.agv.dispatchTask(ps.planSequence);
return R.success(ps.planSequence.toPrettyMap());
}
public static R<Object> agvUnload(@RequestBody Map<String, Object> params) { public static R<Object> agvUnload(@RequestBody Map<String, Object> params) {
Object ret = getCommonParamAndCreateBizTask(params); Object ret = getCommonParamAndCreateBizTask(params);
if (ret instanceof R) { if (ret instanceof R) {
@ -138,16 +237,52 @@ public class RcsController {
} }
RcsCommonParam ps = (RcsCommonParam) ret; RcsCommonParam ps = (RcsCommonParam) ret;
// ==================== 查找卸货货位 ====================
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(targetStoreLoc)) { if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty"); return R.fail("targetStoreLoc Must not be empty");
} }
StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/");
// 查找货位基础资料
LccBasLocation unloadBasLocation = ps.runtime.queryDSL.selectFrom(
lccBasLocation
)
.where(lccBasLocation.envId.eq(ps.envId))
.where(lccBasLocation.rack.eq(targetLocation.rackId()))
.where(lccBasLocation.bay.eq(targetLocation.bay()))
.where(lccBasLocation.level.eq(targetLocation.level()))
.where(lccBasLocation.cell.eq(targetLocation.cell()))
.fetchFirst();
if (unloadBasLocation == null) {
return R.fail("targetStoreLoc location not found!");
}
// ==================== 找到托盘号 ====================
BasLocationVo executorVo = new BasLocationVo(ps.agv);
String lpn = ps.runtime.queryDSL
.select(lccInvLpn.lpn)
.from(lccInvLpn)
.where(lccInvLpn.envId.eq(ps.envId))
.where(lccInvLpn.locCode.eq(executorVo.getLocCode()))
.fetchFirst();
if (Strings.isNullOrEmpty(lpn)) {
return R.fail("LPN not found at StoreLoc: " + executorVo.getLocCode());
}
// ==================== 布置任务 ====================
ps.bizTask.setLpn(lpn);
ps.bizTask.setTaskFrom(ps.fromItem.getId());
ps.bizTask.setTaskTo(unloadBasLocation.getLocCode());
UnloadTask unloadTask = new UnloadTask( UnloadTask unloadTask = new UnloadTask(
ps.agvId, ps.bizTask.getPriority(), ps.agvId, ps.bizTask.getPriority(),
targetLocation targetLocation
); );
ps.planSequence.executorVo = executorVo;
ps.planSequence.loadBasLocationVo = null;
ps.planSequence.unloadBasLocationVo = new BasLocationVo(unloadBasLocation);
ps.planSequence.carryLpn = lpn;
ps.planSequence.carryQty = 1;
ps.runtime.pathPlannerMap.get(ps.agv.getT()) ps.runtime.pathPlannerMap.get(ps.agv.getT())
.planUnloadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, unloadTask); .planUnloadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, unloadTask);
@ -167,16 +302,51 @@ public class RcsController {
} }
RcsCommonParam ps = (RcsCommonParam) ret; RcsCommonParam ps = (RcsCommonParam) ret;
// ==================== 查找来源货位 ====================
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(targetStoreLoc)) { if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty"); return R.fail("targetStoreLoc Must not be empty");
} }
StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/");
// 查找货位基础资料
LccBasLocation loadBasLocation = ps.runtime.queryDSL.selectFrom(
lccBasLocation
)
.where(lccBasLocation.envId.eq(ps.envId))
.where(lccBasLocation.rack.eq(targetLocation.rackId()))
.where(lccBasLocation.bay.eq(targetLocation.bay()))
.where(lccBasLocation.level.eq(targetLocation.level()))
.where(lccBasLocation.cell.eq(targetLocation.cell()))
.fetchFirst();
if (loadBasLocation == null) {
return R.fail("targetStoreLoc location not found!");
}
// ==================== 找到托盘号 ====================
String lpn = ps.runtime.queryDSL
.select(lccInvLpn.lpn)
.from(lccInvLpn)
.where(lccInvLpn.envId.eq(ps.envId))
.where(lccInvLpn.locCode.eq(loadBasLocation.getLocCode()))
.fetchFirst();
if (Strings.isNullOrEmpty(lpn)) {
return R.fail("LPN not found at targetStoreLoc: " + loadBasLocation.getLocCode());
}
// ==================== 布置任务 ====================
ps.bizTask.setLpn(lpn);
ps.bizTask.setTaskFrom(ps.fromItem.getId());
ps.bizTask.setTaskTo(loadBasLocation.getLocCode());
LoadTask loadTask = new LoadTask( LoadTask loadTask = new LoadTask(
ps.agvId, ps.bizTask.getPriority(), ps.agvId, ps.bizTask.getPriority(),
targetLocation targetLocation
); );
ps.planSequence.executorVo = new BasLocationVo(ps.agv);
ps.planSequence.loadBasLocationVo = new BasLocationVo(loadBasLocation);
ps.planSequence.unloadBasLocationVo = null;
ps.planSequence.carryLpn = lpn;
ps.planSequence.carryQty = 1;
ps.runtime.pathPlannerMap.get(ps.agv.getT()) ps.runtime.pathPlannerMap.get(ps.agv.getT())
.planLoadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, loadTask); .planLoadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, loadTask);
@ -224,56 +394,6 @@ public class RcsController {
return R.success(cost); return R.success(cost);
} }
public static R<?> agvCarry(@RequestBody Map<String, Object> params) {
Object ret = getCommonParamAndCreateBizTask(params);
if (ret instanceof R) {
// 异常
return (R<?>) ret;
}
RcsCommonParam ps = (RcsCommonParam) ret;
String fromStoreLoc = Conv.asString(params.get("fromStoreLoc"));
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(fromStoreLoc)) {
return R.fail("fromStoreLoc Must not be empty");
}
if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty");
}
StoreLocation sourceLocation = StoreLocation.of(fromStoreLoc, "/");
StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/");
StaticItem sourceItem = ps.runtime.getStaticItemById(sourceLocation.rackId());
if (sourceItem == null) {
return R.fail("fromStoreLoc storePoint not found!");
}
StaticItem targetItem = ps.runtime.getStaticItemById(targetLocation.rackId());
if (targetItem == null) {
return R.fail("targetStoreLoc storePoint not found!");
}
ps.bizTask.setTaskFrom(fromStoreLoc);
ps.bizTask.setTaskTo(targetStoreLoc);
CarryTask carryTask = new CarryTask(
ps.agvId, "N/A", ps.bizTask.getPriority(),
sourceLocation,
targetLocation
);
ps.runtime.pathPlannerMap.get(ps.agv.getT())
.planCarryTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, carryTask);
ps.agv.logicX = ps.fromItem.logicX;
ps.agv.logicY = ps.fromItem.logicY;
ps.agv.dispatchTask(ps.planSequence);
return R.success(ps.planSequence.toPrettyMap());
}
public static Object getCommonParamAndCreateBizTask(@RequestBody Map<String, Object> params) { public static Object getCommonParamAndCreateBizTask(@RequestBody Map<String, Object> params) {
String projectUUID = Conv.asString(params.get("projectUUID")); String projectUUID = Conv.asString(params.get("projectUUID"));
Long envId = Conv.asLong(params.get("envId")); Long envId = Conv.asLong(params.get("envId"));

7
servo/src/main/java/com/yvan/workbench/service/LccMapService.java

@ -1,21 +1,18 @@
package com.yvan.workbench.service; package com.yvan.workbench.service;
import com.google.common.base.Joiner;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.yvan.LccUtils; import com.yvan.LccUtils;
import com.yvan.workbench.autoconfigure.LccConfigProperties; import com.yvan.workbench.autoconfigure.LccConfigProperties;
import com.yvan.workbench.model.entity.LccProject; import com.yvan.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv; import com.yvan.entity.LccProjectEnv;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.clever.core.Conv; import org.clever.core.Conv;
import org.clever.core.mapper.JacksonMapper; import org.clever.core.mapper.JacksonMapper;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;

Loading…
Cancel
Save