From 877b2519157cea762b1e63e9c57c09614216d684 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期四, 24 七月 2025 19:27:46 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/core/model/protocol/ShuttleProtocol.java       |   17 
 src/main/java/com/zy/core/model/command/ShuttleCommand.java         |   15 
 src/main/java/com/zy/common/utils/NavigateMapUtils.java             |    5 
 src/main/java/com/zy/core/model/command/ShuttleAssignCommand.java   |    3 
 src/main/java/com/zy/core/thread/impl/NyShuttleThread.java          |   10 
 src/main/java/com/zy/common/model/NavigateNode.java                 |    1 
 src/main/java/com/zy/common/utils/ShuttleOperaUtils.java            |   13 
 src/main/java/com/zy/core/thread/ShuttleThread.java                 |    2 
 src/main/java/com/zy/common/utils/NavigateUtils.java                |   24 
 src/main/java/com/zy/core/cache/MessageQueue.java                   |   25 
 src/main/java/com/zy/core/thread/TrafficControlThread.java          |   30 +
 src/main/java/com/zy/core/utils/TrafficControlUtils.java            |   81 +++
 src/main/java/com/zy/common/utils/NavigatePositionConvert.java      |    6 
 src/main/java/com/zy/core/ServerBootstrap.java                      |   12 
 src/main/java/com/zy/core/model/TrafficControlDataModel.java        |   19 
 src/main/java/com/zy/asrs/controller/ShuttleController.java         |    4 
 src/main/java/com/zy/core/action/ShuttleAction.java                 |  584 ++++++++++++++++----
 src/main/java/com/zy/core/enums/SlaveType.java                      |    1 
 src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java |  575 +++++++++++++++++++++
 src/main/java/com/zy/core/enums/RedisKeyType.java                   |    6 
 src/main/java/com/zy/common/utils/NavigateMapData.java              |  125 ++++
 src/main/java/com/zy/common/model/enums/NavigationMapType.java      |    5 
 22 files changed, 1,416 insertions(+), 147 deletions(-)

diff --git a/src/main/java/com/zy/asrs/controller/ShuttleController.java b/src/main/java/com/zy/asrs/controller/ShuttleController.java
index f7bdebb..0f41a90 100644
--- a/src/main/java/com/zy/asrs/controller/ShuttleController.java
+++ b/src/main/java/com/zy/asrs/controller/ShuttleController.java
@@ -35,6 +35,7 @@
 import com.zy.core.model.param.ShuttleMoveLocParam;
 import com.zy.core.model.protocol.ShuttleProtocol;
 import com.zy.core.thread.ShuttleThread;
+import com.zy.core.thread.TrafficControlThread;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -346,6 +347,9 @@
             assignCommand.setCommands(commands);
         } else if (shuttleTaskModeType == ShuttleTaskModeType.RESET) {
             //澶嶄綅
+            TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+            trafficControlThread.cancelTrafficControl(shuttleProtocol.getShuttleNo(), shuttleProtocol.getTaskNo());
+
             shuttleThread.setSyncTaskNo(0);//宸ヤ綔鍙锋竻绌�
             shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.IDLE);//浠诲姟鐘舵��-绌洪棽
             shuttleThread.setPakMk(true);//浣滀笟鏍囪澶嶄綅
diff --git a/src/main/java/com/zy/common/model/NavigateNode.java b/src/main/java/com/zy/common/model/NavigateNode.java
index c1e1a70..4ebf6d6 100644
--- a/src/main/java/com/zy/common/model/NavigateNode.java
+++ b/src/main/java/com/zy/common/model/NavigateNode.java
@@ -22,6 +22,7 @@
     private Integer moveDistance;//琛岃蛋璺濈
     private Integer nodeValue;//鑺傜偣鏁版嵁
     private Boolean linePartAllowGo = false;//鐩寸嚎娈甸儴鍒嗭紝鍏佽鐩存帴琛岃蛋
+    private Long linePartFlag;//鐩寸嚎娈垫暟鎹爣璇�
 
     public NavigateNode(int x, int y) {
         this.x = x;
diff --git a/src/main/java/com/zy/common/model/enums/NavigationMapType.java b/src/main/java/com/zy/common/model/enums/NavigationMapType.java
index 4556a94..fb83272 100644
--- a/src/main/java/com/zy/common/model/enums/NavigationMapType.java
+++ b/src/main/java/com/zy/common/model/enums/NavigationMapType.java
@@ -11,6 +11,7 @@
     SHUTTLE(3, "鍦板浘鎼哄甫灏忚溅"),
     LIFT(4, "鍦板浘鎼哄甫鎻愬崌鏈�"),
     PATH_LOCK(5, "璺緞閿�"),
+    TRAFFIC_CONTROL(6, "浜ら�氱鍒�"),
     ;
 
     public Integer id;
@@ -46,11 +47,11 @@
     }
 
     public static List<NavigationMapType> getDfxWithDevice() {
-        return getMapTypes(DFX, SHUTTLE, LIFT, PATH_LOCK);
+        return getMapTypes(DFX, SHUTTLE, LIFT, PATH_LOCK, TRAFFIC_CONTROL);
     }
 
     public static List<NavigationMapType> getNormalWithDevice() {
-        return getMapTypes(NORMAL, SHUTTLE, LIFT, PATH_LOCK);
+        return getMapTypes(NORMAL, SHUTTLE, LIFT, PATH_LOCK, TRAFFIC_CONTROL);
     }
 
     public static List<NavigationMapType> getMapTypes(NavigationMapType... types) {
diff --git a/src/main/java/com/zy/common/utils/NavigateMapData.java b/src/main/java/com/zy/common/utils/NavigateMapData.java
index 3df92d7..8deec59 100644
--- a/src/main/java/com/zy/common/utils/NavigateMapData.java
+++ b/src/main/java/com/zy/common/utils/NavigateMapData.java
@@ -3,6 +3,8 @@
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.core.common.SpringUtils;
+import com.core.exception.CoolException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.zy.asrs.entity.BasMap;
 import com.zy.asrs.entity.DeviceConfig;
 import com.zy.asrs.entity.LocMast;
@@ -11,16 +13,24 @@
 import com.zy.asrs.service.LocMastService;
 import com.zy.asrs.utils.Utils;
 import com.zy.common.model.MapNode;
+import com.zy.common.model.NavigateNode;
 import com.zy.common.model.enums.NavigationMapType;
 import com.zy.core.cache.SlaveConnection;
 import com.zy.core.enums.MapNodeType;
 import com.zy.core.enums.RedisKeyType;
+import com.zy.core.enums.ShuttleCommandModeType;
 import com.zy.core.enums.SlaveType;
+import com.zy.core.model.TrafficControlDataModel;
+import com.zy.core.model.command.ShuttleAssignCommand;
+import com.zy.core.model.command.ShuttleCommand;
+import com.zy.core.model.command.ShuttleRedisCommand;
 import com.zy.core.model.protocol.ForkLiftStaProtocol;
 import com.zy.core.thread.ForkLiftThread;
+import com.zy.core.thread.TrafficControlThread;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -38,6 +48,8 @@
     private DeviceConfigService deviceConfigService;
     @Autowired
     private BasMapService basMapService;
+    @Autowired
+    private ObjectMapper objectMapper;
 
     public int[][] getData(Integer lev, List<NavigationMapType> mapTypes, List<int[]> whitePoints, List<int[]> shuttlePoints) {
         try {
@@ -188,6 +200,11 @@
             if(mapType.equals(NavigationMapType.PATH_LOCK)) {
                 //鍔犺浇璺緞閿�
                 lists = loadPathLock(lists, lev);
+            }
+
+            if(mapType.equals(NavigationMapType.TRAFFIC_CONTROL)) {
+                //鍔犺浇浜ら�氱鍒�
+                lists = loadTrafficControl(lists, lev);
             }
         }
 
@@ -396,4 +413,112 @@
         return lists;
     }
 
+    //鍔犺浇浜ら�氱鍒�
+    public List<List<MapNode>> loadTrafficControl(List<List<MapNode>> lists, Integer lev) {
+        try {
+            TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+            if (trafficControlThread == null) {
+                throw new CoolException("init traffic control thread error");
+            }
+
+            List<TrafficControlDataModel> trafficList = trafficControlThread.getAllTrafficControl();
+            for (TrafficControlDataModel trafficControlDataModel : trafficList) {
+                List<NavigateNode> totalNodeList = trafficControlDataModel.getTotalNodeList();
+                NavigateNode startNode = totalNodeList.get(0);
+                if (startNode.getZ() != lev) {
+                    continue;
+                }
+
+                for (NavigateNode node : totalNodeList) {
+                    int row = node.getX();
+                    int bay = node.getY();
+
+                    List<MapNode> list = lists.get(row);
+                    MapNode mapNode = list.get(bay);
+
+                    //鑺傜偣璁剧疆鎴怐isable
+                    mapNode.setValue(MapNodeType.DISABLE.id);
+
+                    //鏇存柊list
+                    list.set(bay, mapNode);
+                    lists.set(row, list);
+                }
+            }
+
+//            HashMap<String, Integer> deviceMap = trafficControlThread.getDeviceMap();
+//            if(deviceMap == null) {
+//                throw new CoolException("get traffic control device map error");
+//            }
+//
+//            for (Map.Entry<String, Integer> entry : deviceMap.entrySet()) {
+//                String key = entry.getKey();
+//                Integer shuttleNo = entry.getValue();
+//                if (shuttleNo <= 0) {
+//                    continue;
+//                }
+//
+//                Object object = redisUtil.get(RedisKeyType.SHUTTLE_FLAG.key + shuttleNo);
+//                if (object == null) {
+//                    continue;
+//                }
+//
+//                int taskNo = Integer.parseInt(String.valueOf(object));
+//
+//                Object obj = redisUtil.get(RedisKeyType.SHUTTLE_WORK_FLAG.key + taskNo);
+//                if (obj == null) {
+//                    continue;
+//                }
+//
+//                ShuttleRedisCommand redisCommand = null;
+//                try {
+//                    redisCommand = objectMapper.readValue(String.valueOf(obj), ShuttleRedisCommand.class);
+//                } catch (IOException e) {
+//                    throw new RuntimeException(e);
+//                }
+//
+//                if (redisCommand == null) {
+//                    continue;
+//                }
+//
+//                ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand();
+//                List<ShuttleCommand> commands = assignCommand.getCommands();
+//
+//                List<NavigateNode> controlLocList = new ArrayList<>();
+//                for (ShuttleCommand command : commands) {
+//                    if (command.getComplete()) {
+//                        continue;
+//                    }
+//
+//                    if (command.getMode() == ShuttleCommandModeType.MOVE.id) {
+//                        List<NavigateNode> nodes = command.getNodes();
+//                        for (NavigateNode node : nodes) {
+//                            if(!controlLocList.contains(node)) {
+//                                controlLocList.add(node);
+//                            }
+//                        }
+//                    }
+//                }
+//
+//                for (NavigateNode node : controlLocList) {
+//                    int row = node.getX();
+//                    int bay = node.getY();
+//
+//                    List<MapNode> list = lists.get(row);
+//                    MapNode mapNode = list.get(bay);
+//
+//                    //鑺傜偣璁剧疆鎴怐isable
+//                    mapNode.setValue(MapNodeType.DISABLE.id);
+//
+//                    //鏇存柊list
+//                    list.set(bay, mapNode);
+//                    lists.set(row, list);
+//                }
+//
+//            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return lists;
+    }
+
 }
diff --git a/src/main/java/com/zy/common/utils/NavigateMapUtils.java b/src/main/java/com/zy/common/utils/NavigateMapUtils.java
index 733f56c..8b043c4 100644
--- a/src/main/java/com/zy/common/utils/NavigateMapUtils.java
+++ b/src/main/java/com/zy/common/utils/NavigateMapUtils.java
@@ -58,7 +58,10 @@
 
             //鍒ゆ柇鑺傜偣鏄惁琚攣瀹�
             if(lockMap.containsKey(key)) {
-                return false;
+                Integer deviceNo = (Integer) lockMap.get(key);
+                if (!shuttleNo.equals(deviceNo)) {//绛夊緟閿佸畾鐨勮妭鐐瑰凡琚綋鍓嶅皬杞﹂攣瀹氾紝璁ゅ畾閿佸畾鎴愬姛
+                    return false;
+                }
             }
 
             tmpMap.put(key, shuttleNo);
diff --git a/src/main/java/com/zy/common/utils/NavigatePositionConvert.java b/src/main/java/com/zy/common/utils/NavigatePositionConvert.java
index 76a2bfd..ac71260 100644
--- a/src/main/java/com/zy/common/utils/NavigatePositionConvert.java
+++ b/src/main/java/com/zy/common/utils/NavigatePositionConvert.java
@@ -100,4 +100,10 @@
         return new int[]{col, row};
     }
 
+    public static boolean equalsNode(NavigateNode node1, NavigateNode node2) {
+        if(node1.getX() ==  node2.getX() && node1.getY() == node2.getY() && node1.getZ() == node2.getZ()) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/src/main/java/com/zy/common/utils/NavigateUtils.java b/src/main/java/com/zy/common/utils/NavigateUtils.java
index dd88872..d49b64b 100644
--- a/src/main/java/com/zy/common/utils/NavigateUtils.java
+++ b/src/main/java/com/zy/common/utils/NavigateUtils.java
@@ -2,6 +2,8 @@
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.core.common.SnowflakeIdWorker;
 import com.core.exception.CoolException;
 import com.zy.asrs.utils.Utils;
 import com.zy.common.model.MapNode;
@@ -10,6 +12,8 @@
 import com.zy.core.News;
 import com.zy.core.enums.MapNodeType;
 import com.zy.core.model.PythonSimilarityResult;
+import com.zy.system.entity.Config;
+import com.zy.system.service.ConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
@@ -30,6 +34,10 @@
     private String pythonCalcSimilarity;
     @Autowired
     private NavigateMapData navigateMapData;
+    @Autowired
+    private SnowflakeIdWorker snowflakeIdWorker;
+    @Autowired
+    private ConfigService configService;
 
     public List<NavigateNode> calc(String startPoint, String endPoint, List<NavigationMapType> mapTypes, List<int[]> shuttlePoints, List<int[]> whites) {
         return calcJava(startPoint, endPoint, mapTypes, shuttlePoints, whites);
@@ -315,15 +323,23 @@
         //灏嗘渶鍚庝竴娈垫暟鎹坊鍔犺繘鍏�
         list.add(data);
 
+        //鍒嗘璺緞-澶勭悊瓒呴暱鐩寸嚎娈佃矾寰�
         List<List<NavigateNode>> paths = getSectionPathToSplitOverLength(list);
         return paths;
     }
 
     //鍒嗘璺緞-澶勭悊瓒呴暱鐩寸嚎娈佃矾寰�
     public List<List<NavigateNode>> getSectionPathToSplitOverLength(List<List<NavigateNode>> list) {
+        int overLength = 9;//榛樿9鑺�
+        Config shuttleMoveOverLengthConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "shuttleMoveOverLength"));
+        if (shuttleMoveOverLengthConfig != null) {
+            overLength = Integer.parseInt(shuttleMoveOverLengthConfig.getValue());
+        }
+
         List<List<NavigateNode>> paths = new ArrayList<>();
-        int overLength = 9;
         for (List<NavigateNode> nodes : list) {
+            long nextId = snowflakeIdWorker.nextId();
+
             if (nodes.size() > overLength) {
                 List<NavigateNode> copy = JSON.parseArray(JSON.toJSONString(nodes), NavigateNode.class);
                 List<NavigateNode> tmp = new ArrayList<>();
@@ -337,10 +353,12 @@
                         if (lastNode == null) {
                             NavigateNode startNode = tmp.get(0);
                             startNode.setLinePartAllowGo(true);//鐩寸嚎娈佃秴闀块儴鍒嗗厑璁哥洿鎺ヨ璧�
+                            startNode.setLinePartFlag(nextId);//鐩寸嚎娈垫暟鎹爣璇�
                             tmp.set(0, startNode);
                         }
                         NavigateNode targetNode = tmp.get(tmp.size() - 1);
                         targetNode.setLinePartAllowGo(true);//鐩寸嚎娈佃秴闀块儴鍒嗗厑璁哥洿鎺ヨ璧�
+                        targetNode.setLinePartFlag(nextId);//鐩寸嚎娈垫暟鎹爣璇�
                         if (lastNode != null) {
                             tmp.add(0, lastNode);
                         }
@@ -357,6 +375,10 @@
                     paths.add(tmp);
                 }
             }else {
+                NavigateNode startNode = nodes.get(0);
+                startNode.setLinePartAllowGo(true);//鐩寸嚎娈佃秴闀块儴鍒嗗厑璁哥洿鎺ヨ璧�
+                startNode.setLinePartFlag(nextId);//鐩寸嚎娈垫暟鎹爣璇�
+                nodes.set(0, startNode);
                 paths.add(nodes);
             }
         }
diff --git a/src/main/java/com/zy/common/utils/ShuttleOperaUtils.java b/src/main/java/com/zy/common/utils/ShuttleOperaUtils.java
index 171640f..33739d4 100644
--- a/src/main/java/com/zy/common/utils/ShuttleOperaUtils.java
+++ b/src/main/java/com/zy/common/utils/ShuttleOperaUtils.java
@@ -116,12 +116,15 @@
 
         assignCommand.setNodes(allNode);//褰撳墠浠诲姟鎵�鍗犵敤鐨勮妭鐐筶ist
 
-        boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(startLocNo), shuttleNo, lockNode, true);//閿佸畾璺緞
-        if (!result) {
-            News.error("{} dash {} can't lock path!", startLocNo, endLocNo);
-            shuttleThread.offerSystemMsg("{} dash {} can't lock path!", startLocNo, endLocNo);
-            return null;//璺緞閿佸畾澶辫触
+        //灏忚溅绉诲姩杩炵画涓嬪彂鎸囦护
+        boolean shuttleMoveCommandsContinuously = false;
+        Config shuttleMoveCommandsContinuouslyConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "shuttleMoveCommandsContinuously"));
+        if (shuttleMoveCommandsContinuouslyConfig != null) {
+            if (shuttleMoveCommandsContinuouslyConfig.getValue().equals("Y")) {
+                shuttleMoveCommandsContinuously = true;
+            }
         }
+        assignCommand.setShuttleMoveCommandsContinuously(shuttleMoveCommandsContinuously);
         return commands;
     }
 
diff --git a/src/main/java/com/zy/core/ServerBootstrap.java b/src/main/java/com/zy/core/ServerBootstrap.java
index 003d514..6af478e 100644
--- a/src/main/java/com/zy/core/ServerBootstrap.java
+++ b/src/main/java/com/zy/core/ServerBootstrap.java
@@ -11,7 +11,9 @@
 import com.zy.core.cache.MessageQueue;
 import com.zy.core.cache.SlaveConnection;
 import com.zy.core.enums.SlaveType;
+import com.zy.core.thread.TrafficControlThread;
 import com.zy.core.thread.impl.NyShuttleThread;
+import com.zy.core.thread.impl.TrafficControlImplThread;
 import com.zy.core.thread.impl.ZyForkLiftThread;
 import com.zy.core.utils.DeviceMsgUtils;
 import lombok.extern.slf4j.Slf4j;
@@ -61,14 +63,16 @@
         List<DeviceConfig> forkLiftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                 .eq("device_type", String.valueOf(SlaveType.ForkLift)));
         for (DeviceConfig forkLift : forkLiftList) {
-            MessageQueue.init(SlaveType.ForkLift, forkLift);
+            MessageQueue.init(SlaveType.ForkLift, forkLift.getDeviceNo());
         }
         // 鍒濆鍖栧洓鍚戠┛姊溅mq
         List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                 .eq("device_type", String.valueOf(SlaveType.Shuttle)));
         for (DeviceConfig shuttle : shuttleList) {
-            MessageQueue.init(SlaveType.Shuttle, shuttle);
+            MessageQueue.init(SlaveType.Shuttle, shuttle.getDeviceNo());
         }
+
+        MessageQueue.init(SlaveType.TrafficControl, 1);
     }
 
     private void initThread(){
@@ -128,6 +132,10 @@
         //璁惧鍒濆鍖栧畬姣�
         deviceMsgUtils.sendDeviceConfig(JSON.toJSONString(allDevices));
         deviceMsgUtils.sendFakeDeviceConfig(JSON.toJSONString(fakeDevices));
+
+        TrafficControlThread trafficControlThread = new TrafficControlImplThread(redisUtil);
+        new Thread(trafficControlThread).start();
+        SlaveConnection.put(SlaveType.TrafficControl, 1, trafficControlThread);
     }
 
 
diff --git a/src/main/java/com/zy/core/action/ShuttleAction.java b/src/main/java/com/zy/core/action/ShuttleAction.java
index 1bfe527..393d2cb 100644
--- a/src/main/java/com/zy/core/action/ShuttleAction.java
+++ b/src/main/java/com/zy/core/action/ShuttleAction.java
@@ -13,31 +13,30 @@
 import com.zy.asrs.service.LocMastService;
 import com.zy.asrs.service.WrkMastService;
 import com.zy.asrs.utils.Utils;
-import com.zy.common.ExecuteSupport;
 import com.zy.common.model.NavigateNode;
 import com.zy.common.service.CommonService;
 import com.zy.common.utils.NavigateMapUtils;
+import com.zy.common.utils.NavigatePositionConvert;
 import com.zy.common.utils.RedisUtil;
 import com.zy.core.News;
 import com.zy.core.cache.SlaveConnection;
 import com.zy.core.dispatcher.ShuttleDispatchUtils;
 import com.zy.core.enums.*;
 import com.zy.core.model.CommandResponse;
+import com.zy.core.model.TrafficControlDataModel;
 import com.zy.core.model.command.ShuttleAssignCommand;
 import com.zy.core.model.command.ShuttleCommand;
 import com.zy.core.model.command.ShuttleRedisCommand;
 import com.zy.core.model.protocol.ShuttleProtocol;
 import com.zy.core.thread.ShuttleThread;
+import com.zy.core.thread.TrafficControlThread;
 import com.zy.system.entity.Config;
 import com.zy.system.service.ConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
 
 @Component
 public class ShuttleAction {
@@ -65,6 +64,17 @@
         ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
         if (shuttleThread == null) {
             return false;
+        }
+
+        TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+        if(trafficControlThread == null){
+            return false;
+        }
+
+        //娓呯┖涓嬪彂绱㈠紩
+        Set<String> keys = redisUtil.searchKeys(RedisKeyType.SHUTTLE_SEND_COMMAND_INDEX.key + shuttleNo);
+        for (String key : keys) {
+            redisUtil.del(key);
         }
 
         ShuttleRedisCommand redisCommand = new ShuttleRedisCommand();
@@ -113,139 +123,69 @@
             return false;
         }
 
-        List<ShuttleCommand> commands = redisCommand.getAssignCommand().getCommands();
-        if (commands.isEmpty()) {
+        //妫�娴嬪懡浠�
+        int checked = checkCommand(redisCommand, shuttleNo);
+        if (checked == 0) {
             return false;
         }
 
         ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand();
-        int commandStep = redisCommand.getCommandStep();
-
-        Integer mode = -1;
-        if(commandStep < commands.size()) {
-            //鍙栧嚭鍛戒护
-            ShuttleCommand currentCommand = commands.get(commandStep);
-            mode = currentCommand.getMode();
-        }
-
-        //鍒ゆ柇璁惧鏄惁绌洪棽
-        Integer finalMode = mode;
-        if (!shuttleThread.isDeviceIdle(new ExecuteSupport() {
-            @Override
-            public Boolean judgement() {
-                if (ShuttleCommandModeType.CHARGE_CLOSE.id.equals(finalMode)) {//鍏抽棴鍏呯數
-                    return false;//涓嶉渶瑕佸垽鏂姸鎬�
-                }
-                return true;//闇�瑕佸垽鏂姸鎬�
-            }
-        })) {
+        List<ShuttleCommand> commands = assignCommand.getCommands();
+        if (commands.isEmpty()) {
             return false;
         }
 
-        // 瀹岀粨涓婁竴鏉″懡浠�
-        boolean updateCommand = false;
-        if (commandStep != 0) {
-            ShuttleCommand command = commands.get(commandStep - 1);
-            if (command.getMode() == ShuttleCommandModeType.MOVE.id) {
-                // 姝e父绉诲姩
-                if (command.getTargetLocNo().equals(shuttleProtocol.getCurrentLocNo())) {
-                    command.setComplete(true);
-                    updateCommand = true;
-                    //瑙i攣閿佸畾璺緞锛屼笂涓�鏉¤矾寰�
-                    List<NavigateNode> nodes = null;
-                    try {
-                        String nodesStr = objectMapper.writeValueAsString(command.getNodes());
-                        nodes = objectMapper.readValue(nodesStr, new TypeReference<List<NavigateNode>>() {
-                        });
-                    } catch (IOException e) {
-                        throw new RuntimeException(e);
-                    }
-
-                    if (nodes != null) {
-                        NavigateNode targetNode = assignCommand.getNodes().get(assignCommand.getNodes().size() - 1);//鏈�缁堣妭鐐�
-                        NavigateNode node = nodes.get(nodes.size() - 1);
-                        if (!(targetNode.getX() == node.getX() && targetNode.getY() == node.getY())) {
-                            nodes.remove(nodes.size() - 1);//鍓旈櫎灏捐妭鐐�
-                        }
-                        boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(shuttleProtocol.getCurrentLocNo()), shuttleProtocol.getShuttleNo(), nodes, false);//瑙i攣璺緞
-                        if (!result) {
-                            return false;//瑙i攣澶辫触
-                        }
-                    }
-                }
-            } else if (command.getMode() == ShuttleCommandModeType.PALLET_LIFT.id) {
-                // 鎵樼洏椤跺崌
-                //鍒ゆ柇鏄惁椤跺崌鍒颁綅
-                if (shuttleProtocol.getHasLift()) {
-                    command.setComplete(true);
-                    updateCommand = true;
-//                    //鍒ゆ柇鏄惁鏈夌墿
-//                    if (shuttleProtocol.getHasPallet()) {
-//                        command.setComplete(true);
-//                    }
-                }
-            } else if (command.getMode() == ShuttleCommandModeType.PALLET_DOWN.id) {
-                // 鎵樼洏涓嬮檷鍛戒护
-                // 鍒ゆ柇鏄惁涓嬮檷鍒颁綅
-                if (!shuttleProtocol.getHasLift()) {
-                    command.setComplete(true);
-                    updateCommand = true;
-                }
-            } else if (command.getMode() == ShuttleCommandModeType.CHARGE_OPEN.id) {
-                // 鍏呯數寮�
-                //鍒ゆ柇灏忚溅鍏呯數鐘舵��
-                if (shuttleProtocol.getHasCharge()) {
-                    command.setComplete(true);
-                    updateCommand = true;
-                }
-            }else {
-                command.setComplete(true);//鍏朵粬鍛戒护榛樿璁や负瀹屾垚
-                updateCommand = true;
-            }
-
-            if(updateCommand) {
-                // 鏇存柊redis鏁版嵁
-                redisUtil.set(RedisKeyType.SHUTTLE_WORK_FLAG.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand, SerializerFeature.DisableCircularReferenceDetect));
-            }
-
-            if (!command.getComplete()) {
-                return false;
-            }
-
-            //鍒ゆ柇鏄惁涓烘渶鍚庝竴鏉″懡浠や笖鍛戒护鎵ц瀹屾垚锛屾姏鍑虹瓑寰呯‘璁ょ姸鎬�
-            ShuttleCommand endCommand = commands.get(commands.size() - 1);
-            if (endCommand.getComplete()) {
-                News.info("鍥涘悜绌挎杞︿换鍔℃墽琛屼笅鍙戝畬鎴愮瓑寰呮墽琛岀粨鏉燂紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(commands));
-
-                // 绯荤粺浠诲姟
-                if (assignCommand.getAuto()) {
-                    if (!assignCommand.getCharge()) {
-                        //瀵逛富绾跨▼鎶涘嚭绛夊緟纭鐘舵�亀aiting
-                        shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.WAITING);
-                    }else {
-                        shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.CHARGING_WAITING);
-                    }
-                    News.info("鍥涘悜绌挎杞︿换鍔℃墽琛屼笅鍙戝畬鎴愮瓑寰呮墽琛岀粨鏉燂紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command));
-
-                    // 鎵嬪姩浠诲姟
-                } else {
-                    //鎵嬪姩妯″紡涓嶆姏鍑虹瓑寰呯姸鎬侊紝鐩存帴澶嶄綅绌洪棽鐘舵��
-                    shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.IDLE);
-                    //浠诲姟鍙锋竻闆�
-                    shuttleThread.setSyncTaskNo(0);
-                    //鏍囪澶嶄綅
-                    shuttleThread.setPakMk(true);
-                    News.info("鍥涘悜绌挎杞︽墜鍔ㄤ换鍔℃墽琛屽畬鎴愶紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command));
-                }
-
-                //鍒犻櫎redis
-                redisUtil.del(RedisKeyType.SHUTTLE_WORK_FLAG.key + redisCommand.getWrkNo());
-                return false;//绂佹鍐嶄笅鍙戝懡浠�
-            }
+        int commandStep = redisCommand.getCommandStep();
+        if(commandStep >= commands.size()){
+            return false;
         }
 
         //鍙栧嚭鍛戒护
-        ShuttleCommand command = commands.get(commandStep);
+        ShuttleCommand command = null;
+        if (checked == 1) {
+            //闈炶繛缁寚浠わ紝闇�瑕佹娴嬩笂涓�鏉℃寚浠ゆ槸鍚﹀畬鎴�
+            if (commandStep > 0) {
+                ShuttleCommand lastCommand = commands.get(commandStep - 1);
+                if (!lastCommand.getComplete()) {
+                    return false;//鎸囦护鏈畬鎴�
+                }
+            }
+
+            command = commands.get(commandStep);
+        } else if (checked == 2) {
+            //杩炵画鎸囦护鐩存帴鍙栨暟鎹�
+            command = commands.get(commandStep);
+        }
+
+        if(command == null){
+            return false;
+        }
+
+        //绉诲姩鍛戒护锛岄攣瀹氳矾寰�
+        if (command.getMode() == ShuttleCommandModeType.MOVE.id) {
+            List<NavigateNode> nodes = JSON.parseArray(JSON.toJSONString(command.getNodes()), NavigateNode.class);
+            //鐢宠绠″埗
+            boolean apply = applyTrafficControl(commands, nodes, shuttleNo, taskNo);
+            if(!apply){
+                return false;//鐢宠澶辫触
+            }
+//            //妫�娴嬭矾寰勬槸鍚﹀啿绐�
+//            int conflict = searchShuttlePathConflict(nodes, shuttleNo);
+//            if(conflict == 2){
+//                return false;//妫�娴嬪悗鏈夊啿绐�
+//            }
+
+            if (checked == 2) {
+                nodes.remove(0);
+            }
+
+            boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(command.getTargetLocNo()), shuttleNo, nodes, true);//閿佸畾璺緞
+            if (!result) {
+                News.error("{} device can't lock path!", shuttleNo);
+                shuttleThread.offerSystemMsg("{} device can't lock path!", shuttleNo);
+                return false;//璺緞閿佸畾澶辫触
+            }
+        }
 
         // 涓嬪彂鍛戒护
         CommandResponse response = write(command, shuttleNo);
@@ -273,14 +213,400 @@
         }
 
         shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.WORKING);
-        commandStep++;
+
+        //瀛樺偍涓嬪彂鎸囦护绱㈠紩
+        redisUtil.set(RedisKeyType.SHUTTLE_SEND_COMMAND_INDEX.key + shuttleNo + "_" + taskNo + "_" + commandStep, commandStep);
+
+        commandStep += 1;
         //鏇存柊redis鏁版嵁
         redisCommand.setCommandStep(commandStep);
+
         //浠诲姟鏁版嵁淇濆瓨鍒皉edis
         redisUtil.set(RedisKeyType.SHUTTLE_WORK_FLAG.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
         return true;
     }
 
+    /**
+     * 妫�娴嬪懡浠�
+     * 0:鏈�氳繃 1:閫氳繃 2:閫氳繃涓斿彲鎻愬墠涓嬪彂鎸囦护
+     */
+    private int checkCommand(ShuttleRedisCommand redisCommand, Integer shuttleNo) {
+        TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+        if(trafficControlThread == null){
+            return 0;
+        }
+
+        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
+        if (shuttleThread == null) {
+            return 0;
+        }
+
+        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+        if (shuttleProtocol == null) {
+            return 0;
+        }
+
+        int commandStep = redisCommand.getCommandStep();
+        if (commandStep == 0) {
+            return 1;//绗竴鏉″懡浠ゆ棤闇�妫�娴�
+        }
+
+        ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand();
+        List<ShuttleCommand> commands = assignCommand.getCommands();
+        if (commands.isEmpty()) {
+            return 0;
+        }
+
+        //涓婁竴鏉℃寚浠�
+        String searchKey = RedisKeyType.SHUTTLE_SEND_COMMAND_INDEX.key + shuttleNo + "_" + redisCommand.getWrkNo() + "_";
+        Set<String> keys = redisUtil.searchKeys(searchKey);
+        TreeSet<Integer> treeSet = new TreeSet<>();
+        for (String key : keys) {
+            String[] split = key.split(searchKey);
+            treeSet.add(Integer.parseInt(split[1]));
+        }
+        if (treeSet.isEmpty()) {
+            return 1;
+        }
+
+        String firstKey = searchKey + treeSet.first();
+        Integer lastCommandIdx = (Integer) redisUtil.get(firstKey);
+        ShuttleCommand lastCommand = commands.get(lastCommandIdx);
+        if (!lastCommand.getComplete()) {
+            //妫�娴嬫洿鏂板懡浠ゅ畬鎴�
+            boolean checked = updateCommandComplete(lastCommandIdx, commands, shuttleNo);
+            if (checked) {
+                //鍒犻櫎绱㈠紩
+                redisUtil.del(firstKey);
+
+                // 鏇存柊redis鏁版嵁
+                redisUtil.set(RedisKeyType.SHUTTLE_WORK_FLAG.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand, SerializerFeature.DisableCircularReferenceDetect));
+            }else {
+                //灏忚溅绉诲姩杩炵画涓嬪彂鎸囦护
+                if (assignCommand.getShuttleMoveCommandsContinuously()) {
+                    if (treeSet.size() <= 1) {
+                        if(commandStep >= commands.size()) {
+                            return 0;
+                        }
+
+                        //绉诲姩鎸囦护
+                        if(lastCommand.getMode() != ShuttleCommandModeType.MOVE.id) {
+                            return 0;
+                        }
+
+                        List<NavigateNode> nodes = lastCommand.getNodes();
+                        NavigateNode startNode = nodes.get(0);
+                        if (!startNode.getLinePartAllowGo()) {//鐩寸嚎娈甸儴鍒嗭紝鍏佽鐩存帴琛岃蛋
+                            return 0;
+                        }
+
+                        //鐩寸嚎娈垫暟鎹爣璇�
+                        Long linePartFlag = startNode.getLinePartFlag();
+
+                        //鍙栨寚浠�
+                        ShuttleCommand currentCommand = commands.get(commandStep);
+                        if(currentCommand.getMode() != ShuttleCommandModeType.MOVE.id) {
+                            return 0;
+                        }
+
+                        List<NavigateNode> currentNodes = currentCommand.getNodes();
+                        NavigateNode currentStartNode = currentNodes.get(0);
+                        if(!currentStartNode.getLinePartAllowGo()) {//鐩寸嚎娈甸儴鍒嗭紝鍏佽鐩存帴琛岃蛋
+                            return 0;
+                        }
+
+                        if(currentStartNode.getLinePartFlag().equals(linePartFlag)) {
+                            //鏁版嵁鏍囪瘑涓�鑷�
+                            return 2;//鍏佽灏忚溅绉诲姩杩炵画涓嬪彂鎸囦护
+                        }
+
+                    }
+                }
+
+                return 0;
+            }
+        }
+
+        //鍒ゆ柇鏄惁涓烘渶鍚庝竴鏉″懡浠や笖鍛戒护鎵ц瀹屾垚锛屾姏鍑虹瓑寰呯‘璁ょ姸鎬�
+        ShuttleCommand endCommand = commands.get(commands.size() - 1);
+        if (endCommand.getComplete()) {
+            News.info("鍥涘悜绌挎杞︿换鍔℃墽琛屼笅鍙戝畬鎴愮瓑寰呮墽琛岀粨鏉燂紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(commands));
+
+            // 绯荤粺浠诲姟
+            if (assignCommand.getAuto()) {
+                if (!assignCommand.getCharge()) {
+                    //瀵逛富绾跨▼鎶涘嚭绛夊緟纭鐘舵�亀aiting
+                    shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.WAITING);
+                } else {
+                    shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.CHARGING_WAITING);
+                }
+                News.info("鍥涘悜绌挎杞︿换鍔℃墽琛屼笅鍙戝畬鎴愮瓑寰呮墽琛岀粨鏉燂紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(endCommand));
+
+                // 鎵嬪姩浠诲姟
+            } else {
+                //鎵嬪姩妯″紡涓嶆姏鍑虹瓑寰呯姸鎬侊紝鐩存帴澶嶄綅绌洪棽鐘舵��
+                shuttleThread.setProtocolStatus(ShuttleProtocolStatusType.IDLE);
+                //浠诲姟鍙锋竻闆�
+                shuttleThread.setSyncTaskNo(0);
+                //鏍囪澶嶄綅
+                shuttleThread.setPakMk(true);
+                News.info("鍥涘悜绌挎杞︽墜鍔ㄤ换鍔℃墽琛屽畬鎴愶紝绌挎杞﹀彿={}锛屼换鍔℃暟鎹�={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(endCommand));
+            }
+
+            //鐢宠鍙栨秷绠″埗
+            trafficControlThread.cancelTrafficControl(shuttleNo, shuttleProtocol.getTaskNo());
+            //鍒犻櫎redis
+            redisUtil.del(RedisKeyType.SHUTTLE_WORK_FLAG.key + redisCommand.getWrkNo());
+            return 0;//绂佹鍐嶄笅鍙戝懡浠�
+        }
+
+        return 1;
+    }
+
+    //妫�娴嬫洿鏂板懡浠ゅ畬鎴�
+    private boolean updateCommandComplete(Integer commandIdx, List<ShuttleCommand> commands, Integer shuttleNo) {
+        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
+        if (shuttleThread == null) {
+            return false;
+        }
+
+        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+        if (shuttleProtocol == null) {
+            return false;
+        }
+
+        //鍒ゆ柇璁惧鏄惁绌洪棽
+        boolean deviceIdle = shuttleThread.isDeviceIdle();
+
+        ShuttleCommand command = commands.get(commandIdx);
+        if (command.getMode() == ShuttleCommandModeType.MOVE.id) {
+            // 姝e父绉诲姩
+            List<String> targetPoints = new ArrayList<>();
+
+            //瑙i攣閿佸畾璺緞锛屼笂涓�鏉¤矾寰�
+            List<NavigateNode> nodes = null;
+            try {
+                String nodesStr = objectMapper.writeValueAsString(command.getNodes());
+                nodes = objectMapper.readValue(nodesStr, new TypeReference<List<NavigateNode>>() {
+                });
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            NavigateNode startNode = nodes.get(0);
+            Long linePartFlag = startNode.getLinePartFlag();
+
+            NavigateNode targetNode = nodes.get(nodes.size() - 1);
+            targetPoints.add(targetNode.getX() + "-" + targetNode.getY());
+
+            for (int i = commandIdx + 1; i < commands.size(); i++) {
+                ShuttleCommand nextCommand = commands.get(i);
+                if (nextCommand.getMode() == ShuttleCommandModeType.MOVE.id) {
+                    List<NavigateNode> nextCommandNodes = nextCommand.getNodes();
+                    NavigateNode nextStartNode = nextCommandNodes.get(0);
+                    Long nextLinePartFlag = nextStartNode.getLinePartFlag();
+                    if(nextLinePartFlag.equals(linePartFlag)) {
+                        for (NavigateNode node : nextCommandNodes) {
+                            String key = node.getX() + "-" + node.getY();
+                            if(!targetPoints.contains(key)) {
+                                targetPoints.add(key);
+                            }
+                        }
+                    }
+                }
+            }
+
+            TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+            if (trafficControlThread == null) {
+                return false;
+            }
+
+            TrafficControlDataModel trafficControlDataModel = trafficControlThread.queryTrafficControl(shuttleNo);
+            if (trafficControlDataModel != null) {
+                //鏈夌鍒朵俊鎭紝杩涜妫�娴�
+                if (!trafficControlDataModel.getTaskNo().equals(shuttleProtocol.getTaskNo())) {
+                    return false;//浠诲姟涓嶄竴鑷�
+                }
+
+                //妫�娴嬫槸鍚﹀埌缁堢偣
+                List<NavigateNode> totalNodeList = trafficControlDataModel.getTotalNodeList();
+                NavigateNode trafficTargetNode = totalNodeList.get(totalNodeList.size() - 1);
+                String trafficTargetLoc = Utils.getLocNo(trafficTargetNode.getX(), trafficTargetNode.getY(), trafficTargetNode.getZ());
+
+                //鍒ゆ柇灏忚溅鏄惁鍒扮粓鐐�
+                if(shuttleProtocol.getCurrentLocNo().equals(trafficTargetLoc)) {
+                    //涓婃姤浜ょ
+                    trafficControlThread.trafficReport(command.getNodesDeepCopy(), shuttleNo, shuttleProtocol.getTaskNo());
+                }
+            }
+
+            String currentLocNo = shuttleProtocol.getCurrentLocNo();
+            if (targetPoints.contains(Utils.getRow(currentLocNo) + "-" + Utils.getBay(currentLocNo))) {
+                command.setComplete(true);
+                boolean result = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(shuttleProtocol.getCurrentLocNo()), shuttleProtocol.getShuttleNo(), nodes, false);//瑙i攣璺緞
+                if (!result) {
+                    return false;//瑙i攣澶辫触
+                }
+            }else {
+                return false;
+            }
+        } else if (command.getMode() == ShuttleCommandModeType.PALLET_LIFT.id) {
+            // 鎵樼洏椤跺崌
+            if (!deviceIdle) {
+                return false;//璁惧涓嶇┖闂�
+            }
+
+            //鍒ゆ柇鏄惁椤跺崌鍒颁綅
+            if (shuttleProtocol.getHasLift()) {
+                command.setComplete(true);
+//                    //鍒ゆ柇鏄惁鏈夌墿
+//                    if (shuttleProtocol.getHasPallet()) {
+//                        command.setComplete(true);
+//                    }
+            }else {
+                return false;
+            }
+        } else if (command.getMode() == ShuttleCommandModeType.PALLET_DOWN.id) {
+            // 鎵樼洏涓嬮檷鍛戒护
+            if (!deviceIdle) {
+                return false;//璁惧涓嶇┖闂�
+            }
+
+            // 鍒ゆ柇鏄惁涓嬮檷鍒颁綅
+            if (!shuttleProtocol.getHasLift()) {
+                command.setComplete(true);
+            }else {
+                return false;
+            }
+        } else if (command.getMode() == ShuttleCommandModeType.CHARGE_OPEN.id) {
+            // 鍏呯數寮�
+            //鍒ゆ柇灏忚溅鍏呯數鐘舵��
+            if (shuttleProtocol.getHasCharge()) {
+                command.setComplete(true);
+            }else {
+                return false;
+            }
+        } else if (command.getMode() == ShuttleCommandModeType.CHARGE_CLOSE.id) {
+            //鍏抽棴鍏呯數
+            command.setComplete(true);
+        } else {
+            command.setComplete(true);//鍏朵粬鍛戒护榛樿璁や负瀹屾垚
+        }
+
+        return true;
+    }
+
+    //鐢宠绠″埗
+    public boolean applyTrafficControl(List<ShuttleCommand> commands, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) {
+        TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+        if (trafficControlThread == null) {
+            return false;
+        }
+
+        NavigateNode startNode = nodeList.get(0);
+        Long linePartFlag = startNode.getLinePartFlag();
+
+        List<NavigateNode> totalNodeList = new ArrayList<>();
+        for (ShuttleCommand command : commands) {
+            if (command.getMode() == ShuttleCommandModeType.MOVE.id) {
+                NavigateNode node = command.getNodes().get(0);
+                Long nodeLinePartFlag = node.getLinePartFlag();
+                if (nodeLinePartFlag.equals(linePartFlag)) {
+                    List<NavigateNode> deepCopy = command.getNodesDeepCopy();
+                    if (deepCopy != null) {
+                        totalNodeList.addAll(deepCopy);
+                    }
+                }
+            }
+        }
+        return trafficControlThread.applyTrafficControl(totalNodeList, nodeList, shuttleNo, taskNo);
+    }
+
+//    /**
+//     * 鎼滅储灏忚溅璺緞鏄惁瀛樺湪鍐茬獊
+//     * 0:鏈娴� 1:妫�娴嬫棤鍐茬獊 2:妫�娴嬫湁鍐茬獊
+//     */
+//    public int searchShuttlePathConflict(List<NavigateNode> nodeList, Integer shuttleNo) {
+//        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
+//        if (shuttleThread == null) {
+//            return 0;
+//        }
+//
+//        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+//        if (shuttleProtocol == null) {
+//            return 0;
+//        }
+//
+//        int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());
+//
+//        TrafficControlThread trafficControlThread = (TrafficControlThread) SlaveConnection.get(SlaveType.TrafficControl, 1);
+//        if (trafficControlThread == null) {
+//            return 2;
+//        }
+//        HashMap<String, List<Integer>> nodeMap = trafficControlThread.getNodesMapByLev(lev);
+//        if (nodeMap == null || nodeMap.isEmpty()) {
+//            return 2;
+//        }
+//
+//        List<String> conflictLocList = new ArrayList<>();
+//        for (NavigateNode node : nodeList) {
+//            String locNo = Utils.getLocNo(node.getX(), node.getY(), lev);
+//            if(!nodeMap.containsKey(locNo)) {
+//                return 2;
+//            }
+//
+//            List<Integer> shuttleNos = nodeMap.get(locNo);
+//            if (shuttleNos.size() > 1) {
+//                //璺緞瀛樺湪澶氳溅锛屽啿绐�
+//                conflictLocList.add(locNo);
+//            }
+//        }
+//
+//        if (conflictLocList.isEmpty()) {
+//            //鏃犲啿绐侊紝瑙i櫎浜ら�氱鍒�
+//            shuttleThread.setTrafficControl(false, null);
+//            return 1;//妫�娴嬪悗鏃犲啿绐�
+//        }
+//
+//        //璺緞瀛樺湪鍐茬獊锛屾娴嬪彲鎵ц杞﹁締鏄惁涓哄綋鍓嶅皬杞�
+//        //涓婃姤灏忚溅鐘舵��-浜ら�氱鍒朵腑
+//        shuttleThread.setTrafficControl(true, nodeList);
+//
+//        HashMap<String, Integer> deviceMap = trafficControlThread.getDeviceMap();
+//        if(deviceMap == null) {
+//            return 2;
+//        }
+//
+//        boolean detected = false;
+////            for (Map.Entry<String, Integer> entry : deviceMap.entrySet()) {
+////                List<String> mainList = JSON.parseArray(entry.getKey(), String.class);
+////                Integer device = entry.getValue();
+////                if(result) {
+////                    //鍒ゆ柇绠″埗杞﹁締鏄惁鍖归厤
+////                    if(shuttleNo.equals(device)) {
+////                        detected = true;
+////                        break;
+////                    }
+////                }
+////            }
+//
+//        for (Map.Entry<String, Integer> entry : deviceMap.entrySet()) {
+//            String key = entry.getKey();
+//            Integer value = entry.getValue();
+//            if(shuttleNo.equals(value)) {
+//                //鍒ゆ柇绠″埗杞﹁締鏄惁鍖归厤
+//                detected = true;
+//                break;
+//            }
+//        }
+//
+//        if (detected) {
+//            return 1;//妫�娴嬪悗鏃犲啿绐侊紝浜ら�氱鍒跺凡鍏佽姝ゅ皬杞﹁繍琛�
+//        }
+//
+//        return 2;//妫�娴嬪悗鏈夊啿绐�
+//    }
+
     //婕旂ず妯″紡
     public synchronized void demo(Integer shuttleNo) {
         ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
diff --git a/src/main/java/com/zy/core/cache/MessageQueue.java b/src/main/java/com/zy/core/cache/MessageQueue.java
index 4037c4a..9788407 100644
--- a/src/main/java/com/zy/core/cache/MessageQueue.java
+++ b/src/main/java/com/zy/core/cache/MessageQueue.java
@@ -1,6 +1,5 @@
 package com.zy.core.cache;
 
-import com.zy.asrs.entity.DeviceConfig;
 import com.zy.core.enums.SlaveType;
 import com.zy.core.model.Task;
 
@@ -22,23 +21,28 @@
     private static final Map<Integer, ConcurrentLinkedQueue<Task>> FORK_LIFT_EXCHANGE = new ConcurrentHashMap<>();
     //璐у弶鎻愬崌鏈篗aster mq浜ゆ崲鏈�
     private static final Map<Integer, ConcurrentLinkedQueue<Task>> FORK_LIFT_MASTER_EXCHANGE = new ConcurrentHashMap<>();
+    //Traffic Control mq浜ゆ崲鏈�
+    private static final Map<Integer, ConcurrentLinkedQueue<Task>> TRAFFIC_CONTROL_EXCHANGE = new ConcurrentHashMap<>();
 
     /**
      * mq 浜ゆ崲鏈哄垵濮嬪寲
      */
-    public static void init(SlaveType type, DeviceConfig deviceConfig) {
+    public static void init(SlaveType type, Integer id) {
         switch (type) {
             case Shuttle:
-                SHUTTLE_EXCHANGE.put(deviceConfig.getDeviceNo(), new ConcurrentLinkedQueue<>());
+                SHUTTLE_EXCHANGE.put(id, new ConcurrentLinkedQueue<>());
                 break;
             case ForkLift:
-                FORK_LIFT_EXCHANGE.put(deviceConfig.getDeviceNo(), new ConcurrentLinkedQueue<>());
+                FORK_LIFT_EXCHANGE.put(id, new ConcurrentLinkedQueue<>());
                 break;
             case ForkLiftMaster:
-                FORK_LIFT_MASTER_EXCHANGE.put(deviceConfig.getDeviceNo(), new ConcurrentLinkedQueue<>());
+                FORK_LIFT_MASTER_EXCHANGE.put(id, new ConcurrentLinkedQueue<>());
                 break;
             case Lift:
-                LIFT_EXCHANGE.put(deviceConfig.getDeviceNo(), new ConcurrentLinkedQueue<>());
+                LIFT_EXCHANGE.put(id, new ConcurrentLinkedQueue<>());
+                break;
+            case TrafficControl:
+                TRAFFIC_CONTROL_EXCHANGE.put(id, new ConcurrentLinkedQueue<>());
                 break;
             default:
                 break;
@@ -59,6 +63,8 @@
                 return FORK_LIFT_MASTER_EXCHANGE.get(id).offer(task);
             case Lift:
                 return LIFT_EXCHANGE.get(id).offer(task);
+            case TrafficControl:
+                return TRAFFIC_CONTROL_EXCHANGE.get(id).offer(task);
             default:
                 return false;
         }
@@ -78,6 +84,8 @@
                 return FORK_LIFT_MASTER_EXCHANGE.get(id).poll();
             case Lift:
                 return LIFT_EXCHANGE.get(id).poll();
+            case TrafficControl:
+                return TRAFFIC_CONTROL_EXCHANGE.get(id).poll();
             default:
                 return null;
         }
@@ -96,6 +104,8 @@
                 return FORK_LIFT_MASTER_EXCHANGE.get(id).peek();
             case Lift:
                 return LIFT_EXCHANGE.get(id).peek();
+            case TrafficControl:
+                return TRAFFIC_CONTROL_EXCHANGE.get(id).peek();
             default:
                 return null;
         }
@@ -115,6 +125,9 @@
             case Lift:
                 LIFT_EXCHANGE.get(id).clear();
                 break;
+            case TrafficControl:
+                TRAFFIC_CONTROL_EXCHANGE.get(id).clear();
+                break;
             default:
                 break;
         }
diff --git a/src/main/java/com/zy/core/enums/RedisKeyType.java b/src/main/java/com/zy/core/enums/RedisKeyType.java
index da700bd..d6e6650 100644
--- a/src/main/java/com/zy/core/enums/RedisKeyType.java
+++ b/src/main/java/com/zy/core/enums/RedisKeyType.java
@@ -14,6 +14,12 @@
     FORK_LIFT_PUT_COMPLETE("fork_lift_put_complete_"),
     OUT_TASK_PREVIEW_DISPATCH_FORKLIFT("out_task_preview_dispatch_forklift_"),
 
+    //灏忚溅涓嬪彂鎸囦护绱㈠紩
+    SHUTTLE_SEND_COMMAND_INDEX("shuttle_send_command_index_"),
+
+    //浠诲姟鍫靛鍙敤璁惧鍦板浘
+    TASK_BLOCK_ENABLE_DEVICE_MAP("task_block_enable_device_map"),
+
     //鍦板浘閿佸畾鑺傜偣
     LOCK_MAP_NODES("lock_map_nodes_"),
 
diff --git a/src/main/java/com/zy/core/enums/SlaveType.java b/src/main/java/com/zy/core/enums/SlaveType.java
index 4b65625..0412a07 100644
--- a/src/main/java/com/zy/core/enums/SlaveType.java
+++ b/src/main/java/com/zy/core/enums/SlaveType.java
@@ -6,6 +6,7 @@
     Lift,
     ForkLift,
     ForkLiftMaster,
+    TrafficControl,
     ;
 
     public static SlaveType findInstance(String s){
diff --git a/src/main/java/com/zy/core/model/TrafficControlDataModel.java b/src/main/java/com/zy/core/model/TrafficControlDataModel.java
new file mode 100644
index 0000000..b73396f
--- /dev/null
+++ b/src/main/java/com/zy/core/model/TrafficControlDataModel.java
@@ -0,0 +1,19 @@
+package com.zy.core.model;
+
+import com.zy.common.model.NavigateNode;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TrafficControlDataModel {
+
+    private Integer shuttleNo;
+
+    private Integer taskNo;
+
+    private List<NavigateNode> nodeList;
+
+    private List<NavigateNode> totalNodeList;
+
+}
diff --git a/src/main/java/com/zy/core/model/command/ShuttleAssignCommand.java b/src/main/java/com/zy/core/model/command/ShuttleAssignCommand.java
index a64f1c4..841ec12 100644
--- a/src/main/java/com/zy/core/model/command/ShuttleAssignCommand.java
+++ b/src/main/java/com/zy/core/model/command/ShuttleAssignCommand.java
@@ -77,6 +77,9 @@
      */
     private List<NavigateNode> nodes;
 
+    //灏忚溅绉诲姩杩炵画涓嬪彂鎸囦护
+    private Boolean shuttleMoveCommandsContinuously;
+
     public List<NavigateNode> getNodesDeepCopy() {
         if (this.nodes == null) {
             return null;
diff --git a/src/main/java/com/zy/core/model/command/ShuttleCommand.java b/src/main/java/com/zy/core/model/command/ShuttleCommand.java
index a0c8b22..8e420f9 100644
--- a/src/main/java/com/zy/core/model/command/ShuttleCommand.java
+++ b/src/main/java/com/zy/core/model/command/ShuttleCommand.java
@@ -3,6 +3,8 @@
 import com.zy.common.model.NavigateNode;
 import com.zy.core.enums.ShuttleCommandModeType;
 import lombok.Data;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -50,7 +52,18 @@
         if (this.mode == null) {
             return null;
         }
-
         return ShuttleCommandModeType.get(this.mode).desc;
     }
+
+    public List<NavigateNode> getNodesDeepCopy() {
+        if (this.nodes == null) {
+            return null;
+        }
+        List<NavigateNode> navigateNodes = new ArrayList<>();
+        for (NavigateNode node : nodes) {
+            navigateNodes.add(node.clone());
+        }
+        return navigateNodes;
+    }
+
 }
diff --git a/src/main/java/com/zy/core/model/protocol/ShuttleProtocol.java b/src/main/java/com/zy/core/model/protocol/ShuttleProtocol.java
index a4bf8e0..c4db647 100644
--- a/src/main/java/com/zy/core/model/protocol/ShuttleProtocol.java
+++ b/src/main/java/com/zy/core/model/protocol/ShuttleProtocol.java
@@ -6,6 +6,7 @@
 import com.zy.asrs.entity.LocMast;
 import com.zy.asrs.service.BasShuttleErrService;
 import com.zy.asrs.service.LocMastService;
+import com.zy.common.model.NavigateNode;
 import com.zy.common.utils.RedisUtil;
 import com.zy.core.enums.RedisKeyType;
 import com.zy.core.enums.ShuttleProtocolStatusType;
@@ -13,6 +14,7 @@
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * 鍥涘悜绌挎杞�
@@ -184,6 +186,11 @@
     private Long lastOnlineTime = System.currentTimeMillis();
 
     /**
+     * 灏忚溅绌洪棽鏃堕棿
+     */
+    private Long idleTime = System.currentTimeMillis();
+
+    /**
      * 鎵╁睍瀛楁
      */
     private Object extend;
@@ -193,6 +200,16 @@
      */
     private String systemMsg;
 
+    /**
+     * 浜ら�氱鍒�
+     */
+    private Boolean trafficControl = false;
+
+    /**
+     * 浜ら�氱鍒禢odes
+     */
+    private List<NavigateNode> trafficControlNodes = null;
+
     public String getProtocolStatus$() {
         if (this.protocolStatusType == null) {
             return "";
diff --git a/src/main/java/com/zy/core/thread/ShuttleThread.java b/src/main/java/com/zy/core/thread/ShuttleThread.java
index a1444cc..aaa63c0 100644
--- a/src/main/java/com/zy/core/thread/ShuttleThread.java
+++ b/src/main/java/com/zy/core/thread/ShuttleThread.java
@@ -70,6 +70,8 @@
 
     boolean offerSystemMsg(String format, Object... arguments);
 
+    boolean setTrafficControl(boolean enable, List<NavigateNode> nodeList);
+
     void updateDeviceDataLogTime(long time);
 
     JSONObject parseStatusToMsg(ShuttleProtocol shuttleProtocol);
diff --git a/src/main/java/com/zy/core/thread/TrafficControlThread.java b/src/main/java/com/zy/core/thread/TrafficControlThread.java
new file mode 100644
index 0000000..ea0411a
--- /dev/null
+++ b/src/main/java/com/zy/core/thread/TrafficControlThread.java
@@ -0,0 +1,30 @@
+package com.zy.core.thread;
+
+
+import com.zy.common.model.NavigateNode;
+import com.zy.core.ThreadHandler;
+import com.zy.core.model.TrafficControlDataModel;
+
+import java.util.HashMap;
+import java.util.List;
+
+public interface TrafficControlThread extends ThreadHandler {
+
+//    boolean getDetecting();
+//
+//    void updateDetect();
+//
+//    boolean addNodes(Integer shuttleNo, Integer taskNo, List<NavigateNode> nodeList);
+//
+//    boolean removeNodes(Integer shuttleNo, Integer taskNo);
+
+    boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo);
+
+    boolean trafficReport(List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo);
+
+    boolean cancelTrafficControl(Integer shuttleNo, Integer taskNo);
+
+    TrafficControlDataModel queryTrafficControl(Integer shuttleNo);
+
+    List<TrafficControlDataModel> getAllTrafficControl();
+}
diff --git a/src/main/java/com/zy/core/thread/impl/NyShuttleThread.java b/src/main/java/com/zy/core/thread/impl/NyShuttleThread.java
index 05d895e..2542703 100644
--- a/src/main/java/com/zy/core/thread/impl/NyShuttleThread.java
+++ b/src/main/java/com/zy/core/thread/impl/NyShuttleThread.java
@@ -752,6 +752,9 @@
 
     @Override
     public synchronized boolean setProtocolStatus(ShuttleProtocolStatusType status) {
+        if (status.equals(ShuttleProtocolStatusType.IDLE)) {
+            this.shuttleProtocol.setIdleTime(System.currentTimeMillis());
+        }
         this.shuttleProtocol.setProtocolStatus(status);
         return true;
     }
@@ -821,6 +824,13 @@
     }
 
     @Override
+    public boolean setTrafficControl(boolean enable, List<NavigateNode> nodeList) {
+        shuttleProtocol.setTrafficControl(enable);
+        shuttleProtocol.setTrafficControlNodes(nodeList);
+        return true;
+    }
+
+    @Override
     public void updateDeviceDataLogTime(long time) {
         shuttleProtocol.setDeviceDataLog(time);
     }
diff --git a/src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java b/src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java
new file mode 100644
index 0000000..40379eb
--- /dev/null
+++ b/src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java
@@ -0,0 +1,575 @@
+package com.zy.core.thread.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.core.common.SpringUtils;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zy.asrs.utils.Utils;
+import com.zy.common.model.NavigateNode;
+import com.zy.common.model.enums.NavigationMapType;
+import com.zy.common.utils.NavigatePositionConvert;
+import com.zy.common.utils.NavigateUtils;
+import com.zy.common.utils.RedisUtil;
+import com.zy.core.News;
+import com.zy.core.cache.SlaveConnection;
+import com.zy.core.enums.RedisKeyType;
+import com.zy.core.enums.SlaveType;
+import com.zy.core.model.TrafficControlDataModel;
+import com.zy.core.model.command.ShuttleAssignCommand;
+import com.zy.core.model.command.ShuttleRedisCommand;
+import com.zy.core.model.protocol.ShuttleProtocol;
+import com.zy.core.thread.ShuttleThread;
+import com.zy.core.thread.TrafficControlThread;
+import com.zy.core.utils.TrafficControlUtils;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.function.Function;
+
+public class TrafficControlImplThread implements TrafficControlThread {
+
+    private RedisUtil redisUtil;
+    private boolean detecting = false;
+    private boolean updateDetect = false;
+    private Long detectTime = System.currentTimeMillis();
+    private HashMap<String, Integer> deviceMap = null;
+    private HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = null;
+    private HashMap<String, List<NavigateNode>> taskNodesMap = new HashMap<>();
+    private List<TrafficControlDataModel> trafficControlDataList = new ArrayList<>();
+
+    public TrafficControlImplThread(RedisUtil redisUtil) {
+        this.redisUtil = redisUtil;
+    }
+
+    @Override
+    public void run() {
+//        List<Integer> shuttleNoList = new ArrayList<>();
+//        while (true) {
+//            try {
+//                DeviceConfigService deviceConfigService = null;
+//                try {
+//                    deviceConfigService = SpringUtils.getBean(DeviceConfigService.class);
+//                }catch (Exception e){}
+//
+//                if(deviceConfigService == null){
+//                    continue;
+//                }
+//
+//                if(shuttleNoList.isEmpty()){
+//                    List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
+//                            .eq("device_type", String.valueOf(SlaveType.Shuttle)));
+//                    for (DeviceConfig deviceConfig : shuttleList) {
+//                        shuttleNoList.add(deviceConfig.getDeviceNo());
+//                    }
+//                }
+//
+//                if((updateDetect) || ((System.currentTimeMillis() - detectTime) > 1000 * 2)) {
+//                    detect(shuttleNoList);
+//                }
+//            }catch (Exception e){
+//                e.printStackTrace();
+//            }
+//        }
+
+    }
+
+    public synchronized void detect(List<Integer> shuttleNoList) {
+        detecting = true;
+        updateDetect = false;
+        ObjectMapper objectMapper = null;
+        try {
+            objectMapper = SpringUtils.getBean(ObjectMapper.class);
+        }catch (Exception e){}
+
+        if(objectMapper == null){
+            return;
+        }
+
+        HashMap<String, List<NavigateNode>> tmpTaskNodesMap = new HashMap<>();
+        for (Integer shuttleNo : shuttleNoList) {
+            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
+            if (shuttleThread == null) {
+                continue;
+            }
+
+            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+            if (shuttleProtocol == null) {
+                continue;
+            }
+
+            if (shuttleProtocol.getTaskNo() == 0) {
+                continue;
+            }
+
+            if (shuttleProtocol.getCurrentLocNo() == null) {
+                continue;
+            }
+
+            int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());
+
+            Object obj = redisUtil.get(RedisKeyType.SHUTTLE_WORK_FLAG.key + shuttleProtocol.getTaskNo());
+            if (obj == null) {
+                continue;
+            }
+
+            ShuttleRedisCommand redisCommand = null;
+            try {
+                redisCommand = objectMapper.readValue(String.valueOf(obj), ShuttleRedisCommand.class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            if (redisCommand == null) {
+                continue;
+            }
+
+            ShuttleAssignCommand assignCommand = redisCommand.getAssignCommand();
+            if (assignCommand == null) {
+                continue;
+            }
+
+            List<NavigateNode> nodeList = assignCommand.getNodesDeepCopy();
+            if (nodeList == null || nodeList.isEmpty()) {
+                continue;
+            }
+
+            tmpTaskNodesMap.put(shuttleProtocol.getTaskNo() + "-" + shuttleNo, nodeList);
+        }
+        this.taskNodesMap = tmpTaskNodesMap;
+        HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = calcNodeList();
+
+        HashMap<Integer, HashMap<String, List<Integer>>> levBlockMap = new HashMap<>();
+        //杩囨护涓嶉渶瑕佺鍒惰妭鐐�
+        for (Map.Entry<Integer, HashMap<String, List<Integer>>> entry : levNodesMap.entrySet()) {
+            Integer lev = entry.getKey();
+            HashMap<String, List<Integer>> value = entry.getValue();
+
+            HashMap<String, List<Integer>> blockMap = new HashMap<>();
+            for (Map.Entry<String, List<Integer>> listEntry : value.entrySet()) {
+                String locNo = listEntry.getKey();
+                List<Integer> shuttleNos = listEntry.getValue();
+                if (shuttleNos.size() <= 1) {
+                    continue;
+                }
+                blockMap.put(locNo, shuttleNos);
+            }
+
+            levBlockMap.put(lev, blockMap);
+        }
+
+        //璁$畻鍫靛鑼冨洿
+        List<List<String>> allLocList = new ArrayList<>();
+        List<List<Integer>> allDeviceNodes = new ArrayList<>();
+        for (Map.Entry<Integer, HashMap<String, List<Integer>>> entry : levBlockMap.entrySet()) {
+            Integer lev = entry.getKey();
+            HashMap<String, List<Integer>> nodes = entry.getValue();
+
+            Set<String> sets = new HashSet<>();
+            for (Map.Entry<String, List<Integer>> val : nodes.entrySet()) {
+                String locNo = val.getKey();
+                sets.add(locNo);
+            }
+
+            List<List<String>> locList = TrafficControlUtils.groupNodes(sets);
+            List<List<Integer>> deviceNodes = new ArrayList<>();
+
+            //get devices
+            for (List<String> list : locList) {
+                List<List<Integer>> tmpDeviceNodes = new ArrayList<>();
+                for (String loc : list) {
+                    List<Integer> shuttleNos = nodes.get(loc);
+                    if(!tmpDeviceNodes.contains(shuttleNos)) {
+                        tmpDeviceNodes.add(shuttleNos);
+                    }
+                }
+                //鑺傜偣骞堕泦-鑾峰彇鍫靛璁惧缂栧彿
+                List<List<Integer>> deviceList = mergeConnectedComponents(tmpDeviceNodes);
+                deviceNodes.addAll(deviceList);
+            }
+
+            allLocList.addAll(locList);
+            allDeviceNodes.addAll(deviceNodes);
+        }
+
+        System.out.println(JSON.toJSONString(allLocList));
+        System.out.println(JSON.toJSONString(allDeviceNodes));
+//        //鍒嗛厤鍫靛鑺傜偣鍙墽琛岃澶�
+//        findDeviceByBlockList(allLocList, allDeviceNodes);
+
+        detecting = false;
+        detectTime = System.currentTimeMillis();
+
+        //鍙戝竷鍫靛鑺傜偣鍙敤璁惧缂栧彿
+        redisUtil.set(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key, trafficControlDataList);
+    }
+
+    //鍒嗛厤鍫靛鑺傜偣鍙墽琛岃澶�
+    public void findDeviceByBlockList(List<List<String>> allLocList, List<List<Integer>> blockNodes) {
+        HashMap<String, Integer> map = new HashMap<>();
+        if (deviceMap == null) {
+            Object object = redisUtil.get(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key);
+            if (object != null) {
+                map = (HashMap<String, Integer>) object;
+            }
+        } else {
+            map = deviceMap;
+        }
+
+        HashMap<String, Integer> newMap = new HashMap<>();
+
+        for (int i = 0; i < blockNodes.size(); i++) {
+            List<Integer> blockNode = blockNodes.get(i);
+            List<String> locs = allLocList.get(i);
+
+            String key = JSON.toJSONString(locs);
+
+            Integer value = -1;
+            if (map.containsKey(key)) {
+                value = map.get(key);
+                map.remove(key);
+
+                if (value > 0) {
+                    ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, value);
+                    if (shuttleThread == null) {
+                        continue;
+                    }
+
+                    ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+                    if (shuttleProtocol == null) {
+                        continue;
+                    }
+
+                    if (shuttleProtocol.getTaskNo() == 0) {
+                        value = searchDevice(locs, blockNode, newMap);
+                    }
+
+                    if (!shuttleProtocol.getTrafficControl()) {
+                        value = searchDevice(locs, blockNode, newMap);
+                    }
+                }else {
+                    value = searchDevice(locs, blockNode, newMap);
+                }
+            } else {
+                value = searchDevice(locs, blockNode, newMap);
+            }
+            newMap.put(key, value);
+        }
+
+        deviceMap = newMap;
+        //鍙戝竷鍫靛鑺傜偣鍙敤璁惧缂栧彿
+        redisUtil.set(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key, newMap);
+    }
+
+    public Integer searchDevice(List<String> locs, List<Integer> blockNode, HashMap<String, Integer> deviceMap) {
+        NavigateUtils navigateUtils = null;
+        try {
+            navigateUtils = SpringUtils.getBean(NavigateUtils.class);
+        }catch (Exception e){}
+
+        if(navigateUtils == null){
+            return -1;
+        }
+
+        Integer value = -1;
+        for (Integer shuttleNo : blockNode) {
+            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
+            if (shuttleThread == null) {
+                continue;
+            }
+
+            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
+            if (shuttleProtocol == null) {
+                continue;
+            }
+
+            if (!shuttleThread.isDeviceIdle()) {
+                continue;
+            }
+
+            if (shuttleProtocol.getTaskNo() == 0) {
+                continue;
+            }
+
+            if (!shuttleProtocol.getTrafficControl()) {
+                continue;//灏忚溅鏈敵璇蜂氦閫氱鍒�
+            }
+
+            //妫�娴嬪皬杞︽槸鍚﹀凡缁忓垎閰�
+            if (deviceMap.containsValue(shuttleNo)) {
+                continue;
+            }
+
+            List<NavigateNode> trafficControlNodes = shuttleProtocol.getTrafficControlNodes();
+            List<String> trafficControlLocs = new ArrayList<>();
+            for (NavigateNode node : trafficControlNodes) {
+                trafficControlLocs.add(Utils.getLocNo(node.getX(), node.getY(), node.getZ()));
+            }
+
+            //妫�娴嬪綋鍓嶅皬杞﹁妭鐐规槸鍚﹀尮閰嶄氦閫氱鍒惰妭鐐�
+            boolean result = false;
+            for (String loc : locs) {
+                if (trafficControlLocs.contains(loc)) {
+                    result = true;
+                    break;
+                }
+            }
+
+            if (!result) {
+                continue;
+            }
+
+            //check path
+            String currentLocNo = shuttleProtocol.getCurrentLocNo();
+            for (String loc : locs) {
+                if (loc.equals(currentLocNo)) {
+                    continue;
+                }
+                List<NavigateNode> nodeList = navigateUtils.calc(currentLocNo, loc, NavigationMapType.getNormalWithDevice(), Utils.getShuttlePoints(shuttleNo, Utils.getLev(loc)), null);
+                if (nodeList == null) {
+                    break;
+                }
+            }
+
+            value = shuttleNo;
+            break;
+        }
+
+        return value;
+    }
+
+    //鑺傜偣骞堕泦
+    public List<List<Integer>> mergeConnectedComponents(List<List<Integer>> lists) {
+        // 1. 鏀堕泦鎵�鏈夊敮涓�鍏冪礌
+        Set<Integer> allElements = new HashSet<>();
+        for (List<Integer> list : lists) {
+            allElements.addAll(list);
+        }
+
+        // 2. 鍒濆鍖栧苟鏌ラ泦
+        Map<Integer, Integer> parent = new HashMap<>();
+        for (Integer element : allElements) {
+            parent.put(element, element);
+        }
+
+        // 3. 瀹氫箟鏌ユ壘鏍硅妭鐐圭殑鍑芥暟锛堝甫璺緞鍘嬬缉锛�
+        Function<Integer, Integer> find = x -> {
+            int root = x;
+            while (parent.get(root) != root) {
+                root = parent.get(root);
+            }
+            // 璺緞鍘嬬缉
+            int current = x;
+            while (parent.get(current) != root) {
+                int next = parent.get(current);
+                parent.put(current, root);
+                current = next;
+            }
+            return root;
+        };
+
+        // 4. 閬嶅巻姣忎釜鍒楄〃骞跺悎骞跺厓绱�
+        for (List<Integer> list : lists) {
+            if (list.isEmpty()) continue;
+            int first = list.get(0);
+            for (int i = 1; i < list.size(); i++) {
+                int a = first;
+                int b = list.get(i);
+                int rootA = find.apply(a);
+                int rootB = find.apply(b);
+                if (rootA != rootB) {
+                    parent.put(rootB, rootA); // 鍚堝苟闆嗗悎
+                }
+            }
+        }
+
+        // 5. 鎸夋牴鑺傜偣鍒嗙粍
+        Map<Integer, Set<Integer>> components = new HashMap<>();
+        for (Integer element : allElements) {
+            int root = find.apply(element);
+            components.computeIfAbsent(root, k -> new TreeSet<>()).add(element);
+        }
+
+        // 6. 杞崲涓烘湁搴忓垪琛�
+        List<List<Integer>> result = new ArrayList<>();
+        for (Set<Integer> set : components.values()) {
+            result.add(new ArrayList<>(set));
+        }
+
+        return result;
+    }
+
+    private HashMap<Integer, HashMap<String, List<Integer>>> calcNodeList() {
+        HashMap<Integer, HashMap<String, List<Integer>>> levNodesMap = new HashMap<>();
+        for (Map.Entry<String, List<NavigateNode>> entry : taskNodesMap.entrySet()) {
+            String key = entry.getKey();
+            String[] split = key.split("-");
+            Integer taskNo = Integer.parseInt(split[0]);
+            Integer shuttleNo = Integer.parseInt(split[1]);
+
+            List<NavigateNode> nodeList = entry.getValue();
+            NavigateNode node1 = nodeList.get(0);
+            int lev = node1.getZ();
+
+            HashMap<String, List<Integer>> nodeMap = new HashMap<>();
+            if(levNodesMap.containsKey(lev)) {
+                nodeMap = levNodesMap.get(lev);
+            }
+
+            for (NavigateNode node : nodeList) {
+                String locNo = Utils.getLocNo(node.getX(), node.getY(), lev);
+                List<Integer> shuttleNos = new ArrayList<>();
+                if (nodeMap.containsKey(locNo)) {
+                    shuttleNos = nodeMap.get(locNo);
+                }
+
+                if (!shuttleNos.contains(shuttleNo)) {
+                    shuttleNos.add(shuttleNo);
+                }
+                nodeMap.put(locNo, shuttleNos);
+            }
+            levNodesMap.put(lev, nodeMap);
+        }
+        this.levNodesMap = levNodesMap;
+        return levNodesMap;
+    }
+
+    @Override
+    public synchronized boolean applyTrafficControl(List<NavigateNode> totalNodeList, List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) {
+        //鍙戝竷鍫靛鑺傜偣鍙敤璁惧缂栧彿
+        redisUtil.set(RedisKeyType.TASK_BLOCK_ENABLE_DEVICE_MAP.key, trafficControlDataList);
+        //妫�娴嬭溅瀛愭槸鍚﹀瓨鍦ㄧ鍒�
+        for (int i = 0; i < trafficControlDataList.size(); i++) {
+            TrafficControlDataModel controlDataModel = trafficControlDataList.get(i);
+            if(shuttleNo.equals(controlDataModel.getShuttleNo())) {
+                //瀛樺湪绠″埗
+                if(!controlDataModel.getTaskNo().equals(taskNo)) {
+                    return false;
+                }
+
+                //浠诲姟鎬绘暟閲忎笉涓�鑷�
+                if (totalNodeList.size() != controlDataModel.getTotalNodeList().size()) {
+                    return false;
+                }
+
+                int startIdx = 0;
+                int targetIdx = totalNodeList.size() - 1;
+                NavigateNode applyStartNode = totalNodeList.get(startIdx);
+                NavigateNode applyTargetNode = totalNodeList.get(targetIdx);
+
+                NavigateNode controlStartNode = controlDataModel.getTotalNodeList().get(startIdx);
+                NavigateNode controlTargetNode = controlDataModel.getTotalNodeList().get(targetIdx);
+
+                //璧风偣涓嶅悓
+                if(!NavigatePositionConvert.equalsNode(applyStartNode, controlStartNode)) {
+                    return false;
+                }
+
+                //缁堢偣涓嶅悓
+                if(!NavigatePositionConvert.equalsNode(applyTargetNode, controlTargetNode)) {
+                    return false;
+                }
+
+                News.info("traffic running {},{}", shuttleNo, taskNo);
+                return true;//宸茬粡绠″埗鍏佽鎵ц
+            }
+        }
+
+        NavigateNode startNode = totalNodeList.get(0);
+        List<int[]> shuttlePoints = Utils.getShuttlePoints(shuttleNo, startNode.getZ());
+
+        List<String> shuttleLocList = new ArrayList<>();
+        for (int[] shuttlePoint : shuttlePoints) {
+            String locNo = Utils.getLocNo(shuttlePoint[0], shuttlePoint[1], startNode.getZ());
+            shuttleLocList.add(locNo);
+        }
+
+        for (NavigateNode node : totalNodeList) {
+            String locNo = Utils.getLocNo(node.getX(), node.getY(), node.getZ());
+            if(shuttleLocList.contains(locNo)) {
+               return false;//node has shuttle
+            }
+        }
+
+        //妫�娴嬭妭鐐规槸鍚﹁浣跨敤
+        for (TrafficControlDataModel controlDataModel : trafficControlDataList) {
+            List<NavigateNode> list = controlDataModel.getTotalNodeList();
+            for (NavigateNode node1 : list) {
+                for (NavigateNode node2 : totalNodeList) {
+                    if (NavigatePositionConvert.equalsNode(node1, node2)) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        //浜ょ鎺ユ敹
+        TrafficControlDataModel model = new TrafficControlDataModel();
+        model.setShuttleNo(shuttleNo);
+        model.setTaskNo(taskNo);
+        model.setNodeList(nodeList);
+        model.setTotalNodeList(totalNodeList);
+        trafficControlDataList.add(model);
+        News.info("receipt traffic {},{}", shuttleNo, taskNo);
+        return true;
+    }
+
+    @Override
+    public boolean trafficReport(List<NavigateNode> nodeList, Integer shuttleNo, Integer taskNo) {
+        //妫�娴嬭溅瀛愭槸鍚﹀瓨鍦ㄧ鍒�
+        for (int i = 0; i < trafficControlDataList.size(); i++) {
+            TrafficControlDataModel controlDataModel = trafficControlDataList.get(i);
+            if(shuttleNo.equals(controlDataModel.getShuttleNo())) {
+                if(controlDataModel.getTaskNo().equals(taskNo)) {
+                    List<NavigateNode> totalNodeList = controlDataModel.getTotalNodeList();
+                    totalNodeList.removeAll(nodeList);
+                    controlDataModel.setTotalNodeList(totalNodeList);
+                    trafficControlDataList.set(i, controlDataModel);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean cancelTrafficControl(Integer shuttleNo, Integer taskNo) {
+        //妫�娴嬭溅瀛愭槸鍚﹀瓨鍦ㄧ鍒�
+        for (int i = 0; i < trafficControlDataList.size(); i++) {
+            TrafficControlDataModel controlDataModel = trafficControlDataList.get(i);
+            if(shuttleNo.equals(controlDataModel.getShuttleNo())) {
+                if(controlDataModel.getTaskNo().equals(taskNo)) {
+                    trafficControlDataList.remove(i);//鍙栨秷绠″埗
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public TrafficControlDataModel queryTrafficControl(Integer shuttleNo) {
+        //妫�娴嬭溅瀛愭槸鍚﹀瓨鍦ㄧ鍒�
+        for (int i = 0; i < trafficControlDataList.size(); i++) {
+            TrafficControlDataModel controlDataModel = trafficControlDataList.get(i);
+            if(shuttleNo.equals(controlDataModel.getShuttleNo())) {
+                return controlDataModel;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<TrafficControlDataModel> getAllTrafficControl() {
+        return trafficControlDataList;
+    }
+
+    @Override
+    public boolean connect() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+}
diff --git a/src/main/java/com/zy/core/utils/TrafficControlUtils.java b/src/main/java/com/zy/core/utils/TrafficControlUtils.java
new file mode 100644
index 0000000..d67e225
--- /dev/null
+++ b/src/main/java/com/zy/core/utils/TrafficControlUtils.java
@@ -0,0 +1,81 @@
+package com.zy.core.utils;
+
+import java.util.*;
+
+public class TrafficControlUtils {
+
+    public static List<List<String>> groupNodes(Collection<String> keys) {
+        // 1. 鎸変綅缃仛绫伙細Map<浣嶇疆閿�, 鑺傜偣鍒楄〃>
+        Map<String, List<String>> clusterMap = new HashMap<>();
+        for (String key : keys) {
+            String rowStr = key.substring(0, 2);
+            String colStr = key.substring(2, 5);
+            String posKey = rowStr + "_" + colStr; // 浣嶇疆閿牸寮�: "RR_CCC"
+            clusterMap.computeIfAbsent(posKey, k -> new ArrayList<>()).add(key);
+        }
+
+        // 2. 鍒濆鍖栧苟鏌ラ泦
+        Map<String, String> parentMap = new HashMap<>();
+        Map<String, Integer> rankMap = new HashMap<>();
+        for (String posKey : clusterMap.keySet()) {
+            parentMap.put(posKey, posKey); // 鍒濆鐖惰妭鐐规寚鍚戣嚜宸�
+            rankMap.put(posKey, 0);
+        }
+
+        // 3. 閬嶅巻鎵�鏈変綅缃敭锛屽悎骞剁浉閭荤皣
+        for (String posKey : clusterMap.keySet()) {
+            String[] parts = posKey.split("_");
+            int row = Integer.parseInt(parts[0]);
+            int col = Integer.parseInt(parts[1]);
+
+            // 妫�鏌ュ洓涓柟鍚戯細宸︺�佸彸銆佷笂銆佷笅
+            int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // {dRow, dCol}
+            for (int[] dir : directions) {
+                int newRow = row + dir[0];
+                int newCol = col + dir[1];
+                String neighborKey = String.format("%02d_%03d", newRow, newCol);
+
+                if (parentMap.containsKey(neighborKey)) {
+                    union(posKey, neighborKey, parentMap, rankMap);
+                }
+            }
+        }
+
+        // 4. 鐢熸垚鍒嗙粍缁撴灉
+        Map<String, List<String>> groupMap = new HashMap<>();
+        for (String posKey : clusterMap.keySet()) {
+            String root = find(posKey, parentMap);
+            groupMap.computeIfAbsent(root, k -> new ArrayList<>())
+                    .addAll(clusterMap.get(posKey));
+        }
+
+        return new ArrayList<>(groupMap.values());
+    }
+
+    // 骞舵煡闆嗭細鏌ユ壘鏍硅妭鐐癸紙甯﹁矾寰勫帇缂╋級
+    private static String find(String x, Map<String, String> parentMap) {
+        if (!parentMap.get(x).equals(x)) {
+            parentMap.put(x, find(parentMap.get(x), parentMap));
+        }
+        return parentMap.get(x);
+    }
+
+    // 骞舵煡闆嗭細鎸夌З鍚堝苟
+    private static void union(String x, String y, Map<String, String> parentMap, Map<String, Integer> rankMap) {
+        String rootX = find(x, parentMap);
+        String rootY = find(y, parentMap);
+        if (rootX.equals(rootY)) return;
+
+        int rankX = rankMap.get(rootX);
+        int rankY = rankMap.get(rootY);
+        if (rankX < rankY) {
+            parentMap.put(rootX, rootY);
+        } else if (rankX > rankY) {
+            parentMap.put(rootY, rootX);
+        } else {
+            parentMap.put(rootY, rootX);
+            rankMap.put(rootX, rankX + 1);
+        }
+    }
+
+}

--
Gitblit v1.9.1