| | |
| | | package com.zy.asrs.wcs.core.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | 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.wcs.core.domain.dto.RedisMapDto; |
| | | import com.zy.asrs.wcs.core.domain.dto.StaDto; |
| | | import com.zy.asrs.wcs.core.entity.*; |
| | | import com.zy.asrs.wcs.core.kernel.AnalyzeService; |
| | | import com.zy.asrs.wcs.core.model.MapNode; |
| | | import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; |
| | | import com.zy.asrs.wcs.core.model.enums.MotionStsType; |
| | | import com.zy.asrs.wcs.core.model.enums.TaskStsType; |
| | | import com.zy.asrs.wcs.core.service.*; |
| | | import com.zy.asrs.wcs.core.utils.RedisUtil; |
| | | import com.zy.asrs.wcs.core.utils.ShuttleDispatcher; |
| | | import com.zy.asrs.wcs.core.utils.Utils; |
| | | import com.zy.asrs.wcs.rcs.News; |
| | | import com.zy.asrs.wcs.rcs.cache.SlaveConnection; |
| | | import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant; |
| | | 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.model.protocol.StaProtocol; |
| | | import com.zy.asrs.wcs.rcs.service.DeviceService; |
| | | import com.zy.asrs.wcs.rcs.service.DeviceTypeService; |
| | | import com.zy.asrs.wcs.rcs.thread.BarcodeThread; |
| | | import com.zy.asrs.wcs.rcs.thread.DevpThread; |
| | | import com.zy.asrs.wcs.rcs.thread.ShuttleThread; |
| | | import com.zy.asrs.wcs.system.entity.Dict; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * 立体仓库WCS系统主流程业务 |
| | |
| | | @Autowired |
| | | private DeviceService deviceService; |
| | | @Autowired |
| | | private DeviceTypeService deviceTypeService; |
| | | @Autowired |
| | | private LocCtgService locCtgService; |
| | | @Autowired |
| | | private LocService locService; |
| | |
| | | private TaskCtgService taskCtgService; |
| | | @Autowired |
| | | private DictService dictService; |
| | | @Autowired |
| | | private ShuttleDispatcher shuttleDispatcher; |
| | | @Autowired |
| | | private RedisUtil redisUtil; |
| | | @Autowired |
| | | private BasConveyorService basConveyorService; |
| | | |
| | | /** |
| | | * 组托 |
| | | * 入库站,根据条码扫描生成入库工作档,工作状态 2 |
| | | */ |
| | | public synchronized void generateInboundWrk() { |
| | | try { |
| | | // 根据输送线plc遍历 |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, DeviceCtgType.CONVEYOR.val()) |
| | | .eq(Device::getStatus, 1)); |
| | | for (Device devp : list) { |
| | | BasConveyor basConveyor = basConveyorService.getOne(new LambdaQueryWrapper<BasConveyor>().eq(BasConveyor::getDeviceId, devp.getId()).eq(BasConveyor::getHostId, devp.getHostId())); |
| | | // 遍历入库口 |
| | | for (StaDto inSta : JSON.parseArray(basConveyor.getInSta(), StaDto.class)) { |
| | | // 获取入库站信息 |
| | | DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId().intValue()); |
| | | StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo()); |
| | | if (staProtocol == null) { |
| | | continue; |
| | | } else { |
| | | staProtocol = staProtocol.clone(); |
| | | } |
| | | Short workNo = staProtocol.getWorkNo(); |
| | | // 尺寸检测异常 |
| | | boolean back = false; |
| | | String errMsg = "异常:"; |
| | | if (staProtocol.isFrontErr()) { |
| | | errMsg = errMsg + "前超限;"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isBackErr()) { |
| | | errMsg = errMsg + "后超限"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isHighErr()) { |
| | | errMsg = errMsg + "高超限"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isLeftErr()) { |
| | | errMsg = errMsg + "左超限"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isRightErr()) { |
| | | errMsg = errMsg + "右超限"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isWeightErr()) { |
| | | errMsg = errMsg + "超重"; |
| | | back = true; |
| | | } |
| | | if (staProtocol.isBarcodeErr()) { |
| | | errMsg = errMsg + "扫码失败"; |
| | | back = true; |
| | | } |
| | | // 退回 |
| | | if (back) { |
| | | // // led 异常显示 |
| | | // LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed()); |
| | | // if (ledThread != null) { |
| | | // MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(3, errMsg)); |
| | | // } |
| | | continue; |
| | | } |
| | | |
| | | // 判断是否满足入库条件 |
| | | if (staProtocol.isAutoing() && staProtocol.isLoading() |
| | | && staProtocol.isInEnable() |
| | | && !staProtocol.isEmptyMk() && (workNo == 0 || (workNo >= 9990 && workNo <= 9999)) |
| | | ) { |
| | | |
| | | // 获取条码扫描仪信息 |
| | | BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, inSta.getBarcode()); |
| | | if (barcodeThread == null) { |
| | | continue; |
| | | } |
| | | String barcode = barcodeThread.getBarcode(); |
| | | if (!Cools.isEmpty(barcode)) { |
| | | // News.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode); |
| | | if ("NG".endsWith(barcode) || "NoRead".equals(barcode) || "empty".equals(barcode) || "00000000".equals(barcode)) { |
| | | // staProtocol.setWorkNo((short) 32002); |
| | | // staProtocol.setStaNo(inSta.getBackSta().shortValue()); |
| | | // devpThread.setPakMk(staProtocol.getSiteId(), false); |
| | | // MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol)); |
| | | |
| | | // // led 异常显示 |
| | | // LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed()); |
| | | // if (ledThread != null) { |
| | | // String errorMsg = "扫码失败,请重试"; |
| | | // MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(3, errorMsg)); |
| | | // } |
| | | continue; |
| | | } |
| | | } else { |
| | | // staProtocol.setWorkNo((short) 32002); |
| | | // staProtocol.setStaNo(inSta.getBackSta().shortValue()); |
| | | // devpThread.setPakMk(staProtocol.getSiteId(), false); |
| | | // MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol)); |
| | | |
| | | // // led 异常显示 |
| | | // LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed()); |
| | | // if (ledThread != null) { |
| | | // String errorMsg = "扫码失败,请重试"; |
| | | // MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(3, errorMsg)); |
| | | // } |
| | | continue; |
| | | } |
| | | |
| | | // // 过滤盘点/拣料/并板任务 |
| | | // WrkMast wrkMast1 = wrkMastMapper.selectPickStepByBarcode(barcode); |
| | | // if (null != wrkMast1) { |
| | | // continue; |
| | | // } |
| | | // |
| | | // // 判断重复工作档 |
| | | // WrkMast wrkMast2 = wrkMastMapper.selectPakInStep1(inSta.getStaNo(), barcode); |
| | | // if (wrkMast2 != null) { |
| | | // News.error("工作档中已存在该站状态为( 2.设备上走 )的数据,工作号={}", wrkMast2.getWrkNo()); |
| | | // continue; |
| | | // } |
| | | // |
| | | // try { |
| | | // LocTypeDto locTypeDto = new LocTypeDto(staProtocol); |
| | | // SearchLocParam param = new SearchLocParam(); |
| | | // param.setBarcode(barcode); |
| | | // param.setIoType(1); |
| | | // param.setSourceStaNo(inSta.getStaNo()); |
| | | // param.setLocType1(locTypeDto.getLocType1()); |
| | | // String response = new HttpHandler.Builder() |
| | | // .setUri(wmsUrl) |
| | | // .setPath("/rpc/pakin/loc/v2") |
| | | // .setJson(JSON.toJSONString(param)) |
| | | // .build() |
| | | // .doPost(); |
| | | // JSONObject jsonObject = JSON.parseObject(response); |
| | | // LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed()); |
| | | // Integer code = jsonObject.getInteger("code"); |
| | | // if (code.equals(200)) { |
| | | // StartupDto dto = jsonObject.getObject("data", StartupDto.class); |
| | | //// staProtocol.setWorkNo(dto.getWorkNo().shortValue()); |
| | | //// staProtocol.setStaNo(dto.getStaNo().shortValue()); |
| | | //// devpThread.setPakMk(staProtocol.getSiteId(), false); |
| | | //// |
| | | //// boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol)); |
| | | //// if (!result) { |
| | | //// throw new CoolException("更新plc站点信息失败"); |
| | | //// } |
| | | // |
| | | // // 判断重复工作档 |
| | | // WrkMast wrkMast = wrkMastMapper.selectPakInStep11(inSta.getStaNo()); |
| | | // if (wrkMast == null) { |
| | | // continue; |
| | | // } |
| | | // |
| | | // // 更新工作主档 |
| | | // wrkMast.setWrkSts(2L); // 工作状态:2.设备上走 |
| | | // wrkMast.setModiTime(new Date()); |
| | | // if (wrkMastMapper.updateById(wrkMast) == 0) { |
| | | // News.error("更新工作档失败!!! [工作号:{}]", wrkMast.getWrkNo()); |
| | | // } |
| | | // |
| | | // } else if (code == 500) { |
| | | // if (ledThread != null) { |
| | | // String errorMsg = jsonObject.getString("msg"); |
| | | // if (!Cools.isEmpty(errorMsg)) { |
| | | // MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(3, errorMsg)); |
| | | // ledThread.setLedMk(false); |
| | | // } |
| | | // } |
| | | // News.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/loc/v2", JSON.toJSONString(param), response); |
| | | // } else if (code == 700) { |
| | | //// staProtocol.setWorkNo((short) 32002); |
| | | //// staProtocol.setRollback102(1);//102站回退信号 |
| | | //// devpThread.setPakMk(staProtocol.getSiteId(), false); |
| | | //// MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(5, staProtocol)); |
| | | // |
| | | // // led 异常显示 |
| | | // if (ledThread != null) { |
| | | // String errorMsg = barcode + "托盘识别异常,请先进行组托!"; |
| | | // MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(3, errorMsg)); |
| | | // ledThread.setLedMk(false); |
| | | // } |
| | | // } |
| | | // } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); |
| | | // } |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化实时地图 |
| | | */ |
| | | public synchronized void initRealtimeBasMap() { |
| | | try { |
| | | List<Dict> dicts = dictService.list(new LambdaQueryWrapper<Dict>() |
| | | .like(Dict::getFlag, "map-") |
| | | .eq(Dict::getStatus, 1)); |
| | | |
| | | TreeMap<Integer, ArrayList<ArrayList<MapNode>>> levData = new TreeMap<>(); |
| | | for (Dict dict : dicts) { |
| | | String[] split = dict.getFlag().split("-"); |
| | | int lev = Integer.parseInt(split[1]); |
| | | |
| | | TreeMap<Integer, List<JSONObject>> rows = new TreeMap<>(); |
| | | //排序Row |
| | | JSONArray value = JSON.parseArray(dict.getValue()); |
| | | for (Object o : value) { |
| | | JSONObject item = JSON.parseObject(o.toString()); |
| | | if (item.getString("type").equals("SHELF")) { |
| | | JSONObject property = JSON.parseObject(item.getString("property")); |
| | | Integer row1 = property.getInteger("row"); |
| | | ArrayList<JSONObject> bays = new ArrayList<>(); |
| | | if (rows.containsKey(row1)) { |
| | | bays.addAll(rows.get(row1)); |
| | | } |
| | | bays.add(property); |
| | | rows.put(row1, bays); |
| | | } |
| | | } |
| | | |
| | | ArrayList<ArrayList<MapNode>> list = new ArrayList<>(); |
| | | //排序Bay |
| | | for (Map.Entry<Integer, List<JSONObject>> entry : rows.entrySet()) { |
| | | ArrayList<MapNode> nodes = new ArrayList<>(); |
| | | for (JSONObject object : entry.getValue()) { |
| | | MapNode mapNode = new MapNode(); |
| | | mapNode.setValue(object.getInteger("shelfType")); |
| | | mapNode.setTop(object.getInteger("top")); |
| | | mapNode.setBottom(object.getInteger("bottom")); |
| | | mapNode.setLeft(object.getInteger("left")); |
| | | mapNode.setRight(object.getInteger("right")); |
| | | mapNode.setRow(object.getInteger("row")); |
| | | mapNode.setBay(object.getInteger("bay")); |
| | | mapNode.setNo(object.getString("row") + "-" + object.getString("bay")); |
| | | mapNode.setXBase(object.getInteger("refx")); |
| | | mapNode.setYBase(object.getInteger("refy")); |
| | | nodes.add(mapNode); |
| | | } |
| | | |
| | | Collections.sort(nodes, new Comparator<MapNode>() { |
| | | @Override |
| | | public int compare(MapNode o1, MapNode o2) { |
| | | return Integer.compare(o1.getBay(), o2.getBay()); |
| | | } |
| | | }); |
| | | |
| | | ArrayList<MapNode> sortNodes = new ArrayList<>(); |
| | | int defaultBay = 1;//默认从1列开始 |
| | | for (MapNode node : nodes) { |
| | | if (node.getBay() == defaultBay) { |
| | | defaultBay++; |
| | | sortNodes.add(node); |
| | | continue; |
| | | } |
| | | |
| | | //存在空缺节点,自动补足 |
| | | for (int i = defaultBay; i < node.getBay(); i++) { |
| | | MapNode mapNode = new MapNode(); |
| | | mapNode.setValue(-1); |
| | | mapNode.setTop(1000); |
| | | mapNode.setBottom(1000); |
| | | mapNode.setLeft(1000); |
| | | mapNode.setRight(1000); |
| | | mapNode.setRow(node.getRow()); |
| | | mapNode.setBay(i); |
| | | mapNode.setNo(node.getRow() + "-" + i); |
| | | mapNode.setXBase(0); |
| | | mapNode.setYBase(0); |
| | | sortNodes.add(mapNode); |
| | | } |
| | | |
| | | defaultBay = node.getBay() + 1; |
| | | sortNodes.add(node); |
| | | } |
| | | |
| | | list.add(sortNodes); |
| | | } |
| | | |
| | | levData.put(lev, list); |
| | | } |
| | | |
| | | for (Map.Entry<Integer, ArrayList<ArrayList<MapNode>>> entry : levData.entrySet()) { |
| | | ArrayList<ArrayList<MapNode>> lists = entry.getValue();//获取地图 |
| | | |
| | | MapNode mapNode = new MapNode(); |
| | | mapNode.setValue(-1); |
| | | mapNode.setTop(1000); |
| | | mapNode.setBottom(1000); |
| | | mapNode.setLeft(1000); |
| | | mapNode.setRight(1000); |
| | | mapNode.setRow(0); |
| | | mapNode.setBay(0); |
| | | mapNode.setNo("0-0"); |
| | | mapNode.setXBase(0); |
| | | mapNode.setYBase(0); |
| | | |
| | | //获取最长row |
| | | int row = 0; |
| | | //给每个row首尾增加-1节点 |
| | | for (ArrayList<MapNode> list : lists) { |
| | | if (list.size() > row) { |
| | | row = list.size(); |
| | | } |
| | | |
| | | list.add(0, mapNode.clone()); |
| | | list.add(mapNode.clone()); |
| | | } |
| | | |
| | | ArrayList<MapNode> headNodes = new ArrayList<>(); |
| | | ArrayList<MapNode> footerNodes = new ArrayList<>(); |
| | | for (int i = 0; i < row+2; i++) { |
| | | headNodes.add(mapNode.clone()); |
| | | footerNodes.add(mapNode.clone()); |
| | | } |
| | | |
| | | lists.add(0, headNodes); |
| | | lists.add(footerNodes); |
| | | |
| | | Integer lev = entry.getKey(); |
| | | Date now = new Date(); |
| | | RedisMapDto map = new RedisMapDto(); |
| | | map.setData(JSON.toJSONString(lists)); |
| | | map.setCreateTime(now); |
| | | map.setUpdateTime(now); |
| | | map.setLev(lev); |
| | | |
| | | Object data = redisUtil.get(DeviceRedisConstant.MAP + lev); |
| | | if (data == null) { |
| | | //将地图数据存入redis |
| | | redisUtil.set(DeviceRedisConstant.MAP + lev, JSON.toJSONString(map)); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | // 解析入库工作档 |
| | |
| | | return; |
| | | } |
| | | |
| | | DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper<DeviceType>() |
| | | .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle)) |
| | | .eq(DeviceType::getStatus, 1)); |
| | | if (deviceType == null) { |
| | | return; |
| | | } |
| | | |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, deviceType.getId()) |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .eq(Device::getStatus, 1)); |
| | | for (Device device : list) { |
| | | //获取四向穿梭车线程 |
| | |
| | | } |
| | | |
| | | if (!shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE)) { |
| | | continue; |
| | | } |
| | | |
| | | if (!shuttleThread.isRequireCharge()) { |
| | | continue; |
| | | } |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper<DeviceType>() |
| | | .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle)) |
| | | .eq(DeviceType::getStatus, 1)); |
| | | if (deviceType == null) { |
| | | return; |
| | | } |
| | | |
| | | List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>() |
| | | .eq(Device::getDeviceType, deviceType.getId()) |
| | | .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val()) |
| | | .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; |
| | | } |
| | | |
| | |
| | | continue; |
| | | } |
| | | |
| | | //获取避让位置 |
| | | String standByLocNo = shuttleDispatcher.searchStandByLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo()); |
| | | |
| | | Task task = new Task(); |
| | | task.setUuid(String.valueOf(snowflakeIdWorker.nextId())); |
| | | task.setTaskNo(String.valueOf(Utils.getTaskNo("MOVE"))); |
| | |
| | | task.setOriginSite(null); |
| | | task.setOriginLoc(null); |
| | | task.setDestSite(null); |
| | | task.setDestLoc("1-1-1"); // 暂时未定 |
| | | task.setDestLoc(standByLocNo); // 避让位置 |
| | | task.setIoTime(new Date()); |
| | | task.setStartTime(new Date()); |
| | | task.setHostId(device.getHostId()); |