| | |
| | | import com.zy.core.model.Task; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.core.service.StationTaskLoopService; |
| | | import com.zy.core.thread.StationThread; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | |
| | | @Component |
| | | public class StationOperateProcessUtils { |
| | | private static final int LOOP_LOAD_RESERVE_EXPIRE_SECONDS = 120; |
| | | private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 10; |
| | | private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 2; |
| | | private static final int STATION_IDLE_RECOVER_SECONDS = 10; |
| | | private static final int STATION_IDLE_RECOVER_LIMIT_SECONDS = 10; |
| | | private static final int STATION_IDLE_TRACK_EXPIRE_SECONDS = 60 * 60; |
| | |
| | | private StationPathPolicyService stationPathPolicyService; |
| | | @Autowired |
| | | private BasStationOptService basStationOptService; |
| | | @Autowired |
| | | private StationTaskLoopService stationTaskLoopService; |
| | | |
| | | //执行输送站点入库任务 |
| | | public synchronized void stationInExecute() { |
| | |
| | | && stationProtocol.isLoading() |
| | | && stationProtocol.getTaskNo() == 0 |
| | | ) { |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | wrkMast, |
| | | outOrderList |
| | | outOrderList, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null) { |
| | |
| | | } |
| | | |
| | | DispatchLimitConfig limitConfig = getDispatchLimitConfig(stationProtocol.getStationId(), moveStaNo); |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState); |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState, wrkMast, pathLenFactor); |
| | | |
| | | if (isDispatchBlocked(limitConfig, currentStationTaskCountRef[0], loadGuardState, loopHitResult.isThroughLoop())) { |
| | | return; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | |
| | | && stationProtocol.isLoading() |
| | | && stationProtocol.getTaskNo() == 0 |
| | | ) { |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), wrkMast.getStaNo(), 0); |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | wrkMast.getStaNo(), |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | | if (wrkNo == null || targetStaNo == null) { |
| | | continue; |
| | | } |
| | | |
| | | boolean complete = false; |
| | | Integer targetDeviceNo = null; |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | StationProtocol stationProtocol = statusMap.get(basStation.getStationId()); |
| | | if (stationProtocol == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (stationProtocol.getTaskNo().equals(wrkNo)) { |
| | | complete = true; |
| | | if (basStation != null) { |
| | | targetDeviceNo = basStation.getDeviceNo(); |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); |
| | | if (stationThread != null) { |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | StationProtocol stationProtocol = statusMap.get(basStation.getStationId()); |
| | | if (stationProtocol != null && wrkNo.equals(stationProtocol.getTaskNo())) { |
| | | complete = true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (complete) { |
| | | wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts); |
| | | wrkMast.setIoTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | | notifyUtils.notify(String.valueOf(SlaveType.Devp), basStation.getDeviceNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null); |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | completeStationRunTask(wrkMast, targetDeviceNo); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | private void completeStationRunTask(WrkMast wrkMast, Integer deviceNo) { |
| | | if (wrkMast == null || wrkMast.getWrkNo() == null) { |
| | | return; |
| | | } |
| | | wrkMast.setWrkSts(WrkStsType.STATION_RUN_COMPLETE.sts); |
| | | wrkMast.setIoTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | | if (deviceNo != null) { |
| | | notifyUtils.notify(String.valueOf(SlaveType.Devp), deviceNo, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.STATION_OUT_TASK_RUN_COMPLETE, null); |
| | | } |
| | | redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60); |
| | | } |
| | | |
| | | // 检测任务转完成 |
| | |
| | | } |
| | | } else { |
| | | //运行堵塞,重新计算路线 |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | wrkMast, |
| | | outOrderStationIds |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | |
| | | wrkMast.getWrkNo(), |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | 0 |
| | | 0, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), |
| | |
| | | return countCurrentStationTask(); |
| | | } |
| | | |
| | | public synchronized int getCurrentOutboundTaskCountByTargetStation(Integer stationId) { |
| | | if (stationId == null) { |
| | | return 0; |
| | | } |
| | | return (int) wrkMastService.count(new QueryWrapper<WrkMast>() |
| | | .eq("io_type", WrkIoType.OUT.id) |
| | | .eq("sta_no", stationId) |
| | | .in("wrk_sts", |
| | | WrkStsType.OUTBOUND_RUN.sts, |
| | | WrkStsType.OUTBOUND_RUN_COMPLETE.sts, |
| | | WrkStsType.STATION_RUN.sts)); |
| | | } |
| | | |
| | | // 检测出库排序 |
| | | public synchronized void checkStationOutOrder() { |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>()); |
| | |
| | | continue; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | wrkMast, |
| | | outOrderStationIds |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | |
| | | continue; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = resolveOutboundDispatchDecision( |
| | | stationProtocol.getStationId(), |
| | | wrkMast, |
| | | outOrderList |
| | | outOrderList, |
| | | pathLenFactor |
| | | ); |
| | | Integer moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | if (moveStaNo == null || Objects.equals(moveStaNo, stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private StationCommand buildOutboundMoveCommand(StationThread stationThread, |
| | | WrkMast wrkMast, |
| | | Integer stationId, |
| | | Integer targetStationId, |
| | | Double pathLenFactor) { |
| | | if (stationThread == null || wrkMast == null) { |
| | | return null; |
| | | } |
| | | return stationThread.getCommand( |
| | | StationCommandType.MOVE, |
| | | wrkMast.getWrkNo(), |
| | | stationId, |
| | | targetStationId, |
| | | 0, |
| | | normalizePathLenFactor(pathLenFactor) |
| | | ); |
| | | } |
| | | |
| | | private List<NavigateNode> calcOutboundNavigatePath(WrkMast wrkMast, |
| | | Integer sourceStationId, |
| | | Integer targetStationId, |
| | | Double pathLenFactor) { |
| | | Double normalizedFactor = normalizePathLenFactor(pathLenFactor); |
| | | Integer currentTaskNo = wrkMast == null ? null : wrkMast.getWrkNo(); |
| | | if (currentTaskNo == null) { |
| | | return navigateUtils.calcByStationId(sourceStationId, targetStationId, normalizedFactor); |
| | | } |
| | | return navigateUtils.calcByStationId(sourceStationId, targetStationId, currentTaskNo, normalizedFactor); |
| | | } |
| | | |
| | | private Double resolveOutboundPathLenFactor(WrkMast wrkMast) { |
| | | if (!isBatchOutboundTaskWithSeq(wrkMast)) { |
| | | return 0.0d; |
| | | } |
| | | List<WrkMast> activeBatchTaskList = loadActiveBatchTaskList(wrkMast.getBatch()); |
| | | if (activeBatchTaskList.size() <= 1) { |
| | | return 0.0d; |
| | | } |
| | | |
| | | int activeTaskCount = 0; |
| | | int predecessorCount = 0; |
| | | for (WrkMast item : activeBatchTaskList) { |
| | | if (!isFactorCandidateTask(item)) { |
| | | continue; |
| | | } |
| | | activeTaskCount++; |
| | | if (item.getBatchSeq() < wrkMast.getBatchSeq()) { |
| | | predecessorCount++; |
| | | } |
| | | } |
| | | if (activeTaskCount <= 1 || predecessorCount <= 0) { |
| | | return 0.0d; |
| | | } |
| | | return normalizePathLenFactor((double) predecessorCount / (double) (activeTaskCount - 1)); |
| | | } |
| | | |
| | | private boolean isBatchOutboundTaskWithSeq(WrkMast wrkMast) { |
| | | return wrkMast != null |
| | | && Objects.equals(wrkMast.getIoType(), WrkIoType.OUT.id) |
| | | && !Cools.isEmpty(wrkMast.getBatch()) |
| | | && wrkMast.getBatchSeq() != null |
| | | && wrkMast.getWrkNo() != null; |
| | | } |
| | | |
| | | private List<WrkMast> loadActiveBatchTaskList(String batch) { |
| | | if (Cools.isEmpty(batch)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return wrkMastService.list(new QueryWrapper<WrkMast>() |
| | | .eq("io_type", WrkIoType.OUT.id) |
| | | .eq("batch", batch) |
| | | .notIn("wrk_sts", |
| | | WrkStsType.STATION_RUN_COMPLETE.sts, |
| | | WrkStsType.COMPLETE_OUTBOUND.sts, |
| | | WrkStsType.SETTLE_OUTBOUND.sts)); |
| | | } |
| | | |
| | | private boolean isFactorCandidateTask(WrkMast wrkMast) { |
| | | return wrkMast != null |
| | | && Objects.equals(wrkMast.getIoType(), WrkIoType.OUT.id) |
| | | && wrkMast.getBatchSeq() != null |
| | | && !"taskCancel".equals(wrkMast.getMk()); |
| | | } |
| | | |
| | | public List<Integer> getAllOutOrderList() { |
| | |
| | | |
| | | private OutOrderDispatchDecision resolveOutboundDispatchDecision(Integer currentStationId, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds) { |
| | | List<Integer> outOrderStationIds, |
| | | Double pathLenFactor) { |
| | | if (wrkMast == null || wrkMast.getStaNo() == null) { |
| | | return null; |
| | | } |
| | |
| | | return new OutOrderDispatchDecision(wrkMast.getStaNo(), false); |
| | | } |
| | | Integer dispatchStationId = resolveDispatchOutOrderTarget( |
| | | wrkMast, |
| | | wrkMast.getSourceStaNo(), |
| | | wrkMast.getStaNo(), |
| | | outOrderStationIds |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | if (dispatchStationId == null) { |
| | | return null; |
| | | } |
| | | if (isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds)) { |
| | | return resolveCurrentOutOrderDispatchDecision(currentStationId, wrkMast, outOrderStationIds); |
| | | if (isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds, pathLenFactor)) { |
| | | return resolveCurrentOutOrderDispatchDecision(currentStationId, wrkMast, outOrderStationIds, pathLenFactor); |
| | | } |
| | | if (!Objects.equals(dispatchStationId, wrkMast.getStaNo()) |
| | | && isCurrentOutOrderStation(currentStationId, outOrderStationIds) |
| | | && isWatchingCircleArrival(wrkMast.getWrkNo(), currentStationId)) { |
| | | return new OutOrderDispatchDecision(dispatchStationId, true); |
| | | return new OutOrderDispatchDecision(dispatchStationId, true, null, false); |
| | | } |
| | | return new OutOrderDispatchDecision(dispatchStationId, false); |
| | | } |
| | | |
| | | private OutOrderDispatchDecision resolveCurrentOutOrderDispatchDecision(Integer currentStationId, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds) { |
| | | if (!isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds)) { |
| | | List<Integer> outOrderStationIds, |
| | | Double pathLenFactor) { |
| | | if (!isCurrentOutOrderDispatchStation(currentStationId, wrkMast, outOrderStationIds, pathLenFactor)) { |
| | | return null; |
| | | } |
| | | |
| | |
| | | |
| | | List<NavigateNode> initPath; |
| | | try { |
| | | initPath = navigateUtils.calcByStationId(wrkMast.getSourceStaNo(), wrkMast.getStaNo()); |
| | | initPath = calcOutboundNavigatePath(wrkMast, wrkMast.getSourceStaNo(), wrkMast.getStaNo(), pathLenFactor); |
| | | } catch (Exception e) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "批次:{} 计算排序路径失败,当前站点={}", wrkMast.getBatch(), currentStationId); |
| | | return null; |
| | |
| | | toTarget = Integer.valueOf(seq + 1).equals(wrkMast.getBatchSeq()); |
| | | } |
| | | if (toTarget) { |
| | | if (hasReachableOutReleaseSlot(currentStationId, wrkMast.getStaNo())) { |
| | | if (hasReachableOutReleaseSlot(wrkMast, currentStationId, wrkMast.getStaNo(), pathLenFactor)) { |
| | | return new OutOrderDispatchDecision(wrkMast.getStaNo(), false); |
| | | } |
| | | Integer circleTarget = resolveNextCircleOrderTarget(currentStationId, outOrderStationIds); |
| | | StationTaskLoopService.LoopEvaluation loopEvaluation = evaluateOutOrderLoop( |
| | | wrkMast.getWrkNo(), |
| | | currentStationId, |
| | | outOrderStationIds |
| | | ); |
| | | Integer circleTarget = resolveNextCircleOrderTarget( |
| | | wrkMast, |
| | | currentStationId, |
| | | outOrderStationIds, |
| | | loopEvaluation.getExpectedLoopIssueCount(), |
| | | pathLenFactor |
| | | ); |
| | | if (circleTarget == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "目标站当前不可进,且未找到可执行的下一排序检测点,当前站点={}", currentStationId); |
| | | return null; |
| | | } |
| | | return new OutOrderDispatchDecision(circleTarget, true); |
| | | return new OutOrderDispatchDecision(circleTarget, true, loopEvaluation, true); |
| | | } |
| | | |
| | | Integer circleTarget = resolveNextCircleOrderTarget(currentStationId, outOrderStationIds); |
| | | StationTaskLoopService.LoopEvaluation loopEvaluation = evaluateOutOrderLoop( |
| | | wrkMast.getWrkNo(), |
| | | currentStationId, |
| | | outOrderStationIds |
| | | ); |
| | | Integer circleTarget = resolveNextCircleOrderTarget( |
| | | wrkMast, |
| | | currentStationId, |
| | | outOrderStationIds, |
| | | loopEvaluation.getExpectedLoopIssueCount(), |
| | | pathLenFactor |
| | | ); |
| | | if (circleTarget == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "未找到可执行的下一排序检测点,当前站点={}", currentStationId); |
| | | return null; |
| | | } |
| | | return new OutOrderDispatchDecision(circleTarget, true); |
| | | return new OutOrderDispatchDecision(circleTarget, true, loopEvaluation, true); |
| | | } |
| | | |
| | | private boolean shouldApplyOutOrder(WrkMast wrkMast, List<Integer> outOrderStationIds) { |
| | |
| | | |
| | | private boolean isCurrentOutOrderDispatchStation(Integer currentStationId, |
| | | WrkMast wrkMast, |
| | | List<Integer> outOrderStationIds) { |
| | | List<Integer> outOrderStationIds, |
| | | Double pathLenFactor) { |
| | | if (!shouldApplyOutOrder(wrkMast, outOrderStationIds) || currentStationId == null) { |
| | | return false; |
| | | } |
| | | Integer dispatchStationId = resolveDispatchOutOrderTarget( |
| | | wrkMast, |
| | | wrkMast.getSourceStaNo(), |
| | | wrkMast.getStaNo(), |
| | | outOrderStationIds |
| | | outOrderStationIds, |
| | | pathLenFactor |
| | | ); |
| | | return dispatchStationId != null |
| | | && !Objects.equals(dispatchStationId, wrkMast.getStaNo()) |
| | |
| | | } |
| | | if (dispatchDecision.isCircle()) { |
| | | saveWatchCircleCommand(wrkMast.getWrkNo(), command); |
| | | if (dispatchDecision.shouldCountLoopIssue() |
| | | && stationTaskLoopService != null |
| | | && dispatchDecision.getLoopEvaluation() != null) { |
| | | stationTaskLoopService.recordLoopIssue(dispatchDecision.getLoopEvaluation(), "OUT_ORDER_CIRCLE"); |
| | | } |
| | | } else { |
| | | clearWatchCircleCommand(wrkMast.getWrkNo()); |
| | | } |
| | | } |
| | | |
| | | private Integer resolveDispatchOutOrderTarget(Integer sourceStationId, |
| | | private StationTaskLoopService.LoopEvaluation evaluateOutOrderLoop(Integer taskNo, |
| | | Integer currentStationId, |
| | | List<Integer> outOrderStationIds) { |
| | | if (stationTaskLoopService == null) { |
| | | return new StationTaskLoopService.LoopEvaluation( |
| | | taskNo, |
| | | currentStationId, |
| | | StationTaskLoopService.LoopIdentitySnapshot.empty(), |
| | | 0, |
| | | 0, |
| | | false |
| | | ); |
| | | } |
| | | return stationTaskLoopService.evaluateLoop( |
| | | taskNo, |
| | | currentStationId, |
| | | true, |
| | | outOrderStationIds, |
| | | "outOrderCircle" |
| | | ); |
| | | } |
| | | |
| | | private Integer resolveDispatchOutOrderTarget(WrkMast wrkMast, |
| | | Integer sourceStationId, |
| | | Integer finalTargetStationId, |
| | | List<Integer> outOrderList) { |
| | | List<Integer> outOrderList, |
| | | Double pathLenFactor) { |
| | | if (finalTargetStationId == null) { |
| | | return null; |
| | | } |
| | |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(sourceStationId, finalTargetStationId); |
| | | List<NavigateNode> nodes = calcOutboundNavigatePath(wrkMast, sourceStationId, finalTargetStationId, pathLenFactor); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | Integer stationId = getStationIdFromNode(nodes.get(i)); |
| | | if (stationId == null) { |
| | |
| | | return finalTargetStationId; |
| | | } |
| | | |
| | | private boolean hasReachableOutReleaseSlot(Integer currentStationId, |
| | | Integer finalTargetStationId) { |
| | | private boolean hasReachableOutReleaseSlot(WrkMast wrkMast, |
| | | Integer currentStationId, |
| | | Integer finalTargetStationId, |
| | | Double pathLenFactor) { |
| | | if (currentStationId == null || finalTargetStationId == null) { |
| | | return true; |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(currentStationId, finalTargetStationId); |
| | | List<NavigateNode> nodes = calcOutboundNavigatePath(wrkMast, currentStationId, finalTargetStationId, pathLenFactor); |
| | | if (nodes == null || nodes.isEmpty()) { |
| | | return true; |
| | | } |
| | |
| | | || (stationProtocol.getTaskNo() != null && stationProtocol.getTaskNo() > 0); |
| | | } |
| | | |
| | | private Integer resolveNextCircleOrderTarget(Integer currentStationId, List<Integer> orderedOutStationList) { |
| | | private Integer resolveNextCircleOrderTarget(WrkMast wrkMast, |
| | | Integer currentStationId, |
| | | List<Integer> orderedOutStationList, |
| | | Integer expectedLoopIssueCount, |
| | | Double pathLenFactor) { |
| | | if (currentStationId == null || orderedOutStationList == null || orderedOutStationList.size() <= 1) { |
| | | return null; |
| | | } |
| | | |
| | | int startIndex = orderedOutStationList.indexOf(currentStationId); |
| | | int total = orderedOutStationList.size(); |
| | | List<CircleTargetCandidate> candidateList = new ArrayList<>(); |
| | | for (int offset = 1; offset < total; offset++) { |
| | | int candidateIndex = (startIndex + offset + total) % total; |
| | | Integer candidateStationId = orderedOutStationList.get(candidateIndex); |
| | |
| | | continue; |
| | | } |
| | | try { |
| | | List<NavigateNode> path = navigateUtils.calcByStationId(currentStationId, candidateStationId); |
| | | List<NavigateNode> path = calcOutboundNavigatePath(wrkMast, currentStationId, candidateStationId, pathLenFactor); |
| | | if (path != null && !path.isEmpty()) { |
| | | return candidateStationId; |
| | | candidateList.add(new CircleTargetCandidate(candidateStationId, path.size(), offset)); |
| | | } |
| | | } catch (Exception ignore) {} |
| | | } |
| | | return null; |
| | | if (candidateList.isEmpty()) { |
| | | return null; |
| | | } |
| | | candidateList.sort(new Comparator<CircleTargetCandidate>() { |
| | | @Override |
| | | public int compare(CircleTargetCandidate left, CircleTargetCandidate right) { |
| | | if (left == right) { |
| | | return 0; |
| | | } |
| | | if (left == null) { |
| | | return 1; |
| | | } |
| | | if (right == null) { |
| | | return -1; |
| | | } |
| | | int pathCompare = Integer.compare(left.getPathLength(), right.getPathLength()); |
| | | if (pathCompare != 0) { |
| | | return pathCompare; |
| | | } |
| | | return Integer.compare(left.getOffset(), right.getOffset()); |
| | | } |
| | | }); |
| | | return resolveGradualCircleTargetByPathLength(expectedLoopIssueCount, candidateList, pathLenFactor); |
| | | } |
| | | |
| | | private Integer resolveGradualCircleTargetByPathLength(Integer expectedLoopIssueCount, |
| | | List<CircleTargetCandidate> candidateList, |
| | | Double pathLenFactor) { |
| | | if (candidateList == null || candidateList.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | List<CircleTargetCandidate> tierList = new ArrayList<>(); |
| | | Integer lastPathLength = null; |
| | | for (CircleTargetCandidate candidate : candidateList) { |
| | | if (candidate == null) { |
| | | continue; |
| | | } |
| | | if (lastPathLength == null || !Objects.equals(lastPathLength, candidate.getPathLength())) { |
| | | tierList.add(candidate); |
| | | lastPathLength = candidate.getPathLength(); |
| | | } |
| | | } |
| | | if (tierList.isEmpty()) { |
| | | return candidateList.get(0).getStationId(); |
| | | } |
| | | int defaultTierIndex = expectedLoopIssueCount == null || expectedLoopIssueCount <= 2 |
| | | ? 0 |
| | | : Math.min(expectedLoopIssueCount - 2, tierList.size() - 1); |
| | | int factorTierIndex = (int) Math.round(normalizePathLenFactor(pathLenFactor) * (tierList.size() - 1)); |
| | | int tierIndex = Math.max(defaultTierIndex, factorTierIndex); |
| | | return tierList.get(tierIndex).getStationId(); |
| | | } |
| | | |
| | | private boolean tryAcquireOutOrderDispatchLock(Integer wrkNo, Integer stationId) { |
| | |
| | | return; |
| | | } |
| | | |
| | | Double pathLenFactor = resolveOutboundPathLenFactor(wrkMast); |
| | | OutOrderDispatchDecision dispatchDecision = null; |
| | | Integer moveStaNo; |
| | | if (Objects.equals(wrkMast.getWrkSts(), WrkStsType.STATION_RUN.sts)) { |
| | | dispatchDecision = resolveOutboundDispatchDecision(stationProtocol.getStationId(), wrkMast, outOrderList); |
| | | dispatchDecision = resolveOutboundDispatchDecision(stationProtocol.getStationId(), wrkMast, outOrderList, pathLenFactor); |
| | | moveStaNo = dispatchDecision == null ? null : dispatchDecision.getTargetStationId(); |
| | | } else { |
| | | moveStaNo = wrkMast.getStaNo(); |
| | |
| | | resetSegmentMoveCommandsBeforeReroute(stationProtocol.getTaskNo()); |
| | | int clearedCommandCount = clearIssuedMoveCommandsDuringIdleStay(idleTrack, stationProtocol.getTaskNo(), stationProtocol.getStationId()); |
| | | |
| | | StationCommand command = stationThread.getCommand( |
| | | StationCommandType.MOVE, |
| | | wrkMast.getWrkNo(), |
| | | StationCommand command = buildOutboundMoveCommand( |
| | | stationThread, |
| | | wrkMast, |
| | | stationProtocol.getStationId(), |
| | | moveStaNo, |
| | | 0 |
| | | pathLenFactor |
| | | ); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "站点任务停留超时后重算路径失败,当前站点={},目标站点={}", stationProtocol.getStationId(), moveStaNo); |
| | |
| | | Integer sourceStationId, |
| | | Integer targetStationId, |
| | | LoadGuardState loadGuardState) { |
| | | return findPathLoopHit(config, sourceStationId, targetStationId, loadGuardState, null, null); |
| | | } |
| | | |
| | | private LoopHitResult findPathLoopHit(DispatchLimitConfig config, |
| | | Integer sourceStationId, |
| | | Integer targetStationId, |
| | | LoadGuardState loadGuardState, |
| | | WrkMast wrkMast, |
| | | Double pathLenFactor) { |
| | | if (!config.loopModeEnable) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(sourceStationId, targetStationId); |
| | | List<NavigateNode> nodes = wrkMast == null |
| | | ? navigateUtils.calcByStationId(sourceStationId, targetStationId) |
| | | : calcOutboundNavigatePath(wrkMast, sourceStationId, targetStationId, pathLenFactor); |
| | | if (nodes == null || nodes.isEmpty()) { |
| | | return LoopHitResult.NO_HIT; |
| | | } |
| | |
| | | return value; |
| | | } |
| | | |
| | | private Double normalizePathLenFactor(Double pathLenFactor) { |
| | | if (pathLenFactor == null || pathLenFactor < 0.0d) { |
| | | return 0.0d; |
| | | } |
| | | if (pathLenFactor > 1.0d) { |
| | | return 1.0d; |
| | | } |
| | | return pathLenFactor; |
| | | } |
| | | |
| | | private static class OutOrderDispatchDecision { |
| | | private final Integer targetStationId; |
| | | private final boolean circle; |
| | | private final StationTaskLoopService.LoopEvaluation loopEvaluation; |
| | | private final boolean countLoopIssue; |
| | | |
| | | private OutOrderDispatchDecision(Integer targetStationId, boolean circle) { |
| | | this(targetStationId, circle, null, false); |
| | | } |
| | | |
| | | private OutOrderDispatchDecision(Integer targetStationId, |
| | | boolean circle, |
| | | StationTaskLoopService.LoopEvaluation loopEvaluation, |
| | | boolean countLoopIssue) { |
| | | this.targetStationId = targetStationId; |
| | | this.circle = circle; |
| | | this.loopEvaluation = loopEvaluation; |
| | | this.countLoopIssue = countLoopIssue; |
| | | } |
| | | |
| | | private Integer getTargetStationId() { |
| | |
| | | private boolean isCircle() { |
| | | return circle; |
| | | } |
| | | |
| | | private StationTaskLoopService.LoopEvaluation getLoopEvaluation() { |
| | | return loopEvaluation; |
| | | } |
| | | |
| | | private boolean shouldCountLoopIssue() { |
| | | return countLoopIssue; |
| | | } |
| | | } |
| | | |
| | | private static class CircleTargetCandidate { |
| | | private final Integer stationId; |
| | | private final Integer pathLength; |
| | | private final Integer offset; |
| | | |
| | | private CircleTargetCandidate(Integer stationId, Integer pathLength, Integer offset) { |
| | | this.stationId = stationId; |
| | | this.pathLength = pathLength == null ? 0 : pathLength; |
| | | this.offset = offset == null ? 0 : offset; |
| | | } |
| | | |
| | | private Integer getStationId() { |
| | | return stationId; |
| | | } |
| | | |
| | | private Integer getPathLength() { |
| | | return pathLength; |
| | | } |
| | | |
| | | private Integer getOffset() { |
| | | return offset; |
| | | } |
| | | } |
| | | |
| | | private void saveLoopLoadReserve(Integer wrkNo, LoopHitResult loopHitResult) { |