From 702549f5d846ae76cc005c56d03fd774a3caa341 Mon Sep 17 00:00:00 2001
From: L <L@132>
Date: 星期四, 23 四月 2026 14:23:01 +0800
Subject: [PATCH] *

---
 src/main/java/com/zy/core/thread/RgvThread.java |  943 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 884 insertions(+), 59 deletions(-)

diff --git a/src/main/java/com/zy/core/thread/RgvThread.java b/src/main/java/com/zy/core/thread/RgvThread.java
index 7a15cab..e923ce4 100644
--- a/src/main/java/com/zy/core/thread/RgvThread.java
+++ b/src/main/java/com/zy/core/thread/RgvThread.java
@@ -5,17 +5,24 @@
 import HslCommunication.Profinet.Siemens.SiemensPLCS;
 import HslCommunication.Profinet.Siemens.SiemensS7Net;
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.core.common.DateUtils;
 import com.core.common.SpringUtils;
+import com.zy.asrs.entity.BasCircularShuttle;
 import com.zy.asrs.entity.BasRgv;
+import com.zy.asrs.entity.BasRgvErrLog;
 import com.zy.asrs.entity.BasRgvOpt;
+import com.zy.asrs.service.BasCircularShuttleService;
+import com.zy.asrs.service.BasDevpPositionService;
+import com.zy.asrs.service.BasRgvErrLogService;
 import com.zy.asrs.service.BasRgvOptService;
 import com.zy.asrs.service.BasRgvService;
-import com.zy.asrs.utils.RouteUtils;
+import com.zy.asrs.utils.NumUtils;
 import com.zy.core.ThreadHandler;
 import com.zy.core.cache.MessageQueue;
 import com.zy.core.cache.OutputQueue;
-import com.zy.core.enums.RgvStatusType;
+import com.zy.core.cache.SlaveConnection;
+import com.zy.core.enums.RgvModeType;
 import com.zy.core.enums.RgvTaskModeType;
 import com.zy.core.enums.SlaveType;
 import com.zy.core.model.RgvSlave;
@@ -26,7 +33,8 @@
 import lombok.extern.slf4j.Slf4j;
 
 import java.text.MessageFormat;
-import java.util.Date;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * RGV绾跨▼
@@ -47,6 +55,36 @@
      * 宸ヤ綅2澶嶄綅淇″彿
      */
     private boolean resetFlag2 = false;
+    private boolean connectRgv = false;
+    private boolean alarmChangeSign = false;
+    private boolean csSign = true;//娴嬭瘯鏍囪
+
+    /** 妯℃嫙绉诲姩閫熷害锛歅LC杞ㄩ亾鍗曚綅/tick锛�200ms锛夛紝5000鍗曚綅鈮�2.5m/s */
+    private static final long SIM_CS_MOVE_STEP = 5000;
+    /** 鐜舰杞ㄩ亾鎬婚暱锛圥LC杞ㄩ亾鍗曚綅锛� */
+    private static final long PERIMETER = 1737000;
+    /** 閬胯瀹夊叏璺濈 */
+    private static final long AVOIDANCE_DISTANCE = 50000;
+
+    /** 妯℃嫙浠诲姟闃舵 */
+    private enum SimPhase { IDLE, MOVING, WAITING_AT_SOURCE }
+
+    /** 妯℃嫙浠诲姟鏁版嵁 */
+    @Data
+    static class SimTask {
+        int taskNo;
+        short sourceSta;
+        short destSta;
+        short mode;          // 浠诲姟妯″紡锛�1=鍙栬揣 2=鏀捐揣 3=鍙栨斁璐� 5=婕父
+        SimPhase phase;
+        long targetPos;      // 鐩爣杞ㄩ亾浣嶇疆
+        long startPos;       // 璧峰杞ㄩ亾浣嶇疆
+        long destPos;        // 鏀捐揣绔欎綅缃紙浠呭彇鏀捐揣浠诲姟浣跨敤锛�
+        long waitStartTime;  // 鍒拌揪鍙栬揣绔欏悗鐨勭瓑寰呭紑濮嬫椂闂�
+    }
+
+    /** 鍏ㄥ眬妯℃嫙浠诲姟琛細rgvNo 鈫� SimTask锛岀嚎绋嬪畨鍏� */
+    static final Map<Integer, SimTask> simTasks = new ConcurrentHashMap<>();
 
     public RgvThread(RgvSlave slave) {
         this.slave = slave;
@@ -55,41 +93,217 @@
     @Override
     @SuppressWarnings("InfiniteLoopStatement")
     public void run() {
-        this.connect();
+        if (csSign) {
+            connectRgv = true; // 妯℃嫙妯″紡璺宠繃PLC杩炴帴
+        } else {
+            connectRgv = this.connect();
+        }
+
+        // 鍚姩绾跨▼鑷姩閲嶈繛
+        new Thread(this::rgvConnect).start();
+
+        // 鍚姩璇绘暟鎹嚎绋�
+        new Thread(this::readStatusRgv).start();
+
+        // 鍚姩浠诲姟涓嬪彂绾跨▼
+        new Thread(this::taskIssued).start();
+
+        // 妯℃嫙妯″紡锛氬惎鍔ㄦā鎷熻繍琛岀嚎绋�
+        if (csSign) {
+            new Thread(this::simThreadRun).start();
+        }
+    }
+
+
+    /**
+     * 浠诲姟涓嬪彂
+     */
+    private void taskIssued() {
         while (true) {
             try {
+                if(!connectRgv){
+                    try {
+                        Thread.sleep(1000L);
+                    } catch (Exception e){
+
+                    }
+                    continue;
+                }
                 int step = 1;
                 Task task = MessageQueue.poll(SlaveType.Rgv, slave.getId());
                 if (task != null) {
                     step = task.getStep();
                 }
-                switch (step) {
-                    // 璇绘暟鎹�
-                    case 1:
-                        readStatus();
-                        break;
-                    //宸ヤ綅1鍐欏叆鏁版嵁
-                    case 2:
-                        write((RgvCommand) task.getData());
-                        break;
-                    default:
-                        break;
+                if (csSign) {
+                    // ===== 妯℃嫙妯″紡锛氫笉鍐橮LC锛岀敤妯℃嫙鏂规硶鏇夸唬 =====
+                    switch (step) {
+                        case 1:
+                            taskCompleteCS();
+                            break;
+                        case 2:
+                            RgvCommand command2 = (RgvCommand) task.getData();
+                            rgvOpt(command2);
+                            writeCS(command2);
+                            rgvProtocol.setTaskNo1(command2.getTaskNo1());
+                            break;
+                        case 3:
+                            RgvCommand command = (RgvCommand) task.getData();
+                            if (null == command) {
+                                command = new RgvCommand();
+                            }
+                            command.setRgvNo(slave.getId());
+                            command.setTaskNo1((short) 0);
+                            command.setAckFinish1((short) 1);
+                            command.setTaskMode1(RgvTaskModeType.NONE);
+                            command.setSourceStaNo1((short)0);
+                            command.setDestinationStaNo1((short)0);
+                            rgvOpt(command);
+                            write3CS(command);
+                            break;
+                        case 4:
+                            RgvCommand command4 = (RgvCommand) task.getData();
+                            rgvOpt(command4);
+                            write4CS(command4);
+                            break;
+                        case 5:
+                            Long aLong = (Long) task.getData();
+                            rgvOpt(aLong);
+                            write5CS(aLong);
+                            break;
+                        default:
+                            break;
+                    }
+                } else {
+                    // ===== 鐪熷疄妯″紡锛氬啓PLC =====
+                    switch (step) {
+                        //婕父浠诲姟瀹屾垚淇″彿
+                        case 1:
+//                        readStatus();
+                            taskComplete();
+                            break;
+                        //宸ヤ綅1鍐欏叆鏁版嵁
+                        case 2:
+                            RgvCommand command2 = (RgvCommand) task.getData();
+                            rgvOpt(command2);
+                            write(command2);
+                            break;
+                        // 澶嶄綅
+                        case 3:
+                            RgvCommand command = (RgvCommand) task.getData();
+                            if (null == command) {
+                                command = new RgvCommand();
+                            }
+                            command.setRgvNo(slave.getId()); // RGV缂栧彿
+                            command.setTaskNo1((short) 0); // 宸ヤ綔鍙�
+                            command.setAckFinish1((short) 1);  // 浠诲姟瀹屾垚纭浣�
+                            command.setTaskMode1(RgvTaskModeType.NONE); // 浠诲姟妯″紡
+                            command.setSourceStaNo1((short)0);     // 婧愮珯
+                            command.setDestinationStaNo1((short)0);     // 鐩爣绔�
+                            rgvOpt(command);
+                            write3(command);
+                            break;
+                        //宸ヤ綅1鍐欏叆鍙栨秷鏁版嵁
+                        case 4:
+                            RgvCommand command4 = (RgvCommand) task.getData();
+                            rgvOpt(command4);
+                            write4(command4);
+                            break;
+                        // 婕父
+                        case 5:
+                            Long aLong = (Long) task.getData();
+                            rgvOpt(aLong);
+                            write5(aLong);
+                            break;
+                        default:
+                            break;
+                    }
                 }
-                Thread.sleep(500);
+                Thread.sleep(50);
             } catch (Exception e) {
+                log.error("RGV鍐欑嚎绋嬪紓甯�"+e.getMessage());
 //                e.printStackTrace();
             }
 
         }
     }
 
+    private void rgvConnect() {
+        while (true) {
+            try {
+                Thread.sleep(1000);
+                if(!connectRgv){
+                    try {
+                        // 鏍规嵁瀹炴椂淇℃伅鏇存柊鏁版嵁搴�
+                        BasCircularShuttleService basCircularShuttleService = SpringUtils.getBean(BasCircularShuttleService.class);
+                        BasCircularShuttle basCircularShuttle = basCircularShuttleService.getOne(new QueryWrapper<BasCircularShuttle>().eq("rgv_no",  slave.getId()));
+                        if (basCircularShuttle.getStatus() != 0){
+                            continue;
+                        }
+                    } catch (Exception ignore) {
+
+                    }
+                    try {
+                        connectRgv = this.connect();
+                        Thread.sleep(100);
+                    } catch (Exception e){
+
+                    }
+                }
+            } catch (Exception e) {
+
+                log.error("rgv杩炴帴澶辫触锛侊紒锛� ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+                initRgv();
+//                e.printStackTrace();
+            }
+        }
+    }
+
+    private void readStatusRgv() {
+        while (true) {
+            try {
+                if(!connectRgv){
+                    try {
+                        Thread.sleep(1000L);
+                    } catch (Exception e){
+
+                    }
+                    initRgv();
+                    continue;
+                }
+                Thread.sleep(40);
+//                readStatus();
+                initRgv();
+            } catch (Exception e) {
+                log.error("RGV璇荤嚎绋嬪紓甯�"+e.getMessage());
+
+                log.error("RGV鏁版嵁璇诲彇绾跨▼寮傚父锛侊紒锛� ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+                initRgv();
+//                e.printStackTrace();
+            }
+
+        }
+
+    }
+
     /**
      * 鍒濆鍖朢GV鐘舵��
      */
     private void initRgv() {
+       if (csSign){
+           initRgvCS();
+       } else {
+           initRgvT();
+       }
+    }
+
+    /**
+     * 鍒濆鍖朢GV鐘舵��
+     */
+    private void initRgvT() {
         if (null == rgvProtocol) {
             rgvProtocol = new RgvProtocol();
         }
+        rgvProtocol.setRgvNo(slave.getId());
         rgvProtocol.setMode((short) -1);
         rgvProtocol.setStatus((short)-1);
         rgvProtocol.setTaskNo1((short)0);
@@ -104,6 +318,64 @@
         rgvProtocol.setxSpeed((short) 0);
         rgvProtocol.setxDistance((short) 0);
         rgvProtocol.setxDuration((short) 0);
+        log.error("杩炴帴涓柇锛歊GV鍙凤細"+slave.getId());
+        try {
+            // 鏍规嵁瀹炴椂淇℃伅鏇存柊鏁版嵁搴�
+            BasRgvService basRgvService = SpringUtils.getBean(BasRgvService.class);
+            BasRgv basRgv = new BasRgv();
+            basRgv.setRgvNo(slave.getId());
+            basRgv.setRgvSts((int)rgvProtocol.getMode());
+            basRgv.setLoaded2(rgvProtocol.getLoaded2().intValue());
+            if (!basRgvService.updateById(rgvProtocol.toSqlModel(basRgv))){
+                log.error("RGV plc鏁版嵁搴撴洿鏂板け璐� ===>> [id:{}] [ip:{}] [port:{}] [rack:{}] [slot:{}]", slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot());
+            }
+        } catch (Exception ignore) {
+        }
+    }
+
+    /**
+     * 鍒濆鍖朢GV鐘舵��
+     */
+    private void initRgvCS() {
+        if (null == rgvProtocol) {
+            rgvProtocol = new RgvProtocol();
+            rgvProtocol.setRgvNo(slave.getId());
+            rgvProtocol.setMode((short) 3);
+            rgvProtocol.setStatus((short)0);
+            rgvProtocol.setTaskNo1((short)0);
+            rgvProtocol.setStatus1((short)0);
+            rgvProtocol.setLoaded1((short)0);
+            rgvProtocol.setWalkPos((short)0);
+            if (rgvProtocol.getRgvPos()==null ||  rgvProtocol.getRgvPos()==0){
+                rgvProtocol.setRgvPos(1L+rgvProtocol.getRgvNo()*100000);
+            }
+//        rgvProtocol.setRgvPos(rgvProtocol.getRgvPos()+1000);
+            rgvProtocol.setRgvPos(rgvProtocol.getRgvPos());
+            if (rgvProtocol.getRgvPos()>0){
+                rgvProtocol.setRgvPos((long)rgvProtocol.getRgvPos());
+                rgvProtocol.setRgvPosInt(rgvProtocol.getRgvPos().intValue());
+            }
+            rgvProtocol.setTaskNo2((short)0);
+            rgvProtocol.setStatus2((short)-1);
+            rgvProtocol.setLoaded2((short)0);
+            rgvProtocol.setAlarm((short)0);
+            rgvProtocol.setxSpeed((short) 0);
+            rgvProtocol.setxDistance((short) 0);
+            rgvProtocol.setxDuration((short) 0);
+        }
+//        log.error("杩炴帴涓柇锛歊GV鍙凤細"+slave.getId());
+        try {
+            // 鏍规嵁瀹炴椂淇℃伅鏇存柊鏁版嵁搴�
+            BasRgvService basRgvService = SpringUtils.getBean(BasRgvService.class);
+            BasRgv basRgv = new BasRgv();
+            basRgv.setRgvNo(slave.getId());
+            basRgv.setRgvSts((int)rgvProtocol.getMode());
+            basRgv.setLoaded2(rgvProtocol.getLoaded2().intValue());
+            if (!basRgvService.updateById(rgvProtocol.toSqlModel(basRgv))){
+                log.error("RGV plc鏁版嵁搴撴洿鏂板け璐� ===>> [id:{}] [ip:{}] [port:{}] [rack:{}] [slot:{}]", slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot());
+            }
+        } catch (Exception ignore) {
+        }
     }
 
     @Override
@@ -132,11 +404,15 @@
     private void readStatus(){
         try {
             OperateResultExOne<byte[]> result = siemensNet.Read("DB100.0", (short) 20);
-            if (result.IsSuccess) {
+            OperateResultExOne<byte[]> resultV = siemensNet.Read("DB20.16", (short) 2);
+            OperateResultExOne<byte[]> resultE = siemensNet.Read("DB20.26", (short) 2);
+            OperateResultExOne<byte[]> resultError = siemensNet.Read("DB13.0", (short) 13);
+            if (result.IsSuccess && resultV.IsSuccess && resultE.IsSuccess) {
                 if (null == rgvProtocol) {
                     rgvProtocol = new RgvProtocol();
                     rgvProtocol.setRgvNo(slave.getId());
                 }
+                rgvProtocol.setRgvNo(slave.getId());
                 rgvProtocol.setMode(siemensNet.getByteTransform().TransInt16(result.Content, 2));
                 rgvProtocol.setStartSta(siemensNet.getByteTransform().TransInt16(result.Content, 4));
                 rgvProtocol.setEndSta(siemensNet.getByteTransform().TransInt16(result.Content, 6));
@@ -144,21 +420,29 @@
                 rgvProtocol.setAlarm(siemensNet.getByteTransform().TransInt16(result.Content, 10));
                 rgvProtocol.setStatus(siemensNet.getByteTransform().TransInt16(result.Content, 12));
                 rgvProtocol.setxSpeed(siemensNet.getByteTransform().TransInt16(result.Content, 14));
-                rgvProtocol.setRgvPos(siemensNet.getByteTransform().TransUInt32(result.Content, 16));
-                rgvProtocol.setRgvPos(slave.getId().longValue()*100000);
-                OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] <<<<< 瀹炴椂鏁版嵁鏇存柊鎴愬姛",DateUtils.convert(new Date()), slave.getId()));
-
-                // 宸ヤ綅1澶嶄綅淇″彿
-                if (rgvProtocol.getStatusType1().equals(RgvStatusType.WAITING)
-                        || rgvProtocol.getStatusType1().equals(RgvStatusType.FETCHWAITING)) {
-                    if (resetFlag1) {
-                        RgvCommand rgvCommand = new RgvCommand();
-                        rgvCommand.setAckFinish1((short)1);
-                        if (write(rgvCommand)) {
-                            resetFlag1 = false;
-                        }
+                int poi = siemensNet.getByteTransform().TransInt32(result.Content, 16);
+                if (poi>0){
+                    rgvProtocol.setRgvPos((long)poi);
+                    rgvProtocol.setRgvPosInt(poi);
+                }
+                log.info(rgvProtocol.getRgvNo()+"鍙峰皬杞﹁鍙栧畾浣嶅�硷細"+poi);
+                rgvProtocol.setInstantaneousSpeed(Double.valueOf(siemensNet.getByteTransform().TransInt16(resultV.Content, 0)));
+                rgvProtocol.setEndStaM(siemensNet.getByteTransform().TransInt16(resultE.Content, 0));
+                boolean[] statusAlarmList = siemensNet.getByteTransform().TransBool(resultError.Content, 0, 13);
+                int alarmCount = 0;
+                List<Integer> alarmList = new ArrayList<>();
+                for (boolean alarmSign : statusAlarmList){
+                    alarmCount++;
+                    if (alarmSign){
+                        alarmList.add(alarmCount);
                     }
                 }
+                alarmChangeSign = new HashSet<>(alarmList).equals(new HashSet<>(rgvProtocol.getAlarmList()));
+                rgvProtocol.setAlarmList(alarmList);
+
+//                rgvProtocol.setRgvPos((long) NumUtils.GetRandomIntInRange(1737000));
+                OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] <<<<< 瀹炴椂鏁版嵁鏇存柊鎴愬姛",DateUtils.convert(new Date()), slave.getId()));
+
 
                 try {
                     // 鏍规嵁瀹炴椂淇℃伅鏇存柊鏁版嵁搴�
@@ -170,6 +454,16 @@
                     if (!basRgvService.updateById(rgvProtocol.toSqlModel(basRgv))){
                         log.error("RGV plc鏁版嵁搴撴洿鏂板け璐� ===>> [id:{}] [ip:{}] [port:{}] [rack:{}] [slot:{}]", slave.getId(), slave.getIp(), slave.getPort(), slave.getRack(), slave.getSlot());
                     }
+                    try{
+                        if (!alarmChangeSign && !alarmList.isEmpty()){
+                            BasRgvErrLogService basRgvErrLogService = SpringUtils.getBean(BasRgvErrLogService.class);
+                            BasRgvErrLog basRgvErrLog = new BasRgvErrLog(rgvProtocol.getAlarmList(), rgvProtocol.getTaskNo1(), rgvProtocol.getRgvNo());
+                            basRgvErrLogService.save(basRgvErrLog);
+                        }
+                    } catch (Exception e){
+                        log.error("RGV寮傚父淇℃伅淇濆瓨澶辫触锛侊紒");
+                    }
+
                 } catch (Exception ignore) {
 
                 }
@@ -190,29 +484,53 @@
     /**
      * 宸ヤ綅1鍐欏叆鏁版嵁
      */
+    private void rgvOpt(RgvCommand command) {
+        try{
+            BasRgvOptService basRgvOptService = SpringUtils.getBean(BasRgvOptService.class);
+            BasRgvOpt basRgvOpt = new BasRgvOpt(rgvProtocol.getTaskNo1().intValue(), rgvProtocol.getRgvNo(), rgvProtocol.getRgvPosInt(), command);
+            log.info(rgvProtocol.getRgvNo()+"鍙峰皬杞﹀啓鍏ュ懡浠ゅ畾浣嶅�硷細"+rgvProtocol.getRgvPosInt());
+            basRgvOptService.save(basRgvOpt);
+        }catch (Exception e){
+            log.error("RGV鍐欏叆鍛戒护淇濆瓨澶辫触锛侊紒");
+        }
+    }
+    private void rgvOpt(Long command) {
+        try{
+            BasRgvOptService basRgvOptService = SpringUtils.getBean(BasRgvOptService.class);
+            BasRgvOpt basRgvOpt = new BasRgvOpt(rgvProtocol.getTaskNo1().intValue(), rgvProtocol.getRgvNo(), rgvProtocol.getRgvPosI(), command);
+            basRgvOptService.save(basRgvOpt);
+        }catch (Exception e){
+            log.error("RGV鍐欏叆鍛戒护淇濆瓨澶辫触锛侊紒");
+        }
+    }
     private boolean write(RgvCommand command) throws InterruptedException {
         if (null == command) {
             log.error("RGV鍐欏叆鍛戒护涓虹┖");
             return false;
         }
 
-//        siemensNet.Write("DB100.20", command.getCommand());
+        siemensNet.Write("DB24.10.0", false);
+        siemensNet.Write("DB24.10.1", false);
 
         command.setRgvNo(slave.getId());
         short[] array = new short[5];
-        array[0] = command.getAckFinish1();
-        array[1] = command.getTaskNo1();
-        array[2] = command.getTaskMode1();//浠诲姟妯″紡
-        array[3] = command.getSourceStaNo1();
-        array[4] = command.getDestinationStaNo1();
-//        siemensNet.Write("DB100.20", 0);
+        array[0] = command.getRgvNo().shortValue();
+        array[1] = command.getSourceStaNo1();
+        array[2] = command.getDestinationStaNo1();
+        array[3] = command.getTaskMode1();//浠诲姟妯″紡
+        array[4] = command.getTaskNo1();
 
-        OperateResult result = siemensNet.Write("DB100.0", array);
 
-        if (command.getAckFinish1() == 0) {
-            short commandFinish = 1;  //宸ヤ綅1浠诲姟鍐欏叆
-            Thread.sleep(100L);
-            result = siemensNet.Write("DB100.20", commandFinish);
+
+        OperateResult result = siemensNet.Write("DB24.0", array);
+
+        if (command.getAckFinish1().equals((short)0)) {
+//            Thread.sleep(100L);
+            siemensNet.Write("DB24.10.7", command.getRgvSome() == 1);
+            Thread.sleep(20L);
+            result = siemensNet.Write("DB24.10.0", true);
+        } else {
+            siemensNet.Write("DB24.10.1", true);
         }
 
         try {
@@ -232,12 +550,159 @@
                     new Date(),
                     null
             );
-            bean.insert(basRgvOpt);
+            bean.save(basRgvOpt);
         } catch (Exception ignore) {}
 
         if (result != null && result.IsSuccess) {
-            Thread.sleep(200);
-            this.readStatus();
+//            Thread.sleep(200);
+//            this.readStatus();
+            log.info("RGV 宸ヤ綅1鍛戒护涓嬪彂[id:{}] >>>>> {}", slave.getId(), JSON.toJSONString(command));
+            OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] >>>>> 宸ヤ綅1鍛戒护涓嬪彂锛� {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSONString(command)));
+            return true;
+        } else {
+            OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆戝啓鍏GV plc宸ヤ綅1鏁版嵁澶辫触 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
+            log.error("鍐欏叆RGV plc宸ヤ綅1鏁版嵁澶辫触 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+            return false;
+        }
+    }
+    private boolean write4(RgvCommand command) throws InterruptedException {
+        if (null == command) {
+            log.error("RGV鍐欏叆鍛戒护涓虹┖");
+            return false;
+        }
+
+//        siemensNet.Write("DB24.10.0", false);
+//        siemensNet.Write("DB24.10.1", false);
+
+        command.setRgvNo(slave.getId());
+        short[] array = new short[5];
+        array[0] = command.getRgvNo().shortValue();
+        array[1] = command.getSourceStaNo1();
+        array[2] = command.getDestinationStaNo1();
+        array[3] = command.getTaskMode1();//浠诲姟妯″紡
+        array[4] = command.getTaskNo1();
+
+
+
+        OperateResult result = siemensNet.Write("DB24.0", array);
+//
+//        if (command.getAckFinish1().equals((short)0)) {
+////            Thread.sleep(100L);
+////            siemensNet.Write("DB24.10.7", command.getRgvSome() == 1);
+////            Thread.sleep(20L);
+////            result = siemensNet.Write("DB24.10.0", true);
+//        } else {
+//            siemensNet.Write("DB24.10.1", true);
+//        }
+
+        try {
+            // 鏃ュ織璁板綍
+            BasRgvOptService bean = SpringUtils.getBean(BasRgvOptService.class);
+            BasRgvOpt basRgvOpt = new BasRgvOpt(
+                    command.getTaskNo1().intValue(),
+                    command.getTaskNo2().intValue(),
+                    command.getRgvNo(),
+                    new Date(),
+                    command.getTaskModeType1().toString(),
+                    command.getSourceStaNo1().intValue(),
+                    command.getDestinationStaNo1().intValue(),
+                    command.getSourceStaNo2().intValue(),
+                    command.getDestinationStaNo2().intValue(),
+                    null,
+                    new Date(),
+                    null
+            );
+            bean.save(basRgvOpt);
+        } catch (Exception ignore) {}
+
+        if (result != null && result.IsSuccess) {
+//            Thread.sleep(200);
+//            this.readStatus();
+            log.info("RGV 宸ヤ綅1鍙栨秷鍛戒护涓嬪彂[id:{}] >>>>> {}", slave.getId(), JSON.toJSONString(command));
+            OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] >>>>> 宸ヤ綅1鍛戒护涓嬪彂锛� {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSONString(command)));
+            return true;
+        } else {
+            OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆戝啓鍏GV plc宸ヤ綅1鏁版嵁澶辫触 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
+            log.error("鍐欏叆RGV plc宸ヤ綅1鍙栨秷鏁版嵁澶辫触 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+            return false;
+        }
+    }
+
+    /**
+     * 瀹屾垚
+     */
+    private void taskComplete() {
+        try {
+            OperateResultExOne<byte[]> result = siemensNet.Read("DB24.11", (short) 1);
+            boolean[] status = siemensNet.getByteTransform().TransBool(result.Content, 0, 1);
+            if (status[0]){
+                OperateResult result4 = siemensNet.Write("DB24.11.0", false);
+            }
+        } catch (Exception e) {
+            log.error("RGV鏁版嵁浠诲姟涓嬪彂澶嶄綅绾跨▼寮傚父锛侊紒锛� ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+        }
+    }
+
+    private void write5(Long devperimeter){
+        try {
+            siemensNet.Write("DB24.12", devperimeter.intValue());
+            Thread.sleep(10L);
+            siemensNet.Write("DB24.11.0", true);
+
+        } catch (Exception ignore) {
+            log.error("鍐欏叆RGV plc宸ヤ綅1婕父鏁版嵁澶辫触 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
+        }
+    }
+
+    private boolean write3(RgvCommand command) throws InterruptedException {
+        if (null == command) {
+            log.error("RGV鍐欏叆鍛戒护涓虹┖");
+            return false;
+        }
+
+        siemensNet.Write("DB24.10.0", false);
+        siemensNet.Write("DB24.10.1", false);
+
+        command.setRgvNo(slave.getId());
+        short[] array = new short[5];
+        array[0] = command.getRgvNo().shortValue();
+        array[1] = command.getSourceStaNo1();
+        array[2] = command.getDestinationStaNo1();
+        array[3] = command.getTaskMode1();//浠诲姟妯″紡
+        array[4] = command.getTaskNo1();
+
+//        OperateResult result = siemensNet.Write("DB24.0", array);
+        OperateResult result = null;
+        if (command.getAckFinish1().equals((short)0)) {
+            Thread.sleep(20L);
+            result = siemensNet.Write("DB24.10.0", true);
+        } else {
+            siemensNet.Write("DB24.10.1", true);
+        }
+
+        try {
+            // 鏃ュ織璁板綍
+            BasRgvOptService bean = SpringUtils.getBean(BasRgvOptService.class);
+            BasRgvOpt basRgvOpt = new BasRgvOpt(
+                    command.getTaskNo1().intValue(),
+                    command.getTaskNo2().intValue(),
+                    command.getRgvNo(),
+                    new Date(),
+                    command.getTaskModeType1().toString(),
+                    command.getSourceStaNo1().intValue(),
+                    command.getDestinationStaNo1().intValue(),
+                    command.getSourceStaNo2().intValue(),
+                    command.getDestinationStaNo2().intValue(),
+                    null,
+                    new Date(),
+                    null
+            );
+            bean.save(basRgvOpt);
+        } catch (Exception ignore) {}
+
+        if (result != null && result.IsSuccess) {
+//            Thread.sleep(200);
+//            this.readStatus();
             log.info("RGV 宸ヤ綅1鍛戒护涓嬪彂[id:{}] >>>>> {}", slave.getId(), JSON.toJSONString(command));
             OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] >>>>> 宸ヤ綅1鍛戒护涓嬪彂锛� {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSONString(command)));
             return true;
@@ -250,24 +715,384 @@
 
     @Override
     public void close() {
-        siemensNet.ConnectClose();
+        if (siemensNet != null) {
+            siemensNet.ConnectClose();
+        }
+    }
+
+    // ==================== 妯℃嫙妯″紡鏂规硶 ====================
+
+    /**
+     * 妯℃嫙瀹屾垚纭锛坰tep=1锛夛細妯℃嫙妯″紡鏃犻渶璇籔LC
+     */
+    private void taskCompleteCS() {
+        // 妯℃嫙妯″紡涓嬫棤PLC锛岃烦杩�
+    }
+
+    /**
+     * 妯℃嫙鍙栨斁璐т笅鍙戯紙step=2锛夛細璁板綍鍒皊imTask锛屽惎鍔ㄦā鎷熺Щ鍔�
+     * 鍙栨斁璐�(mode=3): 绗竴闃舵鍘诲彇璐х珯锛屽埌杈惧悗绛夊緟5绉掞紝鍐嶅幓鏀捐揣绔�
+     */
+    private void writeCS(RgvCommand command) {
+        if (command == null) return;
+        SimTask st = new SimTask();
+        st.setTaskNo(command.getTaskNo1());
+        st.setSourceSta(command.getSourceStaNo1());
+        st.setDestSta(command.getDestinationStaNo1());
+        st.setMode(command.getTaskMode1());
+        st.setPhase(SimPhase.MOVING);
+        st.setStartPos(rgvProtocol.getRgvPos() != null ? rgvProtocol.getRgvPos() : 0L);
+
+        if (command.getTaskMode1().intValue() == RgvTaskModeType.FETCH_PUT.id) {
+            // 鍙栨斁璐э細鍏堝幓鍙栬揣绔欙紝璁颁笅鏀捐揣绔欎綅缃�
+            st.setTargetPos(getStationPosition(command.getSourceStaNo1()));
+            st.setDestPos(getStationPosition(command.getDestinationStaNo1()));
+        } else {
+            // 鍏朵粬妯″紡锛氱洿鎺ュ幓鐩爣绔�
+            st.setTargetPos(getStationPosition(command.getDestinationStaNo1()));
+            st.setDestPos(0L);
+        }
+
+        simTasks.put(slave.getId(), st);
+
+        log.info("[妯℃嫙] RGV{} 鍙栨斁璐т换鍔℃帴鏀�: taskNo={} source={} dest={} 鐩爣浣嶇疆={}",
+                slave.getId(), command.getTaskNo1(), command.getSourceStaNo1(),
+                command.getDestinationStaNo1(), st.getTargetPos());
+        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 鍙栨斁璐т换鍔℃帴鏀�: source={2} dest={3} target={4}",
+                DateUtils.convert(new Date()), slave.getId(),
+                command.getSourceStaNo1(), command.getDestinationStaNo1(), st.getTargetPos()));
+    }
+
+    /**
+     * 妯℃嫙澶嶄綅锛坰tep=3锛夛細娓呴櫎妯℃嫙浠诲姟
+     */
+    private void write3CS(RgvCommand command) {
+        simTasks.remove(slave.getId());
+        rgvProtocol.setTaskNo1((short) 0);
+        rgvProtocol.setStatus((short) 0);
+        log.info("[妯℃嫙] RGV{} 澶嶄綅瀹屾垚", slave.getId());
+        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 澶嶄綅瀹屾垚",
+                DateUtils.convert(new Date()), slave.getId()));
+    }
+
+    /**
+     * 妯℃嫙鍙栨秷锛坰tep=4锛夛細娓呴櫎妯℃嫙浠诲姟
+     */
+    private void write4CS(RgvCommand command) {
+        simTasks.remove(slave.getId());
+        log.info("[妯℃嫙] RGV{} 浠诲姟鍙栨秷: taskNo={}", slave.getId(), command.getTaskNo1());
+        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 浠诲姟鍙栨秷: taskNo={2}",
+                DateUtils.convert(new Date()), slave.getId(), command.getTaskNo1()));
+    }
+
+    /**
+     * 妯℃嫙婕父涓嬪彂锛坰tep=5锛夛細璁板綍鍒皊imTask锛屽惎鍔ㄦā鎷熺Щ鍔�
+     */
+    private void write5CS(Long destination) {
+        SimTask st = new SimTask();
+        st.setMode((short) 5);
+        st.setPhase(SimPhase.MOVING);
+        st.setTargetPos(destination);
+        st.setStartPos(rgvProtocol.getRgvPos() != null ? rgvProtocol.getRgvPos() : 0L);
+        simTasks.put(slave.getId(), st);
+
+        log.info("[妯℃嫙] RGV{} 婕父浠诲姟鎺ユ敹: 鐩爣浣嶇疆={}", slave.getId(), destination);
+        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 婕父浠诲姟鎺ユ敹: 鐩爣={2}",
+                DateUtils.convert(new Date()), slave.getId(), destination));
+    }
+
+    // ==================== 妯℃嫙杩愯绾跨▼ ====================
+
+    /**
+     * 妯℃嫙杩愯绾跨▼锛氭瘡200ms鏇存柊鏈溅浣嶇疆 + 妫�娴嬮伩璁╋紙鍚勭嚎绋嬪彧澶勭悊鑷繁鐨剆imTask锛�
+     */
+    private void simThreadRun() {
+        log.info("[妯℃嫙] RGV{} 妯℃嫙杩愯绾跨▼鍚姩", slave.getId());
+        int tick = 0;
+        int myId = slave.getId();
+        while (true) {
+            try {
+                Thread.sleep(200);
+                tick++;
+
+                SimTask st = simTasks.get(myId);
+                if (st == null || st.getPhase() == SimPhase.IDLE) continue;
+
+                if (rgvProtocol == null || rgvProtocol.getRgvPos() == null) continue;
+                long current = rgvProtocol.getRgvPos();
+                long target = st.getTargetPos();
+                double dist = forwardDistance(current, target);
+
+                // 鍒拌揪鍙栬揣绔欙細绛夊緟5绉掑悗鍓嶅線鏀捐揣绔�
+                if (st.getPhase() == SimPhase.WAITING_AT_SOURCE) {
+                    long waited = System.currentTimeMillis() - st.getWaitStartTime();
+                    if (waited >= 5000) {
+                        st.setTargetPos(st.getDestPos());
+                        st.setStartPos(current);
+                        st.setPhase(SimPhase.MOVING);
+                        log.info("[妯℃嫙] RGV{} 绛夊緟{}ms缁撴潫锛屽紑濮嬪墠寰�鏀捐揣绔�: pos={}", myId, waited, st.getDestPos());
+                        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 绛夊緟缁撴潫锛屽墠寰�鏀捐揣绔�: {2}",
+                                DateUtils.convert(new Date()), myId, st.getDestPos()));
+                    }
+                    continue;
+                }
+
+                if (dist <= SIM_CS_MOVE_STEP) {
+                    // 鍒拌揪鐩爣
+                    rgvProtocol.setRgvPos(target);
+                    rgvProtocol.setRgvPosInt((int) target);
+
+                    if (st.getMode() == RgvTaskModeType.FETCH_PUT.id.shortValue() && st.getDestPos() != 0L && target != st.getDestPos()) {
+                        // 闃舵1锛氬埌杈惧彇璐х珯锛岃繘鍏ョ瓑寰�
+                        rgvProtocol.setStatus((short) 2); // 杩涚珯杩愯涓�
+                        st.setPhase(SimPhase.WAITING_AT_SOURCE);
+                        st.setWaitStartTime(System.currentTimeMillis());
+
+                        log.info("[妯℃嫙] RGV{} 鍒拌揪鍙栬揣绔�: pos={}锛岀瓑寰�5绉掑悗鍓嶅線鏀捐揣绔�", myId, target);
+                        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 鍒拌揪鍙栬揣绔�: {2}锛岀瓑寰�5绉�",
+                                DateUtils.convert(new Date()), myId, target));
+                    } else {
+                        // 闃舵2鍒拌揪鏀捐揣绔� / 婕父鍒拌揪 鈫� 鐢宠瀹屾垚浠诲姟
+                        rgvProtocol.setStatus((short) 100); // WAITING
+                        simTasks.remove(myId);
+
+                        log.info("[妯℃嫙] RGV{} 鍒拌揪鏀捐揣绔�: pos={}锛岀姸鎬佸彉涓虹敵璇峰畬鎴�(WAITING)", myId, target);
+                        OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬妯℃嫙][id:{1}] 鍒拌揪鏀捐揣绔�: {2}锛岀敵璇峰畬鎴愪换鍔�",
+                                DateUtils.convert(new Date()), myId, target));
+                    }
+
+                    try {
+                        BasRgvService basRgvService = SpringUtils.getBean(BasRgvService.class);
+                        basRgvService.updateById(rgvProtocol.toSqlModel(new BasRgv()));
+                    } catch (Exception ignore) {}
+                } else {
+                    // 鍓嶈繘锛堝噺閫熼�昏緫锛氬墠鏂规湁杞﹀垯闄嶄綆姝ラ暱锛屼笉閲嶅悎涓嶈秴杩囷級
+                    long step = calcAdjustedStep(myId, current);
+                    long newPos = (current + step) % PERIMETER;
+                    rgvProtocol.setRgvPos(newPos);
+                    rgvProtocol.setRgvPosInt((int) newPos);
+                    rgvProtocol.setStatus((short) 11); // ROAM
+
+                    if (tick % 5 == 0) {
+                        log.info("[妯℃嫙] RGV{} 绉诲姩涓�: {} 鈫� {} (璺濈洰鏍噞}, 姝ラ暱={})",
+                                myId, current, newPos, (long) dist, step);
+                    }
+
+                    try {
+                        BasRgvService basRgvService = SpringUtils.getBean(BasRgvService.class);
+                        basRgvService.updateById(rgvProtocol.toSqlModel(new BasRgv()));
+                    } catch (Exception ignore) {}
+
+                    // 妫�娴嬮伩璁╋細鍙鏌ユ湰杞﹀墠鏂规槸鍚︽湁闃绘尅
+                    checkAndAvoidBlocker(myId, target);
+                }
+
+            } catch (Exception e) {
+                log.error("[妯℃嫙] RGV{} 妯℃嫙绾跨▼寮傚父: {}", slave.getId(), e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 妫�娴嬪墠鏂归樆鎸″苟閫掓帹閬胯
+     * @param myRgvNo   褰撳墠灏忚溅缂栧彿
+     * @param myTarget  褰撳墠灏忚溅鐨勭洰鏍囦綅缃�
+     */
+    private void checkAndAvoidBlocker(int myRgvNo, long myTarget) {
+        RgvThread myThread = getRgvThread(myRgvNo);
+        if (myThread == null || myThread.getRgvProtocol() == null) return;
+        long myPos = myThread.getRgvProtocol().getRgvPos();
+        if (myPos == 0) return;
+
+        double distToTarget = forwardDistance(myPos, myTarget);
+        if (distToTarget <= 0) return;
+
+        try {
+            BasCircularShuttleService shuttleService = SpringUtils.getBean(BasCircularShuttleService.class);
+            List<BasCircularShuttle> shuttles = shuttleService.list(
+                    new QueryWrapper<BasCircularShuttle>().orderByAsc("rgv_id"));
+            if (shuttles == null) return;
+
+            // 鍙壘绂昏嚜宸辨渶杩戠殑鍓嶈溅锛堝湪鑷繁涓庣洰鏍囦箣闂达級
+            int nearestRgvNo = -1;
+            double nearestDist = Double.MAX_VALUE;
+
+            for (BasCircularShuttle shuttle : shuttles) {
+                int otherNo = shuttle.getRgvNo();
+                if (otherNo == myRgvNo) continue;
+                if (!isIdleForAvoidance(otherNo)) continue;
+
+                RgvThread otherThread = getRgvThread(otherNo);
+                if (otherThread == null || otherThread.getRgvProtocol() == null) continue;
+                long otherPos = otherThread.getRgvProtocol().getRgvPos();
+                if (otherPos == 0) continue;
+
+                double fwdDist = forwardDistance(myPos, otherPos);
+                // 瀵规柟鍦ㄥ墠鏂� 涓� 鍦ㄧ洰鏍囩偣涔嬪墠 鈫� 闃绘尅
+                if (fwdDist > 0 && fwdDist < distToTarget) {
+                    if (fwdDist < nearestDist) {
+                        nearestDist = fwdDist;
+                        nearestRgvNo = otherNo;
+                    }
+                }
+            }
+
+            if (nearestRgvNo > 0) {
+                long avoidDest = forwardAvoidDest(myTarget);
+                issueAvoidanceRecursive(nearestRgvNo, avoidDest);
+            }
+        } catch (Exception ignore) {}
+    }
+
+    /**
+     * 鍒ゆ柇RGV鏄惁绌洪棽鍙敤浜庨伩璁�
+     */
+    private boolean isIdleForAvoidance(int rgvNo) {
+        SimTask otherSim = simTasks.get(rgvNo);
+        if (otherSim != null && otherSim.getPhase() == SimPhase.MOVING) return false;
+
+        RgvThread otherThread = getRgvThread(rgvNo);
+        if (otherThread == null) return false;
+        RgvProtocol protocol = otherThread.getRgvProtocol();
+        if (protocol == null) return false;
+
+        int st = protocol.getStatus() != null ? protocol.getStatus() : -1;
+        return (st == 0 || st == 11) && protocol.getTaskNo1() == 0;
+    }
+
+    /**
+     * 涓嬪彂閬胯锛氱粰rgvNo鍐欏叆閬胯simTask鑷砤voidDest
+     * 璇GV鐨勭嚎绋嬩細鍦ㄤ笅涓�tick鑷妫�娴嬮伩璁╄矾寰勪笂鐨勯樆鎸�
+     */
+    private void issueAvoidanceRecursive(int rgvNo, long avoidDest) {
+        MessageQueue.offer(SlaveType.Rgv, rgvNo, new Task(5, avoidDest));
+//        RgvThread otherThread = getRgvThread(rgvNo);
+//        if (otherThread == null || otherThread.getRgvProtocol() == null) return;
+//        long currentPos = otherThread.getRgvProtocol().getRgvPos();
+//
+//        // 鍐欏叆simTask锛堣鐩栧凡鏈夌殑WAITING_AT_SOURCE鎴朚OVING浠诲姟锛�
+//        SimTask st = new SimTask();
+//        st.setMode((short) 5);
+//        st.setPhase(SimPhase.MOVING);
+//        st.setTargetPos(avoidDest);
+//        st.setStartPos(currentPos);
+//        simTasks.put(rgvNo, st);
+//
+//        log.info("[妯℃嫙閬胯] RGV{} 鍓嶆柟RGV{}闃绘尅锛岄伩璁╄嚦: {}",
+//                slave.getId(), rgvNo, avoidDest);
+//        OutputQueue.RGV.offer(MessageFormat.format(
+//                "銆恵0}銆慬妯℃嫙閬胯] RGV{1} 鍓嶆柟RGV{2}闃绘尅, 閬胯鑷�: {3}",
+//                DateUtils.convert(new Date()), slave.getId(), rgvNo, avoidDest));
+    }
+
+    /**
+     * 璁$畻鐩爣鐐瑰墠鏂�10000澶勭殑閬胯浣嶇疆
+     */
+    private long forwardAvoidDest(long target) {
+        long dest = target + 100000;
+        if (dest > PERIMETER) dest -= PERIMETER;
+        return dest;
+    }
+
+    /** 鍓嶈溅璺熼殢璺濈锛氳繘鍏ユ鑼冨洿寮�濮嬪噺閫� */
+    private static final long FOLLOW_DISTANCE = 20000;
+    /** 鏈�灏忓畨鍏ㄩ棿璺濓細涓嶈兘姣旇繖鏇磋繎 */
+    private static final long MIN_GAP = 3000;
+
+    /**
+     * 鏍规嵁鍓嶆柟杞﹁締璺濈璁$畻鏈瀹為檯姝ラ暱
+     * 鍓嶆柟鏃犺溅 鈫� 鍏ㄩ�燂紱鏈夎溅 鈫� 绾挎�у噺閫燂紱璐寸揣 鈫� 鍋滄
+     */
+    private long calcAdjustedStep(int myId, long myPos) {
+        long aheadDist = distanceToNearestAhead(myId, myPos);
+        if (aheadDist < 0) return SIM_CS_MOVE_STEP; // 鍓嶆柟鏃犺溅锛屽叏閫�
+
+        long gap = aheadDist - MIN_GAP;
+        if (gap <= 0) return 0; // 宸插埌鏈�灏忛棿璺濓紝鍋滄
+        return Math.min(SIM_CS_MOVE_STEP, gap);
+    }
+
+    /**
+     * 鏌ユ壘姝e墠鏂规渶杩戜竴杈嗚溅鐨勬鍚戣窛绂伙紝鏃犺溅杩斿洖-1
+     * 鍙叧娉ㄦ湁浠诲姟鎴栨鍦ㄧЩ鍔ㄧ殑杞︼紝绌洪棽闈欐鐨勮溅鐢遍伩璁╅�昏緫澶勭悊
+     */
+    private long distanceToNearestAhead(int myId, long myPos) {
+        long best = -1;
+        try {
+            BasCircularShuttleService shuttleService = SpringUtils.getBean(BasCircularShuttleService.class);
+            List<BasCircularShuttle> shuttles = shuttleService.list(
+                    new QueryWrapper<BasCircularShuttle>().orderByAsc("rgv_id"));
+            if (shuttles == null) return -1;
+
+            for (BasCircularShuttle shuttle : shuttles) {
+                int otherId = shuttle.getRgvNo();
+                if (otherId == myId) continue;
+
+                SimTask otherTask = simTasks.get(otherId);
+                // 鍙叧娉ㄦ湁浠诲姟鐨勮溅锛圡OVING / WAITING_AT_SOURCE锛�
+                if (otherTask == null || otherTask.getPhase() == SimPhase.IDLE) continue;
+
+                RgvThread otherThread = getRgvThread(otherId);
+                if (otherThread == null || otherThread.getRgvProtocol() == null) continue;
+                Long otherPos = otherThread.getRgvProtocol().getRgvPos();
+                if (otherPos == null || otherPos == 0) continue;
+
+                double fwd = forwardDistance(myPos, otherPos);
+                if (fwd > 0 && fwd <= FOLLOW_DISTANCE && (best < 0 || fwd < best)) {
+                    best = (long) fwd;
+                }
+            }
+        } catch (Exception ignore) {}
+        return best;
+    }
+
+    /**
+     * 璁$畻鐜舰杞ㄩ亾涓婁粠current鍒皌arget鐨勬鍚戣窛绂�
+     */
+    private double forwardDistance(long current, long target) {
+        if (target >= current) return target - current;
+        return PERIMETER - current + target;
+    }
+
+    /**
+     * 鑾峰彇绔欑偣鍦ㄨ建閬撲笂鐨勪綅缃�
+     */
+    private long getStationPosition(short staNo) {
+        try {
+            BasDevpPositionService positionService = SpringUtils.getBean(BasDevpPositionService.class);
+            com.zy.asrs.entity.BasDevpPosition pos = positionService.getOne(
+                    new QueryWrapper<com.zy.asrs.entity.BasDevpPosition>().eq("dev_no", (int) staNo));
+            if (pos != null && pos.getPlcPosition() != null) return pos.getPlcPosition();
+        } catch (Exception ignore) {}
+        return 0L;
+    }
+
+    /**
+     * 鑾峰彇鎸囧畾RGV鐨凴gvThread瀹炰緥
+     */
+    private RgvThread getRgvThread(int rgvNo) {
+        try {
+            return (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgvNo);
+        } catch (Exception e) {
+            return null;
+        }
     }
 
     /******************************************************************************************/
     /**************************************** 娴嬭瘯涓撶敤 *****************************************/
     /*****************************************************************************************/
-    public static void main(String[] args) throws InterruptedException {
-        RgvSlave slave = new RgvSlave();
-        slave.setId(1);
-        slave.setIp("192.168.6.9");
-        slave.setRack(0);
-        slave.setSlot(0);
-        RgvThread rgvThread = new RgvThread(slave);
-        rgvThread.connect();
-        rgvThread.readStatus();
-        System.out.println(JSON.toJSONString(rgvThread.rgvProtocol));
-        Thread.sleep(3000L);
-
-    }
+//    public static void main(String[] args) throws InterruptedException {
+//        RgvSlave slave = new RgvSlave();
+//        slave.setId(1);
+//        slave.setIp("192.168.6.9");
+//        slave.setRack(0);
+//        slave.setSlot(0);
+//        RgvThread rgvThread = new RgvThread(slave);
+//        rgvThread.connect();
+//        rgvThread.readStatus();
+//        System.out.println(JSON.toJSONString(rgvThread.rgvProtocol));
+//        Thread.sleep(3000L);
+//
+//    }
 
 }

--
Gitblit v1.9.1