wuhb 2 týždňov pred
rodič
commit
316b905e81

+ 120 - 108
mes/ktg-mes/src/main/java/com/ktg/mes/rms/thread/RailAgvThread.java

@@ -1,21 +1,19 @@
 package com.ktg.mes.rms.thread;
 
-import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.ktg.common.constant.UserConstants;
+import com.ktg.common.utils.DateUtils;
 import com.ktg.common.utils.StringUtils;
 import com.ktg.common.utils.spring.SpringUtils;
 import com.ktg.mes.rms.domain.*;
 import com.ktg.mes.rms.emcsenum.DeviceTypeEnum;
-import com.ktg.mes.rms.emcsenum.RmsStatusEnum;
-import com.ktg.mes.rms.emcsenum.SiteTypeEnum;
 import com.ktg.mes.rms.emcsenum.TaskTypeEnum;
 import com.ktg.mes.rms.server.RmsWebSocketServer;
+import com.ktg.mes.rms.service.IRmsLiftService;
 import com.ktg.mes.rms.service.IRmsTaskOutstockLineService;
 import com.ktg.mes.rms.service.impl.RmsTaskOutstockLineServiceImpl;
 import com.ktg.mes.rms.task.ApiStockTask;
 import com.ktg.mes.rms.util.ApiCache;
-import com.ktg.mes.rms.util.RailHelper;
+import com.ktg.mes.rms.util.RailAgvPlcHelper;
 import com.ktg.mes.wm.domain.WmRmsBox;
 import com.ktg.mes.wm.domain.WmRmsBoxItem;
 import com.ktg.mes.wm.domain.WmStorageArea;
@@ -34,14 +32,15 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
 
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class RailAgvThread extends BaseThread{
     private static final Logger log = LoggerFactory.getLogger(RailAgvThread.class);
     private enum AgvStatus {RUN, DONE, CANCEL, ARRIVER}
 
     private volatile RmsTaskPool rmsTaskPool;
-    private final RailHelper railHelper = RailHelper.getInstance(true);
     private final IWmRmsBoxService wmRmsBoxService;
     private final int waitAgvTime = 600;
 
@@ -55,6 +54,7 @@ public class RailAgvThread extends BaseThread{
     }
 
     public void run(){
+        RailAgvPlcHelper plcHelper = null;
         try{
             log.info("=========收到轨道AGV任务:"+rmsTaskPool.getTaskId()+"=========");
             rmsTaskPoolService.startGroupTask(rmsTaskPool);
@@ -63,56 +63,73 @@ public class RailAgvThread extends BaseThread{
                 System.out.println("=========延迟"+rmsTaskPool.getRunDelay()+"秒执行=========");
                 Thread.sleep(rmsTaskPool.getRunDelay()*1000);
             }
-            String robotType = DeviceTypeEnum.RAILAGV.getKey();
-            String robotId = "";
-            RmsTaskPool bindPool = getBindTask();
-            if(StringUtils.isNotEmpty(bindPool.getLiftCode())){
-                robotId = bindPool.getLiftCode();
+
+            // 获取轨道AGV的PLC连接
+            String agvCode = rmsTaskPool.getLiftCode();
+            if(StringUtils.isEmpty(agvCode)){
+                RmsTaskPool bindPool = getBindTask();
+                if(bindPool != null){
+                    agvCode = bindPool.getLiftCode();
+                }
             }
-            if(StringUtils.isNotEmpty(rmsTaskPool.getLiftCode())){
-                robotId = rmsTaskPool.getLiftCode();
+            if(StringUtils.isEmpty(agvCode)){
+                throw new Exception("未找到轨道AGV编号");
             }
-            String taskType = rmsTaskPool.getTaskType();
-            String data = railHelper.sendAgvTask(rmsTaskPool.getFromSite(), rmsTaskPool.getToSite()
-                    , rmsTaskPool.getPickTime(), rmsTaskPool.getKeyRoute(), taskType
-                    , robotType, robotId);
-            JSONObject dataJson = JSONUtil.toBean(data, JSONObject.class);
-            String rmsRemoteTaskId = dataJson.getStr("id");
-            if(StringUtils.isNotEmpty(rmsRemoteTaskId)){
-                if(rmsTaskPool.getIsWait() == 0){
-                    updateRemark(rmsRemoteTaskId, 1, 3, rmsTaskPool.getTaskName()+"任务已发送");
-                }else{
-                    updateRemark(rmsRemoteTaskId, 1, 3, rmsTaskPool.getTaskName()+"任务已发送,等待中");
-                }
-            }else{
-                throw new Exception("AGV任务请求失败");
+            IRmsLiftService rmsLiftService = SpringUtils.getBean(IRmsLiftService.class);
+            RmsLift rmsLift = rmsLiftService.selectRmsLiftByLiftCode(agvCode);
+            if(rmsLift == null || StringUtils.isEmpty(rmsLift.getLiftIp())){
+                throw new Exception("未找到轨道AGV设备信息:"+agvCode);
             }
-            boolean isRunDone = true;
-            if(TaskTypeEnum.X2B_ROLLER_BACK_UP.getValue().equals(rmsTaskPool.getTaskType())
-                ||TaskTypeEnum.X2B_ROLLER_BACK_DOWN.getValue().equals(rmsTaskPool.getTaskType())){
-                isRunDone = waitAgv(rmsRemoteTaskId);
+            plcHelper = RailAgvPlcHelper.getInstance(rmsLift.getLiftIp(), rmsLift.getLiftPort().intValue());
+
+            // 下发任务参数到PLC
+            Map<String, String> taskParams = new HashMap<>();
+            taskParams.put(RailAgvPlcHelper.sFromSite, rmsTaskPool.getFromSite());
+            taskParams.put(RailAgvPlcHelper.sToSite, rmsTaskPool.getToSite());
+            if(rmsTaskPool.getPickTime() != null){
+                taskParams.put(RailAgvPlcHelper.iPickTime, rmsTaskPool.getPickTime().toString());
+            }
+            taskParams.put(RailAgvPlcHelper.sKeyRoute, rmsTaskPool.getKeyRoute());
+            taskParams.put(RailAgvPlcHelper.iTaskType, rmsTaskPool.getTaskType());
+            plcHelper.setVar(taskParams);
+
+            // 启动任务
+            plcHelper.setVar(RailAgvPlcHelper.bTaskStart, "1", 0);
+            if(rmsTaskPool.getIsWait() == 0){
+                updateRemark(null, 1, 3, rmsTaskPool.getTaskName()+"任务已发送");
             }else{
-                if(rmsTaskPool.getIsWait() != 0){    //不是出入库,不滚动,判断等待用wait
-                    log.info("开始AGV等待任务完成");
-                    isRunDone = waitAgv(rmsRemoteTaskId);
-                }
+                updateRemark(null, 1, 3, rmsTaskPool.getTaskName()+"任务已发送,等待中");
             }
-            if(!isRunDone){
-                log.info("任务被取消,结束线程");
-                cancleOrder();
-                return;
+
+            // 等待AGV执行完成
+            boolean needWait = TaskTypeEnum.X2B_ROLLER_BACK_UP.getValue().equals(rmsTaskPool.getTaskType())
+                || TaskTypeEnum.X2B_ROLLER_BACK_DOWN.getValue().equals(rmsTaskPool.getTaskType())
+                || rmsTaskPool.getIsWait() != 0;
+            if(needWait){
+                log.info("开始AGV等待任务完成");
+                if(!waitAgv(plcHelper)){
+                    log.info("任务被取消,结束线程");
+                    cancleOrder();
+                    return;
+                }
             }
+
             waitByTask();
-            if(StringUtils.isNotNull(rmsRemoteTaskId)){
-                updateOrder();
-                updateRemark(null,2, 2, "成功");
-                checkNextTask();
-            }
+            updateOrder();
+            updateRemark(null,2, 2, "成功");
+            checkNextTask();
             rmsTaskPoolService.closeAutoGroupTask(rmsTaskPool);
         }catch (Exception ex){
             log.error("AGV异常:" + JSONUtil.toJsonStr(rmsTaskPool), ex);
             updateLog(rmsTaskPool, ex.getMessage());
             rmsTaskPoolService.cancelAgvTaskGroup(rmsTaskPool);
+            if(plcHelper != null){
+                try {
+                    plcHelper.setVar(RailAgvPlcHelper.bStop, "1", 0);
+                } catch (Exception e) {
+                    log.error("停止轨道AGV异常", e);
+                }
+            }
             cancleOrder();
         }finally {
             this.rmsTaskPool = null;
@@ -137,25 +154,7 @@ public class RailAgvThread extends BaseThread{
                         rmsTaskPoolService.updateXbMoveStock(rmsTaskPool);
                         // 重置isScan和lineIds
                         wmRmsBox.setIsScan("-1");
-                        if(StringUtils.isNotEmpty(wmRmsBox.getLineIds())){
-                            String lineIds = wmRmsBox.getLineIds();
-                            String[] lineIdArray = lineIds.split(",");
-                            StringBuilder newLineIds = new StringBuilder();
-                            for (String id : lineIdArray) {
-                                if (!id.equals(String.valueOf(lineId)))  {
-                                    if (newLineIds.length()  > 0) {
-                                        newLineIds.append(",");
-                                    }
-                                    newLineIds.append(id);
-                                }
-                            }
-                            if(StringUtils.isNotEmpty(newLineIds.toString())){
-                                wmRmsBox.setLineIds(newLineIds.toString());
-                            }else{
-                                wmRmsBox.setWaitType(-1);
-                                wmRmsBox.setLineIds("-1");
-                            }
-                        }
+                        removeLineIdFromBox(wmRmsBox, lineId);
                         //搬运结束料框加入出库单信息
                         wmRmsBox.setItemOutCode(rmsTaskPool.getSourceType());
                         wmRmsBoxService.updateWmRmsBox2(wmRmsBox);
@@ -198,11 +197,13 @@ public class RailAgvThread extends BaseThread{
         }
     }
 
-    private boolean waitAgv(String rmsRemoteTaskId) throws Exception {
+    private boolean waitAgv(RailAgvPlcHelper plcHelper) throws Exception {
         boolean isStop = false;
         long runTime = new Date().getTime();
+        long maxWaitMs = waitAgvTime * 1000L;
+        boolean timeoutNotified = false;
         while (!isStop){
-            AgvStatus agvStatus = checkRmsStock(rmsRemoteTaskId);
+            AgvStatus agvStatus = checkRmsStock(plcHelper);
             if(agvStatus.equals(AgvStatus.CANCEL)){
                 throw new Exception("AGV异常,取消任务");
             }
@@ -212,43 +213,36 @@ public class RailAgvThread extends BaseThread{
             try {
                 RmsTaskPool pool = rmsTaskPoolService.selectRmsTaskPoolByTaskId(rmsTaskPool.getTaskId());
                 if ("4".equals(pool.getTaskStatus())) {
-                    railHelper.cancelAgvTask(rmsTaskPool.getRmsTaskId());
+                    plcHelper.setVar(RailAgvPlcHelper.bStop, "1", 0);
                     return false;
                 }
             }catch (Exception ex){
                 log.error("查工单状态错误:["+rmsTaskPool.getTaskId()+"]" + ex.getMessage());
             }
-            long longTime = (new Date().getTime() - runTime)/1000;
-            if(longTime > waitAgvTime){
-                throw new Exception("等待AGV任务完成超时");
+            if(!timeoutNotified && (new Date().getTime() - runTime) > maxWaitMs){
+                timeoutNotified = true;
+                log.error("等待轨道AGV任务超时("+waitAgvTime+"秒),等待人工处理");
+                try {
+                    SpringUtils.getBean(RmsWebSocketServer.class)
+                        .sendToUI("lift", DateUtils.getTime() + " 等待轨道AGV任务"+rmsTaskPool.getTaskId()+"超时("+waitAgvTime+"秒),请人工处理");
+                } catch (Exception e) {
+                    log.error("发送超时通知失败", e);
+                }
             }
             sleep(1000);
         }
         return true;
     }
 
-    public AgvStatus checkRmsStock(String rmsTaskId) throws Exception {
-        if(StringUtils.isEmpty(rmsTaskId)){
-            throw new Exception("没有找到AGV执行的任务ID");
-        }
-        if(StringUtils.isEmpty(railHelper.session)){
-            railHelper.init();
+    public AgvStatus checkRmsStock(RailAgvPlcHelper plcHelper) throws Exception {
+        String taskStatus = plcHelper.getValue(RailAgvPlcHelper.iTaskStatus, 0);
+        if("2".equals(taskStatus)){
+            return AgvStatus.DONE;
         }
-//        updateLiftCode(robotId, rmsTaskId);
-        return RailAgvThread.AgvStatus.DONE;
-    }
-
-    private void updateLiftCode(String robotId, String rmsTaskId){
-        if(!StringUtils.isEmpty(robotId)
-                && StringUtils.isEmpty(rmsTaskPool.getLiftCode())){
-            rmsTaskPool.setLiftCode(robotId);
-            RmsTaskPool pool = new RmsTaskPool();
-            pool.setTaskId(rmsTaskPool.getTaskId());
-            pool.setLiftCode(robotId);
-            pool.setRmsTaskId(rmsTaskId);
-            pool.setRemark("获取AGV编号");
-            rmsTaskPoolService.updateRmsTaskPoolMapper(pool);
+        if("3".equals(taskStatus)){
+            return AgvStatus.CANCEL;
         }
+        return AgvStatus.RUN;
     }
 
     public void updateRemark(String rmsTaskId, Integer status, int step, String remark) throws Exception {
@@ -270,9 +264,22 @@ public class RailAgvThread extends BaseThread{
         if(isWait == 3 && StringUtils.isNotEmpty(waitTaskId)){
             String[] taskIds = waitTaskId.split(",");
             boolean isUpdate = false;
+            long waitStart = System.currentTimeMillis();
+            long maxWaitMs = 600000;
+            boolean timeoutNotified = false;
             for(String taskId:taskIds){
                 boolean isStop = false;
                 while (!isStop){
+                    if(!timeoutNotified && System.currentTimeMillis() - waitStart > maxWaitMs){
+                        timeoutNotified = true;
+                        log.error("等待任务"+taskId+"超时("+(maxWaitMs/1000)+"秒),等待人工处理");
+                        try {
+                            SpringUtils.getBean(RmsWebSocketServer.class)
+                                .sendToUI("lift", DateUtils.getTime() + " 等待任务"+taskId+"超时("+(maxWaitMs/1000)+"秒),请人工处理");
+                        } catch (Exception e) {
+                            log.error("发送超时通知失败", e);
+                        }
+                    }
                     RmsTaskPool p = new RmsTaskPool();
                     p.setGroupCode(rmsTaskPool.getGroupCode());
                     p.setFlowLineId(Long.parseLong(taskId));
@@ -299,6 +306,29 @@ public class RailAgvThread extends BaseThread{
         return rmsTaskPool;
     }
 
+    private void removeLineIdFromBox(WmRmsBox wmRmsBox, Long lineId) {
+        if(lineId == null) return;
+        if(StringUtils.isNotEmpty(wmRmsBox.getLineIds())){
+            String lineIds = wmRmsBox.getLineIds();
+            String[] lineIdArray = lineIds.split(",");
+            StringBuilder newLineIds = new StringBuilder();
+            for (String id : lineIdArray) {
+                if (!id.equals(String.valueOf(lineId)))  {
+                    if (newLineIds.length()  > 0) {
+                        newLineIds.append(",");
+                    }
+                    newLineIds.append(id);
+                }
+            }
+            if(StringUtils.isNotEmpty(newLineIds.toString())){
+                wmRmsBox.setLineIds(newLineIds.toString());
+            }else{
+                wmRmsBox.setWaitType(-1);
+                wmRmsBox.setLineIds("-1");
+            }
+        }
+    }
+
     public void cancleOrder(){
         Long deviceType = Long.parseLong(rmsTaskPool.getDeviceType());
         if(deviceType.equals(DeviceTypeEnum.ROLLERAGV.getValue())){
@@ -311,25 +341,7 @@ public class RailAgvThread extends BaseThread{
                     if(wmRmsBox != null && wmRmsBox.getWaitType() != null && wmRmsBox.getWaitType() == 2){
                         //线边库搬运任务。
                         wmRmsBox.setIsScan("-1");
-                        if(StringUtils.isNotEmpty(wmRmsBox.getLineIds()) && lineId != null){
-                            String lineIds = wmRmsBox.getLineIds();
-                            String[] lineIdArray = lineIds.split(",");
-                            StringBuilder newLineIds = new StringBuilder();
-                            for (String id : lineIdArray) {
-                                if (!id.equals(String.valueOf(lineId)))  {
-                                    if (newLineIds.length()  > 0) {
-                                        newLineIds.append(",");
-                                    }
-                                    newLineIds.append(id);
-                                }
-                            }
-                            if(StringUtils.isNotEmpty(newLineIds.toString())){
-                                wmRmsBox.setLineIds(newLineIds.toString());
-                            }else{
-                                wmRmsBox.setWaitType(-1);
-                                wmRmsBox.setLineIds("-1");
-                            }
-                        }
+                        removeLineIdFromBox(wmRmsBox, lineId);
                         wmRmsBoxService.updateWmRmsBox2(wmRmsBox);
                     }
                 }

+ 306 - 0
mes/ktg-mes/src/main/java/com/ktg/mes/rms/util/RailAgvPlcHelper.java

@@ -0,0 +1,306 @@
+package com.ktg.mes.rms.util;
+
+import com.ktg.common.utils.DateUtils;
+import com.ktg.common.utils.ModbusMasterUtil;
+import com.ktg.common.utils.spring.SpringUtils;
+import com.ktg.mes.rms.server.RmsWebSocketServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class RailAgvPlcHelper {
+	private static final Logger log = LoggerFactory.getLogger(RailAgvPlcHelper.class);
+	private static final Map<String, Integer> codeAddress = new HashMap<>();
+	private static final Map<String, RailAgvPlcHelper> instances = new ConcurrentHashMap<>();
+	private ModbusMasterUtil master;
+	private String ip;
+	private int port;
+	private final int reset = 2;
+
+	private synchronized byte[] queryHolding(ModbusMasterUtil master, int io, int quantity) throws Exception {
+		boolean isClose = false;
+		if(master == null){
+			master = ModbusMasterUtil.builder(ip, port);
+			isClose = true;
+		}
+		try {
+			CompletableFuture<byte[]> res = master.readHoldingRegistersByte(1, io, quantity);
+			byte[] val;
+			try {
+				val = res.get(5, TimeUnit.SECONDS);
+			} catch (TimeoutException e) {
+				throw new RejectedExecutionException("读轨道AGV PLC超时(5s)");
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (ExecutionException e) {
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (Exception e) {
+				log.error("读轨道AGV PLC失败", e);
+				throw new RejectedExecutionException("读轨道AGV PLC失败-" + e.getMessage());
+			}
+			return val;
+		} finally {
+			if(isClose && master != null){
+				master.disposeModbusConnector();
+			}
+		}
+	}
+
+	private synchronized int queryHoldingInt(ModbusMasterUtil master, int io, int quantity) throws Exception {
+		boolean isClose = false;
+		if(master == null){
+			master = ModbusMasterUtil.builder(ip, port);
+			isClose = true;
+		}
+		try {
+			CompletableFuture<int[]> res = master.readHoldingRegisters(1, io, quantity);
+			int val;
+			try {
+				val = res.get(5, TimeUnit.SECONDS)[0];
+			} catch (TimeoutException e) {
+				throw new RejectedExecutionException("读轨道AGV PLC超时(5s)");
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (ExecutionException e) {
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (Exception e) {
+				log.error("读轨道AGV PLC失败", e);
+				throw new RejectedExecutionException("读轨道AGV PLC失败-" + e.getMessage());
+			}
+			return val;
+		} finally {
+			if(isClose && master != null){
+				master.disposeModbusConnector();
+			}
+		}
+	}
+
+	private synchronized boolean writeHolding(ModbusMasterUtil master, int address, int value) throws Exception {
+		boolean isClose = false;
+		if(master == null){
+			master = ModbusMasterUtil.builder(ip, port);
+			isClose = true;
+		}
+		try {
+			CompletableFuture<Boolean> res = master.writeSingleRegister(1, address, value);
+			boolean flag;
+			try {
+				flag = res.get(5, TimeUnit.SECONDS);
+			} catch (TimeoutException e) {
+				throw new RejectedExecutionException("写轨道AGV PLC超时(5s)");
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (ExecutionException e) {
+				throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+			} catch (Exception e) {
+				log.error("写轨道AGV PLC失败", e);
+				throw new RejectedExecutionException("写轨道AGV PLC失败-" + e.getMessage());
+			}
+			return flag;
+		} finally {
+			if(isClose && master != null){
+				master.disposeModbusConnector();
+			}
+		}
+	}
+
+	private synchronized boolean writeMultipleHolding(ModbusMasterUtil util, int address, int value) throws Exception {
+		CompletableFuture<Boolean> res = util.writeSingleRegister(1, address, value);
+		boolean flag;
+		try {
+			flag = res.get(5, TimeUnit.SECONDS);
+		} catch (TimeoutException e) {
+			throw new RejectedExecutionException("写轨道AGV PLC超时(5s)");
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+		} catch (ExecutionException e) {
+			throw new RejectedExecutionException("Modbus通讯失败-" + e.getMessage());
+		} catch (Exception e) {
+			log.error("写轨道AGV PLC失败", e);
+			throw new RejectedExecutionException("写轨道AGV PLC失败-" + e.getMessage());
+		}
+		return flag;
+	}
+
+	private synchronized boolean writeMultipleHolding(ModbusMasterUtil master, int[] address, int[] value) throws Exception {
+		if(address.length != value.length){
+			return false;
+		}
+		boolean isClose = false;
+		if(master == null){
+			master = ModbusMasterUtil.builder(ip, port);
+			isClose = true;
+		}
+		try {
+			boolean flag = true;
+			int ix = 0;
+			for(;ix < address.length;ix++){
+				int addr = address[ix];
+				int val = value[ix];
+				flag &= writeMultipleHolding(master, addr, val);
+			}
+			return flag;
+		} finally {
+			if(isClose){
+				master.disposeModbusConnector();
+			}
+		}
+	}
+
+	public boolean setVar(Map<String, String> param) throws Exception {
+		return setVar(param, 0);
+	}
+
+	private boolean setVar(Map<String, String> param, int flag) throws Exception {
+		try {
+			int[] address = new int[param.keySet().size()];
+			int[] values = new int[address.length];
+			int i = 0;
+			for (String key : param.keySet()) {
+				address[i] = codeAddress.get(key);
+				String val = param.get(key);
+				values[i] = Integer.parseInt(val);
+				i++;
+			}
+			return writeMultipleHolding(master, address, values);
+		}catch (RejectedExecutionException ex){
+			Thread.sleep(1000);
+			flag++;
+			if(flag>reset){
+				sendUI(DateUtils.getTime()+" 轨道AGV通讯异常");
+				throw new Exception("重连失败,轨道AGV通讯异常");
+			}
+			log.error("轨道AGV通讯异常,重新连接");
+			closeMaster();
+			master = ModbusMasterUtil.builder(ip, port);
+			return setVar(param, flag);
+		}
+	}
+
+	public boolean setVar(String key, String value, int flag) throws Exception {
+		try {
+			log.info("发送参数:" + key + " = " + value);
+			int address = codeAddress.get(key);
+			int y = Integer.parseInt(value);
+			return writeHolding(master, address, y);
+		}catch (RejectedExecutionException ex){
+			Thread.sleep(1000);
+			flag++;
+			if(flag > reset){
+				sendUI(DateUtils.getTime()+" 轨道AGV通讯异常");
+				throw new Exception("重连失败,轨道AGV通讯异常");
+			}
+			log.error("轨道AGV通讯异常,重新连接");
+			closeMaster();
+			master = ModbusMasterUtil.builder(ip, port);
+			return setVar(key, value, flag);
+		}
+	}
+
+	public String getValue(String params, int flag) throws Exception {
+		try {
+			int address = codeAddress.get(params);
+			int quantity = 1;
+			int val = queryHoldingInt(master, address, quantity);
+			return val + "";
+		}catch (RejectedExecutionException ex){
+			Thread.sleep(1000);
+			flag ++;
+			if(flag > reset){
+				sendUI(DateUtils.getTime()+" 轨道AGV通讯异常");
+				throw new Exception("重连失败,轨道AGV通讯异常");
+			}
+			log.error("轨道AGV通讯异常,重新连接");
+			closeMaster();
+			master = ModbusMasterUtil.builder(ip, port);
+			return getValue(params, flag);
+		} catch (Exception e) {
+			log.error("读轨道AGV PLC异常", e);
+			throw e;
+		}
+	}
+
+	public void sendUI(String remark){
+		RmsWebSocketServer webSocketServer = SpringUtils.getBean(RmsWebSocketServer.class);
+		webSocketServer.sendToUI("lift", remark);
+	}
+
+	public void closeMaster(){
+		if(master != null){
+			master.disposeModbusConnector();
+			master = null;
+			log.info("关闭轨道AGV "+ip+","+port);
+		}
+	}
+
+	public static RailAgvPlcHelper getInstance(String ip, int port) {
+		String key = ip + ":" + port;
+		RailAgvPlcHelper helper = instances.get(key);
+		if (helper == null) {
+			synchronized (RailAgvPlcHelper.class) {
+				helper = instances.get(key);
+				if (helper == null) {
+					helper = new RailAgvPlcHelper();
+					helper.ip = ip;
+					helper.port = port;
+					instances.put(key, helper);
+				}
+			}
+		}
+		return helper;
+	}
+
+	public ModbusMasterUtil getMaster() {
+		return master;
+	}
+
+	// ========== 寄存器名称常量(占位地址,需根据实际PLC点位修改) ==========
+	/** 触发任务:写1启动任务 */
+	public final static String bTaskStart = "bTaskStart";
+	/** 任务状态:0=空闲 1=运行中 2=完成 3=异常 */
+	public final static String iTaskStatus = "iTaskStatus";
+	/** AGV运行状态 */
+	public final static String iCarStatus = "iCarStatus";
+	/** 停止/取消:写1取消 */
+	public final static String bStop = "bStop";
+	/** 任务类型 */
+	public final static String iTaskType = "iTaskType";
+	/** 起点 */
+	public final static String sFromSite = "sFromSite";
+	/** 终点 */
+	public final static String sToSite = "sToSite";
+	/** 取货时间 */
+	public final static String iPickTime = "iPickTime";
+	/** 路径关键字 */
+	public final static String sKeyRoute = "sKeyRoute";
+	/** 机器人类型 */
+	public final static String iRobotType = "iRobotType";
+	/** 机器人ID */
+	public final static String sRobotId = "sRobotId";
+	/** 报警代码 */
+	public final static String iWarningCode = "iWarningCode";
+
+	static {
+		codeAddress.put(iWarningCode, 0x0020);
+		codeAddress.put(iCarStatus, 0x0021);
+		codeAddress.put(iTaskType, 0x0022);
+		codeAddress.put(bTaskStart, 0x0023);
+		codeAddress.put(iTaskStatus, 0x0024);
+		codeAddress.put(bStop, 0x0025);
+		codeAddress.put(sFromSite, 0x0026);
+		codeAddress.put(sToSite, 0x0027);
+		codeAddress.put(iPickTime, 0x0028);
+		codeAddress.put(sKeyRoute, 0x0029);
+		codeAddress.put(iRobotType, 0x002A);
+		codeAddress.put(sRobotId, 0x002B);
+	}
+
+}