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 |  665 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 578 insertions(+), 87 deletions(-)

diff --git a/src/main/java/com/zy/core/thread/RgvThread.java b/src/main/java/com/zy/core/thread/RgvThread.java
index dddf6a7..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,23 @@
 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.NumUtils;
 import com.zy.core.ThreadHandler;
 import com.zy.core.cache.MessageQueue;
 import com.zy.core.cache.OutputQueue;
+import com.zy.core.cache.SlaveConnection;
 import com.zy.core.enums.RgvModeType;
 import com.zy.core.enums.RgvTaskModeType;
 import com.zy.core.enums.SlaveType;
@@ -27,10 +33,8 @@
 import lombok.extern.slf4j.Slf4j;
 
 import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * RGV绾跨▼
@@ -53,6 +57,34 @@
     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;
@@ -61,14 +93,10 @@
     @Override
     @SuppressWarnings("InfiniteLoopStatement")
     public void run() {
-        connectRgv = this.connect();
-        while(!connectRgv){
-            try {
-                connectRgv = this.connect();
-                Thread.sleep(100);
-            } catch (Exception e){
-
-            }
+        if (csSign) {
+            connectRgv = true; // 妯℃嫙妯″紡璺宠繃PLC杩炴帴
+        } else {
+            connectRgv = this.connect();
         }
 
         // 鍚姩绾跨▼鑷姩閲嶈繛
@@ -79,6 +107,11 @@
 
         // 鍚姩浠诲姟涓嬪彂绾跨▼
         new Thread(this::taskIssued).start();
+
+        // 妯℃嫙妯″紡锛氬惎鍔ㄦā鎷熻繍琛岀嚎绋�
+        if (csSign) {
+            new Thread(this::simThreadRun).start();
+        }
     }
 
 
@@ -101,47 +134,89 @@
                 if (task != null) {
                     step = task.getStep();
                 }
-                switch (step) {
-                    //婕父浠诲姟瀹屾垚淇″彿
-                    case 1:
+                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;
+                            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(50);
             } catch (Exception e) {
@@ -157,6 +232,16 @@
             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);
@@ -186,8 +271,8 @@
                     continue;
                 }
                 Thread.sleep(40);
-                readStatus();
-
+//                readStatus();
+                initRgv();
             } catch (Exception e) {
                 log.error("RGV璇荤嚎绋嬪紓甯�"+e.getMessage());
 
@@ -204,6 +289,17 @@
      * 鍒濆鍖朢GV鐘舵��
      */
     private void initRgv() {
+       if (csSign){
+           initRgvCS();
+       } else {
+           initRgvT();
+       }
+    }
+
+    /**
+     * 鍒濆鍖朢GV鐘舵��
+     */
+    private void initRgvT() {
         if (null == rgvProtocol) {
             rgvProtocol = new RgvProtocol();
         }
@@ -222,31 +318,65 @@
         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 initRgv() {
-//        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);
-//        rgvProtocol.setRgvPos(slave.getId()*100000L);
-//        rgvProtocol.setTaskNo2((short)0);
-//        rgvProtocol.setStatus2((short)0);
-//        rgvProtocol.setLoaded2((short)0);
-//        rgvProtocol.setAlarm((short)0);
-//        rgvProtocol.setxSpeed((short) 0);
-//        rgvProtocol.setxDistance((short) 0);
-//        rgvProtocol.setxDuration((short) 0);
-//    }
+    /**
+     * 鍒濆鍖朢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
     public boolean connect() {
@@ -295,7 +425,7 @@
                     rgvProtocol.setRgvPos((long)poi);
                     rgvProtocol.setRgvPosInt(poi);
                 }
-                System.out.println(rgvProtocol.getRgvNo()+"鍙峰皬杞﹁鍙栧畾浣嶅�硷細"+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);
@@ -310,7 +440,7 @@
                 alarmChangeSign = new HashSet<>(alarmList).equals(new HashSet<>(rgvProtocol.getAlarmList()));
                 rgvProtocol.setAlarmList(alarmList);
 
-//                rgvProtocol.setRgvPos((long)NumUtils.GetRandomIntInRange(1737000));
+//                rgvProtocol.setRgvPos((long) NumUtils.GetRandomIntInRange(1737000));
                 OutputQueue.RGV.offer(MessageFormat.format("銆恵0}銆慬id:{1}] <<<<< 瀹炴椂鏁版嵁鏇存柊鎴愬姛",DateUtils.convert(new Date()), slave.getId()));
 
 
@@ -328,7 +458,7 @@
                         if (!alarmChangeSign && !alarmList.isEmpty()){
                             BasRgvErrLogService basRgvErrLogService = SpringUtils.getBean(BasRgvErrLogService.class);
                             BasRgvErrLog basRgvErrLog = new BasRgvErrLog(rgvProtocol.getAlarmList(), rgvProtocol.getTaskNo1(), rgvProtocol.getRgvNo());
-                            basRgvErrLogService.insert(basRgvErrLog);
+                            basRgvErrLogService.save(basRgvErrLog);
                         }
                     } catch (Exception e){
                         log.error("RGV寮傚父淇℃伅淇濆瓨澶辫触锛侊紒");
@@ -357,8 +487,9 @@
     private void rgvOpt(RgvCommand command) {
         try{
             BasRgvOptService basRgvOptService = SpringUtils.getBean(BasRgvOptService.class);
-            BasRgvOpt basRgvOpt = new BasRgvOpt(rgvProtocol.getTaskNo1().intValue(), rgvProtocol.getRgvNo(), rgvProtocol.getRgvPosI(), command);
-            basRgvOptService.insert(basRgvOpt);
+            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鍐欏叆鍛戒护淇濆瓨澶辫触锛侊紒");
         }
@@ -367,7 +498,7 @@
         try{
             BasRgvOptService basRgvOptService = SpringUtils.getBean(BasRgvOptService.class);
             BasRgvOpt basRgvOpt = new BasRgvOpt(rgvProtocol.getTaskNo1().intValue(), rgvProtocol.getRgvNo(), rgvProtocol.getRgvPosI(), command);
-            basRgvOptService.insert(basRgvOpt);
+            basRgvOptService.save(basRgvOpt);
         }catch (Exception e){
             log.error("RGV鍐欏叆鍛戒护淇濆瓨澶辫触锛侊紒");
         }
@@ -419,7 +550,7 @@
                     new Date(),
                     null
             );
-            bean.insert(basRgvOpt);
+            bean.save(basRgvOpt);
         } catch (Exception ignore) {}
 
         if (result != null && result.IsSuccess) {
@@ -481,7 +612,7 @@
                     new Date(),
                     null
             );
-            bean.insert(basRgvOpt);
+            bean.save(basRgvOpt);
         } catch (Exception ignore) {}
 
         if (result != null && result.IsSuccess) {
@@ -566,7 +697,7 @@
                     new Date(),
                     null
             );
-            bean.insert(basRgvOpt);
+            bean.save(basRgvOpt);
         } catch (Exception ignore) {}
 
         if (result != null && result.IsSuccess) {
@@ -584,7 +715,367 @@
 
     @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;
+        }
     }
 
     /******************************************************************************************/

--
Gitblit v1.9.1