From 7f8f7e70019b89b3c1331ed8f3f36dc5f7fe9b5e Mon Sep 17 00:00:00 2001 From: yuliang <398780299@qq.com> Date: Thu, 24 Jul 2025 15:53:12 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/galaxis/rcs/amr/AmrMessage.java | 27 + .../com/galaxis/rcs/amr/AmrMessageHandler.java | 543 +++++++++++++ .../main/java/com/galaxis/rcs/amr/AmrTaskMode.java | 78 ++ .../java/com/galaxis/rcs/amr/ArmMessageType.java | 94 +++ .../main/java/com/galaxis/rcs/amr/ControlMode.java | 7 + .../java/com/galaxis/rcs/amr/JacksonUtils.java | 72 ++ .../java/com/galaxis/rcs/amr/PosDirection.java | 8 + .../java/com/galaxis/rcs/amr/PtrAgvConnector.java | 5 + .../com/galaxis/rcs/amr/PtrAgvConnectorThread.java | 168 ++++ .../java/com/galaxis/rcs/amr/PtrAgvDeviceTask.java | 62 ++ .../main/java/com/galaxis/rcs/amr/PtrAgvItem.java | 889 +++++++++++++++++++++ .../java/com/galaxis/rcs/amr/PtrMqttClient.java | 154 ++++ .../java/com/galaxis/rcs/amr/RcsMessageType.java | 91 +++ .../rcs/amr/receiveEntity/AmrAckMessage.java | 10 + .../rcs/amr/receiveEntity/AmrAppStartMessage.java | 16 + .../rcs/amr/receiveEntity/AmrBootMessage.java | 18 + .../rcs/amr/receiveEntity/AmrExceptionMessage.java | 24 + .../rcs/amr/receiveEntity/AmrHeartbeatMessage.java | 20 + .../rcs/amr/receiveEntity/AmrLandmarkMessage.java | 28 + .../receiveEntity/AmrModuleTaskStatusMessage.java | 16 + .../rcs/amr/receiveEntity/AmrOfflineMessage.java | 10 + .../rcs/amr/receiveEntity/AmrOnlineMessage.java | 12 + .../rcs/amr/receiveEntity/AmrShutdownMessage.java | 14 + .../rcs/amr/receiveEntity/AmrStatusMessage.java | 50 ++ .../amr/receiveEntity/AmrTaskCompletedMessage.java | 36 + .../amr/receiveEntity/AmrTaskStatusMessage.java | 15 + .../amr/receiveEntity/base/AmrCommonMessage.java | 17 + .../rcs/amr/receiveEntity/base/CurBatteryData.java | 20 + .../rcs/amr/receiveEntity/base/GoodsData.java | 31 + .../rcs/amr/receiveEntity/base/LocationData.java | 24 + .../rcs/amr/receiveEntity/base/OffsetPosition.java | 16 + .../rcs/amr/receiveEntity/base/SummaryData.java | 24 + .../amr/receiveEntity/base/TaskCompletedData.java | 36 + .../amr/receiveEntity/base/TaskModeChangeData.java | 14 + .../receiveEntity/base/TaskStatusChangeData.java | 12 + .../amr/receiveEntity/base/TaskTypeChangeData.java | 14 + .../galaxis/rcs/amr/sendEntity/BaseMessage.java | 6 + .../galaxis/rcs/amr/sendEntity/RcsAckMessage.java | 7 + .../rcs/amr/sendEntity/RcsCancelTaskMessage.java | 10 + .../rcs/amr/sendEntity/RcsConfigMessage.java | 33 + .../rcs/amr/sendEntity/RcsControlDoorMessage.java | 21 + .../rcs/amr/sendEntity/RcsHeartBeatMessage.java | 5 + .../rcs/amr/sendEntity/RcsQueryStatusMessage.java | 14 + .../rcs/amr/sendEntity/RcsRotateBodyMessage.java | 21 + .../rcs/amr/sendEntity/RcsRotateRackMessage.java | 21 + .../galaxis/rcs/amr/sendEntity/RcsSRMessage.java | 27 + .../rcs/amr/sendEntity/RcsSetLocationMessage.java | 26 + .../galaxis/rcs/amr/sendEntity/RcsTaskMessage.java | 102 +++ .../galaxis/rcs/amr/sendEntity/RcsWaitMessage.java | 20 + .../rcs/connector/cl2/Cl2DeviceConnector.java | 4 +- .../com/galaxis/rcs/connector/cl2/Cl2Item.java | 4 +- .../main/java/com/galaxis/rcs/ptr/AmrMessage.java | 27 - .../com/galaxis/rcs/ptr/AmrMessageHandler.java | 543 ------------- .../main/java/com/galaxis/rcs/ptr/AmrTaskMode.java | 78 -- .../java/com/galaxis/rcs/ptr/ArmMessageType.java | 94 --- .../main/java/com/galaxis/rcs/ptr/ControlMode.java | 7 - .../java/com/galaxis/rcs/ptr/JacksonUtils.java | 72 -- .../java/com/galaxis/rcs/ptr/PosDirection.java | 8 - .../java/com/galaxis/rcs/ptr/PtrAgvConnector.java | 5 - .../com/galaxis/rcs/ptr/PtrAgvConnectorThread.java | 168 ---- .../java/com/galaxis/rcs/ptr/PtrAgvDeviceTask.java | 62 -- .../main/java/com/galaxis/rcs/ptr/PtrAgvItem.java | 889 --------------------- .../java/com/galaxis/rcs/ptr/PtrMqttClient.java | 154 ---- .../java/com/galaxis/rcs/ptr/RcsMessageType.java | 91 --- .../rcs/ptr/receiveEntity/AmrAckMessage.java | 10 - .../rcs/ptr/receiveEntity/AmrAppStartMessage.java | 16 - .../rcs/ptr/receiveEntity/AmrBootMessage.java | 18 - .../rcs/ptr/receiveEntity/AmrExceptionMessage.java | 24 - .../rcs/ptr/receiveEntity/AmrHeartbeatMessage.java | 20 - .../rcs/ptr/receiveEntity/AmrLandmarkMessage.java | 28 - .../receiveEntity/AmrModuleTaskStatusMessage.java | 16 - .../rcs/ptr/receiveEntity/AmrOfflineMessage.java | 10 - .../rcs/ptr/receiveEntity/AmrOnlineMessage.java | 12 - .../rcs/ptr/receiveEntity/AmrShutdownMessage.java | 14 - .../rcs/ptr/receiveEntity/AmrStatusMessage.java | 50 -- .../ptr/receiveEntity/AmrTaskCompletedMessage.java | 36 - .../ptr/receiveEntity/AmrTaskStatusMessage.java | 15 - .../ptr/receiveEntity/base/AmrCommonMessage.java | 17 - .../rcs/ptr/receiveEntity/base/CurBatteryData.java | 20 - .../rcs/ptr/receiveEntity/base/GoodsData.java | 31 - .../rcs/ptr/receiveEntity/base/LocationData.java | 24 - .../rcs/ptr/receiveEntity/base/OffsetPosition.java | 16 - .../rcs/ptr/receiveEntity/base/SummaryData.java | 24 - .../ptr/receiveEntity/base/TaskCompletedData.java | 36 - .../ptr/receiveEntity/base/TaskModeChangeData.java | 14 - .../receiveEntity/base/TaskStatusChangeData.java | 12 - .../ptr/receiveEntity/base/TaskTypeChangeData.java | 14 - .../galaxis/rcs/ptr/sendEntity/BaseMessage.java | 6 - .../galaxis/rcs/ptr/sendEntity/RcsAckMessage.java | 7 - .../rcs/ptr/sendEntity/RcsCancelTaskMessage.java | 10 - .../rcs/ptr/sendEntity/RcsConfigMessage.java | 33 - .../rcs/ptr/sendEntity/RcsControlDoorMessage.java | 21 - .../rcs/ptr/sendEntity/RcsHeartBeatMessage.java | 5 - .../rcs/ptr/sendEntity/RcsQueryStatusMessage.java | 14 - .../rcs/ptr/sendEntity/RcsRotateBodyMessage.java | 21 - .../rcs/ptr/sendEntity/RcsRotateRackMessage.java | 21 - .../galaxis/rcs/ptr/sendEntity/RcsSRMessage.java | 27 - .../rcs/ptr/sendEntity/RcsSetLocationMessage.java | 26 - .../galaxis/rcs/ptr/sendEntity/RcsTaskMessage.java | 102 --- .../galaxis/rcs/ptr/sendEntity/RcsWaitMessage.java | 20 - .../src/main/java/com/yvan/entity/AgvStatusVo.java | 2 +- .../main/java/com/yvan/event/AgvEventManager.java | 6 +- .../com/yvan/logisticsModel/LogisticsRuntime.java | 4 +- .../yvan/workbench/controller/LccController.java | 2 +- .../yvan/workbench/controller/LccModelManager.java | 2 +- .../yvan/workbench/controller/RcsController.java | 2 +- servo/src/main/resources/logback-spring.xml | 2 +- 107 files changed, 3002 insertions(+), 3002 deletions(-) create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/AmrMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/AmrMessageHandler.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/AmrTaskMode.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/ArmMessageType.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/ControlMode.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/JacksonUtils.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PosDirection.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnector.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnectorThread.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PtrAgvDeviceTask.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PtrAgvItem.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/PtrMqttClient.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/RcsMessageType.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAckMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAppStartMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrBootMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrExceptionMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrHeartbeatMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrLandmarkMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrModuleTaskStatusMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOfflineMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOnlineMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrShutdownMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrStatusMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskCompletedMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskStatusMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/AmrCommonMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/CurBatteryData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/GoodsData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/LocationData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/OffsetPosition.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/SummaryData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskCompletedData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskModeChangeData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskStatusChangeData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskTypeChangeData.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/BaseMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsAckMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsCancelTaskMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsConfigMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsControlDoorMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsHeartBeatMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsQueryStatusMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateBodyMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateRackMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSRMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSetLocationMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsTaskMessage.java create mode 100644 servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsWaitMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/AmrMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/ArmMessageType.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/ControlMode.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/JacksonUtils.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PosDirection.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnector.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnectorThread.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvDeviceTask.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/RcsMessageType.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAckMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAppStartMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrBootMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrExceptionMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrHeartbeatMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrLandmarkMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrModuleTaskStatusMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOfflineMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOnlineMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrShutdownMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrStatusMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskCompletedMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskStatusMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/AmrCommonMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/CurBatteryData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/GoodsData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/LocationData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/OffsetPosition.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/SummaryData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskCompletedData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskModeChangeData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskStatusChangeData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskTypeChangeData.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/BaseMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsAckMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsCancelTaskMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsConfigMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsControlDoorMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsHeartBeatMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsQueryStatusMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateBodyMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateRackMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSRMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSetLocationMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsTaskMessage.java delete mode 100644 servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsWaitMessage.java diff --git a/servo/src/main/java/com/galaxis/rcs/amr/AmrMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/AmrMessage.java new file mode 100644 index 0000000..3abcb0e --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/AmrMessage.java @@ -0,0 +1,27 @@ +package com.galaxis.rcs.amr; + +import lombok.Data; + +// RCS 接收 AMR的消息 +@Data +public class AmrMessage { + /** + * 消息标识 + * 小车作业完成 20010 AmrTaskCompletedMessage + * 任务状态上报 20011 AmrTaskStatusMessage + * 小车子模块任务状态 20012 AmrModuleTaskStatusMessage + * 地标报告 20020 AmrLandmarkMessage + * 消息应答 20050 AmrAckMessage + * 状态上报 20060 AmrStatusMessage + * 心跳 20100 AmrHeartbeatMessage + * 小车主程序启动 20149 AmrAppStartMessage + * 小车上线 20150 AmrOnlineMessage + * 小车离线 20200 AmrOfflineMessage + * 异常上报 20250 AmrExceptionMessage + * 开机上报 20147 AmrBootMessage + * 关机上报 20148 AmrShutdownMessage + */ + public int id; + // 消息内容 + public T content; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/AmrMessageHandler.java b/servo/src/main/java/com/galaxis/rcs/amr/AmrMessageHandler.java new file mode 100644 index 0000000..5daec1f --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/AmrMessageHandler.java @@ -0,0 +1,543 @@ +package com.galaxis.rcs.amr; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.galaxis.rcs.plan.path.PathUtils; +import com.galaxis.rcs.amr.receiveEntity.*; +import com.galaxis.rcs.amr.receiveEntity.base.*; +import com.galaxis.rcs.amr.sendEntity.*; +import com.google.common.base.Splitter; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.yvan.logisticsEnv.EnvConfig; +import com.yvan.logisticsModel.LogisticsRuntime; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.clever.core.BannerUtils; +import org.clever.core.json.JsonWrapper; +import org.clever.core.mapper.BeanCopyUtils; +import org.clever.data.redis.Redis; +import org.clever.data.redis.RedisAdmin; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; + +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +@Slf4j +public class AmrMessageHandler { + private static final TypeReference> typeRef20010Message = new TypeReference>() { + }; + private static final TypeReference>> typeRef20011_defaultMessage = new TypeReference>>() { + }; + private static final TypeReference>> typeRef20011_1Message = new TypeReference>>() { + }; + private static final TypeReference>> typeRef20011_4Message = new TypeReference>>() { + }; + private static final TypeReference>> typeRef20011_8Message = new TypeReference>>() { + }; + private static final TypeReference> typeRef20012Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20020Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20050Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20060Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20100Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20147Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20148Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20149Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20150Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20200Message = new TypeReference>() { + }; + private static final TypeReference> typeRef20250Message = new TypeReference>() { + }; + + private static final Redis redis = RedisAdmin.getRedis(); + + public final LogisticsRuntime runtime; + private volatile PtrMqttClient ptrMqttClient; + + public int getNewSeqNo() { + String redisKey = "lcc:rcs:" + runtime.projectUuid + ":" + runtime.envId + ":seqNo"; + long seqNo = redis.vIncrement(redisKey); + if (seqNo > Integer.MAX_VALUE) { + redis.kDelete(redisKey); + seqNo = redis.vIncrement(redisKey).intValue(); + } + return (int) seqNo; + } + + public AmrMessageHandler(LogisticsRuntime runtime) { + this.runtime = runtime; + } + + public void start(EnvConfig.MqttConfig mqttConfig, String clientId) { + this.ptrMqttClient = new PtrMqttClient(this, mqttConfig, clientId); + } + + public void stop() { + if (ptrMqttClient != null) { + ptrMqttClient.stop(); + } + } + + public void handleAgvRobotStatusMessage(MqttMessage message) throws MqttException, JsonProcessingException { + byte[] messageData = message.getPayload(); + String json = new String(messageData, StandardCharsets.UTF_8); + + log.debug("收到消息: {}", json); + + JsonWrapper jw = new JsonWrapper(json); + int id = jw.asInt("id"); + String agvId = jw.asInt("content", "VehicleId") + ""; + int seqNo = jw.asInt("content", "SeqNo"); + PtrAgvItem agvItem = getPtrAgvItem(agvId); + if (agvItem == null) { + return; + } + + // 计算网络延迟 + long receiveTime = System.currentTimeMillis(); + Long sentTime = lastMessageTimeMap.get(agvId); + if (sentTime != null) { + long netDelay = receiveTime - sentTime; + updateRedisNetDelay(agvId, netDelay); + } + + /* + * 消息标识 + * 小车作业完成 20010 AmrTaskCompletedMessage + * 任务状态上报 20011 AmrTaskStatusMessage + * 小车子模块任务状态 20012 AmrModuleTaskStatusMessage + * 地标报告 20020 AmrLandmarkMessage + * 消息应答 20050 AmrAckMessage + * 状态上报 20060 AmrStatusMessage + * 心跳 20100 AmrHeartbeatMessage + * 开机上报 20147 AmrBootMessage + * 关机上报 20148 AmrShutdownMessage + * 小车主程序启动 20149 AmrAppStartMessage + * 小车上线 20150 AmrOnlineMessage + * 小车离线 20200 AmrOfflineMessage + * 异常上报 20250 AmrExceptionMessage + */ + if (id != ArmMessageType.AMR_ACK.value && id != ArmMessageType.AMR_HEARTBEAT.value) { + var list = Splitter.on("\n").splitToList(jw.toString()); + String[] ar = new String[list.size()]; + list.toArray(ar); + // log.info("3-Received message: " + json); + // BannerUtils.printConfig(log, "MQTT 收到报文 [" + id + "] ArmMessageType." + ArmMessageType.fromValue(id) + " - " + ArmMessageType.fromValue(id).description, ar); + } + + AmrMessage amrMessage = null; + switch (ArmMessageType.fromValue(id)) { + case AMR_TASK_COMPLETED: + AmrMessage taskCompletedMessage = JacksonUtils.parse(json, typeRef20010Message); + handleTaskCompletedMessage(agvItem, taskCompletedMessage.content); + break; + case AMR_TASK_STATUS: + handleTaskStatusMessage(agvItem, jw, json); + break; + case AMR_MODULE_TASK_STATUS: + amrMessage = JacksonUtils.parse(json, typeRef20012Message); + break; + case AMR_LANDMARK: + AmrMessage landmarkMessage = JacksonUtils.parse(json, typeRef20020Message); + handleLandmarkMessage(agvItem, landmarkMessage.content); + break; + case AMR_ACK: + amrMessage = JacksonUtils.parse(json, typeRef20050Message); + break; + case AMR_STATUS: + AmrMessage statusMessage = JacksonUtils.parse(json, typeRef20060Message); + handleStatusMessage(agvItem, statusMessage.content); + break; + case AMR_HEARTBEAT: + AmrMessage heartbeatMessage = JacksonUtils.parse(json, typeRef20100Message); + // sendCmdHeartBeat(heartbeatMessage.content.VehicleId + ""); + handleHeartbeatMessage(agvItem, heartbeatMessage.content); + break; + case AMR_BOOT: + amrMessage = JacksonUtils.parse(json, typeRef20147Message); + break; + case AMR_SHUTDOWN: + amrMessage = JacksonUtils.parse(json, typeRef20148Message); + break; + case AMR_APP_START: + amrMessage = JacksonUtils.parse(json, typeRef20149Message); + break; + case AMR_ONLINE: + AmrMessage onlineMessage = JacksonUtils.parse(json, typeRef20150Message); + this.handleAmrOnlineMessage(agvItem, onlineMessage.content); + this.sendCmdConfig(agvId, agvItem.getConfig()); + break; + case AMR_OFFLINE: + AmrMessage offlineMessage = JacksonUtils.parse(json, typeRef20200Message); + this.handleAmrOfflineMessage(agvItem, offlineMessage.content); + break; + case AMR_EXCEPTION: + amrMessage = JacksonUtils.parse(json, typeRef20250Message); + break; + default: +// log.error("未知消息:{}", json); + break; + } + + + if (id != ArmMessageType.AMR_ACK.value && id != ArmMessageType.AMR_HEARTBEAT.value) { + sendCmdAck(agvId, seqNo); + } + } + + public PtrAgvItem getPtrAgvItem(String vehicleId) { + var executorItem = runtime.executorItemMap.get(vehicleId); + return (PtrAgvItem) executorItem; + } + + @SneakyThrows + private void publish(String topic, String payload, int id) { + if (id != RcsMessageType.RCS_ACK.value && id != RcsMessageType.RCS_HEARTBEAT.value) { + var list = Splitter.on("\n").splitToList(new JsonWrapper(payload).toString()); + String[] ar = new String[list.size()]; + list.toArray(ar); + // BannerUtils.printConfig(log, "MQTT 发送报文 [" + id + "] RcsMessageType." + RcsMessageType.fromValue(id) + " - " + RcsMessageType.fromValue(id).description, ar); + } + log.debug("发送消息: {}", payload); + ptrMqttClient.publish(topic, payload); + } + + /** + * 发送任务 + * + * @param vehicleId 设备id + * @param rcsTaskMessage 任务信息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdTask(String vehicleId, RcsTaskMessage rcsTaskMessage) throws JsonProcessingException, MqttException { + // 记录发送时间 + lastMessageTimeMap.put(vehicleId, System.currentTimeMillis()); + + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_TASK.value; + baseMessage.content = rcsTaskMessage; + String json = JacksonUtils.toJson(baseMessage); + + // log.info("sendCmd10010: {}", json); + // log.debug("Sending task to {}: {}", vehicleId, json); + + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送SR消息 + * + * @param vehicleId 设备id + * @param rcsSRMessage SR消息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdSR(String vehicleId, RcsSRMessage rcsSRMessage) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_SR.value; + baseMessage.content = rcsSRMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送应答消息 + * + * @param vehicleId 设备id + * @param seqNo 被应答的消息序号 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdAck(String vehicleId, int seqNo) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + RcsAckMessage rcsAckMsg = new RcsAckMessage(); + rcsAckMsg.SeqNo = seqNo; + baseMessage.id = RcsMessageType.RCS_ACK.value; + baseMessage.content = rcsAckMsg; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送旋转货架消息 + * + * @param vehicleId 设备id + * @param rcsRotateRackMessage 旋转货架消息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdRotateRack(String vehicleId, RcsRotateRackMessage rcsRotateRackMessage) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_ROTATE_RACK.value; + baseMessage.content = rcsRotateRackMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送旋转车身消息 + * + * @param vehicleId 设备id + * @param rcsRotateBodyMessage 旋转车身消息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdRotateBody(String vehicleId, RcsRotateBodyMessage rcsRotateBodyMessage) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_ROTATE_BODY.value; + baseMessage.content = rcsRotateBodyMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + // 发送控制卷帘门消息 10082 + public void sendCmdControlDoor(String vehicleId, RcsControlDoorMessage rcsControlDoorMessage) throws MqttException, JsonProcessingException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_CONTROL_DOOR.value; + baseMessage.content = rcsControlDoorMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送配置信息 + * + * @param vehicleId 设备id + * @param rcsConfigMessage 配置信息 + * @throws MqttException + * @throws JsonProcessingException + */ + public void sendCmdConfig(String vehicleId, RcsConfigMessage rcsConfigMessage) throws MqttException, JsonProcessingException { + AmrMessage baseMessage = new AmrMessage<>(); + baseMessage.id = RcsMessageType.RCS_CONFIG.value; + baseMessage.content = rcsConfigMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送心跳 + * + * @param vehicleId 设备id + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdHeartBeat(String vehicleId) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_HEARTBEAT.value; + baseMessage.content = new RcsHeartBeatMessage(); + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送状态查询消息 + * + * @param vehicleId 设备id + * @throws MqttException + * @throws JsonProcessingException + */ + public void sendCmdQueryStatus(String vehicleId) throws MqttException, JsonProcessingException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_QUERY_STATUS.value; + RcsQueryStatusMessage rcsQueryStatusMessage = new RcsQueryStatusMessage(this.runtime); + rcsQueryStatusMessage.SeqNo = getNewSeqNo(); + baseMessage.content = rcsQueryStatusMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + log.info("发送查询设备状态消息: {}", json); + } + + /** + * 发送取消任务消息 + * + * @param vehicleId 设备id + * @param seqNo 待取消的任务序号 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdCancelTask(String vehicleId, int seqNo) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_CANCEL_TASK.value; + baseMessage.content = new RcsCancelTaskMessage(seqNo); + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /** + * 发送设置小车坐标消息 + * + * @param vehicleId 设备id + * @param rcsSetLocationMessage 位置信息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdSetLocation(String vehicleId, RcsSetLocationMessage rcsSetLocationMessage) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_SET_LOCATION.value; + baseMessage.content = rcsSetLocationMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + + } + + /** + * 发送等待就绪消息 + * + * @param vehicleId 设备id + * @param rcsWaitMessage 等待消息 + * @throws JsonProcessingException + * @throws MqttException + */ + public void sendCmdWait(String vehicleId, RcsWaitMessage rcsWaitMessage) throws JsonProcessingException, MqttException { + BaseMessage baseMessage = new BaseMessage(); + baseMessage.id = RcsMessageType.RCS_WAIT.value; + baseMessage.content = rcsWaitMessage; + String json = JacksonUtils.toJson(baseMessage); + publish("/wcs_server/" + vehicleId, json, baseMessage.id); + } + + /////////////=============================== 新加入的代码 =========================================== + private final Map lastMessageTimeMap = Maps.newConcurrentMap(); + private final ScheduledExecutorService delayCalculator = Executors.newScheduledThreadPool(4); + + private void handleHeartbeatMessage(PtrAgvItem agvItem, AmrHeartbeatMessage message) { + agvItem.handleHeartbeat(message); + + // 计算延迟 + long now = System.currentTimeMillis(); + long netDelay = now - message.SendTime; + updateRedisNetDelay(agvItem.getId(), netDelay); + } + + private void handleAmrOnlineMessage(PtrAgvItem agvItem, AmrOnlineMessage message) { + agvItem.handleOnlineEvent(); + } + + private void handleAmrOfflineMessage(PtrAgvItem agvItem, AmrOfflineMessage message) { + agvItem.handleOfflineEvent(); + } + + private void handleTaskCompletedMessage(PtrAgvItem agvItem, AmrTaskCompletedMessage message) { + agvItem.taskCompleted(message.CurX, message.CurY, message.CurDirection, 4); + } + + private void handleLandmarkMessage(PtrAgvItem agvItem, AmrLandmarkMessage message) { + // 这是源逻辑,CurLogicX / CurLogicY / CurDirection 需要到 PtrAgvItem 中更新, 因为要触发事件 + agvItem.x = message.X; + agvItem.y = message.Y; + agvItem.orientation = message.CurOrientation; + agvItem.direction = PathUtils.amrAngleToDirection(message.CurOrientation); + agvItem.updatePosition(message.CurLogicX, message.CurLogicY, message.CurDirection); + } + + private void handleStatusMessage(PtrAgvItem agvItem, AmrStatusMessage message) { + // 更新位置. TODO 貌似不包含 direction 信息 + agvItem.updatePosition(message.CurLogicX, message.CurLogicY, agvItem.direction); + + agvItem.battery = new CurBatteryData(); + BeanCopyUtils.copyTo(message.CurBattery, agvItem.battery); + + agvItem.x = message.X; + agvItem.y = message.Y; + agvItem.orientation = message.CurOrientation; + agvItem.logicX = message.CurLogicX; + agvItem.logicY = message.CurLogicY; + agvItem.direction = PathUtils.amrAngleToDirection(message.CurOrientation); + // 更新Redis + agvItem.updateRedisStatus(); + } + + private void handleTaskStatusMessage(PtrAgvItem agvItem, JsonWrapper jw, String json) throws MqttException, JsonProcessingException { + + int EventId = jw.asInt("content", "EventId"); + // log.info("1-Received message: " + json); + switch (EventId) { + case 0: + case 2: + case 3: + case 5: + case 6: + case 7: + AmrMessage> taskStatusChangeDefault = JacksonUtils.parse(json, typeRef20011_defaultMessage); + AmrTaskStatusMessage statusMessage = taskStatusChangeDefault.content; + agvItem.updateDeviceTaskStatus((int) statusMessage.SeqNo, 0, 0, statusMessage.EventId); + break; + case 1: + AmrMessage> taskModeChange = JacksonUtils.parse(json, typeRef20011_1Message); + AmrTaskStatusMessage modeMessage = taskModeChange.content; + agvItem.updateDeviceTaskStatus((int) modeMessage.SeqNo, 0, 0, modeMessage.EventId); + agvItem.updateTaskMode(modeMessage.Info.TaskMode); + if (modeMessage.Info.TaskMode == 1) { + this.sendCmdConfig(agvItem.id, agvItem.getConfig()); + } + break; + case 4: + AmrMessage> taskCompleted = JacksonUtils.parse(json, typeRef20011_4Message); + AmrTaskStatusMessage completedMessage = taskCompleted.content; + agvItem.updateDeviceTaskStatus((int) completedMessage.SeqNo, completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, completedMessage.EventId); + // agvItem.logicX = completedMessage.Info.CurLogicX; + // agvItem.logicY = completedMessage.Info.CurLogicY; + // // agvStatusAndInfo.orientation = landmarkMessage.content.CurOrientation; + // agvItem.direction = taskCompleted.content.Info.CurDirection; +// agvItem.updateTask(completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, taskCompleted.content.Info.CurDirection, 4); + agvItem.updatePosition(completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, taskCompleted.content.Info.CurDirection); + break; + case 8: + AmrMessage> taskTypeChange = JacksonUtils.parse(json, typeRef20011_8Message); + AmrTaskStatusMessage typeMessage = taskTypeChange.content; + agvItem.updateDeviceTaskStatus((int) typeMessage.SeqNo, 0, 0, typeMessage.EventId); + default: + break; + } + } + + private void updateRedisNetDelay(String agvId, long netDelay) { + String statusKey = "lcc:" + runtime.projectUuid + ":" + runtime.envId + ":rcs:id_" + agvId; + redis.hPut(statusKey, "NetDelay", String.valueOf(netDelay)); + } + + private final Set heartBeatSet = Sets.newConcurrentHashSet(); + + /** + * 注册心跳单元 + */ + public void registeHeartBeatSet(PtrAgvItem ptrAgvItem) { + this.heartBeatSet.add(ptrAgvItem.getId()); + } + + /** + * 注销心跳单元 + */ + public void unregisteHeartBeatSet(PtrAgvItem ptrAgvItem) { + this.heartBeatSet.remove(ptrAgvItem.getId()); + } + + // private final ScheduledExecutorService heartBeatMonitor = Executors.newSingleThreadScheduledExecutor(); + // + // private void startHeartBeatSendAndStatusMonitor() { + // heartBeatMonitor.scheduleAtFixedRate(() -> { + // String aliveKey = getRedisKey("alive"); + // if (!redis.kExists(aliveKey)) { + // handleOfflineEvent(); + // } else if (!isOnline) { + // handleOnlineEvent(); + // } + // }, 0, 1, TimeUnit.SECONDS); + // } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/AmrTaskMode.java b/servo/src/main/java/com/galaxis/rcs/amr/AmrTaskMode.java new file mode 100644 index 0000000..da2c2e0 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/AmrTaskMode.java @@ -0,0 +1,78 @@ +package com.galaxis.rcs.amr; + +import com.google.common.collect.Maps; + +import java.util.Collections; +import java.util.Map; + +/** + * AMR 任务模式 + */ +public enum AmrTaskMode { + /** + * 空闲模式 + */ + AMR_FREE_MODE(0, "空闲模式"), + /** + * 初始化模式 + */ + AMR_INIT_MODE(1, "初始化模式"), + /** + * 任务模式 + */ + AMR_TASK_MODE(2, "任务模式"), + /** + * 单动作模式 + */ + AMR_SINGLE_ACTION_MODE(3, "单动作模式"), + /** + * 手动模式 + */ + AMR_MANUAL_MODE(4, "手动模式"), + /** + * 遥控器模式 + */ + AMR_HANDSET_MODE(5, "遥控器模式"), + /** + * 充电模式 + */ + AMR_CHARGE_MODE(6, "充电模式"), + /** + * 任务被中断模式 + */ + AMR_TASK_INTERRUPT_MODE (7, "任务被中断模式"), + /** + * 自定义模式 + */ + AMR_CUSTOMIZE_MODE(8, "自定义模式"); + + // 枚举值映射 + private static final Map VALUE_MAP; + + static { + Map map = Maps.newHashMap(); + for (AmrTaskMode message : values()) { + map.put(message.value, message); + } + VALUE_MAP = Collections.unmodifiableMap(map); + } + + public final int value; + public final String description; + + AmrTaskMode(int value, String description) { + this.value = value; + this.description = description; + } + + /** + * 从整数值获取对应的枚举 + * + * @param value 整数值 + * @return 对应的枚举,如果找不到则返回 null + */ + public static AmrTaskMode fromValue(int value) { + return VALUE_MAP.get(value); + } + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/ArmMessageType.java b/servo/src/main/java/com/galaxis/rcs/amr/ArmMessageType.java new file mode 100644 index 0000000..829d425 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/ArmMessageType.java @@ -0,0 +1,94 @@ +package com.galaxis.rcs.amr; + +import com.google.common.collect.Maps; + +import java.util.Collections; +import java.util.Map; + +/** + * AMR 发送给 RCS 的消息类型枚举 + */ +public enum ArmMessageType { + /** + * 小车作业完成 + */ + AMR_TASK_COMPLETED(20010, "小车作业完成"), + /** + * 任务状态上报 + */ + AMR_TASK_STATUS(20011, "任务状态上报"), + /** + * 小车子模块任务状态 + */ + AMR_MODULE_TASK_STATUS(20012, "小车子模块任务状态"), + /** + * 地标报告 + */ + AMR_LANDMARK(20020, "地标报告"), + /** + * 消息应答 + */ + AMR_ACK(20050, "消息应答"), + /** + * 状态上报 + */ + AMR_STATUS(20060, "状态上报"), + /** + * 心跳 + */ + AMR_HEARTBEAT(20100, "心跳"), + /** + * 开机上报 + */ + AMR_BOOT(20147, "开机上报"), + /** + * 关机上报 + */ + AMR_SHUTDOWN(20148, "关机上报"), + /** + * 小车主程序启动 + */ + AMR_APP_START(20149, "小车主程序启动"), + /** + * 小车上线 + */ + AMR_ONLINE(20150, "小车上线"), + /** + * 小车离线 + */ + AMR_OFFLINE(20200, "小车离线"), + /** + * 异常上报 + */ + AMR_EXCEPTION(20250, "异常上报"); + + // 枚举值映射 + private static final Map VALUE_MAP; + + static { + Map map = Maps.newHashMap(); + for (ArmMessageType message : values()) { + map.put(message.value, message); + } + VALUE_MAP = Collections.unmodifiableMap(map); + } + + public final int value; + public final String description; + + ArmMessageType(int value, String description) { + this.value = value; + this.description = description; + } + + /** + * 从整数值获取对应的枚举 + * + * @param value 整数值 + * @return 对应的枚举,如果找不到则返回 null + */ + public static ArmMessageType fromValue(int value) { + return VALUE_MAP.get(value); + } + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/ControlMode.java b/servo/src/main/java/com/galaxis/rcs/amr/ControlMode.java new file mode 100644 index 0000000..ae003af --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/ControlMode.java @@ -0,0 +1,7 @@ +package com.galaxis.rcs.amr; + +public enum ControlMode { + FULL_AUTO, + MANUAL, + SEMI_AUTO, +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/JacksonUtils.java b/servo/src/main/java/com/galaxis/rcs/amr/JacksonUtils.java new file mode 100644 index 0000000..9be0dc3 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/JacksonUtils.java @@ -0,0 +1,72 @@ +package com.galaxis.rcs.amr; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +public class JacksonUtils { + private static final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); + + private static final Map typeCache = new ConcurrentHashMap<>(); + + // 解析泛型对象(TypeReference方式) + public static T parse(String json, TypeReference typeRef) { + try { + return mapper.readValue(json, typeRef); + } catch (Exception e) { + log.error("JSON解析失败{}", json, e); + throw new RuntimeException("JSON解析失败", e); + } + } + + // 动态构建JavaType(支持嵌套泛型) + public static JavaType buildType(Class rawType, Class... parameterClasses) { + String cacheKey = buildCacheKey(rawType, parameterClasses); + return typeCache.computeIfAbsent(cacheKey, k -> + mapper.getTypeFactory().constructParametricType(rawType, parameterClasses) + ); + } + + // 解析List泛型(高频场景优化) + public static List parseList(String json, Class elementClass) { + try { + JavaType type = buildType(List.class, elementClass); + return mapper.readValue(json, type); + } catch (Exception e) { + throw new RuntimeException("List解析失败", e); + } + } + + // 解析Map泛型(Key为String) + public static Map parseMap(String json, Class valueClass) { + try { + JavaType type = mapper.getTypeFactory() + .constructMapType(Map.class, String.class, valueClass); + return mapper.readValue(json, type); + } catch (Exception e) { + throw new RuntimeException("Map解析失败", e); + } + } + + public static String toJson(Object obj) throws JsonProcessingException { + return mapper.writeValueAsString(obj); + } + + private static String buildCacheKey(Class rawType, Class... parameterClasses) { + StringBuilder key = new StringBuilder(rawType.getName()); + for (Class clazz : parameterClasses) { + key.append("#").append(clazz.getName()); + } + return key.toString(); + } + + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PosDirection.java b/servo/src/main/java/com/galaxis/rcs/amr/PosDirection.java new file mode 100644 index 0000000..13e24ab --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PosDirection.java @@ -0,0 +1,8 @@ +package com.galaxis.rcs.amr; + +import com.galaxis.rcs.common.enums.LCCDirection; + +public record PosDirection(int logicX, + int logicY, + LCCDirection direction) { +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnector.java b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnector.java new file mode 100644 index 0000000..104e90b --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnector.java @@ -0,0 +1,5 @@ +package com.galaxis.rcs.amr; + +public abstract class PtrAgvConnector { + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnectorThread.java b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnectorThread.java new file mode 100644 index 0000000..df4a0d9 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvConnectorThread.java @@ -0,0 +1,168 @@ +package com.galaxis.rcs.amr; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; +import com.galaxis.rcs.amr.sendEntity.RcsTaskMessage; +import com.yvan.logisticsModel.LogisticsRuntime; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.mqttv5.common.MqttException; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +@Slf4j +public class PtrAgvConnectorThread extends Thread { + private final AtomicBoolean running = new AtomicBoolean(false); + private final AtomicBoolean paused = new AtomicBoolean(false); + private final Object pauseLock = new Object(); + + private final Cl2DeviceConnector cl2DeviceConnector; + private final PtrAgvItem ptrAgvItem; + private final LogisticsRuntime logisticsRuntime; + private volatile int __currentTaskSeqNo = 0; + volatile PtrAgvDeviceTask __currentTask; + + public PtrAgvConnectorThread(PtrAgvItem ptrAgvItem, Cl2DeviceConnector cl2DeviceConnector, LogisticsRuntime logisticsRuntime) { + super("ExecutorConnector-" + ptrAgvItem.getId()); + this.cl2DeviceConnector = cl2DeviceConnector; + this.ptrAgvItem = ptrAgvItem; + this.logisticsRuntime = logisticsRuntime; + } + + @Override + public void run() { + running.set(true); + log.info("Connector thread started for executor: {}", this.ptrAgvItem.getId()); + + try { + float distance = 0; + int taskCount = 0; + + PtrAgvDeviceTask startTask = null; + RcsTaskMessage taskMessage = null; + + // 计算中的任务 + List computingTaskList = new ArrayList<>(); + while (running.get()) { + if (paused.get()) { + synchronized (pauseLock) { + while (paused.get()) { + pauseLock.wait(); + } + } + } + + PtrAgvDeviceTask currentTask = this.ptrAgvItem.deviceTaskQueue.take(); + if (startTask == null) { + startTask = currentTask; + taskMessage = new RcsTaskMessage(this.logisticsRuntime); + taskMessage.OperationType = startTask.operationType; + taskMessage.PickMode = startTask.pickMode; + taskMessage.GoNow = true; + taskMessage.StartX = startTask.startPoint.logicX; + taskMessage.StartY = startTask.startPoint.logicY; + taskMessage.Link = new ArrayList<>(); + } + currentTask.seqNo = taskMessage.SeqNo; + RcsTaskMessage.LinkData link = new RcsTaskMessage.LinkData(currentTask.endPoint.logicX, currentTask.endPoint.logicY, currentTask.speed); + taskMessage.Link.add(link); + taskCount++; + distance += euclideanDistance(currentTask.startPoint.tf[0], currentTask.endPoint.tf[0]); + computingTaskList.add(currentTask); + + + PtrAgvDeviceTask nextTask = this.ptrAgvItem.deviceTaskQueue.peek(); + if (currentTask.isGroupEnd + || (taskMessage.Link.size() > 0 && nextTask != null && ((startTask.speed > 0) != (nextTask.speed > 0) || startTask.direction != nextTask.direction)) // 下一个任务和开始任务方向不一致 + // 单向移动距离大于2m时并且点位数量大于1 如果碰到当前点位与任务结束点位相同且当前任务还有后续,则继续添加步骤(link)错开,避免任务发生歧义 + || (distance > 2 && taskCount > 1 && nextTask != null && currentTask.endPoint != currentTask.groupEndPoint)) { + taskMessage.OperationType = currentTask.operationType; + taskMessage.PickMode = currentTask.pickMode; + taskMessage.EndX = currentTask.groupEndPoint.logicX; + taskMessage.EndY = currentTask.groupEndPoint.logicY; + taskMessage.GoodsSlotDirection = currentTask.goodsSlotDirection; + taskMessage.GoodsSlotHeight = currentTask.goodsSlotHeight; + taskMessage.LinkCounts = (short) taskMessage.Link.size(); + taskMessage.ChargeDirection = currentTask.chargeDirection; + taskMessage.ChargeLocation = currentTask.chargeLocation; + taskMessage.EndDirection = currentTask.endDirection; + try { + // 发送任务 + this.__currentTaskSeqNo = taskMessage.SeqNo; + this.__currentTask = currentTask; + cl2DeviceConnector.sendTask(ptrAgvItem.getId(), taskMessage); + this.ptrAgvItem.runningDeviceTaskList.addAll(computingTaskList); + for (PtrAgvDeviceTask task : computingTaskList) { + task.taskStatus = 1; + task.taskGroupStatus = 1; + } + computingTaskList.clear(); + } catch (MqttException | JsonProcessingException e) { + log.error("Cl2DeviceConnector robotMove: id=" + ptrAgvItem.getId() + ", task=" + currentTask.movePlanTaskId, e); + } + distance = 0; + taskCount = 0; + taskMessage = null; + startTask = null; + + if (currentTask.isGroupEnd) { + // 当一组任务结束时,阻塞当前线程,等当前任务执组行完毕后在外部线程中唤醒 + LockSupport.park(); // 阻塞当前线程 + } else { + for (PtrAgvDeviceTask task : this.ptrAgvItem.runningDeviceTaskList) { + if (task.taskGroupStatus < 4) { + LockSupport.park(); // 阻塞当前线程 + break; + } + } + } + } + + } + } catch (InterruptedException e) { + System.out.println("Connector thread interrupted for executor: " + this.ptrAgvItem.getId()); + } finally { + System.out.println("Connector thread stopped for executor: " + this.ptrAgvItem.getId()); + } + } + + public int getCurrentTaskSeqNo() { + return __currentTaskSeqNo; + } + + /** + * 停止连接器线程 + */ + public void stopConnector() { + running.set(false); + this.interrupt(); // 中断阻塞状态 + } + + public void pauseProcessing() { + paused.set(true); + } + + public void resumeProcessing() { + paused.set(false); + synchronized (pauseLock) { + pauseLock.notifyAll(); + } + } + + /** + * 检查连接器是否在运行 + */ + public boolean isRunning() { + return running.get(); + } + + public static float euclideanDistance(float[] p1, float[] p2) { + if (p1.length != 3 || p2.length != 3) throw new IllegalArgumentException(); + float dx = p1[0] - p2[0]; + float dy = p1[1] - p2[1]; + float dz = p1[2] - p2[2]; + return (float) Math.sqrt(dx * dx + dy * dy + dz * dz); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvDeviceTask.java b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvDeviceTask.java new file mode 100644 index 0000000..d38b946 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvDeviceTask.java @@ -0,0 +1,62 @@ +package com.galaxis.rcs.amr; + +import com.yvan.logisticsModel.StaticItem; + +import java.util.HashSet; +import java.util.Set; + +public class PtrAgvDeviceTask { + //该段目标点X坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 + public int x; + //该段目标点Y坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 + public int y; + // 该段行驶速度 Int16 mm/s + public int speed; + // 该段车头朝向 + public short direction; + // 该段起始点 + public StaticItem startPoint; + // 该段目标点 + public StaticItem endPoint; + // 分组起始点 + public StaticItem groupStartPoint; + // 分组目标点 + public StaticItem groupEndPoint; + // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) + public short operationType; + // 提升移栽货物拣货模式 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 + public short pickMode; + + // 目标货位朝向 + public short goodsSlotDirection; + + // 目标货位相对于地面的绝对高度 + public int goodsSlotHeight; + + //充电桩朝向UseBriefLocation UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short chargeDirection; + // 充电工位坐标和充电桩之间距离 UInt16 单位:mm + public Integer chargeLocation; + // 目标货架编号 String 仅做校验使用(仅接货用) + public String storageRacksNo; + // 结束朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short endDirection = null; + + /** 移动规划ID */ + public Long movePlanTaskId; + /** 转动取货放货充电等规划ID */ + public Set planTaskIdSet = new HashSet<>(); + /** 业务任务ID */ + public Long bizTaskId; + // 作业序号 发送给小车的作业序号 + public int seqNo; + + // 任务状态 0创建 1任务模式改变 2任务接收成功 3任务开始 4已完成 5已取消 6已暂停 7已恢复 8任务已经变更 + public int taskStatus = 0; + public int taskGroupStatus = 0; + + // 任务分组结束标记 生成报文时作为判断依据 + public boolean isGroupEnd = false; + public int checkLogicX; + public int checkLogicY; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvItem.java b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvItem.java new file mode 100644 index 0000000..9592317 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PtrAgvItem.java @@ -0,0 +1,889 @@ +package com.galaxis.rcs.amr; + +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.*; +import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; +import com.galaxis.rcs.plan.PlanTaskSequence; +import com.galaxis.rcs.plan.path.PathUtils; +import com.galaxis.rcs.amr.receiveEntity.AmrHeartbeatMessage; +import com.galaxis.rcs.amr.receiveEntity.base.CurBatteryData; +import com.galaxis.rcs.amr.sendEntity.RcsConfigMessage; +import com.galaxis.rcs.amr.sendEntity.RcsSRMessage; +import com.galaxis.rcs.amr.sendEntity.RcsSetLocationMessage; +import com.google.common.collect.Queues; +import com.yvan.entity.AgvStatusVo; +import com.yvan.entity.BasLocationVo; +import com.yvan.logisticsModel.ExecutorItem; +import com.yvan.logisticsModel.LogisticsRuntime; +import com.yvan.logisticsModel.StaticItem; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.clever.core.Conv; +import org.clever.core.json.JsonWrapper; +import org.clever.data.redis.Redis; +import org.clever.data.redis.RedisAdmin; + +import java.util.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.locks.LockSupport; + +/** + * 侧叉式AGV执行器 + */ +@Slf4j +public abstract class PtrAgvItem extends ExecutorItem { + private static final int BLOCKING_QUEUE_CAPACITY = 100; + private static final Redis redis = RedisAdmin.getRedis(); + + // ip + public volatile String ip; + // agv名称 + public volatile String agvName; + // agv类型 + public volatile String agvType; + // agv型号 + public volatile String agvModel; + // AMR功能型号 + public volatile String agvFnModel; + // 电池信息 + public volatile CurBatteryData battery; + // agv当前x坐标 + public volatile double x; + // agv当前y坐标 + public volatile double y; + // agv当前z坐标 + public volatile double z; + // 当前所在站点的逻辑X坐标 Int32 + public volatile int logicX; + // 当前所在站点的逻辑Y坐标 Int32 + public volatile int logicY; + // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public volatile short direction; + // agv当前转动角度值 + public volatile double orientation; + + private volatile boolean isPaused = false; + + private volatile PosDirection lastPausedPosition; + + // 任务模式 + @Getter + private volatile AmrTaskMode __taskMode; + + + // 执行中的任务 + public List runningDeviceTaskList = new ArrayList<>(); + + /** + * 当前执行的任务规划列表 + */ + public volatile PlanTaskSequence planTaskSequence; + + /** + * 当前执行的设备任务列表 + */ + final BlockingQueue deviceTaskQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY); + + final Cl2DeviceConnector cl2DeviceConnector = new Cl2DeviceConnector(this.runtime); + + public final AmrMessageHandler amrMessageHandler; + + /** + * 连接器线程 + */ + private final PtrAgvConnectorThread connectorThread; + + public PtrAgvItem(LogisticsRuntime logisticsRuntime, Map raw) { + super(logisticsRuntime, raw); + this.connectorThread = new PtrAgvConnectorThread(this, this.cl2DeviceConnector, logisticsRuntime); + this.amrMessageHandler = logisticsRuntime.amrMessageHandler; + } + + @Override + public boolean isRunning() { + return connectorThread.isRunning(); + } + + public abstract RcsConfigMessage getConfig(); + + + @Override + public void start() { + this.amrMessageHandler.registeHeartBeatSet(this); + + // 查询当前状态 + requestCurrentStatus(); + this.isRunning = true; + + this.startConnector(); + } + + @Override + public void stop() { + // 停止连接器线程 + stopConnector(); + + this.amrMessageHandler.unregisteHeartBeatSet(this); + + // 清理任务序列 + if (planTaskSequence != null) { + planTaskSequence = null; + } + // 清理设备任务队列 + deviceTaskQueue.clear(); + // 清理运行中的设备任务列表 + runningDeviceTaskList.clear(); + // 更新Redis状态 + updateRedisStatus(); + } + + 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"); + } + + this.planTaskSequence = taskSequence; + buildPlanToDeviceTask(); + this.runtime.eventManager.firePlanTaskSequenceAcceptEvent(this, taskSequence); + connectorThread.resumeProcessing(); + } + + public synchronized void pauseTask() { + if (planTaskSequence == null) { + throw new IllegalStateException("No active task to pause"); + } + + isPaused = true; + lastPausedPosition = new PosDirection(logicX, logicY, PathUtils.getDirectionByArmDirection(direction)); + + // 发送停止指令 + RcsSRMessage stopMsg = new RcsSRMessage(this.runtime); + stopMsg.SeqNo = amrMessageHandler.getNewSeqNo(); + stopMsg.OperationCode = 0; // 停止 + stopMsg.StopX = logicX; + stopMsg.StopY = logicY; + + try { + amrMessageHandler.sendCmdSR(this.getId(), stopMsg); + } catch (Exception e) { + log.error("Failed to send stop command to AGV {}", this.getId(), e); + } + + this.runtime.eventManager.firePlanTaskSequencePauseEvent(this, planTaskSequence); + } + + public synchronized void resumeTask() { + if (!isPaused) { + throw new IllegalStateException("Task is not paused"); + } + + // 检查当前位置是否与暂停位置一致 + if (Math.abs(logicX - lastPausedPosition.logicX()) > 1 || + Math.abs(logicY - lastPausedPosition.logicY()) > 1 || + PathUtils.getDirectionByArmDirection(direction) != lastPausedPosition.direction()) { + // 需要返回暂停位置 + throw new RuntimeException("AGV position has changed since pause, cannot resume task safely"); + } + + isPaused = false; + connectorThread.resumeProcessing(); + this.runtime.eventManager.firePlanTaskSequenceResumeEvent(this, planTaskSequence); + } + + @SneakyThrows + public synchronized void cancelTask() { + // 发送取消指令 + amrMessageHandler.sendCmdCancelTask(this.getId(), this.connectorThread.getCurrentTaskSeqNo()); + + if (planTaskSequence != null) { + planTaskSequence = null; + } + if (!deviceTaskQueue.isEmpty()) { + deviceTaskQueue.clear(); + } + // todo 取消运行中的设备任务 + runningDeviceTaskList.clear(); + // 唤醒连接器线程 + LockSupport.unpark(connectorThread); + this.runtime.eventManager.firePlanTaskSequenceCancelEvent(this, planTaskSequence); + } + + @SneakyThrows + public void setPositionAndDirection(int x, int y, short direction) { + RcsSetLocationMessage setLoc = new RcsSetLocationMessage(amrMessageHandler.getNewSeqNo()); + setLoc.X = (short) x; + setLoc.Y = (short) y; + setLoc.Direction = direction; + + amrMessageHandler.sendCmdSetLocation(this.getId(), setLoc); + } + + @SneakyThrows + public void requestCurrentStatus() { + amrMessageHandler.sendCmdQueryStatus(this.getId()); + } + + public boolean isFree() { + // return (this.logisticsRuntime.isRunning() && this.deviceTaskQueue.isEmpty() && this.connectorThread.isRunning()); + if (!this.runtime.isRunning()) { + return false; + } + if (planTaskSequence != null && !planTaskSequence.isAllCompleted()) { + return false; + } + if (!deviceTaskQueue.isEmpty()) { + return false; + } + if (this.isPaused) { + return false; + } + // if (this.taskMode != AmrTaskMode.AMR_FREE_MODE) { + // return false; + // } + return this.isOnline; + } + + public void taskCompleted(int logicX, int logicY, short direction, int taskStatus) { + + updatePosition(logicX, logicY, direction); + // 查找当前分组任务 + for (PtrAgvDeviceTask task : runningDeviceTaskList) { + task.taskGroupStatus = taskStatus; + if (taskStatus == 4) { + if (task.taskStatus != 4) { + this.runtime.eventManager.fireDeviceTaskCompleteEvent(this, task); + task.taskStatus = 4; + } + + // 更新计划任务 + List planTaskList = planTaskSequence.taskList.stream().filter(pt -> task.movePlanTaskId.equals(pt.getPlanTaskId()) || task.planTaskIdSet.contains(pt.getPlanTaskId())).toList(); + for (RcsTaskPlan planTask : planTaskList) { + if (PlanTaskStatus.FINISHED.toString().equals(planTask.getPlanTaskStatus())) { + continue; + } + + planTask.setPlanTaskStatus(PlanTaskStatus.FINISHED.toString()); + this.runtime.eventManager.firePlanTaskCompleteEvent(this, planTaskSequence, planTask); + } + } + } + + if (planTaskSequence != null && planTaskSequence.isAllCompleted()) { + this.runtime.eventManager.firePlanTaskSequenceCompleteEvent(this, planTaskSequence); + this.runningDeviceTaskList.clear(); + planTaskSequence = null; + } + LockSupport.unpark(connectorThread); + } + + public void updatePosition(int logicX, int logicY, short direction) { + int oldX = this.logicX; + int oldY = this.logicY; + short oldDirection = this.direction; + + this.logicX = logicX; + this.logicY = logicY; + this.direction = direction; + + LCCDirection oldLccDirection = PathUtils.getDirectionByArmDirection(oldDirection); + LCCDirection newLccDirection = PathUtils.getDirectionByArmDirection(direction); + + // 更新Redis + updateRedisStatus(); + + // 触发位置变化事件 + if (oldX != logicX || oldY != logicY) { + this.runtime.eventManager.firePosChangedEvent(this, + new PosDirection(logicX, logicY, newLccDirection), + new PosDirection(oldX, oldY, oldLccDirection)); + } + + if (oldDirection != direction) { + this.runtime.eventManager.fireDirectionChangedEvent(this, newLccDirection, oldLccDirection); + } + + boolean needCompute = false; + + // 从 runningDeviceTaskList 里面,找到完成到什么阶段 + // 比如 (1,2) -> (2,2) -> (3,2) , 如果 updatePosition=3,2 ,那么前2个任务都要完成 + int finishTargetIndex = -1; + if (this.runningDeviceTaskList != null && !this.runningDeviceTaskList.isEmpty() && + this.planTaskSequence != null && !this.planTaskSequence.isEmpty()) { + + for (int i = 0; i < runningDeviceTaskList.size(); i++) { + PtrAgvDeviceTask task = runningDeviceTaskList.get(i); + if (task.checkLogicX == logicX && task.checkLogicY == logicY && task.direction == this.direction) { + if (task.taskStatus < 4) { + finishTargetIndex = i; + } + break; + } + } + + if (finishTargetIndex >= 0) { + needCompute = true; + // 标记前面的任务都完成了 + for (int i = 0; i <= finishTargetIndex; i++) { + PtrAgvDeviceTask task = runningDeviceTaskList.get(i); + task.taskStatus = 4; // 标记为完成 + this.runtime.eventManager.fireDeviceTaskCompleteEvent(this, task); + + // 更新计划任务 + RcsTaskPlan planTask = planTaskSequence.getByPlanTaskId(task.movePlanTaskId); + if (planTask != null && !PlanTaskStatus.FINISHED.toString().equals(planTask.getPlanTaskStatus())) { + planTask.setPlanTaskStatus(PlanTaskStatus.FINISHED.toString()); + this.runtime.eventManager.firePlanTaskCompleteEvent(this, planTaskSequence, planTask); + } + } + + if (planTaskSequence.isAllCompleted()) { + this.runtime.eventManager.firePlanTaskSequenceCompleteEvent(this, planTaskSequence); + this.runningDeviceTaskList.clear(); + planTaskSequence = null; + } + } + } + + // BannerUtils.printConfig(log, "updatePosition", new String[]{ + // "logicX: " + logicX, + // "logicY: " + logicY, + // "direction: " + direction, + // "finishTargetIndex: " + finishTargetIndex, + // "runningDeviceSize:" + (this.runningDeviceTaskList == null ? "null" : this.runningDeviceTaskList.size()), + // "planTask:" + (this.planTaskSequence == null ? "null" : + // ("\n" + Joiner.on("\n").join((List) this.planTaskSequence.toPrettyMap().get("items"))) + // ) + // }); + + if (needCompute && this.runningDeviceTaskList.size() > 0) { + int index = this.runningDeviceTaskList.size() - 1; + PtrAgvDeviceTask task = this.runningDeviceTaskList.get(index); + if (task.groupEndPoint != task.endPoint) { + LockSupport.unpark(connectorThread); + } + } + } + + /** + * 更新设备任务状态 暂时没有处理任务取消相关的状态 + * + * @param seqNo + * @param x + * @param y + * @param messageStatus + */ + public void updateDeviceTaskStatus(int seqNo, int x, int y, int messageStatus) { + // 更新任务状态逻辑 + if (messageStatus < 2) { + return; + } + + // 任务完成逻辑,在地标检查里 + } + + public void updateTaskMode(int taskMode) { + this.setTaskMode(AmrTaskMode.fromValue(taskMode)); + } + + private void setTaskMode(AmrTaskMode taskMode) { + var originalMode = this.__taskMode; + this.__taskMode = taskMode; + this.runtime.eventManager.fireModeChangeEvent(this, taskMode, originalMode); + updateRedisStatus(); + } + + @SneakyThrows + public void updateRedisStatus() { + String statusKey = getRedisKey("status"); + var state = this.getState(); + var statusMap = new JsonWrapper(state).getInnerMap(); + redis.hPutAll(statusKey, statusMap); + } + + public void handleHeartbeat(AmrHeartbeatMessage heartbeat) { + // 更新在线状态 + String aliveKey = getRedisKey("alive"); + redis.vSet(aliveKey, this.runtime.serverId); + redis.kExpire(aliveKey, 5); // 5秒过期 + + // 更新状态信息 + if (this.battery == null) { + this.battery = new CurBatteryData(); + } + this.battery.SOC = heartbeat.Battery; + this.battery.setTemperature(heartbeat.Temperature.Battery); + + // 检查低电量 + if (this.battery.SOC < 20) { + this.runtime.eventManager.fireLowBatteryEvent(this); + } + + updateRedisStatus(); + } + + public void handleOnlineEvent() { + isOnline = true; + this.runtime.eventManager.fireOnlineEvent(this); + requestCurrentStatus(); + } + + public void handleOfflineEvent() { + isOnline = false; + this.runtime.eventManager.fireOfflineEvent(this); + } + + public String getTaskStatus() { + if (planTaskSequence == null) return "IDLE"; + if (isPaused) return "PAUSED"; + return "EXECUTING"; + } + + + /** + * 启动连接器线程 + */ + public void startConnector() { + if (!connectorThread.isRunning()) { + connectorThread.start(); + } + } + + /** + * 停止连接器线程 + */ + public void stopConnector() { + connectorThread.stop(); + } + + private static final int speed = 1000; + + /** + * 添加任务序列到当前执行器 + */ + protected void buildPlanToDeviceTask() { + PlanTaskSequence sequence = this.planTaskSequence; + LogisticsRuntime runtime = sequence.logisticsRuntime; + + short direction = this.direction; + + // 获取当前设备点位(逻辑点位) + StaticItem startPoint = runtime.getStaticItemByLogicXY(this.logicX, this.logicY); + if (startPoint == null) { + log.error("Cl2DeviceConnector robotMove: executorItem={}, task={}, agv当前点位为空 地图上没有标记", this.getId(), sequence.bizTask.getBizTaskId()); + } + StaticItem groupStartPoint = startPoint; + + Set rotationPlanTaskIdSet = new HashSet<>(); + + // 生成移动报文 + List deviceTaskList = new ArrayList<>(); + List> linkStore = null; + // 检查 planList 是不是全都是我的任务 + for (int i = 0; i < sequence.taskList.size(); i++) { + RcsTaskPlan plan = sequence.taskList.get(i); + String endPointId = plan.getTargetId(); + + if (plan.getPlanType().equals(PlanTaskType.MOVE.toString()) || plan.getPlanType().equals(PlanTaskType.MOVE_BACKWARD.toString())) { + // 获取目标点信息 + StaticItem pointItem = runtime.getStaticItemById(endPointId); + linkStore = (List>) pointItem.dt.get("linkStore"); + int d = -1; + if (startPoint.logicX == pointItem.logicX && startPoint.logicY != pointItem.logicY) { + d = pointItem.logicY >= startPoint.logicY ? CDirection.db : CDirection.dt; + if ((d > direction && d - CDirection.dl != direction) || (d < direction && d + CDirection.dl != direction)) { + throw new RuntimeException("方向错误"); + } + + } else if (startPoint.logicY == pointItem.logicY && startPoint.logicX != pointItem.logicX) { + d = pointItem.logicX >= startPoint.logicX ? CDirection.dr : CDirection.dl; + if ((d > direction && d - CDirection.dl != direction) || (d < direction && d + CDirection.dl != direction)) { + throw new RuntimeException("方向错误"); + } + // distance += Math.abs(pointItem.getTransformationX() - startPoint.getTransformationX()); + + } else if (startPoint.logicY == pointItem.logicY && startPoint.logicX == pointItem.logicX) { + d = direction; + // distance += Math.abs(pointItem.getTransformationX() - startPoint.getTransformationX()); + + } else { + throw new RuntimeException("无法识别的点位关系"); + } + PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); + deviceTask.x = pointItem.logicX; + deviceTask.y = pointItem.logicY; + deviceTask.speed = d == direction ? (speed) : (-speed); + deviceTask.direction = direction; + deviceTask.pickMode = 0; + deviceTask.startPoint = startPoint; + deviceTask.endPoint = pointItem; + deviceTask.bizTaskId = plan.getBizTaskId(); + deviceTask.movePlanTaskId = plan.getPlanTaskId(); + deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); + rotationPlanTaskIdSet.clear(); + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = pointItem.logicX; + deviceTask.checkLogicY = pointItem.logicY; + deviceTaskList.add(deviceTask); + // 设置新的起点 + startPoint = pointItem; + + } else if (plan.getPlanType().equals(PlanTaskType.ROTATION.toString())) { + + float r = plan.getTargetRotation().floatValue(); + while (r > 360) { + r -= 360; + } + while (r < 0) { + r += 360; + } + + if (r >= 315 || r < 45) { + direction = CDirection.dr; + + } else if (r >= 45 && r < 135) { + direction = CDirection.dt; + + } else if (r >= 135 && r < 225) { + direction = CDirection.dl; + + } else if (r >= 225 && r < 315) { + direction = CDirection.db; + } + rotationPlanTaskIdSet.add(plan.getPlanTaskId()); + + } else if (plan.getPlanType().equals(PlanTaskType.LOAD.toString())) { + + if (deviceTaskList.isEmpty()) { + PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); + deviceTask.x = startPoint.logicX; + deviceTask.y = startPoint.logicY; + deviceTask.speed = speed; + deviceTask.direction = direction; + deviceTask.pickMode = 0; + deviceTask.startPoint = startPoint; + deviceTask.endPoint = startPoint; + deviceTask.bizTaskId = plan.getBizTaskId(); + deviceTask.movePlanTaskId = plan.getPlanTaskId(); + deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); + rotationPlanTaskIdSet.clear(); + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = startPoint.logicX; + deviceTask.checkLogicY = startPoint.logicY; + deviceTaskList.add(deviceTask); + linkStore = (List>) startPoint.dt.get("linkStore"); + } + PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); + deviceTask.operationType = COperationType.transplantLoadAndUnload; + deviceTask.pickMode = CPickMode.load; + deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); + //处理取货高度 + StaticItem storeItem = runtime.getStaticItemById(endPointId); + Map storeItemRaw = storeItem.dt; + if (storeItemRaw.containsKey("bays")) { + List> bays = (List>) storeItemRaw.get("bays"); + Map bay = bays.get(plan.getTargetBay()); + List levelHeight = (List) bay.get("levelHeight"); + deviceTask.goodsSlotHeight = (int) Math.round(levelHeight.get(plan.getTargetLevel()) * 1000); + } else { + deviceTask.goodsSlotHeight = 1; + } + if (linkStore != null) { + for (Map store : linkStore) { + if (store.get("item").equals(plan.getTargetId()) && store.get("level").equals(plan.getTargetLevel()) && store.get("bay").equals(plan.getTargetBay()) && store.get("cell").equals(plan.getTargetCell())) { + short d = 0; + switch (store.get("direction").toString()) { + case "up": + d = 1; + break; + case "right": + d = 2; + break; + case "down": + d = 3; + break; + case "left": + d = 0; + break; + } + deviceTask.goodsSlotDirection = d; + } + } + } + + // 标记任务分组结束 + deviceTask.isGroupEnd = true; + deviceTask.groupEndPoint = deviceTask.endPoint; + deviceTask.groupStartPoint = groupStartPoint; + groupStartPoint = deviceTask.endPoint; + + } else if (plan.getPlanType().equals(PlanTaskType.UNLOAD.toString())) { + if (deviceTaskList.isEmpty()) { + PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); + deviceTask.x = startPoint.logicX; + deviceTask.y = startPoint.logicY; + deviceTask.speed = speed; + deviceTask.direction = direction; + deviceTask.pickMode = 0; + deviceTask.startPoint = startPoint; + deviceTask.endPoint = startPoint; + deviceTask.bizTaskId = plan.getBizTaskId(); + deviceTask.movePlanTaskId = plan.getPlanTaskId(); + deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); + rotationPlanTaskIdSet.clear(); + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = startPoint.logicX; + deviceTask.checkLogicY = startPoint.logicY; + deviceTaskList.add(deviceTask); + linkStore = (List>) startPoint.dt.get("linkStore"); + } + PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); + deviceTask.operationType = COperationType.transplantLoadAndUnload; + deviceTask.pickMode = CPickMode.unload; + deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); + // 处理卸货高度 + StaticItem storeItem = runtime.getStaticItemById(endPointId); + Map storeItemRaw = storeItem.dt; + if (storeItemRaw.containsKey("bays")) { + List> bays = (List>) storeItemRaw.get("bays"); + Map bay = bays.get(plan.getTargetBay()); + List levelHeight = (List) bay.get("levelHeight"); + deviceTask.goodsSlotHeight = (int) Math.round(levelHeight.get(plan.getTargetLevel()) * 1000); + } else { + deviceTask.goodsSlotHeight = 1; + } + if (linkStore != null) { + for (Map store : linkStore) { + if (store.get("item").equals(plan.getTargetId()) && store.get("level").equals(plan.getTargetLevel()) && store.get("bay").equals(plan.getTargetBay()) && store.get("cell").equals(plan.getTargetCell())) { + short d = 0; + switch (store.get("direction").toString()) { + case "up": + d = 3; + break; + case "right": + d = 0; + break; + case "down": + d = 1; + break; + case "left": + d = 2; + break; + } + deviceTask.goodsSlotDirection = d; + } + } + } + // 标记任务分组结束 + deviceTask.isGroupEnd = true; + deviceTask.groupEndPoint = deviceTask.endPoint; + deviceTask.groupStartPoint = groupStartPoint; + groupStartPoint = deviceTask.endPoint; + + } else if (plan.getPlanType().equals(PlanTaskType.CHARGE.toString())) { + if (deviceTaskList.isEmpty()) { + PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); + deviceTask.x = startPoint.logicX; + deviceTask.y = startPoint.logicY; + deviceTask.speed = speed; + deviceTask.direction = direction; + deviceTask.pickMode = 0; + deviceTask.startPoint = startPoint; + deviceTask.endPoint = startPoint; + deviceTask.bizTaskId = plan.getBizTaskId(); + deviceTask.movePlanTaskId = plan.getPlanTaskId(); + deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); + rotationPlanTaskIdSet.clear(); + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = startPoint.logicX; + deviceTask.checkLogicY = startPoint.logicY; + deviceTaskList.add(deviceTask); + } + PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); + deviceTask.operationType = COperationType.charge; + deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); + // 处理充电距离(车的充电口到充电器被压下后的距离、一般被压下20mm) + deviceTask.chargeDirection = 2; + deviceTask.chargeLocation = 200; + // 标记任务分组结束 + deviceTask.isGroupEnd = true; + deviceTask.groupEndPoint = deviceTask.endPoint; + deviceTask.groupStartPoint = groupStartPoint; + groupStartPoint = deviceTask.endPoint; + } + + if (!plan.getExecutorId().equals(this.getId())) { + throw new RuntimeException("plan not belong executor:" + this.getId() + ", " + plan.getExecutorId()); + } + + } + + if (deviceTaskList.isEmpty()) { + PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); + deviceTask.x = startPoint.logicX; + deviceTask.y = startPoint.logicY; + deviceTask.speed = speed; + deviceTask.direction = direction; + deviceTask.pickMode = 0; + deviceTask.startPoint = startPoint; + deviceTask.endPoint = startPoint; + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = startPoint.logicX; + deviceTask.checkLogicY = startPoint.logicY; + deviceTaskList.add(deviceTask); + } + + // 标记任务分组结束 + PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); + deviceTask.groupEndPoint = deviceTask.endPoint; + deviceTask.groupStartPoint = groupStartPoint; + deviceTask.isGroupEnd = true; + // 最后一个规划任务为旋转时需要添加一个endDirection + if (rotationPlanTaskIdSet.size() > 0) { + deviceTask.operationType = COperationType.move; + deviceTask.pickMode = CPickMode.normal; + deviceTask.endDirection = direction; + deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); + if (deviceTask.movePlanTaskId == null) { + deviceTask.movePlanTaskId = 0L; + } + rotationPlanTaskIdSet.clear(); + } + + // 反向标记任务组 + int lastIndex = deviceTaskList.size() - 1; + for (int i = deviceTaskList.size() - 1; i >= 0; i--) { + PtrAgvDeviceTask d = deviceTaskList.get(i); + if (d.isGroupEnd) { + lastIndex = i; + } else { + d.operationType = deviceTaskList.get(lastIndex).operationType; + d.pickMode = deviceTaskList.get(lastIndex).pickMode; + d.groupStartPoint = deviceTaskList.get(lastIndex).groupStartPoint; + d.groupEndPoint = deviceTaskList.get(lastIndex).groupEndPoint; + d.goodsSlotHeight = deviceTaskList.get(lastIndex).goodsSlotHeight; + d.goodsSlotDirection = deviceTaskList.get(lastIndex).goodsSlotDirection; + d.chargeDirection = deviceTaskList.get(lastIndex).chargeDirection; + d.chargeLocation = deviceTaskList.get(lastIndex).chargeLocation; + } + } + + deviceTaskQueue.addAll(deviceTaskList); + String json = JsonWrapper.toJson(deviceTaskList); + log.info("deviceTaskList: {}", json); + } + + public boolean isSamePosition(PosDirection startPos) { + return this.logicX == startPos.logicX() && this.logicY == startPos.logicY() && + PathUtils.getDirectionByArmDirection(this.direction) == startPos.direction(); + } + + private static class CDirection { + private static final short dr = 0; + private static final short db = 1; + private static final short dl = 2; + private static final short dt = 3; + } + + + private static class COperationType { + public static final short move = 0; + public static final short load = 1; + public static final short unpick = 2; + public static final short charge = 3; + public static final short transplantLoadAndUnload = 4; + public static final short rollerLoadAndUnload = 5; + } + + private static class CPickMode { + public static final short normal = 0; + public static final short load = 1; + public static final short unload = 2; + public static final short adjustHeight = 3; + public static final short adjustHeightToLoad = 5; + public static final short adjustHeightToUnload = 6; + } + + + /** + * 从 AMR 方向转换为 LCC 方向枚举 + * + * @return + */ + public LCCDirection getLCCDirection() { + return switch (direction) { + case 0 -> LCCDirection.RIGHT; + case 1 -> LCCDirection.DOWN; + case 2 -> LCCDirection.LEFT; + case 3 -> LCCDirection.UP; + default -> null; + }; + } + + public short getAmrDirection(LCCDirection lccDirection) { + return switch (lccDirection) { + case RIGHT -> 0; + case DOWN -> 1; + case LEFT -> 2; + case UP -> 3; + default -> -1; // 未知方向 + }; + } + + private String getRedisKey(String type) { + return String.format("lcc:%s:%s:device:%s:%s", + runtime.projectUuid, runtime.envId, this.getId(), type); + } + + public AgvStatusVo getState() { + var ptr = this; + + var state = new AgvStatusVo(); + state.setId(ptr.id); + state.setType(ptr.getT()); + state.setIsOnline(ptr.isOnline); + state.setIsSystemManaged(ptr.isSystemManaged); + + state.setX(ptr.x); + state.setY(ptr.y); + state.setZ(ptr.z); + state.setLogicX(ptr.logicX); + state.setLogicY(ptr.logicY); + + state.setDirection(PathUtils.getDirectionByArmDirection(ptr.direction)); + state.setOrientation(ptr.orientation); + state.setSoc(ptr.battery == null ? -1 : ptr.battery.SOC); + state.setMode(ptr.get__taskMode()); + state.setTaskStatus(ptr.getTaskStatus()); + + state.setIsBlocked(ptr.isBlocked); + if (ptr.planTaskSequence != null) { + state.setTaskCompleted(ptr.planTaskSequence.completedCount()); + state.setTaskTotalCount(ptr.planTaskSequence.taskTotalCount()); + state.setBizTaskId(ptr.planTaskSequence.bizTask.getBizTaskId()); + state.setBizTaskType(BizTaskType.fromString(ptr.planTaskSequence.bizTask.getBizType())); + state.setBizTaskStatus(BizTaskStatus.fromString(ptr.planTaskSequence.bizTask.getBizTaskStatus())); + state.setBizTaskFrom(ptr.planTaskSequence.bizTask.getTaskFrom()); + state.setBizTaskTo(ptr.planTaskSequence.bizTask.getTaskTo()); + state.setBizLpn(ptr.planTaskSequence.bizTask.getLpn()); + + state.setLoadBasLocationVo(ptr.planTaskSequence.loadBasLocationVo); + state.setUnloadBasLocationVo(ptr.planTaskSequence.unloadBasLocationVo); + } + + return state; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/PtrMqttClient.java b/servo/src/main/java/com/galaxis/rcs/amr/PtrMqttClient.java new file mode 100644 index 0000000..482e42e --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/PtrMqttClient.java @@ -0,0 +1,154 @@ +package com.galaxis.rcs.amr; + +import com.yvan.logisticsEnv.EnvConfig; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.clever.core.BannerUtils; +import org.eclipse.paho.mqttv5.client.*; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; +import org.eclipse.paho.mqttv5.common.packet.MqttProperties; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; + +@Slf4j +public class PtrMqttClient implements MqttCallback { + public final AmrMessageHandler amrMessageHandler; + public final EnvConfig.MqttConfig mqttConfig; + private final MqttClient clientForSend; + private final MqttClient client; + private final String clientId; + private CountDownLatch connectLatch = new CountDownLatch(1); + + + @SneakyThrows + public PtrMqttClient(AmrMessageHandler handler, EnvConfig.MqttConfig mqttConfig, String clientId) { + this.amrMessageHandler = handler; + this.mqttConfig = mqttConfig; + this.clientId = clientId; + + String brokerUrl = mqttConfig.getBrokerUrl(); // "tcp://10.10.203.239:1885" + String username = mqttConfig.getUsername(); // admin + String password = mqttConfig.getPassword(); // admin + + clientForSend = new MqttClient(brokerUrl, clientId + "_send"); // String clientId = "LUOYIFAN-PC_send" + client = new MqttClient(brokerUrl, clientId); // String clientId = "LUOYIFAN-PC" + MqttConnectionOptions options = new MqttConnectionOptions(); + options.setServerURIs(new String[]{brokerUrl}); + options.setAutomaticReconnect(true); + options.setUserName(username); + options.setPassword(password.getBytes()); + options.setConnectionTimeout(5000); + options.setKeepAliveInterval(20); + options.setExecutorServiceTimeout(5000); + + client.setCallback(this); + client.connect(options); + + clientForSend.connect(options); + connectLatch.await(); + + BannerUtils.printConfig(log, "PtrMqttClient MQTT 开启监听成功", new String[]{ + "brokerUrl: " + brokerUrl, + "userName: " + username, + "clientId: " + clientId, + "topic: /agv_robot/status"}); + + client.subscribe("/agv_robot/status", 0); + } + + @SneakyThrows + public void publish(String topic, String payloadString) { + MqttMessage message = new MqttMessage(payloadString.getBytes(StandardCharsets.UTF_8)); + message.setQos(0); + message.setRetained(false); + + if (this.clientForSend.isConnected()) { + this.clientForSend.publish(topic, message); + } else { + throw new RuntimeException("MQTT client is not connected, cannot publish message."); + } + log.info("Message published to topic {}", topic); + } + + @SneakyThrows + public static void main(String[] args) { + var config = new EnvConfig.MqttConfig(); + config.setBrokerUrl("tcp://10.10.203.239:1885"); + config.setUsername("admin"); + config.setPassword("admin"); + + PtrMqttClient mqttClient = new PtrMqttClient(null, config, "LUOYIFAN-PC"); + for (int i = 0; i < 100; i++) { + mqttClient.publish("/agv_robot/status", "Hello from Java " + i); + } + log.info("Message published successfully."); + } + + @Override + public void disconnected(MqttDisconnectResponse disconnectResponse) { + log.info("mqtt disconnected"); + } + + @Override + public void mqttErrorOccurred(MqttException exception) { + log.error("mqtt error occurred"); + } + + @Override + public void messageArrived(String topic, MqttMessage message) throws Exception { + switch (topic) { + case "/agv_robot/status": + try { + if (this.amrMessageHandler == null) { + log.info("amrMessageHandler is null, skipping message handling {}", new String(message.getPayload(), StandardCharsets.UTF_8)); + return; + } + this.amrMessageHandler.handleAgvRobotStatusMessage(message); + + } catch (Exception e) { + log.error("amrMessageHandler.handleAgvRobotStatusMessage 异常", e); + } + break; + default: + break; + } + } + + @Override + public void deliveryComplete(IMqttToken token) { + log.info("Message delivery complete: {}", token); + } + + @Override + public void connectComplete(boolean reconnect, String serverURI) { + // BannerUtils.printConfig(log, "MQTT 开启监听", new String[]{serverURI + " topic: /agv_robot/status"}); + log.info("MQTT client connected to server: {}", serverURI); + connectLatch.countDown(); // 放行 + } + + @Override + public void authPacketArrived(int reasonCode, MqttProperties properties) { + } + + @SneakyThrows + public void stop() { + if (client != null && client.isConnected()) { + client.disconnect(); + client.close(); + log.info("MQTT client disconnected and closed."); + } else { + log.warn("MQTT client is not connected, no action taken."); + } + + if(clientForSend != null && clientForSend.isConnected()) { + clientForSend.disconnect(); + clientForSend.close(); + log.info("MQTT clientForSend disconnected and closed."); + } else { + log.warn("MQTT clientForSend is not connected, no action taken."); + } + } + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/RcsMessageType.java b/servo/src/main/java/com/galaxis/rcs/amr/RcsMessageType.java new file mode 100644 index 0000000..8ddd5de --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/RcsMessageType.java @@ -0,0 +1,91 @@ +package com.galaxis.rcs.amr; + +import com.google.common.collect.Maps; + +import java.util.Collections; +import java.util.Map; + +/** + * RCS消息类型枚举 + */ +public enum RcsMessageType { + /** + * AMR作业指令 + */ + RCS_TASK(10010, "AMR作业指令"), + /** + * 停止OR解除 + */ + RCS_SR(10040, "停止OR解除"), + /** + * 电文应答 + */ + RCS_ACK(10050, "电文应答"), + /** + * 配置信息 + */ + RCS_CONFIG(10060, "配置信息"), + /** + * 旋转货架 + */ + RCS_ROTATE_RACK(10080, "旋转货架"), + /** + * 旋转车身 + */ + RCS_ROTATE_BODY(10081, "旋转车身"), + /** + * 控制卷帘门 + */ + RCS_CONTROL_DOOR(10082, "控制卷帘门"), + /** + * 心跳 + */ + RCS_HEARTBEAT(10100, "心跳"), + /** + * 状态查询 + */ + RCS_QUERY_STATUS(10110, "状态查询"), + /** + * 取消已下发小车任务 + */ + RCS_CANCEL_TASK(10120, "取消已下发小车任务"), + /** + * 设置小车坐标 + */ + RCS_SET_LOCATION(10200, "设置小车坐标"), + /** + * 等待就绪 + */ + RCS_WAIT(19997, "等待就绪"); + + // 枚举值映射 + private static final Map VALUE_MAP; + + static { + Map map = Maps.newHashMap(); + for (RcsMessageType command : values()) { + map.put(command.value, command); + } + VALUE_MAP = Collections.unmodifiableMap(map); + } + + public final int value; + public final String description; + + RcsMessageType(int value, String description) { + this.value = value; + this.description = description; + } + + + /** + * 从整数值获取对应的枚举 + * + * @param value 整数值 + * @return 对应的枚举,如果找不到则返回 null + */ + public static RcsMessageType fromValue(int value) { + return VALUE_MAP.get(value); + } + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAckMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAckMessage.java new file mode 100644 index 0000000..6e092eb --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAckMessage.java @@ -0,0 +1,10 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 消息应答 20050 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrAckMessage extends AmrCommonMessage { +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAppStartMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAppStartMessage.java new file mode 100644 index 0000000..e281471 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrAppStartMessage.java @@ -0,0 +1,16 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 小车主程序启动 20149 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrAppStartMessage extends AmrCommonMessage { + // 电量百分比 Uint8 + public short Battery; + // AMR底盘型号 String 对于底盘和功能一体的版本,由底盘型号便知道功能;对于通用底盘,底盘型号指定了底盘的版本 + public String AGVModel; + // AMR功能型号 String 底盘之上的工装的型号 + public String AGVFnModel; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrBootMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrBootMessage.java new file mode 100644 index 0000000..83adddc --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrBootMessage.java @@ -0,0 +1,18 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 开机上报 20147 在开机后上报一次,此后AMR程序重启不会重新上报(与ID#20149的差异),除非人为清除内部记录已上报的标志。 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrBootMessage extends AmrCommonMessage { + // 电量百分比 Uint8 + public short Battery; + // AMR底盘型号 String 对于底盘和功能一体的版本,由底盘型号便知道功能;对于通用底盘,底盘型号指定了底盘的版本 + public String AGVModel; + // AMR功能型号 String 底盘之上的工装的型号 + public String AGVFnModel; + // 上电至今的毫秒数 Uint64 + public long Uptime; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrExceptionMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrExceptionMessage.java new file mode 100644 index 0000000..5c4e08e --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrExceptionMessage.java @@ -0,0 +1,24 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +import java.util.Map; + +// 异常上报 20250 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrExceptionMessage extends AmrCommonMessage { + // 异常代码 UInt8 1. 货架编号不匹配 2. 地标异常 3. 电量低 + public short ErrCode; + // 异常机构代码 UInt8 对于哪吒飞梭类的机型,增加MechNo用于指示异常具体是哪一层发生的。 MechNo: 1- 机构1^[1]^异常 2- 机构2异常 3- 机构3异常 + public short MechNo; + // 异常详情 Struct 根据不同的异常,字段不一样,比如针对ErrCode为2电量低的情况,ErrMsg中使用CurBattery标识当前电量; + public Map ErrMsg; + // 异常事件类型 UInt8 0:无 1:开始 2:更新 3:结束 4:开始并结束 + public short ErrEvtType; + // 异常等级 UInt8 0:Undetermined 12:Info 13:Warning 14:Critical 15:Fatal + public short ErrLevel; + // 异常生命周期 UInt8 0:易变的 1:一次性 2:持续性 3:任务期间 + public short ErrLifecycle; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrHeartbeatMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrHeartbeatMessage.java new file mode 100644 index 0000000..d63e481 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrHeartbeatMessage.java @@ -0,0 +1,20 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +//心跳 20100 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrHeartbeatMessage extends AmrCommonMessage { + // 电量百分比 Uint8 + public short Battery; + // 上电至今的毫秒数 Uint64 + public long Uptime; + // static + public TemperatureData Temperature; + public static class TemperatureData { + // 电池温度 Double 单位:摄氏度 备注:一个电池可能有多个(不同型号的)温度传感器,目前只上报最高的温度 + public Double Battery; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrLandmarkMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrLandmarkMessage.java new file mode 100644 index 0000000..f38f9a2 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrLandmarkMessage.java @@ -0,0 +1,28 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 地标报告 20020 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrLandmarkMessage extends AmrCommonMessage { + // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 + public double CurX; + // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 + public double CurY; + // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public short CurDirection; + // 当前所在站点的逻辑X坐标 Int32 + public int CurLogicX; + // 当前所在站点的逻辑Y坐标 Int32 + public int CurLogicY; + // 当前标准X坐标 double + public double X; + // 当前标准Y坐标 double + public double Y; + // 当前方向 Double 角度 + public double CurOrientation; + // 未知 + public int MarkerType; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrModuleTaskStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrModuleTaskStatusMessage.java new file mode 100644 index 0000000..d2c1f59 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrModuleTaskStatusMessage.java @@ -0,0 +1,16 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 小车子模块任务状态 20012 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrModuleTaskStatusMessage extends AmrCommonMessage { + // 多机构^[1]^的拣货模式 UInt8[3] 数组形式,意义同"PickMode" + public short[] MPickMode; + // 子模块任务状态 UInt8[3] 数组形式,数组下标^\[1\]^分别对应各子模块。 0:无任务 2:任务中 3:任务准备中(已有任务,但还没有执行任务的条件) 5:任务异常 7:任务完成 其它:保留 + public short[] MechStatus; + // 多载货机构上每个机构上面货物的ID String[] 数组形式,分别对应各子模块上货箱的ID码的值,如果无货为"",如果解不出来为"unknown" + public String[] MStorageRacksNo; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOfflineMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOfflineMessage.java new file mode 100644 index 0000000..12b6cd5 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOfflineMessage.java @@ -0,0 +1,10 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 小车离线 20200 注意:目前未实现此报文 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrOfflineMessage extends AmrCommonMessage { +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOnlineMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOnlineMessage.java new file mode 100644 index 0000000..9d0809e --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrOnlineMessage.java @@ -0,0 +1,12 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 小车上线 20150 代表车已经完成初始化,可以接收任务了。 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrOnlineMessage extends AmrCommonMessage { + // 电量百分比 Uint8 + public short Battery; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrShutdownMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrShutdownMessage.java new file mode 100644 index 0000000..738f8ee --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrShutdownMessage.java @@ -0,0 +1,14 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +// 关机上报 20148 在收到关机信号后上报此消息。 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrShutdownMessage extends AmrCommonMessage { + // 电量百分比 Uint8 + public short Battery; + // 上电至今的毫秒数 Uint64 + public long Uptime; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrStatusMessage.java new file mode 100644 index 0000000..aa176f8 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrStatusMessage.java @@ -0,0 +1,50 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; +import com.galaxis.rcs.amr.receiveEntity.base.CurBatteryData; +import com.galaxis.rcs.amr.receiveEntity.base.LocationData; + +// 状态上报 20060 +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrStatusMessage extends AmrCommonMessage { + + // 电池状态 + public CurBatteryData CurBattery; + // 当前方向 Double 角度 + public double CurOrientation; + // 当前所在站点的逻辑X坐标 Int32 + public int CurLogicX; + // 当前所在站点的逻辑Y坐标 Int32 + public int CurLogicY; + // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 + public double CurX; + // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 + public double CurY; + // 货架当前方向 Double + public double RackCurOrientation; + // 货架当前位置 Double + public double RackCurPosition; + // 货架号 String + public String StorageRacksNo; + // 多载货机构上每个机构上面货物的ID String[] + public String[] MStorageRacksNo; + // 任务模式 Byte + public short TaskMode; + // 当前标准X坐标 double + public double X; + // 当前标准Y坐标 double + public double Y; + // 当前货物数量。数组形式。 对于单滚筒等单个托盘的机型,只需关注数据0; 对于双滚筒,滚筒1的数量放到数据0中,滚筒2的货物数量放到数据1中。 其它机型以此类推。UInt16 [4] + public int[] GoodsQuantity; + // 异常数组,存放异常的所有异常ID UInt16 [4] + public int[] Exceptions; + // 是否已进行精准停靠(是否能在原地直接执行对接任务) bool + public boolean InDock; + // 初始化状态 bool + public boolean Initialized; + // 车载货位信息 + public LocationData[] GoodsSlots; + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskCompletedMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskCompletedMessage.java new file mode 100644 index 0000000..0388532 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskCompletedMessage.java @@ -0,0 +1,36 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; +import com.galaxis.rcs.amr.receiveEntity.base.LocationData; +import com.galaxis.rcs.amr.receiveEntity.base.SummaryData; + +// 小车作业完成 20010 +//@Data + +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrTaskCompletedMessage extends AmrCommonMessage { + + // 当前X坐标 UInt16 + public int CurX; + // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 + public int CurY; + // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public short CurDirection; + // 当前方向 Double 角度 + public double CurOrientation; + // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) 135:旋转货架 136:旋转车身 + public short OperationType; + // 作业结果 Int32 参考linux errno + public long OperationResult; + // 货物ID String 在肥波类车型中是货架二维码值;在飞梭车中是箱码(目前未传,未来可能会有);在皮带飞梭中是货物上贴的二维码的码值(如果检测到多个码,则以" + public String StorageRacksNo; + // 电量百分比 Uint8 + public short Battery; + // 任务描述 Object 目前仅在飞梭和侧叉车型的报文中有这个字段,字段详情见下文 + public SummaryData Summary; + // 车载货位信息 + public LocationData[] GoodsSlots; + + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskStatusMessage.java new file mode 100644 index 0000000..efd9853 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/AmrTaskStatusMessage.java @@ -0,0 +1,15 @@ +package com.galaxis.rcs.amr.receiveEntity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.galaxis.rcs.amr.receiveEntity.base.AmrCommonMessage; + +//@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class AmrTaskStatusMessage extends AmrCommonMessage { + // 事件ID UInt8 0:无变化 1:任务模式改变 2:任务接收成功 3:任务开始 4:任务完成 5:任务已取消 6:任务已停止 7:任务已恢复 8:任务已更变 + public short EventId; + // 任务模式 Byte + public short TaskMode; + // 任务信息 由事件ID决定 Object 默认消息(0,2,3,5,6,7):任务状态改变消息 1:任务模式消息 4:任务完成消息 8:任务类型改变消息 + public T Info; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/AmrCommonMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/AmrCommonMessage.java new file mode 100644 index 0000000..3bdb92a --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/AmrCommonMessage.java @@ -0,0 +1,17 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import lombok.Data; + +// 共同信息字段 +public class AmrCommonMessage { + // 作业序号 UInt32 从1开始,0作为超级序号使用,不参与序号规则判断 + public long SeqNo; + // AMR编号 UInt16 + public int VehicleId; + // 消息创建时间 UInt64 毫秒级时间戳 + public long CreateTime; + // 消息创建时主机的开机时长 UInt64 毫秒级时间戳 + public long CreateMonoTime; + // 发送消息的时间 UInt64 毫秒级时间戳 + public long SendTime; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/CurBatteryData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/CurBatteryData.java new file mode 100644 index 0000000..44e2a1f --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/CurBatteryData.java @@ -0,0 +1,20 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 电池状态 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class CurBatteryData { + // 充电电流 + public double ChargingCurrent; + // 放电电流 + public double DischargingCurrent; + // 电量 + public double SOC; + // 电压 + public double Voltage; + // 温度 + public double Temperature; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/GoodsData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/GoodsData.java new file mode 100644 index 0000000..12adcb2 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/GoodsData.java @@ -0,0 +1,31 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import lombok.Data; + +// 货物信息 +@Data +public class GoodsData { + // 货物类型 UInt 对于一类设备可能取放不同货物时有用;如果只有一类货物,则可以不(在地图或者RCS下发的任务报文中)指定,此种情况下报文中不包含此字段 + public int Category; + // 传感器检测到的货物ID String 比如飞梭通过摄像头检测到的箱码、FM系列通过对上摄像头检测到的货架底部二维码等;如果车型没配备可以检测货物ID的传感器,则报文中不包含此字段 + public String DetectedId; + // 上位系统传过来的货物ID String 通常上位传过来的ID应该跟检测到的ID一致,否则会报错;对于没有检测ID功能的车型,不做校验而只是回传该值;有些项目可能会希望两个ID分开,对应此类需求可以特别设置不校验两类ID;也许有些项目会同时传入两种ID,当前暂不支持;如果上位没传入ID,则报文中不包含此字段 + public String UpperSystemDefinedId; + // 高度等级 UInt8 部分车型能检测货物高度,等级从0(最矮,默认值)开始,每一级递增1,各个等级的具体含义与车型有关,需要另行约定;如果有传感器但是由于传感器异常等原因无法获取到检测结果,则设置该值为0xff,代表状态未知。 + public short HeightLevel; + // 长度等级 + public short LengthLevel; + // 宽度等级 + public short WidthLevel; + // 重量等级 + public short WeightLevel; + // 测算的重量,不一定准 Double 单位是千克 + public double ApproximateWeight; + // 货物在地图上的朝向 Double 角度(Degree)值 + public double Orientation; + // 货物相对机器人的位置 包含以下成员: OffsetX:Int32类型 OffsetY:Int32类型 Orientation:Double类型,用角度(Degree)表示 + public OffsetPosition RelativePosition; + // 检测到的货物状态冲突 [UInt8] 1:货物ID不匹配 2:货物高度不匹配 3:货物宽度不匹配 4:货物长度不匹配 5:应该有货但没检测到有货 6:应该没货但检测到有货 + public short[] DetectedStatusConflicts; + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/LocationData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/LocationData.java new file mode 100644 index 0000000..59ee7a5 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/LocationData.java @@ -0,0 +1,24 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 货位信息 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class LocationData { + // 货位ID UInt8 从0开始,每款车自己定义的车载货位的ID + public short ID; + // 货位名称 String 每款车自己定义的货位的名称 + public String Name; + // 逻辑上是否应该有货 bool 有些车型有传感器来检测货物状态,这时实际的货物状态跟逻辑状态就可能不同 + public boolean ShouldHaveGoods; + // 检测到的货位状态 UInt8 0: 正常 1: 冲突,即传感器检测到的状态跟逻辑状态有冲突。逻辑上有货,实际无货,是一种冲突;逻辑上货的属性(比如高度)跟实际检测到的属性不同,也会产生冲突;对于一个货位有多个货物的情况,需要查看货物信息来查找具体是哪个货物出现了什么冲突 + public short DetectedStatus; + // 货位放货平面离地高度 Double + public double Height; + // 货位相对原点(初始化后货位所在位置)的相对位置 Object 包含以下成员: OffsetX:Double类型 OffsetY:Double类型 OffsetZ:Double类型,代表在高度上的位移 Orientation:Double类型,用角度(Degree)表示 + public OffsetPosition Position; + // 货物信息 Object + public GoodsData[] Goods; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/OffsetPosition.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/OffsetPosition.java new file mode 100644 index 0000000..a5c168a --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/OffsetPosition.java @@ -0,0 +1,16 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 相对原点偏移 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class OffsetPosition { + // OffsetX:Double类型 OffsetY:Double类型 OffsetZ:Double类型,代表在高度上的位移 Orientation:Double类型,用角度(Degree)表示 + public double OffsetX; + public double OffsetY; + public double OffsetZ; + public double Orientation; + +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/SummaryData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/SummaryData.java new file mode 100644 index 0000000..0a52fd5 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/SummaryData.java @@ -0,0 +1,24 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 任务描述 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class SummaryData { + // 执行器(比如飞梭的载货台)任务概览列表 Array 车载多少个执行器,数组就有多少个成员 + public ActuatorsData[] Actuators; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ActuatorsData { + // 执行器编号 Uint8 从1开始 + public short MechNo; + // 执行器名称 String + public String Name; + // 任务类型 UInt8 同下发任务中PickMode的定义 + public short PickMode; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskCompletedData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskCompletedData.java new file mode 100644 index 0000000..6af8af9 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskCompletedData.java @@ -0,0 +1,36 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 任务状态上报 20011 中 EventId = 4:任务完成 任务完成消息 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskCompletedData { + // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) 135:旋转货架 136:旋转车身 + public short OperationType; + // 作业结果 Int32 参考linux errno + public long OperationResult; + // 当前所在站点的逻辑X坐标 Int32 + public int CurLogicX; + // 当前所在站点的逻辑Y坐标 Int32 + public int CurLogicY; + // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 + public double CurX; + // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 + public double CurY; + // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public short CurDirection; + // 当前方向 Double 角度 + public double CurOrientation; + // 货架号 String 在肥波类车型中是货架二维码值;在飞梭车中是箱码(目前未传,未来可能会有);在皮带飞梭中是货物上贴的二维码的码值(如果检测到多个码,则以" + public String StorageRacksNo; + // 货架朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public short StorageDirection; + // 任务描述 Object 目前仅在飞梭和侧叉车型的报文中有这个字段,字段详情见下文 + public SummaryData Summary; + // 电量百分比 Uint8 + public short Battery; + // 车载货位信息 + public LocationData[] GoodsSlots; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskModeChangeData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskModeChangeData.java new file mode 100644 index 0000000..7d3c927 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskModeChangeData.java @@ -0,0 +1,14 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +//1: 任务模式改变消息 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskModeChangeData { + // 上一个任务模式 Uint8 0: 空闲模式 1: 初始化模式 2: 任务模式 3: 单动作模式 4: 手动模式 5: 遥控器模式 6: 充电模式 7: 任务被中断模式 有任务,但未收到终点坐标 8: 自定义模式 + public short PrevTaskMode; + // 当前任务模式 Uint8 0: 空闲模式 1: 初始化模式 2: 任务模式 3: 单动作模式 4: 手动模式 5: 遥控器模式 6: 充电模式 7: 任务被中断模式 有任务,但未收到终点坐标 8: 自定义模式 + public short TaskMode; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskStatusChangeData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskStatusChangeData.java new file mode 100644 index 0000000..2318cf8 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskStatusChangeData.java @@ -0,0 +1,12 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 0,2,3,5,6,7:任务状态改变消息 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskStatusChangeData { + // 当前任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 + public short OperationType; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskTypeChangeData.java b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskTypeChangeData.java new file mode 100644 index 0000000..e512fc2 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/receiveEntity/base/TaskTypeChangeData.java @@ -0,0 +1,14 @@ +package com.galaxis.rcs.amr.receiveEntity.base; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +// 8: 任务类型改变消息 +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskTypeChangeData { + // 上一个任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 + public short PrevOperationType; + // 当前任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 + public short OperationType; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/BaseMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/BaseMessage.java new file mode 100644 index 0000000..0c039f4 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/BaseMessage.java @@ -0,0 +1,6 @@ +package com.galaxis.rcs.amr.sendEntity; + +public class BaseMessage { + public int id; + public Object content; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsAckMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsAckMessage.java new file mode 100644 index 0000000..ec76338 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsAckMessage.java @@ -0,0 +1,7 @@ +package com.galaxis.rcs.amr.sendEntity; + +// 电文应答 10050 +public class RcsAckMessage { + // 作业序号 UInt32 所要应答消息的SeqNo(对方的) + public int SeqNo; +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsCancelTaskMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsCancelTaskMessage.java new file mode 100644 index 0000000..45c8c60 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsCancelTaskMessage.java @@ -0,0 +1,10 @@ +package com.galaxis.rcs.amr.sendEntity; + +// 取消已下发小车任务 10120 +public class RcsCancelTaskMessage { + // 作业序号 UInt32 + public int SeqNo; + public RcsCancelTaskMessage(int seqNo) { + SeqNo = seqNo; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsConfigMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsConfigMessage.java new file mode 100644 index 0000000..94262c8 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsConfigMessage.java @@ -0,0 +1,33 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +//配置信息 10060 +public class RcsConfigMessage { + // 作业序号 UInt32 + public int SeqNo; + // X坐标最大长度 UInt16 暂时未使用 + public int XLength = 1000; + // Y坐标最大长度 UInt16 暂时未使用 + public int YLength = 1000; + // 相邻地标间距 UInt16 单位:mm (目前等距) + public int Gap = 1000; + // 心跳间隔 UInt32 单位: s + public int HeartBeat = 60; + // 小车所有上报消息重试间隔(未收到应答消息时重发消息) UInt32 单位: s + public int MqRetryTime = 3; + + public RcsConfigMessage(LogisticsRuntime runtime, int xLength, int yLength, int gap, int heartBeat, int mqRetryTime) { + XLength = xLength; + YLength = yLength; + Gap = gap; + HeartBeat = heartBeat; + MqRetryTime = mqRetryTime; + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } + + public RcsConfigMessage(LogisticsRuntime runtime) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsControlDoorMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsControlDoorMessage.java new file mode 100644 index 0000000..ad42d58 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsControlDoorMessage.java @@ -0,0 +1,21 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +// 控制卷帘门 10082 +public class RcsControlDoorMessage { + // 作业序号 UInt32 + public int SeqNo; + // 卷帘状态 UInt8 0: 不控制(无动作) 1: 关闭状态 2: 半开状态 3: 全开状态 4: 停止(暂不支持) + public short CurtainCmd; + + public RcsControlDoorMessage(LogisticsRuntime runtime, short curtainCmd) { + CurtainCmd = curtainCmd; + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } + + public RcsControlDoorMessage(LogisticsRuntime runtime) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsHeartBeatMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsHeartBeatMessage.java new file mode 100644 index 0000000..95816a2 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsHeartBeatMessage.java @@ -0,0 +1,5 @@ +package com.galaxis.rcs.amr.sendEntity; + +// 心跳 10100 +public class RcsHeartBeatMessage { +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsQueryStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsQueryStatusMessage.java new file mode 100644 index 0000000..e3b3328 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsQueryStatusMessage.java @@ -0,0 +1,14 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +//状态查询 10110 +public class RcsQueryStatusMessage { + // 作业序号 UInt32 + public int SeqNo; + + public RcsQueryStatusMessage(LogisticsRuntime runtime) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateBodyMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateBodyMessage.java new file mode 100644 index 0000000..bb08d85 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateBodyMessage.java @@ -0,0 +1,21 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +//旋转车身 10081 +public class RcsRotateBodyMessage { + // 作业序号 UInt32 + public int SeqNo; + // 车头朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 + public short Direction; + + public RcsRotateBodyMessage(LogisticsRuntime runtime, short direction) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + Direction = direction; + } + + public RcsRotateBodyMessage(LogisticsRuntime runtime) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateRackMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateRackMessage.java new file mode 100644 index 0000000..84d1313 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsRotateRackMessage.java @@ -0,0 +1,21 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +//旋转货架 10080 +public class RcsRotateRackMessage { + // 作业序号 UInt32 + public int SeqNo; + // 货架A面朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 + public short Direction; + + public RcsRotateRackMessage(LogisticsRuntime runtime, short direction) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + Direction = direction; + } + + public RcsRotateRackMessage(LogisticsRuntime runtime) { + SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSRMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSRMessage.java new file mode 100644 index 0000000..beddbf4 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSRMessage.java @@ -0,0 +1,27 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +// 停止/解除 10040 +public class RcsSRMessage { + // 作业序号 UInt32 + public int SeqNo; + // 操作代码 Uint8 0-停止 1-解除 + public short OperationCode; + // 停止点X坐标 Uint16 + public int StopX; + // 停止点Y坐标 Uint16 + public int StopY; + + public RcsSRMessage(LogisticsRuntime runtime, short operationCode, int stopX, int stopY) { + this.OperationCode = operationCode; + this.StopX = stopX; + this.StopY = stopY; + this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } + + public RcsSRMessage(LogisticsRuntime runtime) { + this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSetLocationMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSetLocationMessage.java new file mode 100644 index 0000000..c4705d3 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsSetLocationMessage.java @@ -0,0 +1,26 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; + +// 设置小车坐标 10200 +public class RcsSetLocationMessage { + // 作业序号 UInt32 + public int SeqNo; + // X坐标 Uint16 + public int X; + // Y坐标 Uint16 + public int Y; + // 车头朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知(小车保持原车头方向) + public short Direction; + + public RcsSetLocationMessage(int seqNo, int x, int y, short direction) { + this.X = x; + this.Y = y; + this.Direction = direction; + this.SeqNo = seqNo; + } + + public RcsSetLocationMessage(int seqNo) { + this.SeqNo = seqNo; + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsTaskMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsTaskMessage.java new file mode 100644 index 0000000..a0b125c --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsTaskMessage.java @@ -0,0 +1,102 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; +import lombok.AllArgsConstructor; + +import java.util.List; + +// AMR作业指令 10010 +public class RcsTaskMessage { + // 作业序号 UInt32 + public int SeqNo; + // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) + public short OperationType; + //充电桩朝向UseBriefLocation UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short ChargeDirection; + // 充电工位坐标和充电桩之间距离 UInt16 单位:mm + public Integer ChargeLocation; + // 目标货架编号 String 仅做校验使用(仅接货用) + public String StorageRacksNo; + // 小车起始X坐标 UInt16 + public int StartX; + // 小车起始Y坐标 UInt16 + public int StartY; + // 小车目标X坐标 UInt16 + public int EndX; + // 小车目标Y坐标 UInt16 + public int EndY; + // 任务是否立即执行 bool 默认为true + public Boolean GoNow; + // 路径分段数 UInt8 + public Short LinkCounts; + // 路径分段信息 + public List Link; + // AMR内置货位ID(仅对多层移栽有意义)UInt8 1~N + public Short BuiltinSlotNo; + // 提升移栽货物拣货模式 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 + public Short PickMode; + // 目标货位相对于地面的绝对高度 UInt16 单位:mm + public Integer GoodsSlotHeight; + // 目标货位朝向 UInt8 朝向定义与充电桩朝向相同。 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short GoodsSlotDirection; + // 结束朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short EndDirection; + + // 多机构^[1]^的拣货模式 UInt8[3] 数组形式,意义同"PickMode" + public List MPickMode; + // 多机构^[1]^的目标货位高度 UInt16[3] 单位:mm + public List MGoodsSlotHeight; + // 多机构^[1]^的目标货位朝向 UInt8[3] 朝向定义与充电桩朝向相同。 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public List MGoodsSlotDirection; + // 多机构的目标货箱ID String[3] 仅做校验使用(仅接货用) + public List MStorageRacksNo; + // 滚筒1 运动操作 对于左右滚动的双滚筒机型,此滚筒为靠近车头的滚筒。 对于前后滚动的双滚筒机型,此滚筒为车身左侧的滚筒。 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 + public Short Roll1Motion; + // 滚筒2 运动操作 对于左右滚动的双滚筒机型,此滚筒为靠近车尾的滚筒。 对于前后滚动的双滚筒机型,此滚筒为车身右侧的滚筒。 对于单滚筒机型,此参数无意义。 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 + public Short Roll2Motion; + // 与滚筒1对接的站台朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short Roll1StationDirection; + // 与滚筒2对接的站台朝向 对于单滚筒机型,此参数无意义。 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public Short Roll2StationDirection; + // 滚筒1目标货物长度 UInt16 单位:mm + public Integer Roll1GoodsLength; + // 滚筒2目标货物长度 对于单滚筒机型,此参数无意义。UInt16 单位:mm + public Integer Roll2GoodsLength; + // 滚筒1目标货物数量 UInt16 1~N + public Integer Roll1GoodsQuantity; + // 滚筒2目标货物数量 对于单滚筒机型,此参数无意义。 UInt16 1~N + public Integer Roll2GoodsQuantity; + // 多滚筒运动模式 UInt8[6] 数组形式,0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 + public List MRollMotion; + // 多滚筒对接的站台朝向 UInt8[6] 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 + public List MRollStationDirection; + // 多滚筒目标货物数量 UInt16[6] 数组形式,意义同"RollGoodsQuantity" + public List MRollGoodsQuantity; + // 是否仅执行任务的准备部分 bool 默认为false,仅执行该动作的准备部分,如仅进行导航,调整托盘高度等,但不进行取放货操作 + public Boolean Preparing; + // 货架标识 uint32 车根据货架类型查询尺寸进行避障 + public Long RackTypeId; + // 终点自适应 bool 默认为false,为true时,会根据任务和对应器件的位置,自动调整停止点 + public Boolean EndSelfAdaption; + + + public RcsTaskMessage(LogisticsRuntime runtime) { + this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } + + public RcsTaskMessage(int seqNo) { + this.SeqNo = seqNo; + } + + @AllArgsConstructor + public static class LinkData { + //该段目标点X坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 + public int X; + //该段目标点Y坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 + public int Y; + // 该段行驶速度 Int16 mm/s + public int Speed; + + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsWaitMessage.java b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsWaitMessage.java new file mode 100644 index 0000000..acbf086 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/amr/sendEntity/RcsWaitMessage.java @@ -0,0 +1,20 @@ +package com.galaxis.rcs.amr.sendEntity; + +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.yvan.logisticsModel.LogisticsRuntime; + +public class RcsWaitMessage { + // 作业序号 UInt32 + public int SeqNo; + // 等待时间(s)Double -1:结束等待(仅SLAM车支持) 0:持续等待(仅SLAM车支持) 大于0:等待对应的时间后返回成功 + public double Seconds; + + public RcsWaitMessage(LogisticsRuntime runtime, double seconds) { + this.Seconds = seconds; + this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } + + public RcsWaitMessage(LogisticsRuntime runtime) { + this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); + } +} diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java index f6fb011..1e5b49d 100644 --- a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java +++ b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2DeviceConnector.java @@ -1,8 +1,8 @@ package com.galaxis.rcs.connector.cl2; import com.fasterxml.jackson.core.JsonProcessingException; -import com.galaxis.rcs.ptr.sendEntity.RcsTaskMessage; -import com.galaxis.rcs.ptr.AmrMessageHandler; +import com.galaxis.rcs.amr.sendEntity.RcsTaskMessage; +import com.galaxis.rcs.amr.AmrMessageHandler; import com.yvan.logisticsModel.LogisticsRuntime; import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.mqttv5.common.MqttException; diff --git a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Item.java b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Item.java index 3d2d893..5589844 100644 --- a/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Item.java +++ b/servo/src/main/java/com/galaxis/rcs/connector/cl2/Cl2Item.java @@ -1,8 +1,8 @@ package com.galaxis.rcs.connector.cl2; -import com.galaxis.rcs.ptr.sendEntity.RcsConfigMessage; +import com.galaxis.rcs.amr.sendEntity.RcsConfigMessage; import com.yvan.logisticsModel.LogisticsRuntime; -import com.galaxis.rcs.ptr.PtrAgvItem; +import com.galaxis.rcs.amr.PtrAgvItem; import java.util.Map; diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessage.java deleted file mode 100644 index 1f1eafa..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.galaxis.rcs.ptr; - -import lombok.Data; - -// RCS 接收 AMR的消息 -@Data -public class AmrMessage { - /** - * 消息标识 - * 小车作业完成 20010 AmrTaskCompletedMessage - * 任务状态上报 20011 AmrTaskStatusMessage - * 小车子模块任务状态 20012 AmrModuleTaskStatusMessage - * 地标报告 20020 AmrLandmarkMessage - * 消息应答 20050 AmrAckMessage - * 状态上报 20060 AmrStatusMessage - * 心跳 20100 AmrHeartbeatMessage - * 小车主程序启动 20149 AmrAppStartMessage - * 小车上线 20150 AmrOnlineMessage - * 小车离线 20200 AmrOfflineMessage - * 异常上报 20250 AmrExceptionMessage - * 开机上报 20147 AmrBootMessage - * 关机上报 20148 AmrShutdownMessage - */ - public int id; - // 消息内容 - public T content; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java b/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java deleted file mode 100644 index 49e482b..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java +++ /dev/null @@ -1,543 +0,0 @@ -package com.galaxis.rcs.ptr; - - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.galaxis.rcs.plan.path.PathUtils; -import com.galaxis.rcs.ptr.receiveEntity.*; -import com.galaxis.rcs.ptr.receiveEntity.base.*; -import com.galaxis.rcs.ptr.sendEntity.*; -import com.google.common.base.Splitter; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.yvan.logisticsEnv.EnvConfig; -import com.yvan.logisticsModel.LogisticsRuntime; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.clever.core.BannerUtils; -import org.clever.core.json.JsonWrapper; -import org.clever.core.mapper.BeanCopyUtils; -import org.clever.data.redis.Redis; -import org.clever.data.redis.RedisAdmin; -import org.eclipse.paho.mqttv5.common.MqttException; -import org.eclipse.paho.mqttv5.common.MqttMessage; - -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -@Slf4j -public class AmrMessageHandler { - private static final TypeReference> typeRef20010Message = new TypeReference>() { - }; - private static final TypeReference>> typeRef20011_defaultMessage = new TypeReference>>() { - }; - private static final TypeReference>> typeRef20011_1Message = new TypeReference>>() { - }; - private static final TypeReference>> typeRef20011_4Message = new TypeReference>>() { - }; - private static final TypeReference>> typeRef20011_8Message = new TypeReference>>() { - }; - private static final TypeReference> typeRef20012Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20020Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20050Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20060Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20100Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20147Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20148Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20149Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20150Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20200Message = new TypeReference>() { - }; - private static final TypeReference> typeRef20250Message = new TypeReference>() { - }; - - private static final Redis redis = RedisAdmin.getRedis(); - - public final LogisticsRuntime runtime; - private volatile PtrMqttClient ptrMqttClient; - - public int getNewSeqNo() { - String redisKey = "lcc:rcs:" + runtime.projectUuid + ":" + runtime.envId + ":seqNo"; - long seqNo = redis.vIncrement(redisKey); - if (seqNo > Integer.MAX_VALUE) { - redis.kDelete(redisKey); - seqNo = redis.vIncrement(redisKey).intValue(); - } - return (int) seqNo; - } - - public AmrMessageHandler(LogisticsRuntime runtime) { - this.runtime = runtime; - } - - public void start(EnvConfig.MqttConfig mqttConfig, String clientId) { - this.ptrMqttClient = new PtrMqttClient(this, mqttConfig, clientId); - } - - public void stop() { - if (ptrMqttClient != null) { - ptrMqttClient.stop(); - } - } - - public void handleAgvRobotStatusMessage(MqttMessage message) throws MqttException, JsonProcessingException { - byte[] messageData = message.getPayload(); - String json = new String(messageData, StandardCharsets.UTF_8); - - log.debug("收到消息: {}", json); - - JsonWrapper jw = new JsonWrapper(json); - int id = jw.asInt("id"); - String agvId = jw.asInt("content", "VehicleId") + ""; - int seqNo = jw.asInt("content", "SeqNo"); - PtrAgvItem agvItem = getPtrAgvItem(agvId); - if (agvItem == null) { - return; - } - - // 计算网络延迟 - long receiveTime = System.currentTimeMillis(); - Long sentTime = lastMessageTimeMap.get(agvId); - if (sentTime != null) { - long netDelay = receiveTime - sentTime; - updateRedisNetDelay(agvId, netDelay); - } - - /* - * 消息标识 - * 小车作业完成 20010 AmrTaskCompletedMessage - * 任务状态上报 20011 AmrTaskStatusMessage - * 小车子模块任务状态 20012 AmrModuleTaskStatusMessage - * 地标报告 20020 AmrLandmarkMessage - * 消息应答 20050 AmrAckMessage - * 状态上报 20060 AmrStatusMessage - * 心跳 20100 AmrHeartbeatMessage - * 开机上报 20147 AmrBootMessage - * 关机上报 20148 AmrShutdownMessage - * 小车主程序启动 20149 AmrAppStartMessage - * 小车上线 20150 AmrOnlineMessage - * 小车离线 20200 AmrOfflineMessage - * 异常上报 20250 AmrExceptionMessage - */ - if (id != ArmMessageType.AMR_ACK.value && id != ArmMessageType.AMR_HEARTBEAT.value) { - var list = Splitter.on("\n").splitToList(jw.toString()); - String[] ar = new String[list.size()]; - list.toArray(ar); - // log.info("3-Received message: " + json); - // BannerUtils.printConfig(log, "MQTT 收到报文 [" + id + "] ArmMessageType." + ArmMessageType.fromValue(id) + " - " + ArmMessageType.fromValue(id).description, ar); - } - - AmrMessage amrMessage = null; - switch (ArmMessageType.fromValue(id)) { - case AMR_TASK_COMPLETED: - AmrMessage taskCompletedMessage = JacksonUtils.parse(json, typeRef20010Message); - handleTaskCompletedMessage(agvItem, taskCompletedMessage.content); - break; - case AMR_TASK_STATUS: - handleTaskStatusMessage(agvItem, jw, json); - break; - case AMR_MODULE_TASK_STATUS: - amrMessage = JacksonUtils.parse(json, typeRef20012Message); - break; - case AMR_LANDMARK: - AmrMessage landmarkMessage = JacksonUtils.parse(json, typeRef20020Message); - handleLandmarkMessage(agvItem, landmarkMessage.content); - break; - case AMR_ACK: - amrMessage = JacksonUtils.parse(json, typeRef20050Message); - break; - case AMR_STATUS: - AmrMessage statusMessage = JacksonUtils.parse(json, typeRef20060Message); - handleStatusMessage(agvItem, statusMessage.content); - break; - case AMR_HEARTBEAT: - AmrMessage heartbeatMessage = JacksonUtils.parse(json, typeRef20100Message); - // sendCmdHeartBeat(heartbeatMessage.content.VehicleId + ""); - handleHeartbeatMessage(agvItem, heartbeatMessage.content); - break; - case AMR_BOOT: - amrMessage = JacksonUtils.parse(json, typeRef20147Message); - break; - case AMR_SHUTDOWN: - amrMessage = JacksonUtils.parse(json, typeRef20148Message); - break; - case AMR_APP_START: - amrMessage = JacksonUtils.parse(json, typeRef20149Message); - break; - case AMR_ONLINE: - AmrMessage onlineMessage = JacksonUtils.parse(json, typeRef20150Message); - this.handleAmrOnlineMessage(agvItem, onlineMessage.content); - this.sendCmdConfig(agvId, agvItem.getConfig()); - break; - case AMR_OFFLINE: - AmrMessage offlineMessage = JacksonUtils.parse(json, typeRef20200Message); - this.handleAmrOfflineMessage(agvItem, offlineMessage.content); - break; - case AMR_EXCEPTION: - amrMessage = JacksonUtils.parse(json, typeRef20250Message); - break; - default: -// log.error("未知消息:{}", json); - break; - } - - - if (id != ArmMessageType.AMR_ACK.value && id != ArmMessageType.AMR_HEARTBEAT.value) { - sendCmdAck(agvId, seqNo); - } - } - - public PtrAgvItem getPtrAgvItem(String vehicleId) { - var executorItem = runtime.executorItemMap.get(vehicleId); - return (PtrAgvItem) executorItem; - } - - @SneakyThrows - private void publish(String topic, String payload, int id) { - if (id != RcsMessageType.RCS_ACK.value && id != RcsMessageType.RCS_HEARTBEAT.value) { - var list = Splitter.on("\n").splitToList(new JsonWrapper(payload).toString()); - String[] ar = new String[list.size()]; - list.toArray(ar); - // BannerUtils.printConfig(log, "MQTT 发送报文 [" + id + "] RcsMessageType." + RcsMessageType.fromValue(id) + " - " + RcsMessageType.fromValue(id).description, ar); - } - log.debug("发送消息: {}", payload); - ptrMqttClient.publish(topic, payload); - } - - /** - * 发送任务 - * - * @param vehicleId 设备id - * @param rcsTaskMessage 任务信息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdTask(String vehicleId, RcsTaskMessage rcsTaskMessage) throws JsonProcessingException, MqttException { - // 记录发送时间 - lastMessageTimeMap.put(vehicleId, System.currentTimeMillis()); - - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_TASK.value; - baseMessage.content = rcsTaskMessage; - String json = JacksonUtils.toJson(baseMessage); - - // log.info("sendCmd10010: {}", json); - // log.debug("Sending task to {}: {}", vehicleId, json); - - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送SR消息 - * - * @param vehicleId 设备id - * @param rcsSRMessage SR消息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdSR(String vehicleId, RcsSRMessage rcsSRMessage) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_SR.value; - baseMessage.content = rcsSRMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送应答消息 - * - * @param vehicleId 设备id - * @param seqNo 被应答的消息序号 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdAck(String vehicleId, int seqNo) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - RcsAckMessage rcsAckMsg = new RcsAckMessage(); - rcsAckMsg.SeqNo = seqNo; - baseMessage.id = RcsMessageType.RCS_ACK.value; - baseMessage.content = rcsAckMsg; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送旋转货架消息 - * - * @param vehicleId 设备id - * @param rcsRotateRackMessage 旋转货架消息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdRotateRack(String vehicleId, RcsRotateRackMessage rcsRotateRackMessage) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_ROTATE_RACK.value; - baseMessage.content = rcsRotateRackMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送旋转车身消息 - * - * @param vehicleId 设备id - * @param rcsRotateBodyMessage 旋转车身消息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdRotateBody(String vehicleId, RcsRotateBodyMessage rcsRotateBodyMessage) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_ROTATE_BODY.value; - baseMessage.content = rcsRotateBodyMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - // 发送控制卷帘门消息 10082 - public void sendCmdControlDoor(String vehicleId, RcsControlDoorMessage rcsControlDoorMessage) throws MqttException, JsonProcessingException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_CONTROL_DOOR.value; - baseMessage.content = rcsControlDoorMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送配置信息 - * - * @param vehicleId 设备id - * @param rcsConfigMessage 配置信息 - * @throws MqttException - * @throws JsonProcessingException - */ - public void sendCmdConfig(String vehicleId, RcsConfigMessage rcsConfigMessage) throws MqttException, JsonProcessingException { - AmrMessage baseMessage = new AmrMessage<>(); - baseMessage.id = RcsMessageType.RCS_CONFIG.value; - baseMessage.content = rcsConfigMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送心跳 - * - * @param vehicleId 设备id - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdHeartBeat(String vehicleId) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_HEARTBEAT.value; - baseMessage.content = new RcsHeartBeatMessage(); - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送状态查询消息 - * - * @param vehicleId 设备id - * @throws MqttException - * @throws JsonProcessingException - */ - public void sendCmdQueryStatus(String vehicleId) throws MqttException, JsonProcessingException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_QUERY_STATUS.value; - RcsQueryStatusMessage rcsQueryStatusMessage = new RcsQueryStatusMessage(this.runtime); - rcsQueryStatusMessage.SeqNo = getNewSeqNo(); - baseMessage.content = rcsQueryStatusMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - log.info("发送查询设备状态消息: {}", json); - } - - /** - * 发送取消任务消息 - * - * @param vehicleId 设备id - * @param seqNo 待取消的任务序号 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdCancelTask(String vehicleId, int seqNo) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_CANCEL_TASK.value; - baseMessage.content = new RcsCancelTaskMessage(seqNo); - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /** - * 发送设置小车坐标消息 - * - * @param vehicleId 设备id - * @param rcsSetLocationMessage 位置信息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdSetLocation(String vehicleId, RcsSetLocationMessage rcsSetLocationMessage) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_SET_LOCATION.value; - baseMessage.content = rcsSetLocationMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - - } - - /** - * 发送等待就绪消息 - * - * @param vehicleId 设备id - * @param rcsWaitMessage 等待消息 - * @throws JsonProcessingException - * @throws MqttException - */ - public void sendCmdWait(String vehicleId, RcsWaitMessage rcsWaitMessage) throws JsonProcessingException, MqttException { - BaseMessage baseMessage = new BaseMessage(); - baseMessage.id = RcsMessageType.RCS_WAIT.value; - baseMessage.content = rcsWaitMessage; - String json = JacksonUtils.toJson(baseMessage); - publish("/wcs_server/" + vehicleId, json, baseMessage.id); - } - - /////////////=============================== 新加入的代码 =========================================== - private final Map lastMessageTimeMap = Maps.newConcurrentMap(); - private final ScheduledExecutorService delayCalculator = Executors.newScheduledThreadPool(4); - - private void handleHeartbeatMessage(PtrAgvItem agvItem, AmrHeartbeatMessage message) { - agvItem.handleHeartbeat(message); - - // 计算延迟 - long now = System.currentTimeMillis(); - long netDelay = now - message.SendTime; - updateRedisNetDelay(agvItem.getId(), netDelay); - } - - private void handleAmrOnlineMessage(PtrAgvItem agvItem, AmrOnlineMessage message) { - agvItem.handleOnlineEvent(); - } - - private void handleAmrOfflineMessage(PtrAgvItem agvItem, AmrOfflineMessage message) { - agvItem.handleOfflineEvent(); - } - - private void handleTaskCompletedMessage(PtrAgvItem agvItem, AmrTaskCompletedMessage message) { - agvItem.taskCompleted(message.CurX, message.CurY, message.CurDirection, 4); - } - - private void handleLandmarkMessage(PtrAgvItem agvItem, AmrLandmarkMessage message) { - // 这是源逻辑,CurLogicX / CurLogicY / CurDirection 需要到 PtrAgvItem 中更新, 因为要触发事件 - agvItem.x = message.X; - agvItem.y = message.Y; - agvItem.orientation = message.CurOrientation; - agvItem.direction = PathUtils.amrAngleToDirection(message.CurOrientation); - agvItem.updatePosition(message.CurLogicX, message.CurLogicY, message.CurDirection); - } - - private void handleStatusMessage(PtrAgvItem agvItem, AmrStatusMessage message) { - // 更新位置. TODO 貌似不包含 direction 信息 - agvItem.updatePosition(message.CurLogicX, message.CurLogicY, agvItem.direction); - - agvItem.battery = new CurBatteryData(); - BeanCopyUtils.copyTo(message.CurBattery, agvItem.battery); - - agvItem.x = message.X; - agvItem.y = message.Y; - agvItem.orientation = message.CurOrientation; - agvItem.logicX = message.CurLogicX; - agvItem.logicY = message.CurLogicY; - agvItem.direction = PathUtils.amrAngleToDirection(message.CurOrientation); - // 更新Redis - agvItem.updateRedisStatus(); - } - - private void handleTaskStatusMessage(PtrAgvItem agvItem, JsonWrapper jw, String json) throws MqttException, JsonProcessingException { - - int EventId = jw.asInt("content", "EventId"); - // log.info("1-Received message: " + json); - switch (EventId) { - case 0: - case 2: - case 3: - case 5: - case 6: - case 7: - AmrMessage> taskStatusChangeDefault = JacksonUtils.parse(json, typeRef20011_defaultMessage); - AmrTaskStatusMessage statusMessage = taskStatusChangeDefault.content; - agvItem.updateDeviceTaskStatus((int) statusMessage.SeqNo, 0, 0, statusMessage.EventId); - break; - case 1: - AmrMessage> taskModeChange = JacksonUtils.parse(json, typeRef20011_1Message); - AmrTaskStatusMessage modeMessage = taskModeChange.content; - agvItem.updateDeviceTaskStatus((int) modeMessage.SeqNo, 0, 0, modeMessage.EventId); - agvItem.updateTaskMode(modeMessage.Info.TaskMode); - if (modeMessage.Info.TaskMode == 1) { - this.sendCmdConfig(agvItem.id, agvItem.getConfig()); - } - break; - case 4: - AmrMessage> taskCompleted = JacksonUtils.parse(json, typeRef20011_4Message); - AmrTaskStatusMessage completedMessage = taskCompleted.content; - agvItem.updateDeviceTaskStatus((int) completedMessage.SeqNo, completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, completedMessage.EventId); - // agvItem.logicX = completedMessage.Info.CurLogicX; - // agvItem.logicY = completedMessage.Info.CurLogicY; - // // agvStatusAndInfo.orientation = landmarkMessage.content.CurOrientation; - // agvItem.direction = taskCompleted.content.Info.CurDirection; -// agvItem.updateTask(completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, taskCompleted.content.Info.CurDirection, 4); - agvItem.updatePosition(completedMessage.Info.CurLogicX, completedMessage.Info.CurLogicY, taskCompleted.content.Info.CurDirection); - break; - case 8: - AmrMessage> taskTypeChange = JacksonUtils.parse(json, typeRef20011_8Message); - AmrTaskStatusMessage typeMessage = taskTypeChange.content; - agvItem.updateDeviceTaskStatus((int) typeMessage.SeqNo, 0, 0, typeMessage.EventId); - default: - break; - } - } - - private void updateRedisNetDelay(String agvId, long netDelay) { - String statusKey = "lcc:" + runtime.projectUuid + ":" + runtime.envId + ":rcs:id_" + agvId; - redis.hPut(statusKey, "NetDelay", String.valueOf(netDelay)); - } - - private final Set heartBeatSet = Sets.newConcurrentHashSet(); - - /** - * 注册心跳单元 - */ - public void registeHeartBeatSet(PtrAgvItem ptrAgvItem) { - this.heartBeatSet.add(ptrAgvItem.getId()); - } - - /** - * 注销心跳单元 - */ - public void unregisteHeartBeatSet(PtrAgvItem ptrAgvItem) { - this.heartBeatSet.remove(ptrAgvItem.getId()); - } - - // private final ScheduledExecutorService heartBeatMonitor = Executors.newSingleThreadScheduledExecutor(); - // - // private void startHeartBeatSendAndStatusMonitor() { - // heartBeatMonitor.scheduleAtFixedRate(() -> { - // String aliveKey = getRedisKey("alive"); - // if (!redis.kExists(aliveKey)) { - // handleOfflineEvent(); - // } else if (!isOnline) { - // handleOnlineEvent(); - // } - // }, 0, 1, TimeUnit.SECONDS); - // } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java b/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java deleted file mode 100644 index a740f5c..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.google.common.collect.Maps; - -import java.util.Collections; -import java.util.Map; - -/** - * AMR 任务模式 - */ -public enum AmrTaskMode { - /** - * 空闲模式 - */ - AMR_FREE_MODE(0, "空闲模式"), - /** - * 初始化模式 - */ - AMR_INIT_MODE(1, "初始化模式"), - /** - * 任务模式 - */ - AMR_TASK_MODE(2, "任务模式"), - /** - * 单动作模式 - */ - AMR_SINGLE_ACTION_MODE(3, "单动作模式"), - /** - * 手动模式 - */ - AMR_MANUAL_MODE(4, "手动模式"), - /** - * 遥控器模式 - */ - AMR_HANDSET_MODE(5, "遥控器模式"), - /** - * 充电模式 - */ - AMR_CHARGE_MODE(6, "充电模式"), - /** - * 任务被中断模式 - */ - AMR_TASK_INTERRUPT_MODE (7, "任务被中断模式"), - /** - * 自定义模式 - */ - AMR_CUSTOMIZE_MODE(8, "自定义模式"); - - // 枚举值映射 - private static final Map VALUE_MAP; - - static { - Map map = Maps.newHashMap(); - for (AmrTaskMode message : values()) { - map.put(message.value, message); - } - VALUE_MAP = Collections.unmodifiableMap(map); - } - - public final int value; - public final String description; - - AmrTaskMode(int value, String description) { - this.value = value; - this.description = description; - } - - /** - * 从整数值获取对应的枚举 - * - * @param value 整数值 - * @return 对应的枚举,如果找不到则返回 null - */ - public static AmrTaskMode fromValue(int value) { - return VALUE_MAP.get(value); - } - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/ArmMessageType.java b/servo/src/main/java/com/galaxis/rcs/ptr/ArmMessageType.java deleted file mode 100644 index 63c8913..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/ArmMessageType.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.google.common.collect.Maps; - -import java.util.Collections; -import java.util.Map; - -/** - * AMR 发送给 RCS 的消息类型枚举 - */ -public enum ArmMessageType { - /** - * 小车作业完成 - */ - AMR_TASK_COMPLETED(20010, "小车作业完成"), - /** - * 任务状态上报 - */ - AMR_TASK_STATUS(20011, "任务状态上报"), - /** - * 小车子模块任务状态 - */ - AMR_MODULE_TASK_STATUS(20012, "小车子模块任务状态"), - /** - * 地标报告 - */ - AMR_LANDMARK(20020, "地标报告"), - /** - * 消息应答 - */ - AMR_ACK(20050, "消息应答"), - /** - * 状态上报 - */ - AMR_STATUS(20060, "状态上报"), - /** - * 心跳 - */ - AMR_HEARTBEAT(20100, "心跳"), - /** - * 开机上报 - */ - AMR_BOOT(20147, "开机上报"), - /** - * 关机上报 - */ - AMR_SHUTDOWN(20148, "关机上报"), - /** - * 小车主程序启动 - */ - AMR_APP_START(20149, "小车主程序启动"), - /** - * 小车上线 - */ - AMR_ONLINE(20150, "小车上线"), - /** - * 小车离线 - */ - AMR_OFFLINE(20200, "小车离线"), - /** - * 异常上报 - */ - AMR_EXCEPTION(20250, "异常上报"); - - // 枚举值映射 - private static final Map VALUE_MAP; - - static { - Map map = Maps.newHashMap(); - for (ArmMessageType message : values()) { - map.put(message.value, message); - } - VALUE_MAP = Collections.unmodifiableMap(map); - } - - public final int value; - public final String description; - - ArmMessageType(int value, String description) { - this.value = value; - this.description = description; - } - - /** - * 从整数值获取对应的枚举 - * - * @param value 整数值 - * @return 对应的枚举,如果找不到则返回 null - */ - public static ArmMessageType fromValue(int value) { - return VALUE_MAP.get(value); - } - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/ControlMode.java b/servo/src/main/java/com/galaxis/rcs/ptr/ControlMode.java deleted file mode 100644 index d98fb17..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/ControlMode.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.galaxis.rcs.ptr; - -public enum ControlMode { - FULL_AUTO, - MANUAL, - SEMI_AUTO, -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/JacksonUtils.java b/servo/src/main/java/com/galaxis/rcs/ptr/JacksonUtils.java deleted file mode 100644 index 2850981..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/JacksonUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -@Slf4j -public class JacksonUtils { - private static final ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); - - private static final Map typeCache = new ConcurrentHashMap<>(); - - // 解析泛型对象(TypeReference方式) - public static T parse(String json, TypeReference typeRef) { - try { - return mapper.readValue(json, typeRef); - } catch (Exception e) { - log.error("JSON解析失败{}", json, e); - throw new RuntimeException("JSON解析失败", e); - } - } - - // 动态构建JavaType(支持嵌套泛型) - public static JavaType buildType(Class rawType, Class... parameterClasses) { - String cacheKey = buildCacheKey(rawType, parameterClasses); - return typeCache.computeIfAbsent(cacheKey, k -> - mapper.getTypeFactory().constructParametricType(rawType, parameterClasses) - ); - } - - // 解析List泛型(高频场景优化) - public static List parseList(String json, Class elementClass) { - try { - JavaType type = buildType(List.class, elementClass); - return mapper.readValue(json, type); - } catch (Exception e) { - throw new RuntimeException("List解析失败", e); - } - } - - // 解析Map泛型(Key为String) - public static Map parseMap(String json, Class valueClass) { - try { - JavaType type = mapper.getTypeFactory() - .constructMapType(Map.class, String.class, valueClass); - return mapper.readValue(json, type); - } catch (Exception e) { - throw new RuntimeException("Map解析失败", e); - } - } - - public static String toJson(Object obj) throws JsonProcessingException { - return mapper.writeValueAsString(obj); - } - - private static String buildCacheKey(Class rawType, Class... parameterClasses) { - StringBuilder key = new StringBuilder(rawType.getName()); - for (Class clazz : parameterClasses) { - key.append("#").append(clazz.getName()); - } - return key.toString(); - } - - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PosDirection.java b/servo/src/main/java/com/galaxis/rcs/ptr/PosDirection.java deleted file mode 100644 index 705d9b2..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PosDirection.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.galaxis.rcs.common.enums.LCCDirection; - -public record PosDirection(int logicX, - int logicY, - LCCDirection direction) { -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnector.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnector.java deleted file mode 100644 index 859cca1..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnector.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.galaxis.rcs.ptr; - -public abstract class PtrAgvConnector { - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnectorThread.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnectorThread.java deleted file mode 100644 index e6621b4..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvConnectorThread.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; -import com.galaxis.rcs.ptr.sendEntity.RcsTaskMessage; -import com.yvan.logisticsModel.LogisticsRuntime; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.paho.mqttv5.common.MqttException; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.LockSupport; - -@Slf4j -public class PtrAgvConnectorThread extends Thread { - private final AtomicBoolean running = new AtomicBoolean(false); - private final AtomicBoolean paused = new AtomicBoolean(false); - private final Object pauseLock = new Object(); - - private final Cl2DeviceConnector cl2DeviceConnector; - private final PtrAgvItem ptrAgvItem; - private final LogisticsRuntime logisticsRuntime; - private volatile int __currentTaskSeqNo = 0; - volatile PtrAgvDeviceTask __currentTask; - - public PtrAgvConnectorThread(PtrAgvItem ptrAgvItem, Cl2DeviceConnector cl2DeviceConnector, LogisticsRuntime logisticsRuntime) { - super("ExecutorConnector-" + ptrAgvItem.getId()); - this.cl2DeviceConnector = cl2DeviceConnector; - this.ptrAgvItem = ptrAgvItem; - this.logisticsRuntime = logisticsRuntime; - } - - @Override - public void run() { - running.set(true); - log.info("Connector thread started for executor: {}", this.ptrAgvItem.getId()); - - try { - float distance = 0; - int taskCount = 0; - - PtrAgvDeviceTask startTask = null; - RcsTaskMessage taskMessage = null; - - // 计算中的任务 - List computingTaskList = new ArrayList<>(); - while (running.get()) { - if (paused.get()) { - synchronized (pauseLock) { - while (paused.get()) { - pauseLock.wait(); - } - } - } - - PtrAgvDeviceTask currentTask = this.ptrAgvItem.deviceTaskQueue.take(); - if (startTask == null) { - startTask = currentTask; - taskMessage = new RcsTaskMessage(this.logisticsRuntime); - taskMessage.OperationType = startTask.operationType; - taskMessage.PickMode = startTask.pickMode; - taskMessage.GoNow = true; - taskMessage.StartX = startTask.startPoint.logicX; - taskMessage.StartY = startTask.startPoint.logicY; - taskMessage.Link = new ArrayList<>(); - } - currentTask.seqNo = taskMessage.SeqNo; - RcsTaskMessage.LinkData link = new RcsTaskMessage.LinkData(currentTask.endPoint.logicX, currentTask.endPoint.logicY, currentTask.speed); - taskMessage.Link.add(link); - taskCount++; - distance += euclideanDistance(currentTask.startPoint.tf[0], currentTask.endPoint.tf[0]); - computingTaskList.add(currentTask); - - - PtrAgvDeviceTask nextTask = this.ptrAgvItem.deviceTaskQueue.peek(); - if (currentTask.isGroupEnd - || (taskMessage.Link.size() > 0 && nextTask != null && ((startTask.speed > 0) != (nextTask.speed > 0) || startTask.direction != nextTask.direction)) // 下一个任务和开始任务方向不一致 - // 单向移动距离大于2m时并且点位数量大于1 如果碰到当前点位与任务结束点位相同且当前任务还有后续,则继续添加步骤(link)错开,避免任务发生歧义 - || (distance > 2 && taskCount > 1 && nextTask != null && currentTask.endPoint != currentTask.groupEndPoint)) { - taskMessage.OperationType = currentTask.operationType; - taskMessage.PickMode = currentTask.pickMode; - taskMessage.EndX = currentTask.groupEndPoint.logicX; - taskMessage.EndY = currentTask.groupEndPoint.logicY; - taskMessage.GoodsSlotDirection = currentTask.goodsSlotDirection; - taskMessage.GoodsSlotHeight = currentTask.goodsSlotHeight; - taskMessage.LinkCounts = (short) taskMessage.Link.size(); - taskMessage.ChargeDirection = currentTask.chargeDirection; - taskMessage.ChargeLocation = currentTask.chargeLocation; - taskMessage.EndDirection = currentTask.endDirection; - try { - // 发送任务 - this.__currentTaskSeqNo = taskMessage.SeqNo; - this.__currentTask = currentTask; - cl2DeviceConnector.sendTask(ptrAgvItem.getId(), taskMessage); - this.ptrAgvItem.runningDeviceTaskList.addAll(computingTaskList); - for (PtrAgvDeviceTask task : computingTaskList) { - task.taskStatus = 1; - task.taskGroupStatus = 1; - } - computingTaskList.clear(); - } catch (MqttException | JsonProcessingException e) { - log.error("Cl2DeviceConnector robotMove: id=" + ptrAgvItem.getId() + ", task=" + currentTask.movePlanTaskId, e); - } - distance = 0; - taskCount = 0; - taskMessage = null; - startTask = null; - - if (currentTask.isGroupEnd) { - // 当一组任务结束时,阻塞当前线程,等当前任务执组行完毕后在外部线程中唤醒 - LockSupport.park(); // 阻塞当前线程 - } else { - for (PtrAgvDeviceTask task : this.ptrAgvItem.runningDeviceTaskList) { - if (task.taskGroupStatus < 4) { - LockSupport.park(); // 阻塞当前线程 - break; - } - } - } - } - - } - } catch (InterruptedException e) { - System.out.println("Connector thread interrupted for executor: " + this.ptrAgvItem.getId()); - } finally { - System.out.println("Connector thread stopped for executor: " + this.ptrAgvItem.getId()); - } - } - - public int getCurrentTaskSeqNo() { - return __currentTaskSeqNo; - } - - /** - * 停止连接器线程 - */ - public void stopConnector() { - running.set(false); - this.interrupt(); // 中断阻塞状态 - } - - public void pauseProcessing() { - paused.set(true); - } - - public void resumeProcessing() { - paused.set(false); - synchronized (pauseLock) { - pauseLock.notifyAll(); - } - } - - /** - * 检查连接器是否在运行 - */ - public boolean isRunning() { - return running.get(); - } - - public static float euclideanDistance(float[] p1, float[] p2) { - if (p1.length != 3 || p2.length != 3) throw new IllegalArgumentException(); - float dx = p1[0] - p2[0]; - float dy = p1[1] - p2[1]; - float dz = p1[2] - p2[2]; - return (float) Math.sqrt(dx * dx + dy * dy + dz * dz); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvDeviceTask.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvDeviceTask.java deleted file mode 100644 index 3c83067..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvDeviceTask.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.yvan.logisticsModel.StaticItem; - -import java.util.HashSet; -import java.util.Set; - -public class PtrAgvDeviceTask { - //该段目标点X坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 - public int x; - //该段目标点Y坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 - public int y; - // 该段行驶速度 Int16 mm/s - public int speed; - // 该段车头朝向 - public short direction; - // 该段起始点 - public StaticItem startPoint; - // 该段目标点 - public StaticItem endPoint; - // 分组起始点 - public StaticItem groupStartPoint; - // 分组目标点 - public StaticItem groupEndPoint; - // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) - public short operationType; - // 提升移栽货物拣货模式 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 - public short pickMode; - - // 目标货位朝向 - public short goodsSlotDirection; - - // 目标货位相对于地面的绝对高度 - public int goodsSlotHeight; - - //充电桩朝向UseBriefLocation UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short chargeDirection; - // 充电工位坐标和充电桩之间距离 UInt16 单位:mm - public Integer chargeLocation; - // 目标货架编号 String 仅做校验使用(仅接货用) - public String storageRacksNo; - // 结束朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short endDirection = null; - - /** 移动规划ID */ - public Long movePlanTaskId; - /** 转动取货放货充电等规划ID */ - public Set planTaskIdSet = new HashSet<>(); - /** 业务任务ID */ - public Long bizTaskId; - // 作业序号 发送给小车的作业序号 - public int seqNo; - - // 任务状态 0创建 1任务模式改变 2任务接收成功 3任务开始 4已完成 5已取消 6已暂停 7已恢复 8任务已经变更 - public int taskStatus = 0; - public int taskGroupStatus = 0; - - // 任务分组结束标记 生成报文时作为判断依据 - public boolean isGroupEnd = false; - public int checkLogicX; - public int checkLogicY; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java deleted file mode 100644 index fd5518f..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java +++ /dev/null @@ -1,889 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.galaxis.rcs.common.entity.RcsTaskPlan; -import com.galaxis.rcs.common.enums.*; -import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; -import com.galaxis.rcs.plan.PlanTaskSequence; -import com.galaxis.rcs.plan.path.PathUtils; -import com.galaxis.rcs.ptr.receiveEntity.AmrHeartbeatMessage; -import com.galaxis.rcs.ptr.receiveEntity.base.CurBatteryData; -import com.galaxis.rcs.ptr.sendEntity.RcsConfigMessage; -import com.galaxis.rcs.ptr.sendEntity.RcsSRMessage; -import com.galaxis.rcs.ptr.sendEntity.RcsSetLocationMessage; -import com.google.common.collect.Queues; -import com.yvan.entity.AgvStatusVo; -import com.yvan.entity.BasLocationVo; -import com.yvan.logisticsModel.ExecutorItem; -import com.yvan.logisticsModel.LogisticsRuntime; -import com.yvan.logisticsModel.StaticItem; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.clever.core.Conv; -import org.clever.core.json.JsonWrapper; -import org.clever.data.redis.Redis; -import org.clever.data.redis.RedisAdmin; - -import java.util.*; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.locks.LockSupport; - -/** - * 侧叉式AGV执行器 - */ -@Slf4j -public abstract class PtrAgvItem extends ExecutorItem { - private static final int BLOCKING_QUEUE_CAPACITY = 100; - private static final Redis redis = RedisAdmin.getRedis(); - - // ip - public volatile String ip; - // agv名称 - public volatile String agvName; - // agv类型 - public volatile String agvType; - // agv型号 - public volatile String agvModel; - // AMR功能型号 - public volatile String agvFnModel; - // 电池信息 - public volatile CurBatteryData battery; - // agv当前x坐标 - public volatile double x; - // agv当前y坐标 - public volatile double y; - // agv当前z坐标 - public volatile double z; - // 当前所在站点的逻辑X坐标 Int32 - public volatile int logicX; - // 当前所在站点的逻辑Y坐标 Int32 - public volatile int logicY; - // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public volatile short direction; - // agv当前转动角度值 - public volatile double orientation; - - private volatile boolean isPaused = false; - - private volatile PosDirection lastPausedPosition; - - // 任务模式 - @Getter - private volatile AmrTaskMode __taskMode; - - - // 执行中的任务 - public List runningDeviceTaskList = new ArrayList<>(); - - /** - * 当前执行的任务规划列表 - */ - public volatile PlanTaskSequence planTaskSequence; - - /** - * 当前执行的设备任务列表 - */ - final BlockingQueue deviceTaskQueue = Queues.newArrayBlockingQueue(BLOCKING_QUEUE_CAPACITY); - - final Cl2DeviceConnector cl2DeviceConnector = new Cl2DeviceConnector(this.runtime); - - public final AmrMessageHandler amrMessageHandler; - - /** - * 连接器线程 - */ - private final PtrAgvConnectorThread connectorThread; - - public PtrAgvItem(LogisticsRuntime logisticsRuntime, Map raw) { - super(logisticsRuntime, raw); - this.connectorThread = new PtrAgvConnectorThread(this, this.cl2DeviceConnector, logisticsRuntime); - this.amrMessageHandler = logisticsRuntime.amrMessageHandler; - } - - @Override - public boolean isRunning() { - return connectorThread.isRunning(); - } - - public abstract RcsConfigMessage getConfig(); - - - @Override - public void start() { - this.amrMessageHandler.registeHeartBeatSet(this); - - // 查询当前状态 - requestCurrentStatus(); - this.isRunning = true; - - this.startConnector(); - } - - @Override - public void stop() { - // 停止连接器线程 - stopConnector(); - - this.amrMessageHandler.unregisteHeartBeatSet(this); - - // 清理任务序列 - if (planTaskSequence != null) { - planTaskSequence = null; - } - // 清理设备任务队列 - deviceTaskQueue.clear(); - // 清理运行中的设备任务列表 - runningDeviceTaskList.clear(); - // 更新Redis状态 - updateRedisStatus(); - } - - 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"); - } - - this.planTaskSequence = taskSequence; - buildPlanToDeviceTask(); - this.runtime.eventManager.firePlanTaskSequenceAcceptEvent(this, taskSequence); - connectorThread.resumeProcessing(); - } - - public synchronized void pauseTask() { - if (planTaskSequence == null) { - throw new IllegalStateException("No active task to pause"); - } - - isPaused = true; - lastPausedPosition = new PosDirection(logicX, logicY, PathUtils.getDirectionByArmDirection(direction)); - - // 发送停止指令 - RcsSRMessage stopMsg = new RcsSRMessage(this.runtime); - stopMsg.SeqNo = amrMessageHandler.getNewSeqNo(); - stopMsg.OperationCode = 0; // 停止 - stopMsg.StopX = logicX; - stopMsg.StopY = logicY; - - try { - amrMessageHandler.sendCmdSR(this.getId(), stopMsg); - } catch (Exception e) { - log.error("Failed to send stop command to AGV {}", this.getId(), e); - } - - this.runtime.eventManager.firePlanTaskSequencePauseEvent(this, planTaskSequence); - } - - public synchronized void resumeTask() { - if (!isPaused) { - throw new IllegalStateException("Task is not paused"); - } - - // 检查当前位置是否与暂停位置一致 - if (Math.abs(logicX - lastPausedPosition.logicX()) > 1 || - Math.abs(logicY - lastPausedPosition.logicY()) > 1 || - PathUtils.getDirectionByArmDirection(direction) != lastPausedPosition.direction()) { - // 需要返回暂停位置 - throw new RuntimeException("AGV position has changed since pause, cannot resume task safely"); - } - - isPaused = false; - connectorThread.resumeProcessing(); - this.runtime.eventManager.firePlanTaskSequenceResumeEvent(this, planTaskSequence); - } - - @SneakyThrows - public synchronized void cancelTask() { - // 发送取消指令 - amrMessageHandler.sendCmdCancelTask(this.getId(), this.connectorThread.getCurrentTaskSeqNo()); - - if (planTaskSequence != null) { - planTaskSequence = null; - } - if (!deviceTaskQueue.isEmpty()) { - deviceTaskQueue.clear(); - } - // todo 取消运行中的设备任务 - runningDeviceTaskList.clear(); - // 唤醒连接器线程 - LockSupport.unpark(connectorThread); - this.runtime.eventManager.firePlanTaskSequenceCancelEvent(this, planTaskSequence); - } - - @SneakyThrows - public void setPositionAndDirection(int x, int y, short direction) { - RcsSetLocationMessage setLoc = new RcsSetLocationMessage(amrMessageHandler.getNewSeqNo()); - setLoc.X = (short) x; - setLoc.Y = (short) y; - setLoc.Direction = direction; - - amrMessageHandler.sendCmdSetLocation(this.getId(), setLoc); - } - - @SneakyThrows - public void requestCurrentStatus() { - amrMessageHandler.sendCmdQueryStatus(this.getId()); - } - - public boolean isFree() { - // return (this.logisticsRuntime.isRunning() && this.deviceTaskQueue.isEmpty() && this.connectorThread.isRunning()); - if (!this.runtime.isRunning()) { - return false; - } - if (planTaskSequence != null && !planTaskSequence.isAllCompleted()) { - return false; - } - if (!deviceTaskQueue.isEmpty()) { - return false; - } - if (this.isPaused) { - return false; - } - // if (this.taskMode != AmrTaskMode.AMR_FREE_MODE) { - // return false; - // } - return this.isOnline; - } - - public void taskCompleted(int logicX, int logicY, short direction, int taskStatus) { - - updatePosition(logicX, logicY, direction); - // 查找当前分组任务 - for (PtrAgvDeviceTask task : runningDeviceTaskList) { - task.taskGroupStatus = taskStatus; - if (taskStatus == 4) { - if (task.taskStatus != 4) { - this.runtime.eventManager.fireDeviceTaskCompleteEvent(this, task); - task.taskStatus = 4; - } - - // 更新计划任务 - List planTaskList = planTaskSequence.taskList.stream().filter(pt -> task.movePlanTaskId.equals(pt.getPlanTaskId()) || task.planTaskIdSet.contains(pt.getPlanTaskId())).toList(); - for (RcsTaskPlan planTask : planTaskList) { - if (PlanTaskStatus.FINISHED.toString().equals(planTask.getPlanTaskStatus())) { - continue; - } - - planTask.setPlanTaskStatus(PlanTaskStatus.FINISHED.toString()); - this.runtime.eventManager.firePlanTaskCompleteEvent(this, planTaskSequence, planTask); - } - } - } - - if (planTaskSequence != null && planTaskSequence.isAllCompleted()) { - this.runtime.eventManager.firePlanTaskSequenceCompleteEvent(this, planTaskSequence); - this.runningDeviceTaskList.clear(); - planTaskSequence = null; - } - LockSupport.unpark(connectorThread); - } - - public void updatePosition(int logicX, int logicY, short direction) { - int oldX = this.logicX; - int oldY = this.logicY; - short oldDirection = this.direction; - - this.logicX = logicX; - this.logicY = logicY; - this.direction = direction; - - LCCDirection oldLccDirection = PathUtils.getDirectionByArmDirection(oldDirection); - LCCDirection newLccDirection = PathUtils.getDirectionByArmDirection(direction); - - // 更新Redis - updateRedisStatus(); - - // 触发位置变化事件 - if (oldX != logicX || oldY != logicY) { - this.runtime.eventManager.firePosChangedEvent(this, - new PosDirection(logicX, logicY, newLccDirection), - new PosDirection(oldX, oldY, oldLccDirection)); - } - - if (oldDirection != direction) { - this.runtime.eventManager.fireDirectionChangedEvent(this, newLccDirection, oldLccDirection); - } - - boolean needCompute = false; - - // 从 runningDeviceTaskList 里面,找到完成到什么阶段 - // 比如 (1,2) -> (2,2) -> (3,2) , 如果 updatePosition=3,2 ,那么前2个任务都要完成 - int finishTargetIndex = -1; - if (this.runningDeviceTaskList != null && !this.runningDeviceTaskList.isEmpty() && - this.planTaskSequence != null && !this.planTaskSequence.isEmpty()) { - - for (int i = 0; i < runningDeviceTaskList.size(); i++) { - PtrAgvDeviceTask task = runningDeviceTaskList.get(i); - if (task.checkLogicX == logicX && task.checkLogicY == logicY && task.direction == this.direction) { - if (task.taskStatus < 4) { - finishTargetIndex = i; - } - break; - } - } - - if (finishTargetIndex >= 0) { - needCompute = true; - // 标记前面的任务都完成了 - for (int i = 0; i <= finishTargetIndex; i++) { - PtrAgvDeviceTask task = runningDeviceTaskList.get(i); - task.taskStatus = 4; // 标记为完成 - this.runtime.eventManager.fireDeviceTaskCompleteEvent(this, task); - - // 更新计划任务 - RcsTaskPlan planTask = planTaskSequence.getByPlanTaskId(task.movePlanTaskId); - if (planTask != null && !PlanTaskStatus.FINISHED.toString().equals(planTask.getPlanTaskStatus())) { - planTask.setPlanTaskStatus(PlanTaskStatus.FINISHED.toString()); - this.runtime.eventManager.firePlanTaskCompleteEvent(this, planTaskSequence, planTask); - } - } - - if (planTaskSequence.isAllCompleted()) { - this.runtime.eventManager.firePlanTaskSequenceCompleteEvent(this, planTaskSequence); - this.runningDeviceTaskList.clear(); - planTaskSequence = null; - } - } - } - - // BannerUtils.printConfig(log, "updatePosition", new String[]{ - // "logicX: " + logicX, - // "logicY: " + logicY, - // "direction: " + direction, - // "finishTargetIndex: " + finishTargetIndex, - // "runningDeviceSize:" + (this.runningDeviceTaskList == null ? "null" : this.runningDeviceTaskList.size()), - // "planTask:" + (this.planTaskSequence == null ? "null" : - // ("\n" + Joiner.on("\n").join((List) this.planTaskSequence.toPrettyMap().get("items"))) - // ) - // }); - - if (needCompute && this.runningDeviceTaskList.size() > 0) { - int index = this.runningDeviceTaskList.size() - 1; - PtrAgvDeviceTask task = this.runningDeviceTaskList.get(index); - if (task.groupEndPoint != task.endPoint) { - LockSupport.unpark(connectorThread); - } - } - } - - /** - * 更新设备任务状态 暂时没有处理任务取消相关的状态 - * - * @param seqNo - * @param x - * @param y - * @param messageStatus - */ - public void updateDeviceTaskStatus(int seqNo, int x, int y, int messageStatus) { - // 更新任务状态逻辑 - if (messageStatus < 2) { - return; - } - - // 任务完成逻辑,在地标检查里 - } - - public void updateTaskMode(int taskMode) { - this.setTaskMode(AmrTaskMode.fromValue(taskMode)); - } - - private void setTaskMode(AmrTaskMode taskMode) { - var originalMode = this.__taskMode; - this.__taskMode = taskMode; - this.runtime.eventManager.fireModeChangeEvent(this, taskMode, originalMode); - updateRedisStatus(); - } - - @SneakyThrows - public void updateRedisStatus() { - String statusKey = getRedisKey("status"); - var state = this.getState(); - var statusMap = new JsonWrapper(state).getInnerMap(); - redis.hPutAll(statusKey, statusMap); - } - - public void handleHeartbeat(AmrHeartbeatMessage heartbeat) { - // 更新在线状态 - String aliveKey = getRedisKey("alive"); - redis.vSet(aliveKey, this.runtime.serverId); - redis.kExpire(aliveKey, 5); // 5秒过期 - - // 更新状态信息 - if (this.battery == null) { - this.battery = new CurBatteryData(); - } - this.battery.SOC = heartbeat.Battery; - this.battery.setTemperature(heartbeat.Temperature.Battery); - - // 检查低电量 - if (this.battery.SOC < 20) { - this.runtime.eventManager.fireLowBatteryEvent(this); - } - - updateRedisStatus(); - } - - public void handleOnlineEvent() { - isOnline = true; - this.runtime.eventManager.fireOnlineEvent(this); - requestCurrentStatus(); - } - - public void handleOfflineEvent() { - isOnline = false; - this.runtime.eventManager.fireOfflineEvent(this); - } - - public String getTaskStatus() { - if (planTaskSequence == null) return "IDLE"; - if (isPaused) return "PAUSED"; - return "EXECUTING"; - } - - - /** - * 启动连接器线程 - */ - public void startConnector() { - if (!connectorThread.isRunning()) { - connectorThread.start(); - } - } - - /** - * 停止连接器线程 - */ - public void stopConnector() { - connectorThread.stop(); - } - - private static final int speed = 1000; - - /** - * 添加任务序列到当前执行器 - */ - protected void buildPlanToDeviceTask() { - PlanTaskSequence sequence = this.planTaskSequence; - LogisticsRuntime runtime = sequence.logisticsRuntime; - - short direction = this.direction; - - // 获取当前设备点位(逻辑点位) - StaticItem startPoint = runtime.getStaticItemByLogicXY(this.logicX, this.logicY); - if (startPoint == null) { - log.error("Cl2DeviceConnector robotMove: executorItem={}, task={}, agv当前点位为空 地图上没有标记", this.getId(), sequence.bizTask.getBizTaskId()); - } - StaticItem groupStartPoint = startPoint; - - Set rotationPlanTaskIdSet = new HashSet<>(); - - // 生成移动报文 - List deviceTaskList = new ArrayList<>(); - List> linkStore = null; - // 检查 planList 是不是全都是我的任务 - for (int i = 0; i < sequence.taskList.size(); i++) { - RcsTaskPlan plan = sequence.taskList.get(i); - String endPointId = plan.getTargetId(); - - if (plan.getPlanType().equals(PlanTaskType.MOVE.toString()) || plan.getPlanType().equals(PlanTaskType.MOVE_BACKWARD.toString())) { - // 获取目标点信息 - StaticItem pointItem = runtime.getStaticItemById(endPointId); - linkStore = (List>) pointItem.dt.get("linkStore"); - int d = -1; - if (startPoint.logicX == pointItem.logicX && startPoint.logicY != pointItem.logicY) { - d = pointItem.logicY >= startPoint.logicY ? CDirection.db : CDirection.dt; - if ((d > direction && d - CDirection.dl != direction) || (d < direction && d + CDirection.dl != direction)) { - throw new RuntimeException("方向错误"); - } - - } else if (startPoint.logicY == pointItem.logicY && startPoint.logicX != pointItem.logicX) { - d = pointItem.logicX >= startPoint.logicX ? CDirection.dr : CDirection.dl; - if ((d > direction && d - CDirection.dl != direction) || (d < direction && d + CDirection.dl != direction)) { - throw new RuntimeException("方向错误"); - } - // distance += Math.abs(pointItem.getTransformationX() - startPoint.getTransformationX()); - - } else if (startPoint.logicY == pointItem.logicY && startPoint.logicX == pointItem.logicX) { - d = direction; - // distance += Math.abs(pointItem.getTransformationX() - startPoint.getTransformationX()); - - } else { - throw new RuntimeException("无法识别的点位关系"); - } - PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); - deviceTask.x = pointItem.logicX; - deviceTask.y = pointItem.logicY; - deviceTask.speed = d == direction ? (speed) : (-speed); - deviceTask.direction = direction; - deviceTask.pickMode = 0; - deviceTask.startPoint = startPoint; - deviceTask.endPoint = pointItem; - deviceTask.bizTaskId = plan.getBizTaskId(); - deviceTask.movePlanTaskId = plan.getPlanTaskId(); - deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); - rotationPlanTaskIdSet.clear(); - // 行走任务完成后,检查用的字段 - deviceTask.checkLogicX = pointItem.logicX; - deviceTask.checkLogicY = pointItem.logicY; - deviceTaskList.add(deviceTask); - // 设置新的起点 - startPoint = pointItem; - - } else if (plan.getPlanType().equals(PlanTaskType.ROTATION.toString())) { - - float r = plan.getTargetRotation().floatValue(); - while (r > 360) { - r -= 360; - } - while (r < 0) { - r += 360; - } - - if (r >= 315 || r < 45) { - direction = CDirection.dr; - - } else if (r >= 45 && r < 135) { - direction = CDirection.dt; - - } else if (r >= 135 && r < 225) { - direction = CDirection.dl; - - } else if (r >= 225 && r < 315) { - direction = CDirection.db; - } - rotationPlanTaskIdSet.add(plan.getPlanTaskId()); - - } else if (plan.getPlanType().equals(PlanTaskType.LOAD.toString())) { - - if (deviceTaskList.isEmpty()) { - PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); - deviceTask.x = startPoint.logicX; - deviceTask.y = startPoint.logicY; - deviceTask.speed = speed; - deviceTask.direction = direction; - deviceTask.pickMode = 0; - deviceTask.startPoint = startPoint; - deviceTask.endPoint = startPoint; - deviceTask.bizTaskId = plan.getBizTaskId(); - deviceTask.movePlanTaskId = plan.getPlanTaskId(); - deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); - rotationPlanTaskIdSet.clear(); - // 行走任务完成后,检查用的字段 - deviceTask.checkLogicX = startPoint.logicX; - deviceTask.checkLogicY = startPoint.logicY; - deviceTaskList.add(deviceTask); - linkStore = (List>) startPoint.dt.get("linkStore"); - } - PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); - deviceTask.operationType = COperationType.transplantLoadAndUnload; - deviceTask.pickMode = CPickMode.load; - deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); - //处理取货高度 - StaticItem storeItem = runtime.getStaticItemById(endPointId); - Map storeItemRaw = storeItem.dt; - if (storeItemRaw.containsKey("bays")) { - List> bays = (List>) storeItemRaw.get("bays"); - Map bay = bays.get(plan.getTargetBay()); - List levelHeight = (List) bay.get("levelHeight"); - deviceTask.goodsSlotHeight = (int) Math.round(levelHeight.get(plan.getTargetLevel()) * 1000); - } else { - deviceTask.goodsSlotHeight = 1; - } - if (linkStore != null) { - for (Map store : linkStore) { - if (store.get("item").equals(plan.getTargetId()) && store.get("level").equals(plan.getTargetLevel()) && store.get("bay").equals(plan.getTargetBay()) && store.get("cell").equals(plan.getTargetCell())) { - short d = 0; - switch (store.get("direction").toString()) { - case "up": - d = 1; - break; - case "right": - d = 2; - break; - case "down": - d = 3; - break; - case "left": - d = 0; - break; - } - deviceTask.goodsSlotDirection = d; - } - } - } - - // 标记任务分组结束 - deviceTask.isGroupEnd = true; - deviceTask.groupEndPoint = deviceTask.endPoint; - deviceTask.groupStartPoint = groupStartPoint; - groupStartPoint = deviceTask.endPoint; - - } else if (plan.getPlanType().equals(PlanTaskType.UNLOAD.toString())) { - if (deviceTaskList.isEmpty()) { - PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); - deviceTask.x = startPoint.logicX; - deviceTask.y = startPoint.logicY; - deviceTask.speed = speed; - deviceTask.direction = direction; - deviceTask.pickMode = 0; - deviceTask.startPoint = startPoint; - deviceTask.endPoint = startPoint; - deviceTask.bizTaskId = plan.getBizTaskId(); - deviceTask.movePlanTaskId = plan.getPlanTaskId(); - deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); - rotationPlanTaskIdSet.clear(); - // 行走任务完成后,检查用的字段 - deviceTask.checkLogicX = startPoint.logicX; - deviceTask.checkLogicY = startPoint.logicY; - deviceTaskList.add(deviceTask); - linkStore = (List>) startPoint.dt.get("linkStore"); - } - PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); - deviceTask.operationType = COperationType.transplantLoadAndUnload; - deviceTask.pickMode = CPickMode.unload; - deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); - // 处理卸货高度 - StaticItem storeItem = runtime.getStaticItemById(endPointId); - Map storeItemRaw = storeItem.dt; - if (storeItemRaw.containsKey("bays")) { - List> bays = (List>) storeItemRaw.get("bays"); - Map bay = bays.get(plan.getTargetBay()); - List levelHeight = (List) bay.get("levelHeight"); - deviceTask.goodsSlotHeight = (int) Math.round(levelHeight.get(plan.getTargetLevel()) * 1000); - } else { - deviceTask.goodsSlotHeight = 1; - } - if (linkStore != null) { - for (Map store : linkStore) { - if (store.get("item").equals(plan.getTargetId()) && store.get("level").equals(plan.getTargetLevel()) && store.get("bay").equals(plan.getTargetBay()) && store.get("cell").equals(plan.getTargetCell())) { - short d = 0; - switch (store.get("direction").toString()) { - case "up": - d = 3; - break; - case "right": - d = 0; - break; - case "down": - d = 1; - break; - case "left": - d = 2; - break; - } - deviceTask.goodsSlotDirection = d; - } - } - } - // 标记任务分组结束 - deviceTask.isGroupEnd = true; - deviceTask.groupEndPoint = deviceTask.endPoint; - deviceTask.groupStartPoint = groupStartPoint; - groupStartPoint = deviceTask.endPoint; - - } else if (plan.getPlanType().equals(PlanTaskType.CHARGE.toString())) { - if (deviceTaskList.isEmpty()) { - PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); - deviceTask.x = startPoint.logicX; - deviceTask.y = startPoint.logicY; - deviceTask.speed = speed; - deviceTask.direction = direction; - deviceTask.pickMode = 0; - deviceTask.startPoint = startPoint; - deviceTask.endPoint = startPoint; - deviceTask.bizTaskId = plan.getBizTaskId(); - deviceTask.movePlanTaskId = plan.getPlanTaskId(); - deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); - rotationPlanTaskIdSet.clear(); - // 行走任务完成后,检查用的字段 - deviceTask.checkLogicX = startPoint.logicX; - deviceTask.checkLogicY = startPoint.logicY; - deviceTaskList.add(deviceTask); - } - PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); - deviceTask.operationType = COperationType.charge; - deviceTask.planTaskIdSet.add(plan.getPlanTaskId()); - // 处理充电距离(车的充电口到充电器被压下后的距离、一般被压下20mm) - deviceTask.chargeDirection = 2; - deviceTask.chargeLocation = 200; - // 标记任务分组结束 - deviceTask.isGroupEnd = true; - deviceTask.groupEndPoint = deviceTask.endPoint; - deviceTask.groupStartPoint = groupStartPoint; - groupStartPoint = deviceTask.endPoint; - } - - if (!plan.getExecutorId().equals(this.getId())) { - throw new RuntimeException("plan not belong executor:" + this.getId() + ", " + plan.getExecutorId()); - } - - } - - if (deviceTaskList.isEmpty()) { - PtrAgvDeviceTask deviceTask = new PtrAgvDeviceTask(); - deviceTask.x = startPoint.logicX; - deviceTask.y = startPoint.logicY; - deviceTask.speed = speed; - deviceTask.direction = direction; - deviceTask.pickMode = 0; - deviceTask.startPoint = startPoint; - deviceTask.endPoint = startPoint; - // 行走任务完成后,检查用的字段 - deviceTask.checkLogicX = startPoint.logicX; - deviceTask.checkLogicY = startPoint.logicY; - deviceTaskList.add(deviceTask); - } - - // 标记任务分组结束 - PtrAgvDeviceTask deviceTask = deviceTaskList.get(deviceTaskList.size() - 1); - deviceTask.groupEndPoint = deviceTask.endPoint; - deviceTask.groupStartPoint = groupStartPoint; - deviceTask.isGroupEnd = true; - // 最后一个规划任务为旋转时需要添加一个endDirection - if (rotationPlanTaskIdSet.size() > 0) { - deviceTask.operationType = COperationType.move; - deviceTask.pickMode = CPickMode.normal; - deviceTask.endDirection = direction; - deviceTask.planTaskIdSet.addAll(rotationPlanTaskIdSet); - if (deviceTask.movePlanTaskId == null) { - deviceTask.movePlanTaskId = 0L; - } - rotationPlanTaskIdSet.clear(); - } - - // 反向标记任务组 - int lastIndex = deviceTaskList.size() - 1; - for (int i = deviceTaskList.size() - 1; i >= 0; i--) { - PtrAgvDeviceTask d = deviceTaskList.get(i); - if (d.isGroupEnd) { - lastIndex = i; - } else { - d.operationType = deviceTaskList.get(lastIndex).operationType; - d.pickMode = deviceTaskList.get(lastIndex).pickMode; - d.groupStartPoint = deviceTaskList.get(lastIndex).groupStartPoint; - d.groupEndPoint = deviceTaskList.get(lastIndex).groupEndPoint; - d.goodsSlotHeight = deviceTaskList.get(lastIndex).goodsSlotHeight; - d.goodsSlotDirection = deviceTaskList.get(lastIndex).goodsSlotDirection; - d.chargeDirection = deviceTaskList.get(lastIndex).chargeDirection; - d.chargeLocation = deviceTaskList.get(lastIndex).chargeLocation; - } - } - - deviceTaskQueue.addAll(deviceTaskList); - String json = JsonWrapper.toJson(deviceTaskList); - log.info("deviceTaskList: {}", json); - } - - public boolean isSamePosition(PosDirection startPos) { - return this.logicX == startPos.logicX() && this.logicY == startPos.logicY() && - PathUtils.getDirectionByArmDirection(this.direction) == startPos.direction(); - } - - private static class CDirection { - private static final short dr = 0; - private static final short db = 1; - private static final short dl = 2; - private static final short dt = 3; - } - - - private static class COperationType { - public static final short move = 0; - public static final short load = 1; - public static final short unpick = 2; - public static final short charge = 3; - public static final short transplantLoadAndUnload = 4; - public static final short rollerLoadAndUnload = 5; - } - - private static class CPickMode { - public static final short normal = 0; - public static final short load = 1; - public static final short unload = 2; - public static final short adjustHeight = 3; - public static final short adjustHeightToLoad = 5; - public static final short adjustHeightToUnload = 6; - } - - - /** - * 从 AMR 方向转换为 LCC 方向枚举 - * - * @return - */ - public LCCDirection getLCCDirection() { - return switch (direction) { - case 0 -> LCCDirection.RIGHT; - case 1 -> LCCDirection.DOWN; - case 2 -> LCCDirection.LEFT; - case 3 -> LCCDirection.UP; - default -> null; - }; - } - - public short getAmrDirection(LCCDirection lccDirection) { - return switch (lccDirection) { - case RIGHT -> 0; - case DOWN -> 1; - case LEFT -> 2; - case UP -> 3; - default -> -1; // 未知方向 - }; - } - - private String getRedisKey(String type) { - return String.format("lcc:%s:%s:device:%s:%s", - runtime.projectUuid, runtime.envId, this.getId(), type); - } - - public AgvStatusVo getState() { - var ptr = this; - - var state = new AgvStatusVo(); - state.setId(ptr.id); - state.setType(ptr.getT()); - state.setIsOnline(ptr.isOnline); - state.setIsSystemManaged(ptr.isSystemManaged); - - state.setX(ptr.x); - state.setY(ptr.y); - state.setZ(ptr.z); - state.setLogicX(ptr.logicX); - state.setLogicY(ptr.logicY); - - state.setDirection(PathUtils.getDirectionByArmDirection(ptr.direction)); - state.setOrientation(ptr.orientation); - state.setSoc(ptr.battery == null ? -1 : ptr.battery.SOC); - state.setMode(ptr.get__taskMode()); - state.setTaskStatus(ptr.getTaskStatus()); - - state.setIsBlocked(ptr.isBlocked); - if (ptr.planTaskSequence != null) { - state.setTaskCompleted(ptr.planTaskSequence.completedCount()); - state.setTaskTotalCount(ptr.planTaskSequence.taskTotalCount()); - state.setBizTaskId(ptr.planTaskSequence.bizTask.getBizTaskId()); - state.setBizTaskType(BizTaskType.fromString(ptr.planTaskSequence.bizTask.getBizType())); - state.setBizTaskStatus(BizTaskStatus.fromString(ptr.planTaskSequence.bizTask.getBizTaskStatus())); - state.setBizTaskFrom(ptr.planTaskSequence.bizTask.getTaskFrom()); - state.setBizTaskTo(ptr.planTaskSequence.bizTask.getTaskTo()); - state.setBizLpn(ptr.planTaskSequence.bizTask.getLpn()); - - state.setLoadBasLocationVo(ptr.planTaskSequence.loadBasLocationVo); - state.setUnloadBasLocationVo(ptr.planTaskSequence.unloadBasLocationVo); - } - - return state; - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java deleted file mode 100644 index 7c6e379..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.yvan.logisticsEnv.EnvConfig; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.clever.core.BannerUtils; -import org.eclipse.paho.mqttv5.client.*; -import org.eclipse.paho.mqttv5.common.MqttException; -import org.eclipse.paho.mqttv5.common.MqttMessage; -import org.eclipse.paho.mqttv5.common.packet.MqttProperties; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.CountDownLatch; - -@Slf4j -public class PtrMqttClient implements MqttCallback { - public final AmrMessageHandler amrMessageHandler; - public final EnvConfig.MqttConfig mqttConfig; - private final MqttClient clientForSend; - private final MqttClient client; - private final String clientId; - private CountDownLatch connectLatch = new CountDownLatch(1); - - - @SneakyThrows - public PtrMqttClient(AmrMessageHandler handler, EnvConfig.MqttConfig mqttConfig, String clientId) { - this.amrMessageHandler = handler; - this.mqttConfig = mqttConfig; - this.clientId = clientId; - - String brokerUrl = mqttConfig.getBrokerUrl(); // "tcp://10.10.203.239:1885" - String username = mqttConfig.getUsername(); // admin - String password = mqttConfig.getPassword(); // admin - - clientForSend = new MqttClient(brokerUrl, clientId + "_send"); // String clientId = "LUOYIFAN-PC_send" - client = new MqttClient(brokerUrl, clientId); // String clientId = "LUOYIFAN-PC" - MqttConnectionOptions options = new MqttConnectionOptions(); - options.setServerURIs(new String[]{brokerUrl}); - options.setAutomaticReconnect(true); - options.setUserName(username); - options.setPassword(password.getBytes()); - options.setConnectionTimeout(5000); - options.setKeepAliveInterval(20); - options.setExecutorServiceTimeout(5000); - - client.setCallback(this); - client.connect(options); - - clientForSend.connect(options); - connectLatch.await(); - - BannerUtils.printConfig(log, "PtrMqttClient MQTT 开启监听成功", new String[]{ - "brokerUrl: " + brokerUrl, - "userName: " + username, - "clientId: " + clientId, - "topic: /agv_robot/status"}); - - client.subscribe("/agv_robot/status", 0); - } - - @SneakyThrows - public void publish(String topic, String payloadString) { - MqttMessage message = new MqttMessage(payloadString.getBytes(StandardCharsets.UTF_8)); - message.setQos(0); - message.setRetained(false); - - if (this.clientForSend.isConnected()) { - this.clientForSend.publish(topic, message); - } else { - throw new RuntimeException("MQTT client is not connected, cannot publish message."); - } - log.info("Message published to topic {}", topic); - } - - @SneakyThrows - public static void main(String[] args) { - var config = new EnvConfig.MqttConfig(); - config.setBrokerUrl("tcp://10.10.203.239:1885"); - config.setUsername("admin"); - config.setPassword("admin"); - - PtrMqttClient mqttClient = new PtrMqttClient(null, config, "LUOYIFAN-PC"); - for (int i = 0; i < 100; i++) { - mqttClient.publish("/agv_robot/status", "Hello from Java " + i); - } - log.info("Message published successfully."); - } - - @Override - public void disconnected(MqttDisconnectResponse disconnectResponse) { - log.info("mqtt disconnected"); - } - - @Override - public void mqttErrorOccurred(MqttException exception) { - log.error("mqtt error occurred"); - } - - @Override - public void messageArrived(String topic, MqttMessage message) throws Exception { - switch (topic) { - case "/agv_robot/status": - try { - if (this.amrMessageHandler == null) { - log.info("amrMessageHandler is null, skipping message handling {}", new String(message.getPayload(), StandardCharsets.UTF_8)); - return; - } - this.amrMessageHandler.handleAgvRobotStatusMessage(message); - - } catch (Exception e) { - log.error("amrMessageHandler.handleAgvRobotStatusMessage 异常", e); - } - break; - default: - break; - } - } - - @Override - public void deliveryComplete(IMqttToken token) { - log.info("Message delivery complete: {}", token); - } - - @Override - public void connectComplete(boolean reconnect, String serverURI) { - // BannerUtils.printConfig(log, "MQTT 开启监听", new String[]{serverURI + " topic: /agv_robot/status"}); - log.info("MQTT client connected to server: {}", serverURI); - connectLatch.countDown(); // 放行 - } - - @Override - public void authPacketArrived(int reasonCode, MqttProperties properties) { - } - - @SneakyThrows - public void stop() { - if (client != null && client.isConnected()) { - client.disconnect(); - client.close(); - log.info("MQTT client disconnected and closed."); - } else { - log.warn("MQTT client is not connected, no action taken."); - } - - if(clientForSend != null && clientForSend.isConnected()) { - clientForSend.disconnect(); - clientForSend.close(); - log.info("MQTT clientForSend disconnected and closed."); - } else { - log.warn("MQTT clientForSend is not connected, no action taken."); - } - } - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/RcsMessageType.java b/servo/src/main/java/com/galaxis/rcs/ptr/RcsMessageType.java deleted file mode 100644 index 712b87b..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/RcsMessageType.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.galaxis.rcs.ptr; - -import com.google.common.collect.Maps; - -import java.util.Collections; -import java.util.Map; - -/** - * RCS消息类型枚举 - */ -public enum RcsMessageType { - /** - * AMR作业指令 - */ - RCS_TASK(10010, "AMR作业指令"), - /** - * 停止OR解除 - */ - RCS_SR(10040, "停止OR解除"), - /** - * 电文应答 - */ - RCS_ACK(10050, "电文应答"), - /** - * 配置信息 - */ - RCS_CONFIG(10060, "配置信息"), - /** - * 旋转货架 - */ - RCS_ROTATE_RACK(10080, "旋转货架"), - /** - * 旋转车身 - */ - RCS_ROTATE_BODY(10081, "旋转车身"), - /** - * 控制卷帘门 - */ - RCS_CONTROL_DOOR(10082, "控制卷帘门"), - /** - * 心跳 - */ - RCS_HEARTBEAT(10100, "心跳"), - /** - * 状态查询 - */ - RCS_QUERY_STATUS(10110, "状态查询"), - /** - * 取消已下发小车任务 - */ - RCS_CANCEL_TASK(10120, "取消已下发小车任务"), - /** - * 设置小车坐标 - */ - RCS_SET_LOCATION(10200, "设置小车坐标"), - /** - * 等待就绪 - */ - RCS_WAIT(19997, "等待就绪"); - - // 枚举值映射 - private static final Map VALUE_MAP; - - static { - Map map = Maps.newHashMap(); - for (RcsMessageType command : values()) { - map.put(command.value, command); - } - VALUE_MAP = Collections.unmodifiableMap(map); - } - - public final int value; - public final String description; - - RcsMessageType(int value, String description) { - this.value = value; - this.description = description; - } - - - /** - * 从整数值获取对应的枚举 - * - * @param value 整数值 - * @return 对应的枚举,如果找不到则返回 null - */ - public static RcsMessageType fromValue(int value) { - return VALUE_MAP.get(value); - } - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAckMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAckMessage.java deleted file mode 100644 index 89b4861..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAckMessage.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 消息应答 20050 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrAckMessage extends AmrCommonMessage { -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAppStartMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAppStartMessage.java deleted file mode 100644 index 930b068..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrAppStartMessage.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 小车主程序启动 20149 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrAppStartMessage extends AmrCommonMessage { - // 电量百分比 Uint8 - public short Battery; - // AMR底盘型号 String 对于底盘和功能一体的版本,由底盘型号便知道功能;对于通用底盘,底盘型号指定了底盘的版本 - public String AGVModel; - // AMR功能型号 String 底盘之上的工装的型号 - public String AGVFnModel; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrBootMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrBootMessage.java deleted file mode 100644 index 0108203..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrBootMessage.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 开机上报 20147 在开机后上报一次,此后AMR程序重启不会重新上报(与ID#20149的差异),除非人为清除内部记录已上报的标志。 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrBootMessage extends AmrCommonMessage { - // 电量百分比 Uint8 - public short Battery; - // AMR底盘型号 String 对于底盘和功能一体的版本,由底盘型号便知道功能;对于通用底盘,底盘型号指定了底盘的版本 - public String AGVModel; - // AMR功能型号 String 底盘之上的工装的型号 - public String AGVFnModel; - // 上电至今的毫秒数 Uint64 - public long Uptime; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrExceptionMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrExceptionMessage.java deleted file mode 100644 index af81fcd..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrExceptionMessage.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -import java.util.Map; - -// 异常上报 20250 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrExceptionMessage extends AmrCommonMessage { - // 异常代码 UInt8 1. 货架编号不匹配 2. 地标异常 3. 电量低 - public short ErrCode; - // 异常机构代码 UInt8 对于哪吒飞梭类的机型,增加MechNo用于指示异常具体是哪一层发生的。 MechNo: 1- 机构1^[1]^异常 2- 机构2异常 3- 机构3异常 - public short MechNo; - // 异常详情 Struct 根据不同的异常,字段不一样,比如针对ErrCode为2电量低的情况,ErrMsg中使用CurBattery标识当前电量; - public Map ErrMsg; - // 异常事件类型 UInt8 0:无 1:开始 2:更新 3:结束 4:开始并结束 - public short ErrEvtType; - // 异常等级 UInt8 0:Undetermined 12:Info 13:Warning 14:Critical 15:Fatal - public short ErrLevel; - // 异常生命周期 UInt8 0:易变的 1:一次性 2:持续性 3:任务期间 - public short ErrLifecycle; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrHeartbeatMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrHeartbeatMessage.java deleted file mode 100644 index 393acd3..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrHeartbeatMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -//心跳 20100 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrHeartbeatMessage extends AmrCommonMessage { - // 电量百分比 Uint8 - public short Battery; - // 上电至今的毫秒数 Uint64 - public long Uptime; - // static - public TemperatureData Temperature; - public static class TemperatureData { - // 电池温度 Double 单位:摄氏度 备注:一个电池可能有多个(不同型号的)温度传感器,目前只上报最高的温度 - public Double Battery; - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrLandmarkMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrLandmarkMessage.java deleted file mode 100644 index 4691a82..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrLandmarkMessage.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 地标报告 20020 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrLandmarkMessage extends AmrCommonMessage { - // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 - public double CurX; - // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 - public double CurY; - // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public short CurDirection; - // 当前所在站点的逻辑X坐标 Int32 - public int CurLogicX; - // 当前所在站点的逻辑Y坐标 Int32 - public int CurLogicY; - // 当前标准X坐标 double - public double X; - // 当前标准Y坐标 double - public double Y; - // 当前方向 Double 角度 - public double CurOrientation; - // 未知 - public int MarkerType; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrModuleTaskStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrModuleTaskStatusMessage.java deleted file mode 100644 index a06f963..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrModuleTaskStatusMessage.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 小车子模块任务状态 20012 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrModuleTaskStatusMessage extends AmrCommonMessage { - // 多机构^[1]^的拣货模式 UInt8[3] 数组形式,意义同"PickMode" - public short[] MPickMode; - // 子模块任务状态 UInt8[3] 数组形式,数组下标^\[1\]^分别对应各子模块。 0:无任务 2:任务中 3:任务准备中(已有任务,但还没有执行任务的条件) 5:任务异常 7:任务完成 其它:保留 - public short[] MechStatus; - // 多载货机构上每个机构上面货物的ID String[] 数组形式,分别对应各子模块上货箱的ID码的值,如果无货为"",如果解不出来为"unknown" - public String[] MStorageRacksNo; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOfflineMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOfflineMessage.java deleted file mode 100644 index 24b42fd..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOfflineMessage.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 小车离线 20200 注意:目前未实现此报文 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrOfflineMessage extends AmrCommonMessage { -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOnlineMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOnlineMessage.java deleted file mode 100644 index 53061ae..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrOnlineMessage.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 小车上线 20150 代表车已经完成初始化,可以接收任务了。 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrOnlineMessage extends AmrCommonMessage { - // 电量百分比 Uint8 - public short Battery; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrShutdownMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrShutdownMessage.java deleted file mode 100644 index 2a497bd..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrShutdownMessage.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -// 关机上报 20148 在收到关机信号后上报此消息。 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrShutdownMessage extends AmrCommonMessage { - // 电量百分比 Uint8 - public short Battery; - // 上电至今的毫秒数 Uint64 - public long Uptime; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrStatusMessage.java deleted file mode 100644 index f374087..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrStatusMessage.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; -import com.galaxis.rcs.ptr.receiveEntity.base.CurBatteryData; -import com.galaxis.rcs.ptr.receiveEntity.base.LocationData; - -// 状态上报 20060 -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrStatusMessage extends AmrCommonMessage { - - // 电池状态 - public CurBatteryData CurBattery; - // 当前方向 Double 角度 - public double CurOrientation; - // 当前所在站点的逻辑X坐标 Int32 - public int CurLogicX; - // 当前所在站点的逻辑Y坐标 Int32 - public int CurLogicY; - // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 - public double CurX; - // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 - public double CurY; - // 货架当前方向 Double - public double RackCurOrientation; - // 货架当前位置 Double - public double RackCurPosition; - // 货架号 String - public String StorageRacksNo; - // 多载货机构上每个机构上面货物的ID String[] - public String[] MStorageRacksNo; - // 任务模式 Byte - public short TaskMode; - // 当前标准X坐标 double - public double X; - // 当前标准Y坐标 double - public double Y; - // 当前货物数量。数组形式。 对于单滚筒等单个托盘的机型,只需关注数据0; 对于双滚筒,滚筒1的数量放到数据0中,滚筒2的货物数量放到数据1中。 其它机型以此类推。UInt16 [4] - public int[] GoodsQuantity; - // 异常数组,存放异常的所有异常ID UInt16 [4] - public int[] Exceptions; - // 是否已进行精准停靠(是否能在原地直接执行对接任务) bool - public boolean InDock; - // 初始化状态 bool - public boolean Initialized; - // 车载货位信息 - public LocationData[] GoodsSlots; - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskCompletedMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskCompletedMessage.java deleted file mode 100644 index a606a0f..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskCompletedMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; -import com.galaxis.rcs.ptr.receiveEntity.base.LocationData; -import com.galaxis.rcs.ptr.receiveEntity.base.SummaryData; - -// 小车作业完成 20010 -//@Data - -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrTaskCompletedMessage extends AmrCommonMessage { - - // 当前X坐标 UInt16 - public int CurX; - // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 - public int CurY; - // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public short CurDirection; - // 当前方向 Double 角度 - public double CurOrientation; - // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) 135:旋转货架 136:旋转车身 - public short OperationType; - // 作业结果 Int32 参考linux errno - public long OperationResult; - // 货物ID String 在肥波类车型中是货架二维码值;在飞梭车中是箱码(目前未传,未来可能会有);在皮带飞梭中是货物上贴的二维码的码值(如果检测到多个码,则以" - public String StorageRacksNo; - // 电量百分比 Uint8 - public short Battery; - // 任务描述 Object 目前仅在飞梭和侧叉车型的报文中有这个字段,字段详情见下文 - public SummaryData Summary; - // 车载货位信息 - public LocationData[] GoodsSlots; - - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskStatusMessage.java deleted file mode 100644 index 3c43c6d..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/AmrTaskStatusMessage.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.galaxis.rcs.ptr.receiveEntity.base.AmrCommonMessage; - -//@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class AmrTaskStatusMessage extends AmrCommonMessage { - // 事件ID UInt8 0:无变化 1:任务模式改变 2:任务接收成功 3:任务开始 4:任务完成 5:任务已取消 6:任务已停止 7:任务已恢复 8:任务已更变 - public short EventId; - // 任务模式 Byte - public short TaskMode; - // 任务信息 由事件ID决定 Object 默认消息(0,2,3,5,6,7):任务状态改变消息 1:任务模式消息 4:任务完成消息 8:任务类型改变消息 - public T Info; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/AmrCommonMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/AmrCommonMessage.java deleted file mode 100644 index c514bb1..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/AmrCommonMessage.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import lombok.Data; - -// 共同信息字段 -public class AmrCommonMessage { - // 作业序号 UInt32 从1开始,0作为超级序号使用,不参与序号规则判断 - public long SeqNo; - // AMR编号 UInt16 - public int VehicleId; - // 消息创建时间 UInt64 毫秒级时间戳 - public long CreateTime; - // 消息创建时主机的开机时长 UInt64 毫秒级时间戳 - public long CreateMonoTime; - // 发送消息的时间 UInt64 毫秒级时间戳 - public long SendTime; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/CurBatteryData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/CurBatteryData.java deleted file mode 100644 index fa8bace..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/CurBatteryData.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 电池状态 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class CurBatteryData { - // 充电电流 - public double ChargingCurrent; - // 放电电流 - public double DischargingCurrent; - // 电量 - public double SOC; - // 电压 - public double Voltage; - // 温度 - public double Temperature; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/GoodsData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/GoodsData.java deleted file mode 100644 index 40e74d9..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/GoodsData.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import lombok.Data; - -// 货物信息 -@Data -public class GoodsData { - // 货物类型 UInt 对于一类设备可能取放不同货物时有用;如果只有一类货物,则可以不(在地图或者RCS下发的任务报文中)指定,此种情况下报文中不包含此字段 - public int Category; - // 传感器检测到的货物ID String 比如飞梭通过摄像头检测到的箱码、FM系列通过对上摄像头检测到的货架底部二维码等;如果车型没配备可以检测货物ID的传感器,则报文中不包含此字段 - public String DetectedId; - // 上位系统传过来的货物ID String 通常上位传过来的ID应该跟检测到的ID一致,否则会报错;对于没有检测ID功能的车型,不做校验而只是回传该值;有些项目可能会希望两个ID分开,对应此类需求可以特别设置不校验两类ID;也许有些项目会同时传入两种ID,当前暂不支持;如果上位没传入ID,则报文中不包含此字段 - public String UpperSystemDefinedId; - // 高度等级 UInt8 部分车型能检测货物高度,等级从0(最矮,默认值)开始,每一级递增1,各个等级的具体含义与车型有关,需要另行约定;如果有传感器但是由于传感器异常等原因无法获取到检测结果,则设置该值为0xff,代表状态未知。 - public short HeightLevel; - // 长度等级 - public short LengthLevel; - // 宽度等级 - public short WidthLevel; - // 重量等级 - public short WeightLevel; - // 测算的重量,不一定准 Double 单位是千克 - public double ApproximateWeight; - // 货物在地图上的朝向 Double 角度(Degree)值 - public double Orientation; - // 货物相对机器人的位置 包含以下成员: OffsetX:Int32类型 OffsetY:Int32类型 Orientation:Double类型,用角度(Degree)表示 - public OffsetPosition RelativePosition; - // 检测到的货物状态冲突 [UInt8] 1:货物ID不匹配 2:货物高度不匹配 3:货物宽度不匹配 4:货物长度不匹配 5:应该有货但没检测到有货 6:应该没货但检测到有货 - public short[] DetectedStatusConflicts; - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/LocationData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/LocationData.java deleted file mode 100644 index 1153f1b..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/LocationData.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 货位信息 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class LocationData { - // 货位ID UInt8 从0开始,每款车自己定义的车载货位的ID - public short ID; - // 货位名称 String 每款车自己定义的货位的名称 - public String Name; - // 逻辑上是否应该有货 bool 有些车型有传感器来检测货物状态,这时实际的货物状态跟逻辑状态就可能不同 - public boolean ShouldHaveGoods; - // 检测到的货位状态 UInt8 0: 正常 1: 冲突,即传感器检测到的状态跟逻辑状态有冲突。逻辑上有货,实际无货,是一种冲突;逻辑上货的属性(比如高度)跟实际检测到的属性不同,也会产生冲突;对于一个货位有多个货物的情况,需要查看货物信息来查找具体是哪个货物出现了什么冲突 - public short DetectedStatus; - // 货位放货平面离地高度 Double - public double Height; - // 货位相对原点(初始化后货位所在位置)的相对位置 Object 包含以下成员: OffsetX:Double类型 OffsetY:Double类型 OffsetZ:Double类型,代表在高度上的位移 Orientation:Double类型,用角度(Degree)表示 - public OffsetPosition Position; - // 货物信息 Object - public GoodsData[] Goods; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/OffsetPosition.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/OffsetPosition.java deleted file mode 100644 index bbb019d..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/OffsetPosition.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 相对原点偏移 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class OffsetPosition { - // OffsetX:Double类型 OffsetY:Double类型 OffsetZ:Double类型,代表在高度上的位移 Orientation:Double类型,用角度(Degree)表示 - public double OffsetX; - public double OffsetY; - public double OffsetZ; - public double Orientation; - -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/SummaryData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/SummaryData.java deleted file mode 100644 index 4b92b8c..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/SummaryData.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 任务描述 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class SummaryData { - // 执行器(比如飞梭的载货台)任务概览列表 Array 车载多少个执行器,数组就有多少个成员 - public ActuatorsData[] Actuators; - - @Data - @JsonIgnoreProperties(ignoreUnknown = true) - public static class ActuatorsData { - // 执行器编号 Uint8 从1开始 - public short MechNo; - // 执行器名称 String - public String Name; - // 任务类型 UInt8 同下发任务中PickMode的定义 - public short PickMode; - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskCompletedData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskCompletedData.java deleted file mode 100644 index 943a0a2..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskCompletedData.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 任务状态上报 20011 中 EventId = 4:任务完成 任务完成消息 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class TaskCompletedData { - // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) 135:旋转货架 136:旋转车身 - public short OperationType; - // 作业结果 Int32 参考linux errno - public long OperationResult; - // 当前所在站点的逻辑X坐标 Int32 - public int CurLogicX; - // 当前所在站点的逻辑Y坐标 Int32 - public int CurLogicY; - // 当前X坐标 Double 当前实际位置在地图坐标系中的X坐标 - public double CurX; - // 当前Y坐标 Double 当前实际位置在地图坐标系中的Y坐标 - public double CurY; - // 当前方向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public short CurDirection; - // 当前方向 Double 角度 - public double CurOrientation; - // 货架号 String 在肥波类车型中是货架二维码值;在飞梭车中是箱码(目前未传,未来可能会有);在皮带飞梭中是货物上贴的二维码的码值(如果检测到多个码,则以" - public String StorageRacksNo; - // 货架朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public short StorageDirection; - // 任务描述 Object 目前仅在飞梭和侧叉车型的报文中有这个字段,字段详情见下文 - public SummaryData Summary; - // 电量百分比 Uint8 - public short Battery; - // 车载货位信息 - public LocationData[] GoodsSlots; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskModeChangeData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskModeChangeData.java deleted file mode 100644 index e311252..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskModeChangeData.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -//1: 任务模式改变消息 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class TaskModeChangeData { - // 上一个任务模式 Uint8 0: 空闲模式 1: 初始化模式 2: 任务模式 3: 单动作模式 4: 手动模式 5: 遥控器模式 6: 充电模式 7: 任务被中断模式 有任务,但未收到终点坐标 8: 自定义模式 - public short PrevTaskMode; - // 当前任务模式 Uint8 0: 空闲模式 1: 初始化模式 2: 任务模式 3: 单动作模式 4: 手动模式 5: 遥控器模式 6: 充电模式 7: 任务被中断模式 有任务,但未收到终点坐标 8: 自定义模式 - public short TaskMode; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskStatusChangeData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskStatusChangeData.java deleted file mode 100644 index 60a0352..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskStatusChangeData.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 0,2,3,5,6,7:任务状态改变消息 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class TaskStatusChangeData { - // 当前任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 - public short OperationType; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskTypeChangeData.java b/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskTypeChangeData.java deleted file mode 100644 index 7defb56..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/receiveEntity/base/TaskTypeChangeData.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.galaxis.rcs.ptr.receiveEntity.base; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -// 8: 任务类型改变消息 -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class TaskTypeChangeData { - // 上一个任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 - public short PrevOperationType; - // 当前任务类型 0: 运输 1: 接货 2: 卸货 3: 充电 4: 提升移栽取货或卸货 5: 滚筒取货或卸货(双向作业) 135: 旋转货架 136: 旋转车身 143: 卷帘门控制 224: 等待就绪 - public short OperationType; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/BaseMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/BaseMessage.java deleted file mode 100644 index 137fd28..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/BaseMessage.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -public class BaseMessage { - public int id; - public Object content; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsAckMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsAckMessage.java deleted file mode 100644 index be30515..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsAckMessage.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -// 电文应答 10050 -public class RcsAckMessage { - // 作业序号 UInt32 所要应答消息的SeqNo(对方的) - public int SeqNo; -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsCancelTaskMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsCancelTaskMessage.java deleted file mode 100644 index c659578..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsCancelTaskMessage.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -// 取消已下发小车任务 10120 -public class RcsCancelTaskMessage { - // 作业序号 UInt32 - public int SeqNo; - public RcsCancelTaskMessage(int seqNo) { - SeqNo = seqNo; - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsConfigMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsConfigMessage.java deleted file mode 100644 index cf6fb0f..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsConfigMessage.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -//配置信息 10060 -public class RcsConfigMessage { - // 作业序号 UInt32 - public int SeqNo; - // X坐标最大长度 UInt16 暂时未使用 - public int XLength = 1000; - // Y坐标最大长度 UInt16 暂时未使用 - public int YLength = 1000; - // 相邻地标间距 UInt16 单位:mm (目前等距) - public int Gap = 1000; - // 心跳间隔 UInt32 单位: s - public int HeartBeat = 60; - // 小车所有上报消息重试间隔(未收到应答消息时重发消息) UInt32 单位: s - public int MqRetryTime = 3; - - public RcsConfigMessage(LogisticsRuntime runtime, int xLength, int yLength, int gap, int heartBeat, int mqRetryTime) { - XLength = xLength; - YLength = yLength; - Gap = gap; - HeartBeat = heartBeat; - MqRetryTime = mqRetryTime; - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } - - public RcsConfigMessage(LogisticsRuntime runtime) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsControlDoorMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsControlDoorMessage.java deleted file mode 100644 index 5ada315..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsControlDoorMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -// 控制卷帘门 10082 -public class RcsControlDoorMessage { - // 作业序号 UInt32 - public int SeqNo; - // 卷帘状态 UInt8 0: 不控制(无动作) 1: 关闭状态 2: 半开状态 3: 全开状态 4: 停止(暂不支持) - public short CurtainCmd; - - public RcsControlDoorMessage(LogisticsRuntime runtime, short curtainCmd) { - CurtainCmd = curtainCmd; - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } - - public RcsControlDoorMessage(LogisticsRuntime runtime) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsHeartBeatMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsHeartBeatMessage.java deleted file mode 100644 index 91c6bc7..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsHeartBeatMessage.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -// 心跳 10100 -public class RcsHeartBeatMessage { -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsQueryStatusMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsQueryStatusMessage.java deleted file mode 100644 index e3d7036..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsQueryStatusMessage.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -//状态查询 10110 -public class RcsQueryStatusMessage { - // 作业序号 UInt32 - public int SeqNo; - - public RcsQueryStatusMessage(LogisticsRuntime runtime) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateBodyMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateBodyMessage.java deleted file mode 100644 index 9179f90..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateBodyMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -//旋转车身 10081 -public class RcsRotateBodyMessage { - // 作业序号 UInt32 - public int SeqNo; - // 车头朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 - public short Direction; - - public RcsRotateBodyMessage(LogisticsRuntime runtime, short direction) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - Direction = direction; - } - - public RcsRotateBodyMessage(LogisticsRuntime runtime) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateRackMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateRackMessage.java deleted file mode 100644 index 01ff2a6..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsRotateRackMessage.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -//旋转货架 10080 -public class RcsRotateRackMessage { - // 作业序号 UInt32 - public int SeqNo; - // 货架A面朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 - public short Direction; - - public RcsRotateRackMessage(LogisticsRuntime runtime, short direction) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - Direction = direction; - } - - public RcsRotateRackMessage(LogisticsRuntime runtime) { - SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSRMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSRMessage.java deleted file mode 100644 index 2850292..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSRMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -// 停止/解除 10040 -public class RcsSRMessage { - // 作业序号 UInt32 - public int SeqNo; - // 操作代码 Uint8 0-停止 1-解除 - public short OperationCode; - // 停止点X坐标 Uint16 - public int StopX; - // 停止点Y坐标 Uint16 - public int StopY; - - public RcsSRMessage(LogisticsRuntime runtime, short operationCode, int stopX, int stopY) { - this.OperationCode = operationCode; - this.StopX = stopX; - this.StopY = stopY; - this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } - - public RcsSRMessage(LogisticsRuntime runtime) { - this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSetLocationMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSetLocationMessage.java deleted file mode 100644 index 7a4b1e9..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsSetLocationMessage.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; - -// 设置小车坐标 10200 -public class RcsSetLocationMessage { - // 作业序号 UInt32 - public int SeqNo; - // X坐标 Uint16 - public int X; - // Y坐标 Uint16 - public int Y; - // 车头朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知(小车保持原车头方向) - public short Direction; - - public RcsSetLocationMessage(int seqNo, int x, int y, short direction) { - this.X = x; - this.Y = y; - this.Direction = direction; - this.SeqNo = seqNo; - } - - public RcsSetLocationMessage(int seqNo) { - this.SeqNo = seqNo; - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsTaskMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsTaskMessage.java deleted file mode 100644 index 3236f86..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsTaskMessage.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; -import lombok.AllArgsConstructor; - -import java.util.List; - -// AMR作业指令 10010 -public class RcsTaskMessage { - // 作业序号 UInt32 - public int SeqNo; - // 作业类型 UInt8 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) - public short OperationType; - //充电桩朝向UseBriefLocation UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short ChargeDirection; - // 充电工位坐标和充电桩之间距离 UInt16 单位:mm - public Integer ChargeLocation; - // 目标货架编号 String 仅做校验使用(仅接货用) - public String StorageRacksNo; - // 小车起始X坐标 UInt16 - public int StartX; - // 小车起始Y坐标 UInt16 - public int StartY; - // 小车目标X坐标 UInt16 - public int EndX; - // 小车目标Y坐标 UInt16 - public int EndY; - // 任务是否立即执行 bool 默认为true - public Boolean GoNow; - // 路径分段数 UInt8 - public Short LinkCounts; - // 路径分段信息 - public List Link; - // AMR内置货位ID(仅对多层移栽有意义)UInt8 1~N - public Short BuiltinSlotNo; - // 提升移栽货物拣货模式 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 - public Short PickMode; - // 目标货位相对于地面的绝对高度 UInt16 单位:mm - public Integer GoodsSlotHeight; - // 目标货位朝向 UInt8 朝向定义与充电桩朝向相同。 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short GoodsSlotDirection; - // 结束朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short EndDirection; - - // 多机构^[1]^的拣货模式 UInt8[3] 数组形式,意义同"PickMode" - public List MPickMode; - // 多机构^[1]^的目标货位高度 UInt16[3] 单位:mm - public List MGoodsSlotHeight; - // 多机构^[1]^的目标货位朝向 UInt8[3] 朝向定义与充电桩朝向相同。 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public List MGoodsSlotDirection; - // 多机构的目标货箱ID String[3] 仅做校验使用(仅接货用) - public List MStorageRacksNo; - // 滚筒1 运动操作 对于左右滚动的双滚筒机型,此滚筒为靠近车头的滚筒。 对于前后滚动的双滚筒机型,此滚筒为车身左侧的滚筒。 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 - public Short Roll1Motion; - // 滚筒2 运动操作 对于左右滚动的双滚筒机型,此滚筒为靠近车尾的滚筒。 对于前后滚动的双滚筒机型,此滚筒为车身右侧的滚筒。 对于单滚筒机型,此参数无意义。 UInt8 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 - public Short Roll2Motion; - // 与滚筒1对接的站台朝向 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short Roll1StationDirection; - // 与滚筒2对接的站台朝向 对于单滚筒机型,此参数无意义。 UInt8 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public Short Roll2StationDirection; - // 滚筒1目标货物长度 UInt16 单位:mm - public Integer Roll1GoodsLength; - // 滚筒2目标货物长度 对于单滚筒机型,此参数无意义。UInt16 单位:mm - public Integer Roll2GoodsLength; - // 滚筒1目标货物数量 UInt16 1~N - public Integer Roll1GoodsQuantity; - // 滚筒2目标货物数量 对于单滚筒机型,此参数无意义。 UInt16 1~N - public Integer Roll2GoodsQuantity; - // 多滚筒运动模式 UInt8[6] 数组形式,0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作 - public List MRollMotion; - // 多滚筒对接的站台朝向 UInt8[6] 0: X轴正向 1: Y轴正向 2: X轴负向 3: Y轴负向 15: 未知方向 - public List MRollStationDirection; - // 多滚筒目标货物数量 UInt16[6] 数组形式,意义同"RollGoodsQuantity" - public List MRollGoodsQuantity; - // 是否仅执行任务的准备部分 bool 默认为false,仅执行该动作的准备部分,如仅进行导航,调整托盘高度等,但不进行取放货操作 - public Boolean Preparing; - // 货架标识 uint32 车根据货架类型查询尺寸进行避障 - public Long RackTypeId; - // 终点自适应 bool 默认为false,为true时,会根据任务和对应器件的位置,自动调整停止点 - public Boolean EndSelfAdaption; - - - public RcsTaskMessage(LogisticsRuntime runtime) { - this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } - - public RcsTaskMessage(int seqNo) { - this.SeqNo = seqNo; - } - - @AllArgsConstructor - public static class LinkData { - //该段目标点X坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 - public int X; - //该段目标点Y坐标 UInt16 逻辑单位,乘以一定系数才是物理距离 - public int Y; - // 该段行驶速度 Int16 mm/s - public int Speed; - - } -} diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsWaitMessage.java b/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsWaitMessage.java deleted file mode 100644 index 8c14b6e..0000000 --- a/servo/src/main/java/com/galaxis/rcs/ptr/sendEntity/RcsWaitMessage.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.galaxis.rcs.ptr.sendEntity; - -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.yvan.logisticsModel.LogisticsRuntime; - -public class RcsWaitMessage { - // 作业序号 UInt32 - public int SeqNo; - // 等待时间(s)Double -1:结束等待(仅SLAM车支持) 0:持续等待(仅SLAM车支持) 大于0:等待对应的时间后返回成功 - public double Seconds; - - public RcsWaitMessage(LogisticsRuntime runtime, double seconds) { - this.Seconds = seconds; - this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } - - public RcsWaitMessage(LogisticsRuntime runtime) { - this.SeqNo = runtime.amrMessageHandler.getNewSeqNo(); - } -} diff --git a/servo/src/main/java/com/yvan/entity/AgvStatusVo.java b/servo/src/main/java/com/yvan/entity/AgvStatusVo.java index 22078e2..f294a01 100644 --- a/servo/src/main/java/com/yvan/entity/AgvStatusVo.java +++ b/servo/src/main/java/com/yvan/entity/AgvStatusVo.java @@ -3,7 +3,7 @@ package com.yvan.entity; 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.ptr.AmrTaskMode; +import com.galaxis.rcs.amr.AmrTaskMode; import lombok.Data; @Data diff --git a/servo/src/main/java/com/yvan/event/AgvEventManager.java b/servo/src/main/java/com/yvan/event/AgvEventManager.java index 9e78eff..8f7bc66 100644 --- a/servo/src/main/java/com/yvan/event/AgvEventManager.java +++ b/servo/src/main/java/com/yvan/event/AgvEventManager.java @@ -3,9 +3,9 @@ package com.yvan.event; import com.galaxis.rcs.common.entity.RcsTaskPlan; import com.galaxis.rcs.common.enums.LCCDirection; import com.galaxis.rcs.plan.PlanTaskSequence; -import com.galaxis.rcs.ptr.AmrTaskMode; -import com.galaxis.rcs.ptr.PosDirection; -import com.galaxis.rcs.ptr.PtrAgvDeviceTask; +import com.galaxis.rcs.amr.AmrTaskMode; +import com.galaxis.rcs.amr.PosDirection; +import com.galaxis.rcs.amr.PtrAgvDeviceTask; import com.yvan.logisticsModel.ExecutorItem; import java.util.Set; diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java index c2651c7..89a1024 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java @@ -7,8 +7,8 @@ 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; -import com.galaxis.rcs.ptr.PtrAgvItem; +import com.galaxis.rcs.amr.AmrMessageHandler; +import com.galaxis.rcs.amr.PtrAgvItem; import com.galaxis.rcs.task.TaskDispatchFactory; import com.galaxis.rcs.task.TaskService; import com.google.common.base.Joiner; diff --git a/servo/src/main/java/com/yvan/workbench/controller/LccController.java b/servo/src/main/java/com/yvan/workbench/controller/LccController.java index d7a14db..dab8be8 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/LccController.java +++ b/servo/src/main/java/com/yvan/workbench/controller/LccController.java @@ -1,7 +1,7 @@ package com.yvan.workbench.controller; import com.galaxis.rcs.common.enums.LCCDirection; -import com.galaxis.rcs.ptr.PtrAgvItem; +import com.galaxis.rcs.amr.PtrAgvItem; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.yvan.entity.AgvStatusVo; diff --git a/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java b/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java index 84235f3..2d27a43 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java +++ b/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java @@ -2,7 +2,7 @@ package com.yvan.workbench.controller; import com.galaxis.rcs.common.entity.LccBasLocation; import com.galaxis.rcs.common.entity.StoreLocation; -import com.galaxis.rcs.ptr.JacksonUtils; +import com.galaxis.rcs.amr.JacksonUtils; import com.yvan.workbench.SpringContext; import com.yvan.entity.LccProject; import com.yvan.workbench.service.LccMapService; diff --git a/servo/src/main/java/com/yvan/workbench/controller/RcsController.java b/servo/src/main/java/com/yvan/workbench/controller/RcsController.java index 66c3aa7..390d769 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/RcsController.java +++ b/servo/src/main/java/com/yvan/workbench/controller/RcsController.java @@ -8,7 +8,7 @@ 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.*; -import com.galaxis.rcs.ptr.PtrAgvItem; +import com.galaxis.rcs.amr.PtrAgvItem; import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.yvan.entity.BasLocationVo; diff --git a/servo/src/main/resources/logback-spring.xml b/servo/src/main/resources/logback-spring.xml index d2a0a9e..d33756c 100644 --- a/servo/src/main/resources/logback-spring.xml +++ b/servo/src/main/resources/logback-spring.xml @@ -93,7 +93,7 @@ - +