| | |
| | | package com.zy.asrs.wcs.core.utils; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.zy.asrs.framework.common.Cools; |
| | | import com.zy.asrs.framework.common.SnowflakeIdWorker; |
| | | import com.zy.asrs.framework.exception.CoolException; |
| | | import com.zy.asrs.wcs.core.entity.BasShuttle; |
| | | import com.zy.asrs.wcs.core.entity.Motion; |
| | | import com.zy.asrs.wcs.core.entity.Task; |
| | | import com.zy.asrs.wcs.core.entity.TaskCtg; |
| | | import com.zy.asrs.wcs.core.entity.*; |
| | | import com.zy.asrs.wcs.core.kernel.AnalyzeService; |
| | | import com.zy.asrs.wcs.core.model.NavigateNode; |
| | | import com.zy.asrs.wcs.core.model.enums.LiftCodeType; |
| | | import com.zy.asrs.wcs.core.model.enums.NavigationMapType; |
| | | import com.zy.asrs.wcs.core.model.enums.TaskStsType; |
| | | import com.zy.asrs.wcs.core.service.BasShuttleService; |
| | | import com.zy.asrs.wcs.core.service.TaskCtgService; |
| | | import com.zy.asrs.wcs.core.service.TaskService; |
| | | import com.zy.asrs.wcs.core.model.enums.*; |
| | | import com.zy.asrs.wcs.core.service.*; |
| | | import com.zy.asrs.wcs.rcs.News; |
| | | import com.zy.asrs.wcs.rcs.cache.SlaveConnection; |
| | | import com.zy.asrs.wcs.rcs.entity.Device; |
| | | import com.zy.asrs.wcs.rcs.entity.DeviceType; |
| | | import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType; |
| | | import com.zy.asrs.wcs.rcs.model.enums.SlaveType; |
| | | import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; |
| | | import com.zy.asrs.wcs.rcs.service.DeviceService; |
| | | import com.zy.asrs.wcs.rcs.service.DeviceTypeService; |
| | | import com.zy.asrs.wcs.core.service.MotionService; |
| | | import com.zy.asrs.wcs.rcs.thread.LiftThread; |
| | | import com.zy.asrs.wcs.rcs.thread.ShuttleThread; |
| | | import com.zy.asrs.wcs.system.entity.Dict; |
| | | import com.zy.asrs.wcs.system.service.DictService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * Created by vincent on 2023/10/12 |
| | |
| | | private LiftDispatcher liftDispatcher; |
| | | @Autowired |
| | | private SnowflakeIdWorker snowflakeIdWorker; |
| | | // @Autowired |
| | | // private CommonService commonService; |
| | | @Autowired |
| | | private AnalyzeService analyzeService; |
| | | @Autowired |
| | |
| | | @Autowired |
| | | private DeviceService deviceService; |
| | | @Autowired |
| | | private DeviceTypeService deviceTypeService; |
| | | @Autowired |
| | | private BasShuttleService basShuttleService; |
| | | @Autowired |
| | | private TaskCtgService taskCtgService; |
| | | @Autowired |
| | | private ShuttleStandbyService shuttleStandbyService; |
| | | @Autowired |
| | | private DictService dictService; |
| | | @Autowired |
| | | private NavigateUtils navigateUtils; |
| | | |
| | | public ShuttleThread queryShuttleWhichConvenient(Task task, Integer liftNo) { |
| | | String locNo = taskService.judgeInbound(task) ? task.getDestLoc() : task.getOriginLoc(); |
| | | /** |
| | | * 调度车辆 |
| | | */ |
| | | public Device dispatchShuttle(Task task, String locNo) { |
| | | ArrayList<ShuttleThread> sameLev = new ArrayList<>();//相同楼层的穿梭车 |
| | | ArrayList<ShuttleThread> diffLev = new ArrayList<>();//不同楼层的穿梭车 |
| | | |
| | | ShuttleThread resThread = null; |
| | | Integer finalDistance = ShuttleDispatcher.INF; |
| | | |
| | | DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper<DeviceType>() |
| | | .eq(DeviceType::getHostId, task.getHostId()) |
| | | .eq(DeviceType::getStatus, 1) |
| | | .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle))); |
| | | if (deviceType == null) { |
| | | throw new CoolException("设备类型不存在"); |
| | | } |
| | | |
| | | int lev = Utils.getLev(locNo); |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, deviceType.getId()) |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .eq(Device::getHostId, task.getHostId()) |
| | | .eq(Device::getStatus, 1)); |
| | | |
| | | //获取同层小车 |
| | | List<Device> currentLevDevices = new ArrayList<>(); |
| | | //获取跨层小车 |
| | | HashMap<Integer, List<Device>> diffLevDeviceMap = new HashMap<>(); |
| | | for (Device device : list) { |
| | | //获取四向穿梭车线程 |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null || shuttleProtocol.getShuttleNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (shuttleProtocol.getCurrentLocNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | int shuttleLev = Utils.getLev(shuttleProtocol.getCurrentLocNo()); |
| | | if (shuttleLev == lev) { |
| | | currentLevDevices.add(device); |
| | | } else { |
| | | List<Device> devices = null; |
| | | if (diffLevDeviceMap.containsKey(shuttleLev)) { |
| | | devices = diffLevDeviceMap.get(shuttleLev); |
| | | } else { |
| | | devices = new ArrayList<>(); |
| | | } |
| | | devices.add(device); |
| | | diffLevDeviceMap.put(shuttleLev, devices); |
| | | } |
| | | } |
| | | |
| | | //搜索同层 |
| | | resThread = this.searchCurrentLevShuttle(currentLevDevices, locNo); |
| | | |
| | | //同层没有搜索到合适小车,跨楼层搜索 |
| | | if (resThread == null) { |
| | | resThread = this.searchDiffLevShuttle(diffLevDeviceMap, locNo, task); |
| | | } |
| | | |
| | | if (resThread != null) { |
| | | Task result = generateMoveTask(resThread.getDevice(), locNo); |
| | | if (result != null) { |
| | | return resThread.getDevice(); |
| | | } |
| | | } |
| | | |
| | | News.info("{}目标库位没有搜索到可用穿梭车", locNo); |
| | | return null; |
| | | } |
| | | |
| | | public synchronized ShuttleThread searchIdleShuttle(Task task) { |
| | | String locNo = taskService.judgeInbound(task) ? task.getDestLoc() : task.getOriginLoc(); |
| | | ShuttleThread resThread = null; |
| | | int lev = Utils.getLev(locNo); |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .eq(Device::getHostId, task.getHostId()) |
| | | .eq(Device::getStatus, 1)); |
| | | //获取同层小车 |
| | | List<Device> currentLevDevices = new ArrayList<>(); |
| | | //获取跨层小车 |
| | | HashMap<Integer,List<Device>> diffLevDeviceMap = new HashMap<>(); |
| | | for (Device device : list) { |
| | | //获取四向穿梭车线程 |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null || shuttleProtocol.getShuttleNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | int shuttleLev = Utils.getLev(shuttleProtocol.getCurrentLocNo()); |
| | | if (shuttleLev == lev) { |
| | | currentLevDevices.add(device); |
| | | }else { |
| | | List<Device> devices = null; |
| | | if(diffLevDeviceMap.containsKey(shuttleLev)) { |
| | | devices = diffLevDeviceMap.get(shuttleLev); |
| | | }else { |
| | | devices = new ArrayList<>(); |
| | | } |
| | | devices.add(device); |
| | | diffLevDeviceMap.put(shuttleLev, devices); |
| | | } |
| | | } |
| | | //搜索同层 |
| | | resThread = this.searchCurrentLevShuttle(currentLevDevices, locNo); |
| | | |
| | | //同层没有搜索到合适小车,跨楼层搜索 |
| | | if(resThread == null) { |
| | | resThread = this.searchDiffLevShuttle(diffLevDeviceMap, locNo, task); |
| | | } |
| | | |
| | | return resThread; |
| | | } |
| | | |
| | | private synchronized ShuttleThread searchCurrentLevShuttle(List<Device> devices, String locNo) { |
| | | ShuttleThread resThread = null; |
| | | Integer finalDistance = ShuttleDispatcher.INF; |
| | | for (Device device : devices) { |
| | | if (taskService.hasBusyOutboundByShuttle(Integer.parseInt(device.getDeviceNo()))) { |
| | | continue; |
| | | } |
| | |
| | | continue; |
| | | } |
| | | |
| | | BasShuttle basShuttle = basShuttleService.getOne(new LambdaQueryWrapper<BasShuttle>() |
| | | .eq(BasShuttle::getShuttleNo, device.getDeviceNo()) |
| | | .eq(BasShuttle::getHostId, device.getHostId())); |
| | | if (basShuttle == null) { |
| | | continue;//小车基础数据不存在 |
| | | } |
| | | |
| | | if (!Cools.isEmpty(basShuttle.getDisableLev())) { |
| | | List<Integer> disableLev = JSON.parseArray(basShuttle.getDisableLev(), Integer.class); |
| | | //检查小车是否禁用该楼层 |
| | | if (disableLev.contains(Utils.getLev(locNo))) { |
| | | continue;//小车禁用该楼层跳过该车 |
| | | } |
| | | } |
| | | |
| | | //检测是否存在充电任务 |
| | | Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo())); |
| | | if (taskCharge != null) { |
| | |
| | | } |
| | | |
| | | // 有没有被其他任务调度 |
| | | List<Task> taskList = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo()), null); |
| | | if (!taskList.isEmpty()) { |
| | | continue; |
| | | } |
| | | |
| | | |
| | | int currentLev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车当前层高 |
| | | String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车当前库位号 |
| | | |
| | |
| | | break; |
| | | } |
| | | |
| | | String targetLocNo = LiftCodeType.getStandbyLocNo(liftNo, currentLev);//默认到提升机待机位 |
| | | // 同楼层直接计算到目标库位 |
| | | if (currentLev == Utils.getLev(locNo)) { |
| | | targetLocNo = locNo; |
| | | } |
| | | |
| | | //当前穿梭车线程到当前车子所在楼层的提升机口距离 |
| | | List<NavigateNode> currentShuttlePath = NavigateUtils.calc( |
| | | //当前穿梭车线程到当前车子所在楼层的目标库位距离 |
| | | List<NavigateNode> currentShuttlePath = navigateUtils.calcWhiteList( |
| | | currentLocNo |
| | | , targetLocNo |
| | | , NavigationMapType.NORMAL.id |
| | | , locNo |
| | | , NavigationMapType.DFX.id |
| | | , Utils.getShuttlePoints(Integer.parseInt(shuttleThread.getDevice().getDeviceNo()), currentLev) |
| | | );//搜索空闲穿梭车,使用正常通道地图 |
| | | if (currentShuttlePath == null) { |
| | | continue; |
| | | } |
| | | |
| | | Integer currDistance = NavigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 |
| | | |
| | | // 不同楼层权重 |
| | | if (currentLev != Utils.getLev(locNo)) { |
| | | currDistance += WEIGHT; |
| | | } |
| | | Integer currDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 |
| | | |
| | | // 挂载任务权重 |
| | | List<Task> tasks = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo())); |
| | | List<Task> tasks = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo()), null); |
| | | if (!Cools.isEmpty(tasks)) { |
| | | currDistance += tasks.size() * WEIGHT; |
| | | } |
| | |
| | | return resThread; |
| | | } |
| | | |
| | | private synchronized ShuttleThread searchDiffLevShuttle(HashMap<Integer,List<Device>> devicesMap, String locNo, Task task) { |
| | | ShuttleThread resThread = null; |
| | | Integer finalDistance = ShuttleDispatcher.INF; |
| | | |
| | | //检测目标楼层车数量是否小于允许的最大数量 |
| | | boolean checkDispatchMaxNum = checkDispatchMaxNum(Utils.getLev(locNo), task.getHostId()); |
| | | |
| | | for (Map.Entry<Integer, List<Device>> entry : devicesMap.entrySet()) { |
| | | Integer lev = entry.getKey(); |
| | | List<Device> devices = entry.getValue(); |
| | | for (Device device : devices) { |
| | | if (taskService.hasBusyOutboundByShuttle(Integer.parseInt(device.getDeviceNo()))) { |
| | | continue; |
| | | } |
| | | //获取四向穿梭车线程 |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null || shuttleProtocol.getShuttleNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (!shuttleThread.isIdle()) { |
| | | continue; |
| | | } |
| | | |
| | | BasShuttle basShuttle = basShuttleService.getOne(new LambdaQueryWrapper<BasShuttle>() |
| | | .eq(BasShuttle::getShuttleNo, device.getDeviceNo()) |
| | | .eq(BasShuttle::getHostId, device.getHostId())); |
| | | if (basShuttle == null) { |
| | | continue;//小车基础数据不存在 |
| | | } |
| | | |
| | | if (!Cools.isEmpty(basShuttle.getDisableLev())) { |
| | | List<Integer> disableLev = JSON.parseArray(basShuttle.getDisableLev(), Integer.class); |
| | | //检查小车是否禁用该楼层 |
| | | if (disableLev.contains(Utils.getLev(locNo))) { |
| | | continue;//小车禁用该楼层跳过该车 |
| | | } |
| | | } |
| | | |
| | | //检测是否存在充电任务 |
| | | Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo())); |
| | | if (taskCharge != null) { |
| | | continue; |
| | | } |
| | | |
| | | // 有没有被其他任务调度 |
| | | List<Task> taskList = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo()), null); |
| | | if (!taskList.isEmpty()) { |
| | | continue; |
| | | } |
| | | |
| | | int currentLev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车当前层高 |
| | | String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车当前库位号 |
| | | |
| | | if (!checkDispatchMaxNum) { |
| | | News.info("{}任务,{}层,已经达到当前楼层调度车辆最大值", task.getTaskNo(), Utils.getLev(locNo)); |
| | | continue; |
| | | } |
| | | |
| | | //获取距离小车位置最近的空闲可换层提升机 |
| | | LiftThread liftThread = liftDispatcher.searchIdleLift(currentLocNo, task.getHostId(), true); |
| | | if (liftThread == null) { |
| | | continue; |
| | | } |
| | | Device recentTransferLift = liftThread.getDevice(); |
| | | |
| | | //获取小车楼层提升机待机位 |
| | | ShuttleStandby shuttleStandby = shuttleStandbyService.getOne(new LambdaQueryWrapper<ShuttleStandby>() |
| | | .eq(ShuttleStandby::getDeviceId, recentTransferLift.getId()) |
| | | .eq(ShuttleStandby::getDeviceLev, currentLev) |
| | | .eq(ShuttleStandby::getStatus, 1)); |
| | | String targetLocNo = shuttleStandby.getDeviceLoc(); |
| | | |
| | | //当前穿梭车线程到当前车子所在楼层的提升机待机位距离 |
| | | List<NavigateNode> currentShuttlePath = navigateUtils.calc( |
| | | currentLocNo |
| | | , targetLocNo |
| | | , NavigationMapType.DFX.id |
| | | , Utils.getShuttlePoints(Integer.parseInt(shuttleThread.getDevice().getDeviceNo()), currentLev) |
| | | );//搜索空闲穿梭车,使用正常通道地图 |
| | | if (currentShuttlePath == null) { |
| | | continue; |
| | | } |
| | | |
| | | Integer currDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 |
| | | |
| | | // 不同楼层权重 |
| | | if (currentLev != Utils.getLev(locNo)) { |
| | | currDistance += WEIGHT; |
| | | } |
| | | |
| | | // 挂载任务权重 |
| | | List<Task> tasks = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo()), null); |
| | | if (!Cools.isEmpty(tasks)) { |
| | | currDistance += tasks.size() * WEIGHT; |
| | | } |
| | | |
| | | if (currDistance < finalDistance) { |
| | | finalDistance = currDistance; |
| | | resThread = shuttleThread; |
| | | } |
| | | } |
| | | |
| | | if (resThread != null) { |
| | | break; |
| | | } |
| | | } |
| | | return resThread; |
| | | } |
| | | |
| | | //生成迁移任务 |
| | | public synchronized Task generateMoveTask(Device device, String locNo) { |
| | | // 已有迁移任务 |
| | |
| | | |
| | | //获取迁移任务类型 |
| | | TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>() |
| | | .eq(TaskCtg::getFlag, "MOVE") |
| | | .eq(TaskCtg::getFlag, String.valueOf(TaskCtgType.MOVE)) |
| | | .eq(TaskCtg::getStatus, 1)); |
| | | if (taskCtg == null) { |
| | | return null; |
| | |
| | | return null; |
| | | } |
| | | |
| | | //获取避让位置 |
| | | String standByLocNo = this.searchStandByLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo()); |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null) { |
| | | return null; |
| | | } |
| | | |
| | | Task task = new Task(); |
| | | task.setUuid(String.valueOf(snowflakeIdWorker.nextId())); |
| | | task.setTaskNo(String.valueOf(Utils.getTaskNo("MOVE"))); |
| | | task.setTaskSts(TaskStsType.NEW_MOVE.getId()); |
| | | task.setTaskSts(TaskStsType.NEW_MOVE.sts); |
| | | task.setTaskCtg(taskCtg.getId()); |
| | | task.setPriority(10); |
| | | task.setOriginSite(null); |
| | | task.setOriginLoc(null); |
| | | task.setOriginLoc(shuttleProtocol.getCurrentLocNo()); |
| | | task.setDestSite(null); |
| | | task.setDestLoc(standByLocNo); // 避让位置 |
| | | task.setDestLoc(locNo); // 迁移位置 |
| | | task.setIoTime(new Date()); |
| | | task.setStartTime(new Date()); |
| | | task.setHostId(device.getHostId()); |
| | |
| | | News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo()); |
| | | return null; |
| | | } |
| | | motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo())); |
| | | motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), device.getHostId()); |
| | | |
| | | task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts); |
| | | |
| | |
| | | return task; |
| | | } |
| | | |
| | | //生成手动取放货任务 |
| | | public synchronized Task generateManuaTakeMoveTask(Device device, String sourceLocNo, String locNo) { |
| | | // 已有手动任务 |
| | | if (taskService.selectManualWorking(Integer.valueOf(device.getDeviceNo())) != null) { |
| | | return null; |
| | | } |
| | | |
| | | //获取手动任务类型 |
| | | TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>() |
| | | .eq(TaskCtg::getFlag, String.valueOf(TaskCtgType.MANUAL)) |
| | | .eq(TaskCtg::getStatus, 1)); |
| | | if (taskCtg == null) { |
| | | return null; |
| | | } |
| | | |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | if (shuttleThread == null) { |
| | | return null; |
| | | } |
| | | |
| | | Task task = new Task(); |
| | | task.setUuid(String.valueOf(snowflakeIdWorker.nextId())); |
| | | task.setTaskNo(String.valueOf(Utils.getTaskNo("MANUAL"))); |
| | | task.setTaskSts(TaskStsType.NEW_MANUAL.sts); |
| | | task.setTaskCtg(taskCtg.getId()); |
| | | task.setPriority(10); |
| | | task.setOriginSite(null); |
| | | task.setOriginLoc(sourceLocNo); |
| | | task.setDestSite("takeMove"); |
| | | task.setDestLoc(locNo); |
| | | task.setIoTime(new Date()); |
| | | task.setStartTime(new Date()); |
| | | task.setStatus(1); |
| | | task.setMemo("manual"); |
| | | task.setShuttleNo(Integer.valueOf(device.getDeviceNo())); |
| | | task.setRecordLoc("Y");//记录库存信息 |
| | | task.setHostId(device.getHostId()); |
| | | |
| | | // generate motion list |
| | | List<Motion> motionList = analyzeService.generateShuttleManualMotion(task); |
| | | if (Cools.isEmpty(motionList)) { |
| | | News.error("保存{}号四向穿梭车手动任务失败!!!", device.getDeviceNo()); |
| | | return null; |
| | | } |
| | | motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), device.getHostId()); |
| | | |
| | | task.setTaskSts(TaskStsType.ANALYZE_MANUAL.sts); |
| | | |
| | | if (!taskService.save(task)) { |
| | | News.error("保存{}号四向穿梭车手动任务失败!!!", device.getDeviceNo()); |
| | | return null; |
| | | } |
| | | |
| | | return task; |
| | | } |
| | | |
| | | /** |
| | | * 搜索避让库位,通过小车号和目标库位 |
| | | * 搜索可用库位,通过小车号和目标库位 |
| | | */ |
| | | public String searchStandByLocNo(Integer shuttleNo, Long hostId, String locNo) { |
| | | public String searchAvailableLocNo(Integer shuttleNo, Long hostId, String currentLocNo, List<String> locNos) { |
| | | BasShuttle basShuttle = basShuttleService.getOne(new LambdaQueryWrapper<BasShuttle>() |
| | | .eq(BasShuttle::getShuttleNo, shuttleNo) |
| | | .eq(BasShuttle::getHostId, hostId)); |
| | |
| | | throw new CoolException("小车基础数据不存在"); |
| | | } |
| | | |
| | | String idleLoc = basShuttle.getIdleLoc(); |
| | | if (Cools.isEmpty(idleLoc)) { |
| | | throw new CoolException("小车避让数据不存在"); |
| | | if (locNos.isEmpty()) { |
| | | throw new CoolException("当前层无避让位置"); |
| | | } |
| | | |
| | | int lev = Utils.getLev(locNo);//当前楼层 |
| | | JSONArray standbyLoc = JSON.parseArray(idleLoc); |
| | | if (lev > standbyLoc.size()) { |
| | | throw new CoolException("避让数据异常"); |
| | | } |
| | | |
| | | Object object = standbyLoc.get(lev - 1); |
| | | List<String> locs = JSON.parseArray(object.toString(), String.class); |
| | | if (locs.isEmpty()) { |
| | | throw new CoolException("避让数据为空"); |
| | | } |
| | | int lev = Utils.getLev(currentLocNo); |
| | | |
| | | Integer finalDistance = ShuttleDispatcher.INF; |
| | | String recentLoc = null; |
| | | for (String loc : locs) { |
| | | for (String loc : locNos) { |
| | | //当前穿梭车到避让位计算 |
| | | List<NavigateNode> currentShuttlePath = NavigateUtils.calc( |
| | | locNo |
| | | List<NavigateNode> currentShuttlePath = navigateUtils.calc( |
| | | currentLocNo |
| | | , loc |
| | | , NavigationMapType.NORMAL.id |
| | | , Utils.getShuttlePoints(shuttleNo, lev) |
| | |
| | | continue; |
| | | } |
| | | |
| | | Integer currDistance = NavigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 |
| | | Integer currDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 |
| | | if (currDistance < finalDistance) { |
| | | finalDistance = currDistance; |
| | | recentLoc = loc; |
| | |
| | | return recentLoc; |
| | | } |
| | | |
| | | /** |
| | | * 检测目标楼层车数量是否小于允许的最大数量 |
| | | * true: 小于最大数量 false: 大于或等于最大数量 |
| | | */ |
| | | public boolean checkDispatchMaxNum(Integer lev, Long hostId) { |
| | | Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>().eq(Dict::getFlag, "dispatchShuttleMaxNum")); |
| | | if (dict == null) { |
| | | return false; |
| | | } |
| | | |
| | | ArrayList<Integer> shuttleNos = new ArrayList<>(); |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .eq(Device::getHostId, hostId) |
| | | .eq(Device::getStatus, 1)); |
| | | |
| | | for (Device device : list) { |
| | | //获取四向穿梭车线程 |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | if (shuttleThread == null) { |
| | | continue; |
| | | } |
| | | |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.OFFLINE)) { |
| | | continue; |
| | | } |
| | | |
| | | if(!shuttleThread.isDeviceIdle()) { |
| | | continue; |
| | | } |
| | | |
| | | if(shuttleProtocol.getCurrentLocNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (Utils.getLev(shuttleProtocol.getCurrentLocNo()) == lev) { |
| | | if (shuttleProtocol.getHasCharge()) { |
| | | continue;//充电中 |
| | | } |
| | | |
| | | shuttleNos.add(shuttleProtocol.getShuttleNo());//目标楼层有车,添加进list |
| | | } |
| | | } |
| | | |
| | | //搜索是否存在前往目标楼层的小车移动工作档 |
| | | for (Task task : taskService.list(new LambdaQueryWrapper<Task>() |
| | | .in(Task::getTaskSts, TaskStsType.NEW_MOVE.sts, TaskStsType.ANALYZE_MOVE.sts, TaskStsType.EXECUTE_MOVE.sts, TaskStsType.COMPLETE_MOVE.sts))) { |
| | | if (task.getOriginLoc() == null || task.getDestLoc() == null) { |
| | | continue; |
| | | } |
| | | |
| | | int sourceLev = Utils.getLev(task.getOriginLoc());//工作档源楼层 |
| | | int targetLev = Utils.getLev(task.getDestLoc());//工作档目标楼层 |
| | | if (sourceLev == targetLev) { |
| | | continue;//工作档楼层和目标楼层相同,跳过 |
| | | } |
| | | |
| | | if (targetLev == lev) { |
| | | //工作档目标楼层和实际楼层相同,数量增加 |
| | | if (!shuttleNos.contains(task.getShuttleNo())) { |
| | | shuttleNos.add(task.getShuttleNo()); |
| | | } |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | //搜索是否存在前往目标楼层的小车工作档 |
| | | for (Task task : taskService.list(new LambdaQueryWrapper<Task>() |
| | | .in(Task::getTaskSts, TaskStsType.NEW_INBOUND.sts, TaskStsType.ANALYZE_INBOUND.sts, TaskStsType.EXECUTE_INBOUND.sts, TaskStsType.COMPLETE_INBOUND.sts |
| | | , TaskStsType.NEW_OUTBOUND.sts, TaskStsType.ANALYZE_OUTBOUND.sts, TaskStsType.EXECUTE_OUTBOUND.sts, TaskStsType.COMPLETE_OUTBOUND.sts))) { |
| | | String locNo = taskService.judgeInbound(task) ? task.getDestLoc() : task.getOriginLoc(); |
| | | if (Utils.getLev(locNo) != lev) { |
| | | continue; |
| | | } |
| | | |
| | | if (task.getShuttleNo() == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (!shuttleNos.contains(task.getShuttleNo())) { |
| | | shuttleNos.add(task.getShuttleNo()); |
| | | } |
| | | } |
| | | |
| | | |
| | | return shuttleNos.size() < Integer.parseInt(dict.getValue()); |
| | | } |
| | | |
| | | //分析出库路径待机库位 |
| | | public String analyzeOutPathWaitLoc(String startLoc, String targetLoc, Device shuttleDevice) { |
| | | //计算路径并分解成两段动作 |
| | | List<NavigateNode> nodeList = navigateUtils.calc(startLoc, targetLoc, NavigationMapType.DFX.id, Utils.getShuttlePoints(Integer.parseInt(shuttleDevice.getDeviceNo()), Utils.getLev(startLoc))); |
| | | if (nodeList == null) { |
| | | News.error("{} dash {} can't find navigate path!", startLoc, targetLoc); |
| | | return null; |
| | | } |
| | | //获取分段路径 |
| | | ArrayList<ArrayList<NavigateNode>> data = navigateUtils.getSectionPath(nodeList); |
| | | if (data.size() <= 1) { |
| | | return startLoc;//两点之间只有一段路径,在起点位置等待 |
| | | } |
| | | |
| | | //取出倒数第二段路径 |
| | | ArrayList<NavigateNode> navigateNodes = data.get(data.size() - 2); |
| | | NavigateNode startNode = navigateNodes.get(0); |
| | | String lastPathStartLoc = Utils.getLocNo(startNode.getX(), startNode.getY(), startNode.getZ()); |
| | | return lastPathStartLoc; |
| | | } |
| | | |
| | | //获取小车坐标 |
| | | public String findShuttleLocNo(Integer shuttleNo, Long hostId) { |
| | | Device device = deviceService.getOne(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .eq(Device::getDeviceNo, shuttleNo) |
| | | .eq(Device::getHostId, hostId) |
| | | .eq(Device::getStatus, 1)); |
| | | if(device == null) { |
| | | return null; |
| | | } |
| | | |
| | | //获取四向穿梭车线程 |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (shuttleProtocol == null || shuttleProtocol.getShuttleNo() == null) { |
| | | return null; |
| | | } |
| | | |
| | | return shuttleProtocol.getCurrentLocNo(); |
| | | } |
| | | |
| | | |
| | | } |