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.StaticItem;
import com.yvan.workbench.SpringContext;
import com.yvan.workbench.model.entity.LccProject;
import com.yvan.entity.LccProject;
import com.yvan.workbench.service.LccMapService;
import lombok.SneakyThrows;
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.querydsl.core.util.StringUtils;
import org.clever.core.id.SnowFlake;
import org.clever.data.jdbc.DaoFactory;
import org.clever.data.jdbc.QueryDSL;
@ -15,15 +16,16 @@ public class InvManager {
/**
* 记录库存
* @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号
*
* @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号
* @param layerIndex 堆叠层
* @param qty 数量 >0 增加数量 <0 减数量
* @param qtyIn 入库数量 >0 减数量 <0 减数量
* @param qtyOut 出库数量 >0 减数量 <0 减数量
* @param qty 数量 >0 增加数量 <0 减数量
* @param qtyIn 入库数量 >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
|| lpn == null || StringUtils.isNullOrEmpty(lpn) || lpn.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) {
queryDSL.update(lccInvLpn)
.set(lccInvLpn.qty, lccInvLpn.qty.add(qty))
.set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn))
.set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut))
.set(lccInvLpn.layerIndex, layerIndex)
// .set(lccInvLpn.updateAt, )
.where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn)))
.execute();
// 记录账页
queryDSL.insert(lccInvLedger)
.set(lccInvLedger.envId, envId)
.set(lccInvLedger.lpn, lpn)
.set(lccInvLedger.locCode, locCode)
.set(lccInvLedger.layerIndex, layerIndex)
.set(lccInvLedger.qtyChange, qty)
.set(lccInvLedger.qtyInChange, qtyIn)
.set(lccInvLedger.qtyOutChange, qtyOut)
.set(lccInvLedger.qty, lccInvLpnData.getQty() + qty)
.set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn)
.set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + qtyOut)
.set(lccInvLedger.ledgerType, "记账")
.set(lccInvLedger.ledgerRemark, "N/A")
.execute();
} else {
queryDSL.insert(lccInvLpn)
.set(lccInvLpn.envId, envId)
.set(lccInvLpn.lpn, lpn)
.set(lccInvLpn.locCode, locCode)
.set(lccInvLpn.layerIndex, layerIndex)
.set(lccInvLpn.qty, qty)
.set(lccInvLpn.qtyIn, qtyIn)
.set(lccInvLpn.qtyOut, qtyOut)
.execute();
// 记录账页
queryDSL.insert(lccInvLedger)
.set(lccInvLedger.envId, envId)
.set(lccInvLedger.lpn, lpn)
.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")
.execute();
}
// 删除所有数量预占预扣都为0的库存
queryDSL.delete(lccInvLpn).where(lccInvLpn.qty.eq(0).and(lccInvLpn.qtyIn.eq(0)).and(lccInvLpn.qtyOut.eq(0))).execute();
});
if (lccInvLpnData != null) {
queryDSL.update(lccInvLpn)
.set(lccInvLpn.qty, lccInvLpn.qty.add(qty))
.set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn))
.set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut))
.set(lccInvLpn.layerIndex, layerIndex)
.set(lccInvLpn.updateAt, new Date(System.currentTimeMillis()))
.set(lccInvLpn.updateBy, "system")
.where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn)))
.execute();
// 记录账页
queryDSL.insert(lccInvLedger)
.set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId())
.set(lccInvLedger.envId, envId)
.set(lccInvLedger.lpn, lpn)
.set(lccInvLedger.bizTaskId, bizTaskId)
.set(lccInvLedger.locCode, locCode)
.set(lccInvLedger.layerIndex, layerIndex)
.set(lccInvLedger.qtyChange, qty)
.set(lccInvLedger.qtyInChange, qtyIn)
.set(lccInvLedger.qtyOutChange, qtyOut)
.set(lccInvLedger.qty, lccInvLpnData.getQty() + qty)
.set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn)
.set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + 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();
} else {
queryDSL.insert(lccInvLpn)
.set(lccInvLpn.envId, envId)
.set(lccInvLpn.lpn, lpn)
.set(lccInvLpn.locCode, locCode)
.set(lccInvLpn.layerIndex, layerIndex)
.set(lccInvLpn.qty, qty)
.set(lccInvLpn.qtyIn, qtyIn)
.set(lccInvLpn.qtyOut, qtyOut)
.set(lccInvLpn.createAt, new Date(System.currentTimeMillis()))
.set(lccInvLpn.createBy, "system")
.set(lccInvLpn.updateAt, new Date(System.currentTimeMillis()))
.set(lccInvLpn.updateBy, "system")
.execute();
// 记录账页
queryDSL.insert(lccInvLedger)
.set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId())
.set(lccInvLedger.envId, envId)
.set(lccInvLedger.lpn, lpn)
.set(lccInvLedger.bizTaskId, bizTaskId)
.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 qty 数量 >0 减数量 <0 减数量
* @param qtyIn 入库数量 >0 减数量 <0 减数量
* @param qtyOut 出库数量 >0 减数量 <0 减数量
* @param qty 数量 >0 减数量 <0 减数量
* @param qtyIn 入库数量 >0 减数量 <0 减数量
* @param qtyOut 出库数量 >0 减数量 <0 减数量
*/
public static void invSave(Long envId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) {
invSave(envId, lpn, locCode, 0, qty, qtyIn, qtyOut);
public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) {
invSave(envId, bizTaskId, lpn, locCode, 0, qty, qtyIn, qtyOut);
}
/**
* 保存库存
* @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号
*
* @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号
* @param layerIndex 堆叠层
* @param qty 数量 >0 减数量 <0 减数量
* @param qty 数量 >0 减数量 <0 减数量
*/
public static void invSave(Long envId, String lpn, String locCode, int layerIndex, int qty) {
invSave(envId, lpn, locCode, layerIndex, qty, 0, 0);
public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int layerIndex, int qty) {
invSave(envId, bizTaskId, lpn, locCode, layerIndex, qty, 0, 0);
}
/**
* 保存库存
* @param envId 环境ID
* @param lpn 容器号
*
* @param envId 环境ID
* @param lpn 容器号
* @param locCode 库位号
* @param qty 数量 >0 减数量 <0 减数量
* @param qty 数量 >0 减数量 <0 减数量
*/
public static void invSave(Long envId, String lpn, String locCode, int qty) {
invSave(envId, lpn, locCode, 0, qty, 0, 0);
public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty) {
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.PlanTaskType;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yvan.entity.BasLocationVo;
import com.yvan.logisticsModel.LogisticsRuntime;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.clever.core.BannerUtils;
import org.clever.core.id.SnowFlake;
import org.clever.core.json.JsonWrapper;
@ -33,7 +31,12 @@ public class PlanTaskSequence {
public String lastWayPointId;
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) {
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());
task.setTargetId(rackId);
task.setTargetBay(bay);
task.setTargetLevel(level);
task.setTargetCell(cell);
this.lastLoadLpn = lpn;
return task;
}
@ -107,7 +109,6 @@ public class PlanTaskSequence {
task.setTargetBay(bay);
task.setTargetLevel(level);
task.setTargetCell(cell);
this.lastLoadLpn = "";
return task;
}

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

@ -123,7 +123,7 @@ public class PtrPathPlanner {
// 生成指令序列
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);
plan.addUnload(unloadRackId, task.to().level(), task.to().bay(), task.to().cell());
@ -218,7 +218,7 @@ public class PtrPathPlanner {
// 生成指令序列
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();
}

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(
String agv,
String lpn,
int priority,
StoreLocation from,
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) {
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");
}

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;

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 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(
/**

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

@ -1,14 +1,8 @@
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.google.common.collect.Queues;
import com.yvan.workbench.model.entity.Vector2;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
/**
* 物流任务执行单元(如拣货台小车AGV堆垛机人等)

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

@ -1,6 +1,10 @@
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.inv.InvManager;
import com.galaxis.rcs.plan.PlanTaskSequence;
import com.galaxis.rcs.plan.path.NavigationGraph;
import com.galaxis.rcs.plan.path.PtrPathPlanner;
import com.galaxis.rcs.ptr.AmrMessageHandler;
@ -12,26 +16,27 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.yvan.event.AgvEventManager;
import com.yvan.event.AgvEventType;
import com.yvan.mqtt.FrontendMessagePushService;
import com.yvan.pusher.FrontendMessagePushService;
import com.yvan.redis.LccRedisService;
import com.yvan.workbench.model.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv;
import com.yvan.entity.LccProject;
import com.yvan.entity.LccProjectEnv;
import lombok.extern.slf4j.Slf4j;
import org.clever.core.BannerUtils;
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.RedisAdmin;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* 物流运行时
*/
@Slf4j
public class LogisticsRuntime {
public final QueryDSL queryDSL = DaoFactory.getQueryDSL();
/**
* 项目UUID
*/
@ -134,12 +139,53 @@ public class LogisticsRuntime {
for (int i = 1; i < args.length; 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);
});
}
/**
* 库存转移 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() {

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

@ -1,8 +1,8 @@
package com.yvan.logisticsModel;
import com.google.common.collect.Maps;
import com.yvan.workbench.model.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv;
import com.yvan.entity.LccProject;
import com.yvan.entity.LccProjectEnv;
import lombok.SneakyThrows;
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.logisticsModel.LogisticsRuntime;
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 before 更新前库存
* @param after 更新后库存
* @param lpn 容器号
* @param before 更新前库存
* @param after 更新后库存
*/
public void pushInventoryUpdate(String catalogCode, Object before, Object after) {
String topic = buildTopic("inv/" + catalogCode);
public void pushInventoryUpdate(String lpn, BasLocationVo before, BasLocationVo after, int qty) {
String topic = buildTopic("inv");
Map<String, Object> data = new HashMap<>();
data.put("lpn", lpn);
data.put("before", before);
data.put("after", after);
data.put("qty", qty);
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.ptr.JacksonUtils;
import com.yvan.workbench.SpringContext;
import com.yvan.workbench.model.entity.LccProject;
import com.yvan.entity.LccProject;
import com.yvan.workbench.service.LccMapService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;

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

@ -1,6 +1,6 @@
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.StoreLocation;
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.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.yvan.entity.BasLocationVo;
import com.yvan.logisticsModel.ExecutorItem;
import com.yvan.logisticsModel.LogisticsRuntime;
import com.yvan.logisticsModel.LogisticsRuntimeService;
@ -22,6 +23,9 @@ import org.clever.web.mvc.annotation.RequestBody;
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 {
static final SnowFlake snowFlake = new SnowFlake();
@ -130,6 +134,101 @@ public class RcsController {
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) {
Object ret = getCommonParamAndCreateBizTask(params);
if (ret instanceof R) {
@ -138,16 +237,52 @@ public class RcsController {
}
RcsCommonParam ps = (RcsCommonParam) ret;
// ==================== 查找卸货货位 ====================
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty");
}
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(
ps.agvId, ps.bizTask.getPriority(),
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())
.planUnloadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, unloadTask);
@ -167,16 +302,51 @@ public class RcsController {
}
RcsCommonParam ps = (RcsCommonParam) ret;
// ==================== 查找来源货位 ====================
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
if (Strings.isNullOrEmpty(targetStoreLoc)) {
return R.fail("targetStoreLoc Must not be empty");
}
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(
ps.agvId, ps.bizTask.getPriority(),
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())
.planLoadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, loadTask);
@ -224,56 +394,6 @@ public class RcsController {
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) {
String projectUUID = Conv.asString(params.get("projectUUID"));
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;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.yvan.LccUtils;
import com.yvan.workbench.autoconfigure.LccConfigProperties;
import com.yvan.workbench.model.entity.LccProject;
import com.yvan.workbench.model.entity.LccProjectEnv;
import com.yvan.entity.LccProject;
import com.yvan.entity.LccProjectEnv;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.clever.core.Conv;
import org.clever.core.mapper.JacksonMapper;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;

Loading…
Cancel
Save