diff --git a/servo/src/main/java/com/galaxis/rcs/RCSService.java b/servo/src/main/java/com/galaxis/rcs/RCSService.java index c66103a..8ae56f4 100644 --- a/servo/src/main/java/com/galaxis/rcs/RCSService.java +++ b/servo/src/main/java/com/galaxis/rcs/RCSService.java @@ -28,6 +28,8 @@ import org.clever.data.jdbc.DaoFactory; import org.clever.data.jdbc.QueryDSL; import org.clever.data.jdbc.querydsl.utils.QueryDslUtils; +import java.lang.management.ManagementFactory; +import java.net.InetAddress; import java.util.Map; import static com.galaxis.rcs.common.query.QLccEnvInfo.lccEnvInfo; @@ -52,6 +54,7 @@ public class RCSService { * 加载所有自动启动的环境和楼层数据 * 并启动对应的环境 */ + @SneakyThrows private void createAutoStartEnv() { QueryDSL queryDSL = DaoFactory.getQueryDSL(); var list = queryDSL.select(QueryDslUtils.linkedMap( @@ -98,6 +101,7 @@ public class RCSService { param.setTimeRate(1); param.setVirtual(false); param.setEnvPayload(envPayload); + param.setClientId(InetAddress.getLocalHost().getHostName()); runtime.start(param); } 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 789b6ff..6a29965 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 @@ -27,11 +27,10 @@ public class Cl2DeviceConnector { } public void sendTask(String vehicleId, RcsTaskMessage rcsTaskMessage) throws MqttException, JsonProcessingException { - var list = Splitter.on("\n").splitToList(JsonWrapper.toJsonPretty(rcsTaskMessage)); - String[] ar = new String[list.size()]; - list.toArray(ar); - BannerUtils.printConfig(log, "CL2 发送报文", ar); - + // var list = Splitter.on("\n").splitToList(JsonWrapper.toJsonPretty(rcsTaskMessage)); + // String[] ar = new String[list.size()]; + // list.toArray(ar); + // BannerUtils.printConfig(log, "CL2 发送报文", ar); amrMessageHandler.sendCmdTask(vehicleId, rcsTaskMessage); } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java index 5b8beb3..e17c822 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java @@ -5,8 +5,12 @@ import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.common.entity.RcsTaskPlan; import com.galaxis.rcs.common.enums.PlanTaskStatus; import com.galaxis.rcs.common.enums.PlanTaskType; +import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.yvan.logisticsModel.LogisticsRuntime; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.clever.core.BannerUtils; import org.clever.core.id.SnowFlake; import org.clever.core.json.JsonWrapper; @@ -15,6 +19,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +@Slf4j public class PlanTaskSequence { @JsonIgnore public static final SnowFlake snowFlake = new SnowFlake(); @@ -27,7 +32,6 @@ public class PlanTaskSequence { public String lastWayPointId; public Float lastRotationAngle = null; - public boolean isFinished = false; public String lastLoadLpn = ""; public PlanTaskSequence(String executorId, LogisticsRuntime logisticsRuntime, RcsTaskBiz bizTask, String createBy) { @@ -103,7 +107,6 @@ public class PlanTaskSequence { // 添加完成动作 public RcsTaskPlan addFinish() { RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.FINISH.toString()); - this.isFinished = true; return task; } @@ -139,10 +142,59 @@ public class PlanTaskSequence { taskStr = "FINISH"; break; } + taskStr = taskStr + " STATE:" + task.getPlanTaskStatus(); list.add(taskStr); } jw.set("items", list); return jw.getInnerMap(); } + + /** + * 是不是所有的任务都完成了 + */ + public boolean isAllCompleted() { + boolean isAllComplete = true; + for (RcsTaskPlan task : taskList) { + if (PlanTaskType.valueOf(task.getPlanType()) != PlanTaskType.FINISH) { + if (!PlanTaskStatus.FINISHED.toString().equals(task.getPlanTaskStatus())) { + isAllComplete = false; + break; + } + } + } + return isAllComplete; + } + + public RcsTaskPlan getByPlanTaskId(Long planTaskId) { + for (RcsTaskPlan task : taskList) { + if (task.getPlanTaskId().equals(planTaskId)) { + return task; + } + } + return null; + } + + @SneakyThrows + public void savePlanTask(RcsTaskPlan planTask) { + //TODO: 保存数据库 + var jw = new JsonWrapper(planTask); + jw.set("isAllCompleted", this.isAllCompleted()); + + 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, "保存业务任务 planTask", ar); + } + + public boolean isEmpty() { + return this.taskList.isEmpty(); + } + + public int size() { + return this.taskList.size(); + } } diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java b/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java index 5e24bee..7d1611a 100644 --- a/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java +++ b/servo/src/main/java/com/galaxis/rcs/ptr/AmrMessageHandler.java @@ -14,17 +14,15 @@ import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.PtrAgvItem; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.clever.core.AppContextHolder; 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.eclipse.paho.mqttv5.client.MqttClient; +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.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Executors; @@ -65,10 +63,10 @@ public class AmrMessageHandler { private static final TypeReference> typeRef20250Message = new TypeReference>() { }; - private static final Redis redis = AppContextHolder.getBean("defaultRedis", Redis.class, true); + private static final Redis redis = RedisAdmin.getRedis(); public final LogisticsRuntime runtime; - public volatile PtrMqttClient ptrMqttClient; + private volatile PtrMqttClient ptrMqttClient; public int getNewSeqNo() { String redisKey = "lcc:rcs:" + runtime.projectUUID + ":" + runtime.envId + ":seqNo"; @@ -84,8 +82,8 @@ public class AmrMessageHandler { this.runtime = runtime; } - public void start(EnvPayload.MqttConfig mqttConfig) { - this.ptrMqttClient = new PtrMqttClient(this, mqttConfig); + public void start(EnvPayload.MqttConfig mqttConfig, String clientId) { + this.ptrMqttClient = new PtrMqttClient(this, mqttConfig, clientId); } public void stop() { @@ -162,7 +160,7 @@ public class AmrMessageHandler { break; case AMR_HEARTBEAT: AmrMessage heartbeatMessage = JacksonUtils.parse(json, typeRef20100Message); - sendCmdHeartBeat(heartbeatMessage.content.VehicleId + ""); + // sendCmdHeartBeat(heartbeatMessage.content.VehicleId + ""); handleHeartbeatMessage(agvItem, heartbeatMessage.content); break; case AMR_BOOT: @@ -209,7 +207,7 @@ public class AmrMessageHandler { BannerUtils.printConfig(log, "MQTT 发送报文 [" + id + "] RcsMessageType." + RcsMessageType.fromValue(id) + " - " + RcsMessageType.fromValue(id).description, ar); } - ptrMqttClient.client.publish(topic, payload.getBytes(StandardCharsets.UTF_8), 0, false); + ptrMqttClient.publish(topic, payload); } /** @@ -229,7 +227,7 @@ public class AmrMessageHandler { baseMessage.content = rcsTaskMessage; String json = JacksonUtils.toJson(baseMessage); - log.info("sendCmd10010: {}", json); + // log.info("sendCmd10010: {}", json); // log.debug("Sending task to {}: {}", vehicleId, json); publish("/wcs_server/" + vehicleId, json, baseMessage.id); @@ -425,6 +423,7 @@ public class AmrMessageHandler { // 这是源逻辑,CurLogicX / CurLogicY / CurDirection 需要到 PtrAgvItem 中更新, 因为要触发事件 agvItem.x = message.X; agvItem.y = message.Y; + agvItem.orientation = message.CurOrientation; agvItem.updatePosition(message.CurLogicX, message.CurLogicY, message.CurDirection); } @@ -479,6 +478,7 @@ public class AmrMessageHandler { 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); break; case 4: AmrMessage> taskCompleted = JacksonUtils.parse(json, typeRef20011_4Message); diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java b/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java new file mode 100644 index 0000000..8ade272 --- /dev/null +++ b/servo/src/main/java/com/galaxis/rcs/ptr/AmrTaskMode.java @@ -0,0 +1,82 @@ +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, "自定义模式"), + /** + * 主程序退出(关机或关服务)时会进入这个模式 + */ + AMR_SHUTDOWN_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/PtrMqttClient.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java index cea8883..bf43cb4 100644 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java +++ b/servo/src/main/java/com/galaxis/rcs/ptr/PtrMqttClient.java @@ -1,45 +1,92 @@ package com.galaxis.rcs.ptr; -import com.google.common.base.Splitter; import com.yvan.logisticsEnv.EnvPayload; -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.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.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; + @Slf4j public class PtrMqttClient implements MqttCallback { public final AmrMessageHandler amrMessageHandler; public final EnvPayload.MqttConfig mqttConfig; - public final MqttClient client; + private final MqttClient clientForSend; + private final MqttClient client; + private final String clientId; + private CountDownLatch connectLatch = new CountDownLatch(1); + @SneakyThrows - public PtrMqttClient(AmrMessageHandler handler, EnvPayload.MqttConfig mqttConfig) { + public PtrMqttClient(AmrMessageHandler handler, EnvPayload.MqttConfig mqttConfig, String clientId) { this.amrMessageHandler = handler; this.mqttConfig = mqttConfig; + this.clientId = clientId; - String brokerUrl = mqttConfig.getBrokerUrl(); - String username = mqttConfig.getUsername(); - String password = mqttConfig.getPassword(); - - client = new MqttClient(brokerUrl, mqttConfig.getClientId()); - client.setCallback(this); + 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.setAutomaticReconnect(true); options.setUserName(username); options.setPassword(password.getBytes()); + options.setConnectionTimeout(1); + options.setKeepAliveInterval(20); + options.setExecutorServiceTimeout(1); + client.setCallback(this); client.connect(options); + + clientForSend.connect(options); + connectLatch.await(); + + BannerUtils.printConfig(log, "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 {}: finish", topic); + } + + @SneakyThrows + public static void main(String[] args) { + var config = new EnvPayload.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"); @@ -55,7 +102,11 @@ public class PtrMqttClient implements MqttCallback { switch (topic) { case "/agv_robot/status": try { - amrMessageHandler.handleAgvRobotStatusMessage(message); + 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); @@ -68,11 +119,14 @@ public class PtrMqttClient implements MqttCallback { @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"}); + // BannerUtils.printConfig(log, "MQTT 开启监听", new String[]{serverURI + " topic: /agv_robot/status"}); + log.info("MQTT client connected to server: {}", serverURI); + connectLatch.countDown(); // 放行 } @Override @@ -81,10 +135,13 @@ public class PtrMqttClient implements MqttCallback { @SneakyThrows public void stop() { - if (client.isConnected()) { + 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."); } - client.close(); - log.info("MQTT client stopped"); } + } diff --git a/servo/src/main/java/com/yvan/logisticsEnv/EnvPayload.java b/servo/src/main/java/com/yvan/logisticsEnv/EnvPayload.java index c5b8fea..2692634 100644 --- a/servo/src/main/java/com/yvan/logisticsEnv/EnvPayload.java +++ b/servo/src/main/java/com/yvan/logisticsEnv/EnvPayload.java @@ -12,7 +12,6 @@ public class EnvPayload implements Serializable { @Data public static class MqttConfig { private String brokerUrl; - private String clientId; private String username; private String password; } diff --git a/servo/src/main/java/com/yvan/logisticsEnv/EnvStartParam.java b/servo/src/main/java/com/yvan/logisticsEnv/EnvStartParam.java index f984317..b9ed166 100644 --- a/servo/src/main/java/com/yvan/logisticsEnv/EnvStartParam.java +++ b/servo/src/main/java/com/yvan/logisticsEnv/EnvStartParam.java @@ -10,6 +10,8 @@ import lombok.Setter; @Setter public class EnvStartParam { + public String clientId; + /** * 是否虚拟仿真环境 */ diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java index 7fdbee6..6694ba4 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java @@ -176,7 +176,7 @@ public class LogisticsRuntime { this.logisticsEnv.start(param); // 启动 MQTT 监听 - this.amrMessageHandler.start(param.getEnvPayload().getMqtt()); + this.amrMessageHandler.start(param.getEnvPayload().getMqtt(), param.clientId); // 开启所有机器人的任务处理 Set executorTypes = Sets.newHashSet(); diff --git a/servo/src/main/java/com/yvan/logisticsModel/PtrAgvDeviceTask.java b/servo/src/main/java/com/yvan/logisticsModel/PtrAgvDeviceTask.java index 0eb806f..79a93ac 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/PtrAgvDeviceTask.java +++ b/servo/src/main/java/com/yvan/logisticsModel/PtrAgvDeviceTask.java @@ -38,4 +38,6 @@ public class PtrAgvDeviceTask { // 是否最后任务 public boolean isLastTask = false; + public int checkLogicX; + public int checkLogicY; } diff --git a/servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java b/servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java index 149c42f..98354aa 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/PtrAgvItem.java @@ -4,21 +4,21 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.galaxis.rcs.common.entity.RcsTaskPlan; import com.galaxis.rcs.common.enums.AgvEventType; import com.galaxis.rcs.common.enums.LCCDirection; +import com.galaxis.rcs.common.enums.PlanTaskStatus; import com.galaxis.rcs.common.enums.PlanTaskType; import com.galaxis.rcs.connector.cl2.Cl2DeviceConnector; import com.galaxis.rcs.plan.PlanTaskSequence; -import com.galaxis.rcs.ptr.AgvEventListener; -import com.galaxis.rcs.ptr.AmrMessageHandler; -import com.galaxis.rcs.ptr.ControlMode; -import com.galaxis.rcs.ptr.PosDirection; +import com.galaxis.rcs.ptr.*; 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.base.Joiner; import com.google.common.collect.Queues; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.clever.core.BannerUtils; import org.clever.core.json.JsonWrapper; import org.clever.data.redis.Redis; import org.clever.data.redis.RedisAdmin; @@ -63,6 +63,9 @@ public abstract class PtrAgvItem extends ExecutorItem { // agv当前转动角度值 public double orientation; + // 任务模式 + public AmrTaskMode taskMode; + private volatile boolean isManualMode = false; private volatile boolean isPaused = false; private volatile PosDirection lastPausedPosition; @@ -221,7 +224,19 @@ public abstract class PtrAgvItem extends ExecutorItem { public boolean isFree() { // return (this.logisticsRuntime.isRunning() && this.deviceTaskQueue.isEmpty() && this.connectorThread.isRunning()); - return this.runtime.isRunning() && planTaskSequence == null && deviceTaskQueue.isEmpty() && !isPaused; + if (!this.runtime.isRunning()) { + return false; + } + if (planTaskSequence != null && !planTaskSequence.isAllCompleted()) { + return false; + } + if (!deviceTaskQueue.isEmpty()) { + return false; + } + if (this.isPaused) { + return false; + } + return true; } public void updatePosition(int logicX, int logicY, short direction) { @@ -247,6 +262,62 @@ public abstract class PtrAgvItem extends ExecutorItem { fireEvent(AgvEventType.DIRECTION_CHANGED, this, oldDirection, direction); } + + 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) { + finishTargetIndex = i; + break; + } + } + + if (finishTargetIndex >= 0) { + needCompute = true; + // 标记前面的任务都完成了 + for (int i = 0; i <= finishTargetIndex; i++) { + PtrAgvDeviceTask task = runningDeviceTaskList.get(i); + + task.taskStatus = 4; // 标记为完成 + task.taskGroupStatus = 4; // 标记为任务组完成 + fireEvent(AgvEventType.DEVICE_TASK_COMPLETE, this, task); + + // 更新计划任务 + RcsTaskPlan planTask = planTaskSequence.getByPlanTaskId(task.planTaskId); + if (planTask != null) { + planTask.setPlanTaskStatus(PlanTaskStatus.FINISHED.toString()); + planTaskSequence.savePlanTask(planTask); + } + } + + if (planTaskSequence.isAllCompleted()) { + fireEvent(AgvEventType.PLAN_COMPLETE, this); + 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) { + LockSupport.unpark(connectorThread); + } } /** @@ -263,46 +334,11 @@ public abstract class PtrAgvItem extends ExecutorItem { return; } - boolean needCompute = true; - for (PtrAgvDeviceTask task : runningDeviceTaskList) { - if (task.seqNo == seqNo) { - task.taskGroupStatus = messageStatus; - if (task.x == x && task.y == y) { - task.taskStatus = 4; - } - } - if (task.taskGroupStatus < 3 /*|| task.taskStatus < 4*/) { - needCompute = false; - } - } - if (needCompute) { - LockSupport.unpark(connectorThread); - } - - // 如果是任务完成事件 - if (messageStatus == 4) { - fireEvent(AgvEventType.DEVICE_TASK_COMPLETE, this, this.connectorThread.__currentTask); - - if (isTaskSequenceComplete()) { - fireEvent(AgvEventType.PLAN_COMPLETE, this); - planTaskSequence = null; - } - } + // 任务完成逻辑,在地标检查里 } - /** - * 检查当前任务序列是否完成 - */ - public boolean isTaskSequenceComplete() { - if (planTaskSequence == null) { - return false; - } - for (PtrAgvDeviceTask task : runningDeviceTaskList) { - if (task.taskGroupStatus < 3 /*|| task.taskStatus < 4*/) { - return false; - } - } - return true; + public void updateTaskMode(int taskMode) { + } public void updateRedisStatus() { @@ -451,6 +487,9 @@ public abstract class PtrAgvItem extends ExecutorItem { deviceTask.endPoint = pointItem; deviceTask.bizTaskId = plan.getBizTaskId(); deviceTask.planTaskId = plan.getPlanTaskId(); + // 行走任务完成后,检查用的字段 + deviceTask.checkLogicX = pointItem.logicX; + deviceTask.checkLogicY = pointItem.logicY; deviceTaskList.add(deviceTask); // 设置新的起点 startPoint = pointItem; @@ -626,6 +665,16 @@ public abstract class PtrAgvItem extends ExecutorItem { }; } + 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:rcs:%s_%s", runtime.projectUUID, runtime.envId, type, this.getId());