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.Task; 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.service.BasShuttleService; import com.zy.asrs.wcs.core.service.TaskService; 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.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.ShuttleThread; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * Created by vincent on 2023/10/12 */ @Service public class ShuttleDispatcher { private static final Integer INF = 9999999; private static final Integer WEIGHT = 1000000; @Autowired private TaskService taskService; @Autowired private LiftDispatcher liftDispatcher; @Autowired private SnowflakeIdWorker snowflakeIdWorker; // @Autowired // private CommonService commonService; @Autowired private AnalyzeService analyzeService; @Autowired private MotionService motionService; @Autowired private DeviceService deviceService; @Autowired private DeviceTypeService deviceTypeService; @Autowired private BasShuttleService basShuttleService; public ShuttleThread queryShuttleWhichConvenient(Task task, Integer liftNo) { String locNo = taskService.judgeInbound(task) ? task.getDestLoc() : task.getOriginLoc(); ShuttleThread resThread = null; Integer finalDistance = ShuttleDispatcher.INF; DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper() .eq(DeviceType::getHostId, task.getHostId()) .eq(DeviceType::getStatus, 1) .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle))); if (deviceType == null) { throw new CoolException("设备类型不存在"); } List list = deviceService.list(new LambdaQueryWrapper() .eq(Device::getDeviceType, deviceType.getId()) .eq(Device::getHostId, task.getHostId()) .eq(Device::getStatus, 1)); for (Device device : list) { 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; } //检测是否存在充电任务 Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo())); if (taskCharge != null) { continue; } // 有没有被其他任务调度 int currentLev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车当前层高 String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车当前库位号 if (currentLocNo.equals(locNo)) { resThread = shuttleThread; break; } String targetLocNo = LiftCodeType.getStandbyLocNo(liftNo, currentLev);//默认到提升机待机位 // 同楼层直接计算到目标库位 if (currentLev == Utils.getLev(locNo)) { targetLocNo = locNo; } //当前穿梭车线程到当前车子所在楼层的提升机口距离 List currentShuttlePath = NavigateUtils.calc( currentLocNo , targetLocNo , NavigationMapType.NORMAL.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 tasks = taskService.selectWorkingByShuttle(Integer.valueOf(device.getDeviceNo())); if (!Cools.isEmpty(tasks)) { currDistance += tasks.size() * WEIGHT; } if (currDistance < finalDistance) { finalDistance = currDistance; resThread = shuttleThread; } } return resThread; } /** * 搜索避让库位,通过小车号和目标库位 */ public String searchStandByLocNo(Integer shuttleNo, Long hostId, String locNo) { BasShuttle basShuttle = basShuttleService.getOne(new LambdaQueryWrapper() .eq(BasShuttle::getShuttleNo, shuttleNo) .eq(BasShuttle::getHostId, hostId)); if (basShuttle == null) { throw new CoolException("小车基础数据不存在"); } String idleLoc = basShuttle.getIdleLoc(); if (Cools.isEmpty(idleLoc)) { 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 locs = JSON.parseArray(object.toString(), String.class); if (locs.isEmpty()) { throw new CoolException("避让数据为空"); } Integer finalDistance = ShuttleDispatcher.INF; String recentLoc = null; for (String loc : locs) { //当前穿梭车到避让位计算 List currentShuttlePath = NavigateUtils.calc( locNo , loc , NavigationMapType.NORMAL.id , Utils.getShuttlePoints(shuttleNo, lev) );//使用正常通道地图 if (currentShuttlePath == null) { continue; } Integer currDistance = NavigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离 if (currDistance < finalDistance) { finalDistance = currDistance; recentLoc = loc; } } if (recentLoc == null) { throw new CoolException("搜索避让位置失败"); } return recentLoc; } }