Browse Source

RCS / LCC 脚本支持

master
修宁 6 months ago
parent
commit
1e0de1724c
  1. 422
      examples/f1.json
  2. 62
      servo/src/main/java/com/galaxis/rcs/RCS.java
  3. 2
      servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java
  4. 4
      servo/src/main/java/com/galaxis/rcs/plan/path2/NavigationGraph.java
  5. 23
      servo/src/main/java/com/galaxis/rcs/plan/path2/PtrPathPlanner.java
  6. 2
      servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java
  7. 8
      servo/src/main/java/com/galaxis/rcs/plan/task/MoveTask.java
  8. 4
      servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java
  9. 3
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java
  10. 12
      servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java
  11. 15
      servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java
  12. 23
      servo/src/main/java/com/yvan/workbench/controller/LccController.java
  13. 244
      servo/src/main/java/com/yvan/workbench/controller/RcsController.java
  14. 8
      servo/src/main/java/com/yvan/workbench/model/entity/Model.java

422
examples/f1.json

@ -0,0 +1,422 @@
[
{
"id": "rack1",
"t": "rack",
"v": true,
"tf": [
[
1.55,
0,
-1.5
],
[
0,
0,
0
],
[
2.2,
2.8,
1
]
],
"dt": {
"rackDepth": 1,
"bottomBarHeight": 0.2,
"bottomLinkHeight": 0.2,
"topLinkDistance": 0.2,
"levelCount": 2,
"bayCount": 2,
"hideFloor": 0,
"extendColumns": 1,
"columnSpacing": 1,
"bays": [
{
"bayWidth": 1.1,
"levelHeight": [
1.4,
1.4
]
},
{
"bayWidth": 1.1,
"levelHeight": [
1.4,
1.4
]
}
],
"center": [],
"in": [],
"out": [],
"rackWidth": 2.2,
"rackHeight": 2.8
},
"_rid": "_2"
},
{
"id": "rack2",
"t": "rack",
"v": true,
"tf": [
[
3.9,
0,
-1.5
],
[
0,
0,
0
],
[
2.2,
2.8,
1
]
],
"dt": {
"rackDepth": 1,
"bottomBarHeight": 0.2,
"bottomLinkHeight": 0.2,
"topLinkDistance": 0.2,
"levelCount": 2,
"bayCount": 2,
"hideFloor": 0,
"extendColumns": 1,
"columnSpacing": 1,
"bays": [
{
"bayWidth": 1.1,
"levelHeight": [
1.4,
1.4
]
},
{
"bayWidth": 1.1,
"levelHeight": [
1.4,
1.4
]
}
],
"center": [],
"in": [],
"out": [],
"rackWidth": 2.2,
"rackHeight": 2.8
},
"_rid": "_3"
},
{
"id": "1_2",
"t": "way",
"v": true,
"logicX": 1,
"logicY": 2,
"tf": [
[
1,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"2_2"
],
"out": [
"2_2"
],
"center": [],
"linkStore": [
{
"item": "rack1",
"bay": 0,
"level": 0,
"cell": 0,
"direction": "up"
},
{
"item": "rack1",
"bay": 0,
"level": 1,
"cell": 0,
"direction": "up"
}
]
},
"_rid": "_4"
},
{
"id": "2_2",
"t": "way",
"v": true,
"logicX": 2,
"logicY": 2,
"tf": [
[
2.1,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"1_2",
"3_2"
],
"out": [
"1_2",
"3_2"
],
"center": [],
"linkStore": [
{
"item": "rack1",
"bay": 1,
"level": 0,
"cell": 0,
"direction": "up"
},
{
"item": "rack1",
"bay": 1,
"level": 1,
"cell": 0,
"direction": "up"
}
]
},
"_rid": "_5"
},
{
"id": "3_2",
"t": "way",
"v": true,
"logicX": 3,
"logicY": 2,
"tf": [
[
3.39,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"2_2",
"4_2"
],
"out": [
"2_2",
"4_2"
],
"center": [],
"linkStore": [
{
"item": "rack2",
"bay": 0,
"level": 0,
"cell": 0,
"direction": "up"
},
{
"item": "rack2",
"bay": 0,
"level": 1,
"cell": 0,
"direction": "up"
}
]
},
"_rid": "_6"
},
{
"id": "4_2",
"t": "way",
"v": true,
"logicX": 4,
"logicY": 2,
"tf": [
[
4.44,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"3_2",
"5_2"
],
"out": [
"3_2",
"5_2"
],
"center": [],
"linkStore": [
{
"item": "rack2",
"bay": 1,
"level": 0,
"cell": 0,
"direction": "up"
},
{
"item": "rack2",
"bay": 1,
"level": 1,
"cell": 0,
"direction": "up"
}
]
},
"_rid": "_7"
},
{
"id": "5_2",
"t": "way",
"v": true,
"logicX": 5,
"logicY": 2,
"tf": [
[
5.44,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"4_2",
"6_2"
],
"out": [
"4_2",
"6_2"
],
"center": []
},
"_rid": "_8"
},
{
"id": "6_2",
"t": "way",
"v": true,
"logicX": 6,
"logicY": 2,
"tf": [
[
6.44,
0.01,
0
],
[
0,
0,
0
],
[
0.25,
0.1,
0.25
]
],
"dt": {
"in": [
"5_2"
],
"out": [
"5_2"
],
"center": [],
"agvRotation": [
"cl2",
"clx"
]
},
"_rid": "_9"
},
{
"id": "3",
"t": "cl2",
"v": true,
"tf": [
[
6.440,
0,
0
],
[
0,
0,
0
],
[
1.5,
1.98,
1.5
]
],
"dt": {
"in": [],
"out": [],
"center": [],
"ptrWidth": 1.5,
"ptrDepth": 1.5,
"ptrHeight": 1.98
}
}
]

62
servo/src/main/java/com/galaxis/rcs/RCS.java

@ -11,41 +11,21 @@ import com.galaxis.rcs.plan.planner.Planner;
import com.galaxis.rcs.plan.TaskPlannerFactory; import com.galaxis.rcs.plan.TaskPlannerFactory;
import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.PlanTaskSequence;
import com.galaxis.rcs.plan.task.CarryTask; import com.galaxis.rcs.plan.task.CarryTask;
import com.google.common.base.Joiner; import com.google.common.base.Strings;
import com.yvan.logisticsEnv.EnvStartParam; import com.yvan.logisticsEnv.EnvStartParam;
import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntime;
import com.yvan.logisticsModel.LogisticsRuntimeService; import com.yvan.logisticsModel.LogisticsRuntimeService;
import com.yvan.workbench.model.query.QLccModelFloor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.clever.core.json.JsonWrapper; import org.clever.core.json.JsonWrapper;
import org.clever.data.jdbc.DaoFactory;
import java.io.File; import org.clever.data.jdbc.QueryDSL;
import java.nio.charset.StandardCharsets;
/** /**
* RCS 对外API调用类 * RCS 对外API调用类
*/ */
public class RCS { public class RCS {
static { static {
init();
}
@SneakyThrows
public static void init() {
if (LogisticsRuntimeService.INSTANCE.findByEnvCode(1L) == null) {
String fs = Joiner.on("\n").join(FileUtils.readLines(new File("./examples/example1.json"), StandardCharsets.UTF_8));
JsonWrapper jw = new JsonWrapper(fs);
LogisticsRuntimeService.INSTANCE.createEnv(1L);
LogisticsRuntime runtime = LogisticsRuntimeService.INSTANCE.findByEnvCode(1L);
runtime.loadMap(jw);
EnvStartParam param = new EnvStartParam();
param.setTimeRate(1);
param.setVirtual(false);
runtime.start(param);
}
} }
public static void ok() { public static void ok() {
@ -79,6 +59,40 @@ public class RCS {
return result; return result;
} }
/**
* 加载项目的楼层数据 (只加载物理生产环境)
*/
@SneakyThrows
public static boolean loadFloor(String projectUUID, String catalogCode, long envId) {
LogisticsRuntime runtime = LogisticsRuntimeService.INSTANCE.findByProjectFloor(projectUUID, catalogCode);
if (runtime == null) {
QueryDSL queryDsl = DaoFactory.getQueryDSL();
String floorPayload = queryDsl.select(QLccModelFloor.lccModelFloor.items)
.from(QLccModelFloor.lccModelFloor)
.where(QLccModelFloor.lccModelFloor.projectUuid.eq(projectUUID))
.where(QLccModelFloor.lccModelFloor.catalogCode.eq(catalogCode))
.fetchFirst();
if (Strings.isNullOrEmpty(floorPayload)) {
throw new RuntimeException("not found floor data for projectUUID: " + projectUUID + ", catalogCode: " + catalogCode);
}
JsonWrapper jw = new JsonWrapper("{ \"catalogCode\": \"" + catalogCode + "\", \"t\": \"floor\", \"items\": " + floorPayload + "}");
LogisticsRuntimeService.INSTANCE.createEnv(envId);
runtime = LogisticsRuntimeService.INSTANCE.findByEnvCode(envId);
runtime.projectUUID = projectUUID;
runtime.catalogCode = catalogCode;
runtime.loadMap(jw);
EnvStartParam param = new EnvStartParam();
param.setTimeRate(1);
param.setVirtual(false);
runtime.start(param);
}
return true;
}
public static Object runPath() { public static Object runPath() {
String executorId = "10"; // 执行器ID String executorId = "10"; // 执行器ID
String lpn = "pallet1124"; String lpn = "pallet1124";

2
servo/src/main/java/com/galaxis/rcs/common/enums/BizTaskType.java

@ -1,6 +1,8 @@
package com.galaxis.rcs.common.enums; package com.galaxis.rcs.common.enums;
public enum BizTaskType { public enum BizTaskType {
MOVE, // 移动任务
CHARGE, // 充电任务
CARRY; // 搬运任务 CARRY; // 搬运任务
public static BizTaskType fromString(String value) { public static BizTaskType fromString(String value) {

4
servo/src/main/java/com/galaxis/rcs/plan/path2/NavigationGraph.java

@ -50,6 +50,10 @@ public class NavigationGraph {
pathCache.put(cacheKey, path); pathCache.put(cacheKey, path);
} }
public Node getNodeById(String nodeId){
return nodeMap.get(nodeId);
}
public List<Node> getNodesForStore(String storeId) { public List<Node> getNodesForStore(String storeId) {
List<Node> nodes = new ArrayList<>(); List<Node> nodes = new ArrayList<>();
List<String> nodeIds = storeToNodes.get(storeId); List<String> nodeIds = storeToNodes.get(storeId);

23
servo/src/main/java/com/galaxis/rcs/plan/path2/PtrPathPlanner.java

@ -3,6 +3,7 @@ package com.galaxis.rcs.plan.path2;
import com.galaxis.rcs.common.enums.LCCDirection; import com.galaxis.rcs.common.enums.LCCDirection;
import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.PlanTaskSequence;
import com.galaxis.rcs.plan.task.CarryTask; import com.galaxis.rcs.plan.task.CarryTask;
import com.galaxis.rcs.plan.task.MoveTask;
import java.util.List; import java.util.List;
@ -18,6 +19,16 @@ public class PtrPathPlanner {
this.astar = new AStarPathPlanner(graph); this.astar = new AStarPathPlanner(graph);
} }
public void planMoveTask(PlanTaskSequence plan, String startNodeId, LCCDirection startDirection, MoveTask moveTask) {
Node node = this.graph.getNodeById(moveTask.targetWayPointId());
List<State> toPath = astar.findPath(startNodeId, startDirection, node.id(), startDirection);
generateMoves(plan, toPath);
plan.addFinish();
}
public void planCarryTask(PlanTaskSequence plan, String startNodeId, LCCDirection startDirection, CarryTask task) { public void planCarryTask(PlanTaskSequence plan, String startNodeId, LCCDirection startDirection, CarryTask task) {
// 取货点 // 取货点
String loadRackId = task.from().rackId(); String loadRackId = task.from().rackId();
@ -91,17 +102,6 @@ public class PtrPathPlanner {
} }
/** /**
* 获取指定节点和货架的所需朝向
*/
private LCCDirection getRequiredHeading(Node node, int bay) {
return node.storeLinks().stream()
.filter(link -> link.bay() == bay)
.findFirst()
.map(link -> link.direction())
.orElseThrow(() -> new RuntimeException("Not found storeLink in id=" + node.id() + ", bay=" + bay));
}
/**
* 根据A*状态生成移动指令序列 * 根据A*状态生成移动指令序列
*/ */
private void generateMoves(PlanTaskSequence sequence, List<State> path) { private void generateMoves(PlanTaskSequence sequence, List<State> path) {
@ -136,6 +136,7 @@ public class PtrPathPlanner {
} }
} }
// 辅助记录类 // 辅助记录类
private record NodeDirection(Node node, LCCDirection direction) { private record NodeDirection(Node node, LCCDirection direction) {
} }

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

@ -32,3 +32,5 @@ public record CarryTask(
StoreLocation to StoreLocation to
) { ) {
} }

8
servo/src/main/java/com/galaxis/rcs/plan/task/MoveTask.java

@ -0,0 +1,8 @@
package com.galaxis.rcs.plan.task;
public record MoveTask(
String agv,
String targetWayPointId,
int priority
) {
}

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

@ -1,5 +1,6 @@
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.common.entity.RcsTaskPlan;
import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.PlanTaskSequence;
import com.google.common.collect.Queues; import com.google.common.collect.Queues;
@ -14,8 +15,9 @@ import java.util.concurrent.BlockingQueue;
* 每个物流任务执行器都会有一个 Connector 线程专门用来消费 currentPlanList 队列变成实际的设备指令 * 每个物流任务执行器都会有一个 Connector 线程专门用来消费 currentPlanList 队列变成实际的设备指令
*/ */
public abstract class ExecutorItem extends BaseItem { public abstract class ExecutorItem extends BaseItem {
@JsonIgnore
public final LogisticsRuntime logisticsRuntime; public final LogisticsRuntime logisticsRuntime;
@JsonIgnore
public boolean isMapReady = false; public boolean isMapReady = false;
public void mapReady() { public void mapReady() {

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

@ -66,6 +66,9 @@ public class LogisticsRuntime {
this.logisticsEnv = logisticsEnv; this.logisticsEnv = logisticsEnv;
} }
public String projectUUID;
public String catalogCode;
/** /**
* 获取当前空闲的执行器列表 * 获取当前空闲的执行器列表
*/ */

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

@ -22,6 +22,18 @@ public class LogisticsRuntimeService {
} }
} }
/**
* 根据项目UUID和目录代码查找物流运行时实例
*/
public LogisticsRuntime findByProjectFloor(String projectUUID, String catalogCode) {
for (LogisticsRuntime runtime : runtimeMap.values()) {
if (projectUUID.equals(runtime.projectUUID) && catalogCode.equals(runtime.catalogCode)) {
return runtime;
}
}
return null;
}
public void createEnv(long envId) { public void createEnv(long envId) {
synchronized (LOCK) { synchronized (LOCK) {
if (runtimeMap.containsKey(envId)) { if (runtimeMap.containsKey(envId)) {

15
servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java

@ -1,6 +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.common.entity.RcsTaskPlan;
import com.galaxis.rcs.common.enums.LCCDirection;
import com.galaxis.rcs.common.enums.PlanTaskType; import com.galaxis.rcs.common.enums.PlanTaskType;
import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector;
import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.PlanTaskSequence;
@ -61,15 +63,27 @@ public class PtrAgvItem extends ExecutorItem {
// agv当前转动角度值 // agv当前转动角度值
public double orientation; public double orientation;
public LCCDirection getLCCDirection() {
return switch (direction) {
case 0 -> LCCDirection.RIGHT;
case 1 -> LCCDirection.DOWN;
case 2 -> LCCDirection.LEFT;
case 3 -> LCCDirection.UP;
default -> null;
};
}
// 执行中的任务 // 执行中的任务
@JsonIgnore
public List<PtrAgvDeviceTask> runningDeviceTaskList = new ArrayList<>(); public List<PtrAgvDeviceTask> runningDeviceTaskList = new ArrayList<>();
/** /**
* 当前执行的任务规划列表 * 当前执行的任务规划列表
*/ */
@JsonIgnore
final BlockingQueue<RcsTaskPlan> planQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY); final BlockingQueue<RcsTaskPlan> planQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY);
@JsonIgnore
final BlockingQueue<PtrAgvDeviceTask> deviceTaskQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY); final BlockingQueue<PtrAgvDeviceTask> deviceTaskQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY);
@ -80,6 +94,7 @@ public class PtrAgvItem extends ExecutorItem {
/** /**
* 更新设备任务状态 暂时没有处理任务取消相关的状态 * 更新设备任务状态 暂时没有处理任务取消相关的状态
*
* @param seqNo * @param seqNo
* @param x * @param x
* @param y * @param y

23
servo/src/main/java/com/yvan/workbench/controller/LccController.java

@ -0,0 +1,23 @@
package com.yvan.workbench.controller;
import com.galaxis.rcs.RCS;
import com.yvan.workbench.model.entity.Model;
import org.clever.core.Conv;
import org.clever.web.mvc.annotation.RequestBody;
import java.util.Map;
public class LccController {
/**
* 支持前端 RCSScript.loadFloor 方法加载楼层数据
*/
Model<Boolean> loadFloor(@RequestBody Map<String, Object> params) {
String projectUUID = Conv.asString(params.get("projectUUID"));
String catalogCode = Conv.asString(params.get("catalogCode"));
Long envId = Conv.asLong(params.get("envId"));
boolean result = RCS.loadFloor(projectUUID, catalogCode, envId);
return Model.newSuccess(result);
}
}

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

@ -0,0 +1,244 @@
package com.yvan.workbench.controller;
import com.galaxis.rcs.RCS;
import com.galaxis.rcs.common.entity.RcsTaskBiz;
import com.galaxis.rcs.common.entity.StoreLocation;
import com.galaxis.rcs.common.enums.BizTaskStatus;
import com.galaxis.rcs.common.enums.BizTaskType;
import com.galaxis.rcs.common.enums.LCCDirection;
import com.galaxis.rcs.plan.PlanTaskSequence;
import com.galaxis.rcs.plan.task.CarryTask;
import com.galaxis.rcs.plan.task.MoveTask;
import com.google.common.base.Strings;
import com.yvan.logisticsModel.*;
import com.yvan.workbench.model.entity.Model;
import org.apache.commons.lang3.NotImplementedException;
import org.clever.core.Conv;
import org.clever.core.id.SnowFlake;
import org.clever.web.mvc.annotation.RequestBody;
import java.util.Map;
public class RcsController {
// /**
// * 后台机器人移动
// * @param agvId 机器人ID
// * @param targetWayPointId 目标路径点ID
// * @param option 选项
// */
// agvMove(agvId: string, targetWayPointId: string, option: any = {}): Promise<ServerResponse<boolean>>
//
// /**
// * 后台机器人搬运(库存点 -> 库存点)
// * @param agvId 机器人ID
// * @param fromStoreLoc 库存点ID
// * @param targetStoreLoc 目标库存点ID
// * @param option 其他选项
// */
// agvCarry(agvId: string, fromStoreLoc: string, targetStoreLoc: string, option: any = {}): Promise<ServerResponse<boolean>>
//
// /**
// * 机器人充电
// * @param agvId 机器人ID
// * @param chargerId 充电桩ID
// * @param option 其他选项
// */
// agvToCharger(agvId: string, chargerId: string, option: any = {}): Promise<ServerResponse<boolean>>
static final SnowFlake snowFlake = new SnowFlake();
public static Model<Object> agvMove(@RequestBody Map<String, Object> params) {
String projectUUID = Conv.asString(params.get("projectUUID"));
String catalogCode = Conv.asString(params.get("catalogCode"));
Long envId = Conv.asLong(params.get("envId"));
String agvId = Conv.asString(params.get("agvId"));
String targetWayPointId = Conv.asString(params.get("targetWayPointId"));
Map<String, Object> option = (Map<String, Object>) params.get("option");
if (Strings.isNullOrEmpty(agvId)) {
return Model.newFail("agvId Must not be empty");
}
if (Strings.isNullOrEmpty(targetWayPointId)) {
return Model.newFail("targetWayPointId Must not be empty");
}
RCS.loadFloor(projectUUID, catalogCode, envId);
LogisticsRuntime logisticsRuntime = LogisticsRuntimeService.INSTANCE.findByProjectFloor(projectUUID, catalogCode);
StaticItem toItem = logisticsRuntime.getStaticItemById(targetWayPointId);
if (toItem == null) {
return Model.newFail("target wayPoint not found!");
}
ExecutorItem executorItem = logisticsRuntime.executorItemMap.get(agvId);
if (executorItem == null) {
return Model.newFail("executor not found: " + agvId);
}
if (!(executorItem instanceof PtrAgvItem)) {
return Model.newFail("executor is not a PtrAgvItem id=" + agvId);
}
// 获取机器人当前所在位置, 也可以前端强制指定
// forceStartWayPointId: '6_2', forceStartDirectior: 'right'
StaticItem fromItem = null;
LCCDirection fromDirection = null;
if (option.get("forceStartWayPointId") != null) {
fromItem = logisticsRuntime.getStaticItemById(Conv.asString(option.get("forceStartWayPointId")));
} else {
fromItem = logisticsRuntime.getStaticItemByLogicXY(((PtrAgvItem) executorItem).logicX, ((PtrAgvItem) executorItem).logicY);
}
if (option.get("forceStartDirection") != null) {
fromDirection = LCCDirection.fromString(Conv.asString(option.get("forceStartDirection")));
} else {
fromDirection = ((PtrAgvItem) executorItem).getLCCDirection();
}
if (fromItem == null) {
return Model.newFail("PtrAgvItem not found at current location: " + ((PtrAgvItem) executorItem).logicX + "_" + ((PtrAgvItem) executorItem).logicY + ", id=" + agvId);
}
if (fromDirection == null) {
return Model.newFail("PtrAgvItem unkown direction id=" + agvId);
}
RcsTaskBiz bizTask = new RcsTaskBiz();
bizTask.setBizTaskId(snowFlake.nextId());
bizTask.setEnvId(envId);
bizTask.setBizType(BizTaskType.MOVE.toString());
bizTask.setLpn("N/A");
bizTask.setPriority(Conv.asInteger(option.get("priority"), 1));
bizTask.setTaskFrom(fromItem.getId());
bizTask.setTaskTo(targetWayPointId);
bizTask.setAllocatedExecutorId(agvId);
bizTask.setBizTaskPayload("N/A");
bizTask.setBizTaskErrorInfo("N/A");
bizTask.setBizTaskDescription("N/A");
bizTask.setBizTaskStatus(BizTaskStatus.WAITING_FOR_DISPATCH.toString());
PlanTaskSequence planSequence = new PlanTaskSequence(agvId, logisticsRuntime, bizTask, "demo");
MoveTask moveTask = new MoveTask(
agvId, bizTask.getTaskTo(), bizTask.getPriority()
);
logisticsRuntime.pathPlannerMap.get(executorItem.getT())
.planMoveTask(planSequence, fromItem.getId(), fromDirection, moveTask);
return Model.newSuccess(planSequence.toPrettyMap());
}
public static Model<Object> agvInfo(@RequestBody Map<String, Object> params) {
String projectUUID = Conv.asString(params.get("projectUUID"));
String catalogCode = Conv.asString(params.get("catalogCode"));
Long envId = Conv.asLong(params.get("envId"));
String agvId = Conv.asString(params.get("agvId"));
if (Strings.isNullOrEmpty(agvId)) {
return Model.newFail("agvId Must not be empty");
}
RCS.loadFloor(projectUUID, catalogCode, envId);
LogisticsRuntime logisticsRuntime = LogisticsRuntimeService.INSTANCE.findByProjectFloor(projectUUID, catalogCode);
ExecutorItem executorItem = logisticsRuntime.executorItemMap.get(agvId);
if (executorItem == null) {
return Model.newFail("executor not found: " + agvId);
}
if (!(executorItem instanceof PtrAgvItem)) {
return Model.newFail("executor is not a PtrAgvItem id=" + agvId);
}
return Model.newSuccess(executorItem);
}
public static Model<Object> agvCarry(@RequestBody Map<String, Object> params) {
String projectUUID = Conv.asString(params.get("projectUUID"));
String catalogCode = Conv.asString(params.get("catalogCode"));
Long envId = Conv.asLong(params.get("envId"));
String agvId = Conv.asString(params.get("agvId"));
String fromStoreLoc = Conv.asString(params.get("fromStoreLoc"));
String targetStoreLoc = Conv.asString(params.get("targetStoreLoc"));
Map<String, Object> option = (Map<String, Object>) params.get("option");
if (Strings.isNullOrEmpty(agvId)) {
return Model.newFail("agvId Must not be empty");
}
if (Strings.isNullOrEmpty(fromStoreLoc)) {
return Model.newFail("fromStoreLoc Must not be empty");
}
if (Strings.isNullOrEmpty(targetStoreLoc)) {
return Model.newFail("targetStoreLoc Must not be empty");
}
RCS.loadFloor(projectUUID, catalogCode, envId);
LogisticsRuntime logisticsRuntime = LogisticsRuntimeService.INSTANCE.findByProjectFloor(projectUUID, catalogCode);
StaticItem sourceItem = logisticsRuntime.getStaticItemById(fromStoreLoc);
if (sourceItem == null) {
return Model.newFail("fromStoreLoc storePoint not found!");
}
StaticItem targetItem = logisticsRuntime.getStaticItemById(targetStoreLoc);
if (targetItem == null) {
return Model.newFail("targetStoreLoc storePoint not found!");
}
ExecutorItem executorItem = logisticsRuntime.executorItemMap.get(agvId);
if (executorItem == null) {
return Model.newFail("executor not found: " + agvId);
}
if (!(executorItem instanceof PtrAgvItem)) {
return Model.newFail("executor is not a PtrAgvItem id=" + agvId);
}
// 获取机器人当前所在位置, 也可以前端强制指定
// forceStartWayPointId: '6_2', forceStartDirectior: 'right'
StaticItem fromItem = null;
LCCDirection fromDirection = null;
if (option.get("forceStartWayPointId") != null) {
fromItem = logisticsRuntime.getStaticItemById(Conv.asString(option.get("forceStartWayPointId")));
} else {
fromItem = logisticsRuntime.getStaticItemByLogicXY(((PtrAgvItem) executorItem).logicX, ((PtrAgvItem) executorItem).logicY);
}
if (option.get("forceStartDirection") != null) {
fromDirection = LCCDirection.fromString(Conv.asString(option.get("forceStartDirection")));
} else {
fromDirection = ((PtrAgvItem) executorItem).getLCCDirection();
}
if (fromItem == null) {
return Model.newFail("PtrAgvItem not found at current location: " + ((PtrAgvItem) executorItem).logicX + "_" + ((PtrAgvItem) executorItem).logicY + ", id=" + agvId);
}
if (fromDirection == null) {
return Model.newFail("PtrAgvItem unkown direction id=" + agvId);
}
RcsTaskBiz bizTask = new RcsTaskBiz();
bizTask.setBizTaskId(snowFlake.nextId());
bizTask.setEnvId(1L);
bizTask.setBizType(BizTaskType.MOVE.toString());
bizTask.setLpn("N/A");
bizTask.setPriority(Conv.asInteger(option.get("priority"), 1));
bizTask.setTaskFrom(sourceItem.getId());
bizTask.setTaskTo(targetItem.getId());
bizTask.setAllocatedExecutorId(agvId);
bizTask.setBizTaskPayload("N/A");
bizTask.setBizTaskErrorInfo("N/A");
bizTask.setBizTaskDescription("N/A");
bizTask.setBizTaskStatus(BizTaskStatus.WAITING_FOR_DISPATCH.toString());
PlanTaskSequence planSequence = new PlanTaskSequence(agvId, logisticsRuntime, bizTask, "demo");
CarryTask carryTask = new CarryTask(
agvId, "dummy", 1,
new StoreLocation("rack1", 0, 1, 0),
new StoreLocation("54", 0, 0, 0)
);
logisticsRuntime.pathPlannerMap.get(executorItem.getT())
.planCarryTask(planSequence, fromItem.getId(), fromDirection, carryTask);
return Model.newSuccess(planSequence.toPrettyMap());
}
public static Model<Boolean> agvToCharger(@RequestBody Map<String, Object> params) {
throw new NotImplementedException("agvToCharger not implemented yet");
}
}

8
servo/src/main/java/com/yvan/workbench/model/entity/Model.java

@ -9,6 +9,14 @@ public class Model<T> implements java.io.Serializable {
return new Model<T>().setData(data).setSuccess(true).setMsg("操作成功"); return new Model<T>().setData(data).setSuccess(true).setMsg("操作成功");
} }
public static <T> Model<T> newFail(Exception e, T data) {
return new Model<T>().setMsg(e.toString()).setSuccess(false).setData(data);
}
public static <T> Model<T> newFail(String msg) {
return new Model<T>().setMsg(msg).setSuccess(false);
}
public T getData() { public T getData() {
return data; return data;
} }

Loading…
Cancel
Save