| | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.alibaba.fastjson.serializer.SerializerFeature; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.core.common.Cools; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.domain.enums.NotifyMsgType; |
| | |
| | | @Component |
| | | public class StationOperateProcessUtils { |
| | | private static final int LOOP_LOAD_RESERVE_EXPIRE_SECONDS = 120; |
| | | private static final int OUT_ORDER_DISPATCH_LIMIT_SECONDS = 10; |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | |
| | | int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()}; |
| | | LoadGuardState loadGuardState = buildLoadGuardState(limitConfig); |
| | | |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | |
| | | && stationProtocol.getTaskNo() > 0 |
| | | ) { |
| | | //检测任务是否生成 |
| | | WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("barcode", stationProtocol.getBarcode())); |
| | | WrkMast wrkMast = wrkMastService.getOne(new QueryWrapper<WrkMast>().eq("barcode", stationProtocol.getBarcode())); |
| | | if (wrkMast == null) { |
| | | continue; |
| | | } |
| | |
| | | int[] currentStationTaskCountRef = new int[]{countCurrentStationTask()}; |
| | | LoadGuardState loadGuardState = buildLoadGuardState(limitConfig); |
| | | |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | List<WrkMast> wrkMasts = wrkMastService.list(new QueryWrapper<WrkMast>() |
| | | .eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts) |
| | | .isNotNull("crn_no") |
| | | ); |
| | |
| | | && stationProtocol.isLoading() |
| | | && stationProtocol.getTaskNo() == 0 |
| | | ) { |
| | | Integer moveStaNo = wrkMast.getStaNo(); |
| | | |
| | | if (!outOrderList.isEmpty()) { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo()); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | NavigateNode node = nodes.get(i); |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | if (outOrderList.contains(stationId)) { |
| | | moveStaNo = stationId; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | Integer moveStaNo = resolveDispatchOutOrderTarget( |
| | | stationProtocol.getStationId(), |
| | | wrkMast.getStaNo(), |
| | | outOrderList, |
| | | true |
| | | ); |
| | | |
| | | LoopHitResult loopHitResult = findPathLoopHit(limitConfig, stationProtocol.getStationId(), moveStaNo, loadGuardState); |
| | | |
| | |
| | | //执行双工位堆垛机输送站点出库任务 |
| | | public synchronized void dualCrnStationOutExecute() { |
| | | try { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | List<WrkMast> wrkMasts = wrkMastService.list(new QueryWrapper<WrkMast>() |
| | | .eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts) |
| | | .isNotNull("dual_crn_no") |
| | | ); |
| | |
| | | //检测输送站点出库任务执行完成 |
| | | public synchronized void stationOutExecuteFinish() { |
| | | try { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN.sts)); |
| | | List<WrkMast> wrkMasts = wrkMastService.list(new QueryWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN.sts)); |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | | |
| | | boolean complete = false; |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | |
| | | // 检测任务转完成 |
| | | public synchronized void checkTaskToComplete() { |
| | | try { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts)); |
| | | List<WrkMast> wrkMasts = wrkMastService.list(new QueryWrapper<WrkMast>().eq("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts)); |
| | | for (WrkMast wrkMast : wrkMasts) { |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Integer targetStaNo = wrkMast.getStaNo(); |
| | |
| | | } |
| | | |
| | | boolean complete = false; |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", targetStaNo)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | |
| | | //检测输送站点是否运行堵塞 |
| | | public synchronized void checkStationRunBlock() { |
| | | try { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | |
| | | //站点处于重新分配库位区域 |
| | | //运行堵塞,重新申请任务 |
| | | String response = wmsOperateUtils.applyReassignTaskLocNo(wrkMast.getWrkNo(), stationProtocol.getStationId()); |
| | | if (response == null) { |
| | | if (Cools.isEmpty(response)) { |
| | | News.taskError(wrkMast.getWrkNo(), "请求WMS重新分配库位接口失败,接口未响应!!!response:{}", response); |
| | | continue; |
| | | } |
| | |
| | | |
| | | // 检测出库排序 |
| | | public synchronized void checkStationOutOrder() { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getId()); |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap(); |
| | | List<StationObjModel> orderList = basDevp.getOutOrderList$(); |
| | | List<Integer> outOrderStationIds = basDevp.getOutOrderIntList(); |
| | | for (StationObjModel stationObjModel : orderList) { |
| | | StationProtocol stationProtocol = statusMap.get(stationObjModel.getStationId()); |
| | | if (stationProtocol == null) { |
| | |
| | | continue; |
| | | } |
| | | |
| | | if (isWatchingCircleArrival(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | |
| | | if (Cools.isEmpty(wrkMast.getBatch())) { |
| | | continue; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | List<WrkMast> batchWrkList = wrkMastService.selectList(new EntityWrapper<WrkMast>() |
| | | List<WrkMast> batchWrkList = wrkMastService.list(new QueryWrapper<WrkMast>() |
| | | .notIn("wrk_sts", WrkStsType.STATION_RUN_COMPLETE.sts, WrkStsType.COMPLETE_OUTBOUND.sts) |
| | | .eq("batch", wrkMast.getBatch()) |
| | | .orderBy("batch") |
| | | .orderBy(true, true, "batch_seq") |
| | | ); |
| | | if (batchWrkList.isEmpty()) { |
| | | continue; |
| | |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | clearWatchCircleCommand(wrkMast.getWrkNo()); |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | News.info("{}任务直接去目标点", wrkMast.getWrkNo()); |
| | | } else if (commandType.equals("toCircle")) { |
| | | Integer circleTarget = null; |
| | | for (NavigateNode node : initPath) { |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | try { |
| | | List<NavigateNode> enableMovePath = navigateUtils.calcByStationId(stationProtocol.getStationId(), stationId); |
| | | if (enableMovePath.isEmpty()) { |
| | | continue; |
| | | } |
| | | } catch (Exception e) { |
| | | continue; |
| | | } |
| | | |
| | | circleTarget = stationId; |
| | | break; |
| | | } |
| | | } |
| | | Integer circleTarget = resolveNextCircleOrderTarget(stationProtocol.getStationId(), outOrderStationIds); |
| | | |
| | | if (circleTarget == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "未找到可执行的下一排序检测点,当前站点={}", stationProtocol.getStationId()); |
| | | continue; |
| | | } |
| | | |
| | |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command)); |
| | | redisUtil.set(RedisKeyType.WATCH_CIRCLE_STATION_.key + wrkMast.getWrkNo(), JSON.toJSONString(command, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24); |
| | | saveWatchCircleCommand(wrkMast.getWrkNo(), command); |
| | | News.info("{}任务进行绕圈", wrkMast.getWrkNo()); |
| | | } |
| | | } |
| | |
| | | |
| | | // 监控绕圈站点 |
| | | public synchronized void watchCircleStation() { |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getId()); |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | Object circleObj = redisUtil.get(RedisKeyType.WATCH_CIRCLE_STATION_.key + stationProtocol.getTaskNo()); |
| | | if (circleObj == null) { |
| | | StationCommand circleCommand = getWatchCircleCommand(stationProtocol.getTaskNo()); |
| | | if (circleCommand == null) { |
| | | continue; |
| | | } |
| | | |
| | | StationCommand circleCommand = JSON.parseObject(circleObj.toString(), StationCommand.class); |
| | | if (!stationProtocol.getStationId().equals(circleCommand.getTargetStaNo())) { |
| | | continue; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | Integer moveStaNo = wrkMast.getStaNo(); |
| | | |
| | | if (!outOrderList.isEmpty()) { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(stationProtocol.getStationId(), wrkMast.getStaNo()); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | NavigateNode node = nodes.get(i); |
| | | JSONObject v = JSONObject.parseObject(node.getNodeValue()); |
| | | if (v != null) { |
| | | Integer stationId = v.getInteger("stationId"); |
| | | if (outOrderList.contains(stationId)) { |
| | | moveStaNo = stationId; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | Integer moveStaNo = resolveDispatchOutOrderTarget( |
| | | stationProtocol.getStationId(), |
| | | wrkMast.getStaNo(), |
| | | outOrderList, |
| | | true |
| | | ); |
| | | |
| | | StationCommand command = stationThread.getCommand(StationCommandType.MOVE, wrkMast.getWrkNo(), stationProtocol.getStationId(), moveStaNo, 0); |
| | | if (command == null) { |
| | | News.taskInfo(wrkMast.getWrkNo(), "获取输送线命令失败"); |
| | | continue; |
| | | } |
| | | if (!tryAcquireOutOrderDispatchLock(wrkMast.getWrkNo(), stationProtocol.getStationId())) { |
| | | continue; |
| | | } |
| | | if (Objects.equals(moveStaNo, wrkMast.getStaNo())) { |
| | | clearWatchCircleCommand(wrkMast.getWrkNo()); |
| | | } else { |
| | | saveWatchCircleCommand(wrkMast.getWrkNo(), command); |
| | | } |
| | | MessageQueue.offer(SlaveType.Devp, basDevp.getDevpNo(), new Task(2, command)); |
| | | } |
| | |
| | | |
| | | public List<Integer> getAllOutOrderList() { |
| | | List<Integer> list = new ArrayList<>(); |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | List<Integer> orderList = basDevp.getOutOrderIntList(); |
| | | list.addAll(orderList); |
| | | } |
| | | return list; |
| | | } |
| | | |
| | | private Integer resolveDispatchOutOrderTarget(Integer currentStationId, |
| | | Integer finalTargetStationId, |
| | | List<Integer> outOrderList, |
| | | boolean skipCurrentStation) { |
| | | if (finalTargetStationId == null) { |
| | | return null; |
| | | } |
| | | if (currentStationId == null || outOrderList == null || outOrderList.isEmpty()) { |
| | | return finalTargetStationId; |
| | | } |
| | | |
| | | try { |
| | | List<NavigateNode> nodes = navigateUtils.calcByStationId(currentStationId, finalTargetStationId); |
| | | for (int i = nodes.size() - 1; i >= 0; i--) { |
| | | Integer stationId = getStationIdFromNode(nodes.get(i)); |
| | | if (stationId == null) { |
| | | continue; |
| | | } |
| | | if (skipCurrentStation && currentStationId.equals(stationId)) { |
| | | continue; |
| | | } |
| | | if (outOrderList.contains(stationId)) { |
| | | return stationId; |
| | | } |
| | | } |
| | | } catch (Exception ignore) {} |
| | | return finalTargetStationId; |
| | | } |
| | | |
| | | private Integer resolveNextCircleOrderTarget(Integer currentStationId, List<Integer> orderedOutStationList) { |
| | | if (currentStationId == null || orderedOutStationList == null || orderedOutStationList.size() <= 1) { |
| | | return null; |
| | | } |
| | | |
| | | int startIndex = orderedOutStationList.indexOf(currentStationId); |
| | | int total = orderedOutStationList.size(); |
| | | for (int offset = 1; offset < total; offset++) { |
| | | int candidateIndex = (startIndex + offset + total) % total; |
| | | Integer candidateStationId = orderedOutStationList.get(candidateIndex); |
| | | if (candidateStationId == null || currentStationId.equals(candidateStationId)) { |
| | | continue; |
| | | } |
| | | try { |
| | | List<NavigateNode> path = navigateUtils.calcByStationId(currentStationId, candidateStationId); |
| | | if (path != null && !path.isEmpty()) { |
| | | return candidateStationId; |
| | | } |
| | | } catch (Exception ignore) {} |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private boolean tryAcquireOutOrderDispatchLock(Integer wrkNo, Integer stationId) { |
| | | if (wrkNo == null || wrkNo <= 0 || stationId == null) { |
| | | return true; |
| | | } |
| | | String key = RedisKeyType.STATION_OUT_ORDER_DISPATCH_LIMIT_.key + wrkNo + "_" + stationId; |
| | | Object lock = redisUtil.get(key); |
| | | if (lock != null) { |
| | | return false; |
| | | } |
| | | redisUtil.set(key, "lock", OUT_ORDER_DISPATCH_LIMIT_SECONDS); |
| | | return true; |
| | | } |
| | | |
| | | private boolean isWatchingCircleArrival(Integer wrkNo, Integer stationId) { |
| | | StationCommand command = getWatchCircleCommand(wrkNo); |
| | | return command != null && stationId != null && stationId.equals(command.getTargetStaNo()); |
| | | } |
| | | |
| | | private StationCommand getWatchCircleCommand(Integer wrkNo) { |
| | | if (wrkNo == null || wrkNo <= 0) { |
| | | return null; |
| | | } |
| | | Object circleObj = redisUtil.get(RedisKeyType.WATCH_CIRCLE_STATION_.key + wrkNo); |
| | | if (circleObj == null) { |
| | | return null; |
| | | } |
| | | try { |
| | | return JSON.parseObject(circleObj.toString(), StationCommand.class); |
| | | } catch (Exception ignore) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private void saveWatchCircleCommand(Integer wrkNo, StationCommand command) { |
| | | if (wrkNo == null || wrkNo <= 0 || command == null) { |
| | | return; |
| | | } |
| | | redisUtil.set(RedisKeyType.WATCH_CIRCLE_STATION_.key + wrkNo, |
| | | JSON.toJSONString(command, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24); |
| | | } |
| | | |
| | | private void clearWatchCircleCommand(Integer wrkNo) { |
| | | if (wrkNo == null || wrkNo <= 0) { |
| | | return; |
| | | } |
| | | redisUtil.del(RedisKeyType.WATCH_CIRCLE_STATION_.key + wrkNo); |
| | | } |
| | | |
| | | public Integer getOutStationBatchSeq(List<NavigateNode> pathList, Integer searchStationId, String searchBatch) { |
| | |
| | | |
| | | HashMap<String, Integer> batchMap = new HashMap<>(); |
| | | for (Integer station : checkList) { |
| | | BasStation basStation = basStationService.selectOne(new EntityWrapper<BasStation>().eq("station_id", station)); |
| | | BasStation basStation = basStationService.getOne(new QueryWrapper<BasStation>().eq("station_id", station)); |
| | | if (basStation == null) { |
| | | continue; |
| | | } |
| | |
| | | |
| | | private int countCurrentStationTask() { |
| | | int currentStationTaskCount = 0; |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | List<BasDevp> basDevps = basDevpService.list(new QueryWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basDevp.getDevpNo()); |
| | | if (stationThread == null) { |
| | |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (config.stationMaxTaskCount > 0 && currentStationTaskCount >= config.stationMaxTaskCount) { |
| | | News.warn("输送站点任务数量达到上限,已停止站点任务下发。当前任务数={},上限={}", currentStationTaskCount, config.stationMaxTaskCount); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | |
| | | } |
| | | config.loopModeEnable = parseBoolean(loopModeValue, config.loopModeEnable); |
| | | |
| | | String stationMaxTaskCountValue = getConfigValue(systemConfigMap, "stationMaxTaskCountLimit"); |
| | | if (isBlank(stationMaxTaskCountValue)) { |
| | | stationMaxTaskCountValue = getConfigValue(systemConfigMap, "stationMaxTaskCount"); |
| | | } |
| | | if (isBlank(stationMaxTaskCountValue)) { |
| | | stationMaxTaskCountValue = getConfigValue(systemConfigMap, "conveyorStationTaskLimit"); |
| | | } |
| | | config.stationMaxTaskCount = parseInt(stationMaxTaskCountValue, config.stationMaxTaskCount); |
| | | |
| | | return config; |
| | | } |
| | | |
| | |
| | | private double circleMaxLoadLimit = 0.8d; |
| | | // 是否启用绕圈模式(仅启用时才生效承载限制) |
| | | private boolean loopModeEnable = false; |
| | | // 站点最大任务数量上限,0表示不限制 |
| | | private int stationMaxTaskCount = 30; |
| | | } |
| | | |
| | | private static class LoadGuardState { |