package com.zy.acs.manager.core.service.astart; import com.zy.acs.common.constant.RedisConstant; import com.zy.acs.common.utils.RedisSupport; import com.zy.acs.framework.common.Cools; import com.zy.acs.manager.common.utils.MapDataUtils; import com.zy.acs.manager.core.domain.Lane; import com.zy.acs.manager.core.service.LaneService; import com.zy.acs.manager.core.service.astart.domain.DynamicNode; import com.zy.acs.manager.core.utils.RouteGenerator; import com.zy.acs.manager.manager.entity.Route; import com.zy.acs.manager.manager.entity.Segment; import com.zy.acs.manager.manager.service.CodeService; import com.zy.acs.manager.manager.service.JamService; import com.zy.acs.manager.manager.service.RouteService; import com.zy.acs.manager.system.service.ConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; /** * Created by vincent on 6/12/2024 */ @Service public class AStarNavigateService { private final RedisSupport redis = RedisSupport.defaultRedisSupport; public static final boolean OPEN_TURN_COST_WEIGHT = Boolean.TRUE; public static final int WEIGHT_CALC_FACTOR = 1; @Autowired private CodeService codeService; @Autowired private RouteService routeService; @Autowired private MapDataDispatcher mapDataDispatcher; @Autowired private JamService jamService; @Autowired private LaneService laneService; @Autowired private ConfigService configService; public synchronized NavigateNode execute(String agvNo, NavigateNode start, NavigateNode end , Boolean lock, List blackList, Segment segment) { if (start.getX() == end.getX() && start.getY() == end.getY()) { return end; } Integer maxAgvCountInLane = configService.getVal("maxAgvCountInLane", Integer.class); PriorityQueue openQueue = new PriorityQueue<>(); Set existNodes = new HashSet<>(); openQueue.add(start); existNodes.add(start); int[][] mapMatrix = mapDataDispatcher.getMapMatrix(null, null); DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(null); String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(null); while (!openQueue.isEmpty()) { // 取优先队列顶部元素并且把这个元素从Open表中删除,取F值最小的节点 NavigateNode currentNode = openQueue.poll(); ArrayList neighbourNodes = this.getNeighborNodes(currentNode, mapMatrix, existNodes); for (NavigateNode node : neighbourNodes) { boolean isEndNode = node.getX() == end.getX() && node.getY() == end.getY(); int weight = 0; if (!Cools.isEmpty(blackList) && blackList.contains(node.getCodeData())) { continue; } // 特殊情况,当blackList有且只有一个元素且为startNode时 // 说明blackList已经知道当前导航起始点和目标点为相邻节点 // 但是当前blackList的任务是不让系统走相邻的最短路径,所以才会有下面的判断和continue if (blackList.size() == 1 && blackList.get(0).equals(start.getCodeData())) { if (isEndNode && currentNode.getCodeData().equals(start.getCodeData())) { continue; } } // 节点被占用 DynamicNode dynamicNode = dynamicMatrix[node.getX()][node.getY()]; String vehicle = dynamicNode.getVehicle(); assert !vehicle.equals(DynamicNodeType.BLOCK.val); if (!vehicle.equals(DynamicNodeType.ACCESS.val)) { if (!vehicle.equals(agvNo)) { // 如果存在车辆,则增加权重 2 或者 3,因为拐点会增加权重 1 // vehicle已经为当前segment做过了避让,且避让任务已完成,则权重值增加 if (null != segment) { if (!Cools.isEmpty(jamService.getJamFromSegmentByAvo(segment, vehicle))) { weight += (WEIGHT_CALC_FACTOR * 3); } else { weight += (WEIGHT_CALC_FACTOR * 2); } } if (lock) { continue; } } } // 避障波 String waveNode = waveMatrix[node.getX()][node.getY()]; assert !waveNode.equals(WaveNodeType.DISABLE.val); if (!waveNode.equals(WaveNodeType.ENABLE.val)) { List waveNodeList = MapDataUtils.parseWaveNode(waveNode); List otherWaveList = MapDataUtils.hasOtherWave(waveNodeList, agvNo); if (!Cools.isEmpty(otherWaveList)) { if (lock) { continue; } } } // 单巷道车辆容载数量 Lane lane = laneService.search(node.getCodeData()); if (null != lane) { Set lanVehicleSet = new HashSet<>(); List laneCodes = lane.getCodes(); for (String laneCodeData : laneCodes) { int[] laneCodeMatrixIdx = mapDataDispatcher.getCodeMatrixIdx(null, laneCodeData); // scan dynamicMatrix or WaveMatrix DynamicNode laneDynamicNode = dynamicMatrix[laneCodeMatrixIdx[0]][laneCodeMatrixIdx[1]]; String laneVehicle = laneDynamicNode.getVehicle(); assert !laneVehicle.equals(DynamicNodeType.BLOCK.val); if (!laneVehicle.equals(DynamicNodeType.ACCESS.val)) { if (!laneVehicle.equals(agvNo)) { lanVehicleSet.add(laneVehicle); // redis.setObject(RedisConstant.AGV_TO_STANDBY_FLAG, laneVehicle, true, 30); } } } if (lanVehicleSet.size() + 1 > maxAgvCountInLane) { continue; } } //找到目标结点就返回 if (isEndNode) { //并且计算出G, F, H等值 node.initNode(currentNode, end); return node; } // G + H + T (对启发函数增加去拐点方案calcNodeTurnCost) int gCost = calcNodeCost(currentNode, node); if (OPEN_TURN_COST_WEIGHT) { gCost += calcNodeTurnCost(currentNode, node, end); } //进行计算对 G, F, H 等值 node.setWeight(weight); node.setLastDistance(gCost); node.initNode(currentNode, end); node.setH(calcNodeCost(node, end)); node.setF(node.getG() + node.getH()); openQueue.add(node); existNodes.add(node); } } //如果遍历完所有出现的结点都没有找到最终的结点,返回null return null; } // 获取四周节点 private ArrayList getNeighborNodes(NavigateNode currentNode, int[][] mapMatrix, Set existNodes) { //获取当前结点的x, y int x = currentNode.getX(); int y = currentNode.getY(); //如果当前结点的邻结点合法,就加入到neighbour_node ArrayList neighbourNodes = new ArrayList<>(); NavigateNode rightNode = extendNeighborNodes(currentNode, new NavigateNode(x, y + 1), mapMatrix, existNodes, null, null); if (null != rightNode) { neighbourNodes.add(rightNode); } NavigateNode leftNode = extendNeighborNodes(currentNode, new NavigateNode(x, y - 1), mapMatrix, existNodes, null, null); if (null != leftNode) { neighbourNodes.add(leftNode); } NavigateNode topNode = extendNeighborNodes(currentNode, new NavigateNode(x - 1, y), mapMatrix, existNodes, null, null); if (null != topNode) { neighbourNodes.add(topNode); } NavigateNode bottomNode = extendNeighborNodes(currentNode, new NavigateNode(x + 1, y), mapMatrix, existNodes, null, null); if (null != bottomNode) { neighbourNodes.add(bottomNode); } return neighbourNodes; } private NavigateNode extendNeighborNodes(NavigateNode currentNode, NavigateNode extendNode, int[][] mapMatrix, Set existNodes, Integer dx, Integer dy) { NavigateNode nextNode = null; if (null == dx || null == dy) { dx = extendNode.getX() - currentNode.getX(); dy = extendNode.getY() - currentNode.getY(); nextNode = extendNode; } else { nextNode = new NavigateNode(extendNode.getX() + dx, extendNode.getY() + dy); } int x = nextNode.getX(); int y = nextNode.getY(); // 数组越界 if (x < 0 || x >= mapMatrix.length || y < 0 || y >= mapMatrix[0].length) { return null; } if (mapMatrix[x][y] == MapNodeType.DISABLE.val) { return extendNeighborNodes(currentNode, nextNode, mapMatrix, existNodes, dx, dy); } else { if (existNodes.contains(nextNode)) { return null; } // 节点是否可用 if (mapMatrix[x][y] != MapNodeType.ENABLE.val) { return null; } String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(null); String currentNodeCodeData = codeMatrix[currentNode.getX()][currentNode.getY()]; String nextNodeCodeData = codeMatrix[nextNode.getX()][nextNode.getY()]; nextNode.setCodeData(nextNodeCodeData); // 判断通过性 String routeKey = RouteGenerator.generateRouteKey(currentNodeCodeData, nextNodeCodeData); Object routeVal = redis.getMap(RedisConstant.AGV_MAP_ROUTE_HASH_FLAG, routeKey); if (routeVal == null || !(Boolean) routeVal) { return null; } return nextNode; } } //------------------A*启发函数------------------// //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) private int calcNodeCost(NavigateNode node1, NavigateNode node2) { return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); } //去除拐点算法,给直线增加优先级 private int calcNodeTurnCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { // 第一个点或直线点 if (currNode.getParent() == null || nextNode.getX() == currNode.getParent().getX() || nextNode.getY() == currNode.getParent().getY() ) { return 0; } // 拐向终点的点 if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { return 1; } // 普通拐点 return 1; } }