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);//作业标记复位 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; 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) { 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); //节点设置成Disable 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); // // //节点设置成Disable // mapNode.setValue(MapNodeType.DISABLE.id); // // //更新list // list.set(bay, mapNode); // lists.set(row, list); // } // // } } catch (Exception e) { e.printStackTrace(); } return lists; } } 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); 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; } } 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); } } src/main/java/com/zy/common/utils/ShuttleOperaUtils.java
@@ -116,12 +116,15 @@ assignCommand.setNodes(allNode);//当前任务所占用的节点list 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; } 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); } 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) { // 正常移动 if (command.getTargetLocNo().equals(shuttleProtocol.getCurrentLocNo())) { command.setComplete(true); updateCommand = true; //解锁锁定路径,上一条路径 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);//解锁路径 if (!result) { return false;//解锁失败 } } } } 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()) { //对主线程抛出等待确认状态waiting 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); //任务数据保存到redis 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()) { //对主线程抛出等待确认状态waiting 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) { // 正常移动 List<String> targetPoints = new ArrayList<>(); //解锁锁定路径,上一条路径 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);//解锁路径 if (!result) { return false;//解锁失败 } }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()) { // //无冲突,解除交通管制 // 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); 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<>(); //货叉提升机Master 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; } 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_"), src/main/java/com/zy/core/enums/SlaveType.java
@@ -6,6 +6,7 @@ Lift, ForkLift, ForkLiftMaster, TrafficControl, ; public static SlaveType findInstance(String s){ src/main/java/com/zy/core/model/TrafficControlDataModel.java
New file @@ -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; } 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; 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; } } 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; /** * 交通管制Nodes */ private List<NavigateNode> trafficControlNodes = null; public String getProtocolStatus$() { if (this.protocolStatusType == null) { return ""; 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); src/main/java/com/zy/core/thread/TrafficControlThread.java
New file @@ -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(); } 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); } src/main/java/com/zy/core/thread/impl/TrafficControlImplThread.java
New file @@ -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() { } } src/main/java/com/zy/core/utils/TrafficControlUtils.java
New file @@ -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); } } }