zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/MainProcess.java
@@ -42,7 +42,7 @@ } // 入库 ===>> 入库站到堆垛机站,根据条码扫描生成入库工作档 mainService.generateInboundWrk(); // 组托 // mainService.generateInboundWrk(); // 组托 // 间隔 Thread.sleep(500); zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/action/ShuttleAction.java
@@ -1,8 +1,10 @@ package com.zy.asrs.wcs.core.action; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.zy.asrs.wcs.common.ExecuteSupport; import com.zy.asrs.wcs.core.entity.Loc; @@ -70,7 +72,7 @@ redisCommand.setCommandStep(0);//命令执行步序 redisCommand.setAssignCommand(assignCommand);//命令 //任务数据保存到redis if (redisUtil.set(DeviceRedisConstant.SHUTTLE_WORK_FLAG + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand))) { if (redisUtil.set(DeviceRedisConstant.SHUTTLE_WORK_FLAG + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand, SerializerFeature.DisableCircularReferenceDetect))) { if (assignCommand.getTaskMode() == ShuttleTaskModeType.PAK_IN.id || assignCommand.getTaskMode() == ShuttleTaskModeType.PAK_OUT.id || assignCommand.getTaskMode() == ShuttleTaskModeType.MOVE_LOC_NO.id @@ -135,7 +137,15 @@ if (command.getTargetLocNo().equals(shuttleProtocol.getCurrentLocNo())) { command.setComplete(true); //解锁锁定路径,上一条路径 List<NavigateNode> nodes = JSON.parseArray(JSON.toJSONString(command.getNodes()), NavigateNode.class);//进行深度copy List<NavigateNode> nodes = null; try { String nodesStr = objectMapper.writeValueAsString(command.getNodes()); nodes = objectMapper.readValue(nodesStr, new TypeReference<List<NavigateNode>>() { }); } catch (JsonProcessingException e) { throw new RuntimeException(e); } if (nodes != null) { NavigateNode targetNode = assignCommand.getNodes().get(assignCommand.getNodes().size() - 1);//最终节点 NavigateNode node = nodes.get(nodes.size() - 1); @@ -175,7 +185,7 @@ } // 更新redis数据 redisUtil.set(DeviceRedisConstant.SHUTTLE_WORK_FLAG + redisCommand.getTaskNo(), JSON.toJSONString(redisCommand)); redisUtil.set(DeviceRedisConstant.SHUTTLE_WORK_FLAG + redisCommand.getTaskNo(), JSON.toJSONString(redisCommand, SerializerFeature.DisableCircularReferenceDetect)); if (!command.getComplete()) { return false; zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/service/impl/MainServiceImpl.java
@@ -7,6 +7,7 @@ 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; @@ -26,6 +27,7 @@ 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.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; @@ -68,13 +70,201 @@ 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(); } } /** @@ -134,7 +324,36 @@ } }); list.add(nodes); 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); @@ -186,7 +405,7 @@ map.setLev(lev); Object data = redisUtil.get(DeviceRedisConstant.MAP + lev); if (data != null) { if (data == null) { //将地图数据存入redis redisUtil.set(DeviceRedisConstant.MAP + lev, JSON.toJSONString(map)); } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/NavigateMapData.java
@@ -1,24 +1,24 @@ package com.zy.asrs.wcs.core.utils; 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.common.wms.entity.BasMap; import com.zy.asrs.common.wms.entity.LocMast; import com.zy.asrs.common.wms.service.LocMastService; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.wcs.core.domain.dto.RedisMapDto; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.model.MapNode; import com.zy.asrs.wcs.core.model.NavigateNode; import com.zy.asrs.wcs.core.model.enums.NavigationMapType; import com.zy.asrs.wcs.core.service.LocService; import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant; 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.Component; import java.io.*; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.*; /** * A*算法地图获取类 @@ -28,6 +28,8 @@ @Autowired private LocService locService; @Autowired private DictService dictService; private Integer lev;//地图楼层 @@ -125,6 +127,154 @@ return map; } //获取JSON格式数据-原始地图 public List<List<MapNode>> getJsonDataFromDict(Integer mapType, List<int[]> whitePoints, List<int[]> shuttlePoints) { List<List<MapNode>> arrayList = getMapFromDict(lev); return arrayList; } //从数据字典中解析指定楼层地图数据 public List<List<MapNode>> getMapFromDict(Integer currentLev) { List<Dict> dicts = dictService.list(new LambdaQueryWrapper<Dict>() .like(Dict::getFlag, "map-" + currentLev) .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); List<List<MapNode>> mapNodeList = new ArrayList<>(); mapNodeList.addAll(lists); return mapNodeList; } return null; } //获取JSON格式数据 public List<List<MapNode>> getJsonData(Integer mapType, List<int[]> whitePoints, List<int[]> shuttlePoints) { RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class); @@ -163,7 +313,8 @@ //过滤数据 //获取当前楼层库位数据 List<Loc> locs = locService.list(new LambdaQueryWrapper<Loc>() .eq(Loc::getLev, lev)); .eq(Loc::getLev, lev) .orderByAsc(Loc::getRow, Loc::getBay)); for (Loc loc : locs) { Integer row = loc.getRow(); Integer bay = loc.getBay(); @@ -224,61 +375,6 @@ } return lists; } /** * 锁/解锁 路径节点 * 写入路径节点数据到redis地图中 * lock为true 禁用库位,lock为false恢复库位 */ public synchronized boolean writeNavigateNodeToRedisMap(List<NavigateNode> nodes, boolean lock) { RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class); Object o = redisUtil.get("realtimeBasMap_" + lev); if (o == null) { return false; } BasMap basMap = JSON.parseObject(o.toString(), BasMap.class); ArrayList arrayList = JSON.parseObject(basMap.getData(), ArrayList.class); List<List<MapNode>> lists = filterMap(NavigationMapType.NONE.id, arrayList, lev, null, null);//获取全部地图数据 // 防止重复锁路径 if (lock) { for (NavigateNode node : nodes) { List<MapNode> listX = lists.get(node.getX()); MapNode mapNode = listX.get(node.getY()); if (mapNode.getValue() == -999) { return false; } } } this.setLev(nodes.get(0).getZ()); List<List<MapNode>> realMap = this.getJsonData(-1, null, null);//获取完整地图(包括入库出库) for (NavigateNode node : nodes) { if (node.getZ() != lev) { continue; } List<MapNode> listX = lists.get(node.getX()); MapNode mapNode = listX.get(node.getY()); if (lock) { mapNode.setValue(-999);//禁用库位 }else { //获取原始节点数据 List<MapNode> rows = realMap.get(node.getX()); MapNode col = rows.get(node.getY()); mapNode.setValue(col.getValue());//恢复库位 } listX.set(node.getY(), mapNode); lists.set(node.getX(), listX); } basMap.setData(JSON.toJSONString(lists)); basMap.setUpdateTime(new Date()); //将数据库地图数据存入redis redisUtil.set("realtimeBasMap_" + lev, JSON.toJSONString(basMap)); return true; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/NavigateMapUtils.java
@@ -62,7 +62,7 @@ //尝试锁定/解锁路径 navigateMapData.setLev(nodes.get(0).getZ()); List<List<MapNode>> realMap = navigateMapData.getJsonData(-1, null, null);//获取完整地图(包括入库出库) List<List<MapNode>> realMap = navigateMapData.getJsonDataFromDict(-1, null, null);//获取完整地图(包括入库出库) for (NavigateNode node : nodes) { if (node.getZ() != lev) { continue; zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/impl/SurayShuttleThread.java
@@ -46,7 +46,7 @@ @SuppressWarnings("all") public class SurayShuttleThread implements ShuttleThread { private static final String API_URL = "http://127.0.0.1:8082"; private static final String API_URL = "http://192.168.7.149:8082"; private Device device; private RedisUtil redisUtil; @@ -238,6 +238,16 @@ @Override public synchronized boolean movePath(List<NavigateNode> nodes, Integer taskNo) { try { //默认地图母轨方向x String mapDirection = "x"; DictService dictService = SpringUtils.getBean(DictService.class); Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>() .eq(Dict::getFlag, "direction_map") .eq(Dict::getStatus, 1)); if (dict != null) { mapDirection = dict.getValue(); } String loginToken = requestLoginToken(); if (loginToken == null) { return false; @@ -262,13 +272,13 @@ NavigateNode startPath = sectionNodes.get(0); //结束路径 NavigateNode targetPath = sectionNodes.get(sectionNodes.size() - 1); if (ShuttleRunDirection.get(startPath.getDirection()) == ShuttleRunDirection.LEFT if (mapDirection.equals("y") && ShuttleRunDirection.get(startPath.getDirection()) == ShuttleRunDirection.LEFT || ShuttleRunDirection.get(startPath.getDirection()) == ShuttleRunDirection.RIGHT) { //子轨方向 oper = 6; } else { //母轨方向 oper = 5; } else { //子轨方向 oper = 6; } for (int i = 0; i < sectionNodes.size(); i++) {