| | |
| | | import com.zy.asrs.task.escalationParam.RgvTaskReportingParam; |
| | | import com.zy.asrs.utils.PostMesDataUtils; |
| | | import com.zy.asrs.utils.SortTheExecutionOfTheCarUtil; |
| | | import com.zy.asrs.utils.TaskDispatchPriorityUtil; |
| | | import com.zy.asrs.utils.TimeCalculatorUtils; |
| | | import com.zy.common.CodeRes; |
| | | import com.zy.common.service.CommonService; |
| | |
| | | private boolean reportSwitch; |
| | | @Value("${wms.reportSwitchAuto}") |
| | | private boolean reportSwitchAuto; |
| | | @Value("${constant-parameters.priority.distance-threshold:10000}") |
| | | private Long priorityDistanceThreshold; |
| | | @Value("${constant-parameters.priority.weight.time:0.4}") |
| | | private Double priorityTimeWeight; |
| | | @Value("${constant-parameters.priority.weight.distance:0.4}") |
| | | private Double priorityDistanceWeight; |
| | | @Value("${constant-parameters.priority.weight.region:0.2}") |
| | | private Double priorityRegionWeight; |
| | | @Value("${constant-parameters.priority.region-values:}") |
| | | private String regionPriorityValues; |
| | | private volatile String cachedRegionPriorityRaw = ""; |
| | | private volatile Map<Integer, Double> cachedRegionPriorityMap = new HashMap<>(); |
| | | |
| | | /* |
| | | * 验证许可证是否有效 |
| | |
| | | * 站点任务检测 下发小车取放任务 |
| | | */ |
| | | public synchronized void DevpTaskNoRun() { |
| | | |
| | | try { |
| | | List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", 1L).orderBy("modi_time", true)); |
| | | if (wrkMasts.isEmpty()) { |
| | | return; |
| | | } |
| | | long differenceInSeconds = TimeCalculatorUtils.differenceInMilliseconds(wrkMasts.get(0).getModiTime(), new Date()); |
| | | if (differenceInSeconds <= 1000) { |
| | | return; |
| | | } |
| | | |
| | | BasCircularShuttle basCircularShuttle = basCircularShuttleService.selectOne(new EntityWrapper<BasCircularShuttle>().eq("rgv_id", 1)); |
| | | RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, basCircularShuttle.getRgvNo()); |
| | | RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); |
| | | if (rgvProtocol == null) { |
| | | return; |
| | | } |
| | | List<BasDevpPosition> basDevpPositions = basDevpPositionService.selectList(new EntityWrapper<BasDevpPosition>().orderBy("plc_position", true)); |
| | | List<BasDevpPosition> basDevpPositionDevRegion = basDevpPositionService.selectList(new EntityWrapper<BasDevpPosition>().orderBy("dev_region", true)); |
| | | Integer devNo = SortTheExecutionOfTheCarUtil.LatelyAndLessThan(basDevpPositions, rgvProtocol.getRgvPos(), perimeter); |
| | | BasDevpPosition[] basDevpPositionsList = SortTheExecutionOfTheCarUtil.devpNoSort(basDevpPositions, devNo); |
| | | BasDevpPosition[] basDevpPositionsListUN = SortTheExecutionOfTheCarUtil.devpNoSortUN(basDevpPositionsList); |
| | | List<List<Integer>> siteListAll = SortTheExecutionOfTheCarUtil.siteListAll(basDevpPositionDevRegion); |
| | | // List<List<WrkMast>> wrkMastLists = getWrkMastLists(basDevpPositionsListUN); |
| | | List<List<List<WrkMast>>> wrkMastListAll = getWrkMastListAll(siteListAll, basDevpPositionsListUN); |
| | | //下发任务 |
| | | // taskDown(wrkMastLists); |
| | | taskDown(wrkMastListAll); |
| | | dispatchTaskByFlow(); |
| | | } catch (Exception e) { |
| | | log.error("自动下发小车任务失败,异常:" + e); |
| | | log.error("自动下发小车任务失败,异常:{}", e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 流程图版: 任务池挑任务并下发RGV |
| | | * 时间/距离/区域按权重计算最终优先级,再执行下发。 |
| | | */ |
| | | private void dispatchTaskByFlow() { |
| | | Date now = new Date(); |
| | | List<WrkMast> taskPool = wrkMastService.selectList( |
| | | new EntityWrapper<WrkMast>().eq("wrk_sts", 1L).orderBy("modi_time", true) |
| | | ); |
| | | if (taskPool.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | Date firstTaskTime = taskPool.get(0).getAppeTime() == null ? taskPool.get(0).getModiTime() : taskPool.get(0).getAppeTime(); |
| | | if (firstTaskTime == null) { |
| | | return; |
| | | } |
| | | long oldestWaitMs = TimeCalculatorUtils.differenceInMilliseconds(firstTaskTime, now); |
| | | if (oldestWaitMs <= 1000) { |
| | | return; |
| | | } |
| | | |
| | | List<BasDevpPosition> sitePositions = basDevpPositionService.selectList( |
| | | new EntityWrapper<BasDevpPosition>().orderBy("plc_position", true) |
| | | ); |
| | | if (sitePositions == null || sitePositions.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | Map<Integer, BasDevpPosition> siteMap = new HashMap<>(); |
| | | for (BasDevpPosition site : sitePositions) { |
| | | siteMap.put(site.getDevNo(), site); |
| | | } |
| | | |
| | | List<RgvRuntimeState> availableRgvs = loadAvailableRgvs(); |
| | | if (availableRgvs.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<Integer, RgvRuntimeState> rgvStateMap = new HashMap<>(); |
| | | List<TaskDispatchPriorityUtil.RgvSnapshot> snapshots = new ArrayList<>(); |
| | | for (RgvRuntimeState rgv : availableRgvs) { |
| | | if (rgv.protocol == null || rgv.protocol.getRgvPos() == null) { |
| | | continue; |
| | | } |
| | | rgvStateMap.put(rgv.shuttle.getRgvNo(), rgv); |
| | | snapshots.add(new TaskDispatchPriorityUtil.RgvSnapshot(rgv.shuttle.getRgvNo(), rgv.protocol.getRgvPos())); |
| | | } |
| | | if (snapshots.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | double[] weights = resolveWeights(taskPool.size(), snapshots.size()); |
| | | List<TaskDispatchPriorityUtil.DispatchPlan> plans = TaskDispatchPriorityUtil.rankDispatchPlans( |
| | | taskPool, |
| | | siteMap, |
| | | snapshots, |
| | | parseRegionPriorityMap(), |
| | | now, |
| | | Math.max(1L, priorityDistanceThreshold == null ? 10000L : priorityDistanceThreshold), |
| | | Math.max(1L, perimeter == null ? 1L : perimeter), |
| | | weights[0], |
| | | weights[1], |
| | | weights[2] |
| | | ); |
| | | if (plans.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | TaskDispatchPriorityUtil.DispatchPlan topPlan = plans.get(0); |
| | | WrkMast task = topPlan.getTask(); |
| | | if (task == null || task.getSourceStaNo() == null) { |
| | | return; |
| | | } |
| | | BasDevpPosition source = siteMap.get(task.getSourceStaNo()); |
| | | if (source == null) { |
| | | return; |
| | | } |
| | | RgvRuntimeState chosenRgv = rgvStateMap.get(topPlan.getRgvNo()); |
| | | if (chosenRgv == null) { |
| | | return; |
| | | } |
| | | |
| | | log.info("任务优先级计算: wrkNo={} rgvNo={} final={} (time={} distance={} region={}) distance={} inRange={}", |
| | | task.getWrkNo(), |
| | | topPlan.getRgvNo(), |
| | | topPlan.getFinalPriority(), |
| | | topPlan.getTimePriority(), |
| | | topPlan.getDistancePriority(), |
| | | topPlan.getRegionPriority(), |
| | | topPlan.getDistance(), |
| | | topPlan.isInRange()); |
| | | |
| | | if (topPlan.isInRange() && canFetchFromRoam(chosenRgv.protocol, source.getPlcPosition())) { |
| | | if (issueFetchTask(task, chosenRgv)) { |
| | | updateStePosition(); |
| | | } |
| | | return; |
| | | } |
| | | issueRoamTask(chosenRgv, source.getPlcPosition()); |
| | | } |
| | | |
| | | private List<RgvRuntimeState> loadAvailableRgvs() { |
| | | List<RgvRuntimeState> result = new ArrayList<>(); |
| | | List<BasCircularShuttle> shuttles = basCircularShuttleService.selectList( |
| | | new EntityWrapper<BasCircularShuttle>().orderBy("rgv_id", true) |
| | | ); |
| | | if (shuttles == null || shuttles.isEmpty()) { |
| | | return result; |
| | | } |
| | | |
| | | for (BasCircularShuttle shuttle : shuttles) { |
| | | try { |
| | | if (shuttle.getStatus() != 0) { |
| | | continue; |
| | | } |
| | | RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, shuttle.getRgvNo()); |
| | | if (rgvThread == null) { |
| | | continue; |
| | | } |
| | | RgvProtocol protocol = rgvThread.getRgvProtocol(); |
| | | if (!isAvailableRgv(protocol)) { |
| | | continue; |
| | | } |
| | | if (isRgvRunningTask(shuttle.getRgvNo())) { |
| | | continue; |
| | | } |
| | | result.add(new RgvRuntimeState(shuttle, protocol)); |
| | | } catch (Exception ignore) { |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private boolean isAvailableRgv(RgvProtocol protocol) { |
| | | return protocol != null |
| | | && protocol.getModeType() == RgvModeType.AUTO |
| | | && (protocol.getStatusType() == RgvStatusType.IDLE || protocol.getStatusType() == RgvStatusType.ROAM) |
| | | && protocol.getTaskNo1() == 0 |
| | | && protocol.getRgvPosInt() != 0 |
| | | && protocol.getAlarm() == 0; |
| | | } |
| | | |
| | | private boolean isRgvRunningTask(Integer rgvNo) { |
| | | List<WrkMast> running = wrkMastService.selectList( |
| | | new EntityWrapper<WrkMast>().eq("rgv_no", rgvNo).eq("wrk_sts", 2L) |
| | | ); |
| | | return running != null && !running.isEmpty(); |
| | | } |
| | | |
| | | private boolean canFetchFromRoam(RgvProtocol protocol, long sourcePos) { |
| | | if (protocol.getStatusType() != RgvStatusType.ROAM) { |
| | | return true; |
| | | } |
| | | if (protocol.getInstantaneousSpeed() == null || acceleration == null || acceleration == 0) { |
| | | return true; |
| | | } |
| | | double finalVelocity = 0.0; |
| | | double distance = (Math.pow(finalVelocity, 2) - Math.pow(protocol.getInstantaneousSpeed() / 60, 2)) / (2 * acceleration); |
| | | double threshold = distance * proportion + (protocol.getInstantaneousSpeed() / 60) * proportion * rgvDate; |
| | | double sourceDistance = SortTheExecutionOfTheCarUtil.LatelyAndLessThan(sourcePos, protocol.getRgvPos(), perimeter); |
| | | return !(threshold > sourceDistance); |
| | | } |
| | | |
| | | private boolean issueFetchTask(WrkMast task, RgvRuntimeState rgv) { |
| | | RgvCommand command = new RgvCommand(); |
| | | command.setRgvNo(rgv.shuttle.getRgvNo()); |
| | | command.setAckFinish1((short) 0); |
| | | command.setTaskNo1(task.getWrkNo().shortValue()); |
| | | command.setTaskMode1(RgvTaskModeType.FETCH_PUT); |
| | | command.setSourceStaNo1(task.getSourceStaNo().shortValue()); |
| | | command.setDestinationStaNo1(task.getStaNo().shortValue()); |
| | | command.setCommand((short) 1); |
| | | command.setRgvSome(rgv.shuttle.getRgvSome() == 1 ? (short) 1 : (short) 0); |
| | | |
| | | if (!MessageQueue.offer(SlaveType.Rgv, rgv.shuttle.getRgvNo(), new Task(2, command))) { |
| | | task.setLogErrTime(new Date()); |
| | | task.setLogErrMemo("RGV命令下发失败,RGV号={" + rgv.shuttle.getRgvNo() + "}===>跳过"); |
| | | wrkMastService.updateById(task); |
| | | log.error("RGV命令下发失败,RGV号={},任务数据={}", rgv.shuttle.getRgvNo(), JSON.toJSON(command)); |
| | | return false; |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | task.setWrkSts(2L); |
| | | task.setRgvNo(rgv.shuttle.getRgvNo()); |
| | | task.setAppeTime(now); |
| | | task.setCrnStrTime(now); |
| | | wrkMastService.updateById(task); |
| | | log.info("RGV命令下发成功,RGV号={},任务号={},source={},target={}", |
| | | rgv.shuttle.getRgvNo(), task.getWrkNo(), task.getSourceStaNo(), task.getStaNo()); |
| | | return true; |
| | | } |
| | | |
| | | private void issueRoamTask(RgvRuntimeState rgv, long sourcePos) { |
| | | if (rgv == null || rgv.protocol == null) { |
| | | return; |
| | | } |
| | | if (rgv.protocol.getStatusType() != RgvStatusType.IDLE) { |
| | | return; |
| | | } |
| | | long destination = getRoamDestination(sourcePos); |
| | | if (!MessageQueue.offer(SlaveType.Rgv, rgv.shuttle.getRgvNo(), new Task(5, destination))) { |
| | | log.error("RGV漫游任务下发失败,RGV号={},目的地={}", rgv.shuttle.getRgvNo(), destination); |
| | | return; |
| | | } |
| | | log.info("RGV漫游任务下发成功,RGV号={},目的地={}", rgv.shuttle.getRgvNo(), destination); |
| | | } |
| | | |
| | | private long getRoamDestination(long sourcePos) { |
| | | long destination = sourcePos - taskRunPerimeter + 10000; |
| | | if (destination > perimeter) { |
| | | return 10000L; |
| | | } |
| | | if (destination <= 0) { |
| | | destination = perimeter + destination; |
| | | } |
| | | return destination; |
| | | } |
| | | |
| | | private Map<Integer, Double> parseRegionPriorityMap() { |
| | | String raw = regionPriorityValues == null ? "" : regionPriorityValues.trim(); |
| | | if (raw.equals(cachedRegionPriorityRaw)) { |
| | | return cachedRegionPriorityMap; |
| | | } |
| | | Map<Integer, Double> regionMap = new HashMap<>(); |
| | | if (raw.isEmpty()) { |
| | | cachedRegionPriorityRaw = raw; |
| | | cachedRegionPriorityMap = regionMap; |
| | | return regionMap; |
| | | } |
| | | String[] items = raw.split(","); |
| | | for (String item : items) { |
| | | if (item == null || item.trim().isEmpty()) { |
| | | continue; |
| | | } |
| | | String[] pair = item.split(":"); |
| | | if (pair.length != 2) { |
| | | continue; |
| | | } |
| | | try { |
| | | Integer region = Integer.valueOf(pair[0].trim()); |
| | | Double priority = Double.valueOf(pair[1].trim()); |
| | | if (priority > 1D) { |
| | | priority = 1D; |
| | | } else if (priority < -1D) { |
| | | priority = -1D; |
| | | } |
| | | regionMap.put(region, priority); |
| | | } catch (Exception ignore) { |
| | | } |
| | | } |
| | | cachedRegionPriorityRaw = raw; |
| | | cachedRegionPriorityMap = regionMap; |
| | | return regionMap; |
| | | } |
| | | |
| | | private double[] resolveWeights(int pendingTaskCount, int availableRgvCount) { |
| | | double timeW = priorityTimeWeight == null ? 0.4D : priorityTimeWeight; |
| | | double distanceW = priorityDistanceWeight == null ? 0.4D : priorityDistanceWeight; |
| | | double regionW = priorityRegionWeight == null ? 0.2D : priorityRegionWeight; |
| | | |
| | | double capacity = Math.max(1D, availableRgvCount * 2D); |
| | | double loadFactor = Math.min(1D, pendingTaskCount / capacity); |
| | | if (loadFactor > 0.7D) { |
| | | timeW = Math.min(0.55D, timeW + 0.10D); |
| | | distanceW = Math.max(0.10D, distanceW - 0.05D); |
| | | } else if (loadFactor < 0.4D) { |
| | | timeW = Math.max(0.25D, timeW - 0.05D); |
| | | distanceW = Math.min(0.55D, distanceW + 0.05D); |
| | | } |
| | | |
| | | double sum = Math.abs(timeW) + Math.abs(distanceW) + Math.abs(regionW); |
| | | if (sum <= 0D) { |
| | | return new double[]{0.4D, 0.4D, 0.2D}; |
| | | } |
| | | return new double[]{timeW / sum, distanceW / sum, regionW / sum}; |
| | | } |
| | | |
| | | private static class RgvRuntimeState { |
| | | private final BasCircularShuttle shuttle; |
| | | private final RgvProtocol protocol; |
| | | |
| | | private RgvRuntimeState(BasCircularShuttle shuttle, RgvProtocol protocol) { |
| | | this.shuttle = shuttle; |
| | | this.protocol = protocol; |
| | | } |
| | | } |
| | | |
| | | //获取小车取放任务列表失败 |