| | |
| | | return R.ok(); |
| | | } |
| | | |
| | | @GetMapping("/basMap/lev/{lev}/auth") |
| | | @ManagerAuth |
| | | public R getByLev(@PathVariable("lev") Integer lev) { |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", lev)); |
| | | if (basMap == null){ |
| | | return R.error("地图不存在"); |
| | | } |
| | | return R.ok().add(basMap.getData()); |
| | | } |
| | | |
| | | @Autowired |
| | | private MapExcelUtils mapExcelUtils; |
| | | |
| | |
| | | }else if (nodeType.equals("RGB(0,112,192)")) { |
| | | //输送线 |
| | | nodeData.put("type", "devp"); |
| | | nodeData.put("value", (int) Double.parseDouble(map.get("value").toString())); |
| | | }else if (nodeType.equals("RGB(0,176,240)")) { |
| | | //RGV |
| | | nodeData.put("type", "rgv"); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | return R.ok().add(JSON.toJSONString(dataList)); |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", 1)); |
| | | if (basMap == null){ |
| | | basMap = new BasMap(); |
| | | } |
| | | basMap.setLev(1); |
| | | basMap.setData(JSON.toJSONString(dataList)); |
| | | basMap.setOriginData(JSON.toJSONString(dataList)); |
| | | basMap.setCreateTime(new Date()); |
| | | basMap.setUpdateTime(new Date()); |
| | | basMapService.insertOrUpdate(basMap); |
| | | return R.ok(); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.zy.asrs.controller; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.Cools; |
| | | import com.core.common.R; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.domain.enums.CrnStatusType; |
| | | import com.zy.asrs.domain.enums.StationStatusType; |
| | | import com.zy.asrs.domain.param.SystemSwitchParam; |
| | | import com.zy.asrs.domain.vo.CrnDetailVo; |
| | | import com.zy.asrs.domain.vo.CrnLatestDataVo; |
| | | import com.zy.asrs.domain.vo.StationLatestDataVo; |
| | | import com.zy.asrs.entity.BasCrnpErr; |
| | | import com.zy.asrs.entity.DeviceConfig; |
| | | import com.zy.asrs.entity.WrkMast; |
| | |
| | | import com.zy.asrs.service.DeviceConfigService; |
| | | import com.zy.asrs.service.WrkMastService; |
| | | import com.zy.common.CodeRes; |
| | | import com.zy.core.Slave; |
| | | import com.zy.core.ThreadHandler; |
| | | import com.zy.core.cache.SlaveConnection; |
| | | import com.zy.core.enums.CrnModeType; |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.model.protocol.CrnProtocol; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.core.properties.SystemProperties; |
| | | import com.zy.core.thread.CrnThread; |
| | | import com.zy.core.thread.impl.ZySiemensCrnThread; |
| | | import com.zy.core.thread.StationThread; |
| | | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | |
| | | return R.ok().add(Cools.add("status", SystemProperties.WCS_RUNNING_STATUS.get())); |
| | | } |
| | | |
| | | // @PostMapping("/latest/data/site") |
| | | // @ManagerAuth(memo = "站点实时数据") |
| | | // public R siteLatestData(){ |
| | | // List<SiteLatestDataVo> vos = new ArrayList<>(); |
| | | // Map<Integer, StaProtocol> stations = new HashMap<>(); |
| | | // for (DevpSlave devp : slaveProperties.getDevp()) { |
| | | // DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId()); |
| | | // if (null != devpThread) { |
| | | // stations.putAll(devpThread.getStation()); |
| | | // } |
| | | // } |
| | | // for (Map.Entry<Integer, StaProtocol> entry : stations.entrySet()) { |
| | | // SiteLatestDataVo vo = new SiteLatestDataVo(); |
| | | // StaProtocol staProtocol = entry.getValue(); |
| | | // vo.setSiteId(String.valueOf(entry.getKey())); // 站点编号 |
| | | // vo.setWorkNo(staProtocol.getWorkNo()); // 工作号 |
| | | // vo.setSiteStatus(SiteStatusType.process(staProtocol)); // 状态 |
| | | // vos.add(vo); |
| | | // } |
| | | // return R.ok().add(vos); |
| | | // } |
| | | @PostMapping("/latest/data/station") |
| | | @ManagerAuth(memo = "站点实时数据") |
| | | public R stationLatestData() { |
| | | List<StationLatestDataVo> vos = new ArrayList<>(); |
| | | |
| | | List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() |
| | | .eq("device_type", String.valueOf(SlaveType.Devp))); |
| | | for (DeviceConfig deviceConfig : devpList) { |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, |
| | | deviceConfig.getDeviceNo()); |
| | | if (stationThread == null) { |
| | | continue; |
| | | } |
| | | |
| | | List<StationProtocol> statusList = stationThread.getStatus(); |
| | | if (statusList == null || statusList.isEmpty()) { |
| | | continue; |
| | | } |
| | | for (StationProtocol stationProtocol : statusList) { |
| | | StationLatestDataVo vo = new StationLatestDataVo(); |
| | | vo.setStationId(stationProtocol.getStationId()); // 站点编号 |
| | | vo.setTaskNo(stationProtocol.getTaskNo()); // 任务号 |
| | | vo.setTargetStaNo(stationProtocol.getTargetStaNo()); // 目标站点 |
| | | vo.setAutoing(stationProtocol.isAutoing()); // 是否自动 |
| | | vo.setLoading(stationProtocol.isLoading()); // 是否有物 |
| | | vo.setInEnable(stationProtocol.isInEnable()); // 是否可入 |
| | | vo.setOutEnable(stationProtocol.isOutEnable()); // 是否可出 |
| | | vo.setEmptyMk(stationProtocol.isEmptyMk()); // 是否空板 |
| | | vo.setFullPlt(stationProtocol.isFullPlt()); // 是否满板 |
| | | vo.setPalletHeight(stationProtocol.getPalletHeight()); // 托盘高度 |
| | | vo.setError(stationProtocol.getError()); // 错误码 |
| | | vo.setBarcode(stationProtocol.getBarcode()); // 条码 |
| | | String stationStatus = StationStatusType.process(stationProtocol).toString().toLowerCase().replaceAll("_", "-"); |
| | | vo.setStationStatus(stationStatus); |
| | | vos.add(vo); |
| | | } |
| | | |
| | | } |
| | | return R.ok().add(vos); |
| | | } |
| | | |
| | | @PostMapping("/latest/data/crn") |
| | | @ManagerAuth(memo = "堆垛机实时数据") |
| | |
| | | if (wrkMast != null) { |
| | | vo.setCrnStatus(CrnStatusType.process(wrkMast.getIoType())); |
| | | } else { |
| | | vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO)? CrnStatusType.MACHINE_AUTO: CrnStatusType.MACHINE_UN_AUTO); |
| | | vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO) ? CrnStatusType.MACHINE_AUTO |
| | | : CrnStatusType.MACHINE_UN_AUTO); |
| | | } |
| | | } else { |
| | | vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO)? CrnStatusType.MACHINE_AUTO: CrnStatusType.MACHINE_UN_AUTO); |
| | | vo.setCrnStatus(crnProtocol.modeType.equals(CrnModeType.AUTO) ? CrnStatusType.MACHINE_AUTO |
| | | : CrnStatusType.MACHINE_UN_AUTO); |
| | | } |
| | | } |
| | | vos.add(vo); |
| | |
| | | // List<RgvLatestDataVo> vos = new ArrayList<>(); |
| | | // for (RgvSlave rgvSlave : slaveProperties.getRgv()) { |
| | | // // 获取堆垛机信息 |
| | | // RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgvSlave.getId()); |
| | | // RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, |
| | | // rgvSlave.getId()); |
| | | // if (rgvThread == null) { |
| | | // continue; |
| | | // } |
| | |
| | | // public R barcodeLatestData(){ |
| | | // List<BarcodeDataVo> list = new ArrayList<>(); |
| | | // for (Slave barcode : slaveProperties.getBarcode()) { |
| | | // BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, barcode.getId()); |
| | | // BarcodeThread barcodeThread = (BarcodeThread) |
| | | // SlaveConnection.get(SlaveType.Barcode, barcode.getId()); |
| | | // if (null == barcodeThread) { |
| | | // continue; |
| | | // } |
| | |
| | | |
| | | DeviceConfig deviceConfig = deviceConfigService.selectOne(new EntityWrapper<DeviceConfig>() |
| | | .eq("device_type", String.valueOf(SlaveType.Crn)) |
| | | .eq("device_no", crnNo) |
| | | ); |
| | | .eq("device_no", crnNo)); |
| | | |
| | | if (deviceConfig == null) { |
| | | return R.error("设备不存在"); |
| New file |
| | |
| | | package com.zy.asrs.controller; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.service.BasDevpService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import com.core.common.Cools; |
| | | import com.core.common.R; |
| | | import com.zy.asrs.domain.param.StationCommandMoveParam; |
| | | import com.zy.core.cache.MessageQueue; |
| | | import com.zy.core.cache.SlaveConnection; |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.model.Task; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.thread.StationThread; |
| | | |
| | | import java.util.List; |
| | | |
| | | @RestController |
| | | @RequestMapping("/station") |
| | | public class StationController { |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | | |
| | | @PostMapping("/command/move") |
| | | public R commandMove(@RequestBody StationCommandMoveParam param) { |
| | | if (Cools.isEmpty(param)) { |
| | | return R.error("缺少参数"); |
| | | } |
| | | |
| | | Integer stationId = param.getStationId(); |
| | | Integer taskNo = param.getTaskNo(); |
| | | Integer targetStationId = param.getTargetStationId(); |
| | | |
| | | JSONObject finalStation = null; |
| | | List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<BasDevp>()); |
| | | for (BasDevp basDevp : basDevps) { |
| | | List<JSONObject> list = JSON.parseArray(basDevp.getStationList(), JSONObject.class); |
| | | for (JSONObject entity : list) { |
| | | if(entity.getInteger("stationId").equals(stationId)){ |
| | | finalStation = entity; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if(finalStation != null){ |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if(finalStation == null){ |
| | | return R.error("站点不存在"); |
| | | } |
| | | |
| | | Integer devpNo = finalStation.getInteger("devpNo"); |
| | | |
| | | StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, devpNo); |
| | | if (stationThread == null) { |
| | | return R.error("线程不存在"); |
| | | } |
| | | |
| | | StationCommand command = stationThread.getMoveCommand(taskNo, stationId, targetStationId, 0); |
| | | MessageQueue.offer(SlaveType.Devp, devpNo, new Task(2, command)); |
| | | return R.ok(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.domain.enums; |
| | | |
| | | |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | |
| | | /** |
| | | * 站点状态枚举 |
| | | */ |
| | | public enum StationStatusType { |
| | | |
| | | // 自动 |
| | | SITE_AUTO, |
| | | // 非自动 |
| | | SITE_UNAUTO, |
| | | // 自动+有物+ID |
| | | SITE_AUTO_RUN_ID, |
| | | // 自动+有物 |
| | | SITE_AUTO_RUN, |
| | | // 自动+ID |
| | | SITE_AUTO_ID, |
| | | ; |
| | | |
| | | public static StationStatusType process(StationProtocol stationProtocol){ |
| | | if (stationProtocol == null) { |
| | | return null; |
| | | } |
| | | if (stationProtocol.isAutoing() && stationProtocol.isLoading() && stationProtocol.getTaskNo() > 0) { |
| | | return SITE_AUTO_RUN_ID; |
| | | } |
| | | if (stationProtocol.isAutoing() && stationProtocol.isLoading()) { |
| | | return SITE_AUTO_RUN; |
| | | } |
| | | if (stationProtocol.isAutoing() && stationProtocol.getTaskNo() > 0) { |
| | | return SITE_AUTO_ID; |
| | | } |
| | | if (stationProtocol.isAutoing()) { |
| | | return SITE_AUTO; |
| | | } |
| | | if (!stationProtocol.isAutoing()) { |
| | | return SITE_UNAUTO; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.domain.param; |
| | | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | public class StationCommandMoveParam { |
| | | |
| | | // 站点编号 |
| | | private Integer stationId; |
| | | |
| | | // 目标站点编号 |
| | | private Integer targetStationId; |
| | | |
| | | // 任务编号 |
| | | private Integer taskNo; |
| | | |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.domain.vo; |
| | | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | public class StationLatestDataVo { |
| | | |
| | | // 站点编号 |
| | | private Integer stationId; |
| | | |
| | | // 工作号 |
| | | private Integer taskNo; |
| | | |
| | | // 目标站 |
| | | private Integer targetStaNo; |
| | | |
| | | // 自动 |
| | | private boolean autoing; |
| | | |
| | | // 有物 |
| | | private boolean loading; |
| | | |
| | | // 可入 |
| | | private boolean inEnable; |
| | | |
| | | // 可出 |
| | | private boolean outEnable; |
| | | |
| | | // 空板信号 |
| | | private boolean emptyMk; |
| | | |
| | | // 满托盘 |
| | | private boolean fullPlt; |
| | | |
| | | // 托盘高度 |
| | | private Integer palletHeight; |
| | | |
| | | //报警 |
| | | private Integer error; |
| | | |
| | | //条码 |
| | | private String barcode; |
| | | |
| | | private String stationStatus; |
| | | |
| | | } |
| | |
| | | |
| | | HashMap<String, Object> mapData = data.get(k - 2).get(l - 2); |
| | | mapData.put("bgColor", "merge"); |
| | | mapData.put("value", map.get("value")); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.common.model; |
| | | |
| | | import lombok.Data; |
| | | import lombok.ToString; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * A*寻路算法Node节点 |
| | | */ |
| | | @Data |
| | | public class NavigateNode implements Comparable<NavigateNode>, Cloneable, Serializable { |
| | | |
| | | private int x;//坐标x |
| | | private int y;//坐标y |
| | | private int F;//综合花费的步数 |
| | | private int G;//已经花费的步数 |
| | | private int H;//将要花费的步数 |
| | | private int value; |
| | | @ToString.Exclude |
| | | private NavigateNode Father;//父节点 |
| | | private List<String> directionList;//行走方向 |
| | | private String nodeValue;//节点数据 |
| | | private String nodeType;//节点类型 |
| | | |
| | | public NavigateNode(int x, int y) { |
| | | this.x = x; |
| | | this.y = y; |
| | | } |
| | | |
| | | //通过结点的坐标和目标结点的坐标可以计算出F, G, H三个属性 |
| | | //需要传入这个节点的上一个节点和最终的结点 |
| | | public void init_node(NavigateNode father, NavigateNode end) { |
| | | this.Father = father; |
| | | if (this.Father != null) { |
| | | //走过的步数等于父节点走过的步数加一 |
| | | this.G = father.G + this.G; |
| | | } else { //父节点为空代表它是第一个结点 |
| | | this.G = 0; |
| | | } |
| | | |
| | | //以下计算方案为算法原始方案,没有去拐点方案。已被Solution计算时自动覆盖。 |
| | | //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) |
| | | this.H = Math.abs(this.x - end.x) + Math.abs(this.y - end.y); |
| | | this.F = this.G + this.H; |
| | | } |
| | | |
| | | @Override |
| | | public int compareTo(NavigateNode o) { |
| | | return Integer.compare(this.F, o.F); |
| | | } |
| | | |
| | | @Override |
| | | public NavigateNode clone() { |
| | | try { |
| | | return (NavigateNode) super.clone(); |
| | | } catch (CloneNotSupportedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.zy.common.utils; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.core.common.SpringUtils; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.entity.BasMap; |
| | | import com.zy.asrs.service.BasMapService; |
| | | import com.zy.common.model.NavigateNode; |
| | | import com.zy.core.enums.MapNodeType; |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * A*算法实现类 |
| | | */ |
| | | public class NavigateSolution { |
| | | |
| | | // Open表用优先队列 |
| | | public PriorityQueue<NavigateNode> Open = new PriorityQueue<NavigateNode>(); |
| | | //Close表用普通的数组 |
| | | public ArrayList<NavigateNode> Close = new ArrayList<NavigateNode>(); |
| | | //用来存放已经出现过的结点。 |
| | | Map<String, Integer> bestGMap = new HashMap<>(); |
| | | |
| | | public List<List<NavigateNode>> getStationMap() { |
| | | BasMapService basMapService = SpringUtils.getBean(BasMapService.class); |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", 1)); |
| | | if (basMap == null) { |
| | | throw new CoolException("地图不存在"); |
| | | } |
| | | |
| | | List<List<JSONObject>> dataList = JSON.parseObject(basMap.getData(), List.class); |
| | | |
| | | List<List<NavigateNode>> navigateNodeList = new ArrayList<>(); |
| | | for (int i = 0; i < dataList.size(); i++) { |
| | | List<JSONObject> row = dataList.get(i); |
| | | List<NavigateNode> navigateNodeRow = new ArrayList<>(); |
| | | for (int j = 0; j < row.size(); j++) { |
| | | JSONObject map = row.get(j); |
| | | NavigateNode navigateNode = new NavigateNode(i, j); |
| | | |
| | | String nodeType = map.getString("type"); |
| | | if(nodeType == null) { |
| | | navigateNode.setValue(MapNodeType.DISABLE.id); |
| | | }else if(nodeType.equals("devp") || nodeType.equals("merge")){ |
| | | navigateNode.setValue(MapNodeType.NORMAL_PATH.id); |
| | | |
| | | JSONObject valueObj = JSON.parseObject(map.getString("value")); |
| | | List<String> directionList = valueObj.getJSONArray("direction").toJavaList(String.class); |
| | | navigateNode.setDirectionList(directionList); |
| | | }else { |
| | | navigateNode.setValue(MapNodeType.DISABLE.id); |
| | | } |
| | | |
| | | navigateNode.setNodeType(nodeType); |
| | | navigateNode.setNodeValue(map.getString("value")); |
| | | navigateNodeRow.add(navigateNode); |
| | | } |
| | | navigateNodeList.add(navigateNodeRow); |
| | | } |
| | | |
| | | return navigateNodeList; |
| | | } |
| | | |
| | | public NavigateNode astarSearchJava(List<List<NavigateNode>> map, NavigateNode start, NavigateNode end) { |
| | | // 清理上次搜索的状态,防止复用实例导致记录残留 |
| | | this.Open.clear(); |
| | | this.Close.clear(); |
| | | this.bestGMap.clear(); |
| | | //把第一个开始的结点加入到Open表中 |
| | | this.Open.add(start); |
| | | //主循环 |
| | | while (Open.size() > 0) { |
| | | //取优先队列顶部元素并且把这个元素从Open表中删除 |
| | | NavigateNode current_node = Open.poll(); |
| | | |
| | | if (current_node.getX() == end.getX() && current_node.getY() == end.getY()) {//找到目标结点就返回 |
| | | return current_node; |
| | | } |
| | | |
| | | //将这个结点加入到Close表中 |
| | | Close.add(current_node); |
| | | //对当前结点进行扩展,得到一个四周结点的数组 |
| | | ArrayList<NavigateNode> neighbour_node = extend_current_node(map, current_node); |
| | | //对这个结点遍历,看是否有目标结点出现 |
| | | for (NavigateNode node : neighbour_node) { |
| | | // 已在关闭列表中的节点不再处理,避免父链反复改写形成环 |
| | | if (Close.contains(node)) { |
| | | continue; |
| | | } |
| | | // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) |
| | | int gCost = calcNodeExtraCost(current_node, node, end); |
| | | |
| | | //进行计算对G, F, H 等值 |
| | | node.setG(1 + gCost); |
| | | node.init_node(current_node, end); |
| | | node.setH(calcNodeCost(node, end)); |
| | | node.setF(node.getG() + node.getH()); |
| | | |
| | | String key = node.getX() + "_" + node.getY(); |
| | | Integer recordedG = bestGMap.get(key); |
| | | // 仅当找到更小的代价时才更新与入Open,避免等价代价反复入队导致父链抖动 |
| | | if (recordedG == null || node.getG() < recordedG) { |
| | | bestGMap.put(key, node.getG()); |
| | | |
| | | Open.add(node); |
| | | } |
| | | } |
| | | } |
| | | //如果遍历完所有出现的结点都没有找到最终的结点,返回null |
| | | return null; |
| | | } |
| | | |
| | | public ArrayList<NavigateNode> extend_current_node(List<List<NavigateNode>> map, NavigateNode current_node) { |
| | | //获取当前结点的x, y |
| | | int x = current_node.getX(); |
| | | int y = current_node.getY(); |
| | | //如果当前结点的邻结点合法,就加入到neighbour_node |
| | | ArrayList<NavigateNode> neighbour_node = new ArrayList<NavigateNode>(); |
| | | |
| | | if(current_node.getValue() == MapNodeType.DISABLE.id) { |
| | | return neighbour_node; |
| | | } |
| | | |
| | | List<String> directionList = current_node.getDirectionList(); |
| | | if(directionList == null || directionList.size() == 0) { |
| | | return neighbour_node; |
| | | } |
| | | |
| | | for(String direction : directionList) { |
| | | if(direction.equals("top")) { |
| | | NavigateNode node = getValidNavigateNode(map, x - 1, y); |
| | | if(node != null) { |
| | | neighbour_node.add(node); |
| | | } |
| | | }else if(direction.equals("bottom")) { |
| | | NavigateNode node = getValidNavigateNode(map, x + 1, y); |
| | | if(node != null) { |
| | | neighbour_node.add(node); |
| | | } |
| | | }else if(direction.equals("left")) { |
| | | NavigateNode node = getValidNavigateNode(map, x, y - 1); |
| | | if(node != null) { |
| | | neighbour_node.add(node); |
| | | } |
| | | }else if(direction.equals("right")) { |
| | | NavigateNode node = getValidNavigateNode(map, x, y + 1); |
| | | if(node != null) { |
| | | neighbour_node.add(node); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return neighbour_node; |
| | | } |
| | | |
| | | public NavigateNode getValidNavigateNode(List<List<NavigateNode>> map, int x, int y) { |
| | | if (x < 0 || x >= map.size() |
| | | || y < 0 || y >= map.get(0).size()) { |
| | | return null; |
| | | } |
| | | |
| | | NavigateNode node = map.get(x).get(y); |
| | | if(node.getValue() == MapNodeType.DISABLE.id) { |
| | | return null; |
| | | } |
| | | |
| | | return node; |
| | | } |
| | | |
| | | public NavigateNode findStationNavigateNode(List<List<NavigateNode>> map, int stationId) { |
| | | for(int x = 0; x < map.size(); x++) { |
| | | for(int y = 0; y < map.get(0).size(); y++) { |
| | | NavigateNode node = map.get(x).get(y); |
| | | if("devp".equals(node.getNodeType())) { |
| | | JSONObject valueObj = JSON.parseObject(node.getNodeValue()); |
| | | if(valueObj.getInteger("stationId") == stationId) { |
| | | return node; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | //------------------A*启发函数------------------// |
| | | |
| | | //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) |
| | | private int calcNodeCost(NavigateNode node1, NavigateNode node2) { |
| | | return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); |
| | | } |
| | | |
| | | //去除拐点算法,给直线增加优先级 |
| | | private int calcNodeExtraCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { |
| | | // 第一个点或直线点 |
| | | if (currNode.getFather() == null || nextNode.getX() == currNode.getFather().getX() |
| | | || nextNode.getY() == currNode.getFather().getY()) { |
| | | return 0; |
| | | } |
| | | |
| | | // 拐向终点的点 |
| | | if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { |
| | | return 1; |
| | | } |
| | | |
| | | // 普通拐点 |
| | | /* |
| | | 拐点判断逻辑 |
| | | 拿到父节点和下一节点 |
| | | 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 |
| | | */ |
| | | return 1; |
| | | } |
| | | |
| | | //------------------A*启发函数-end------------------// |
| | | |
| | | } |
| New file |
| | |
| | | package com.zy.common.utils; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.common.model.NavigateNode; |
| | | |
| | | @Component |
| | | public class NavigateUtils { |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) { |
| | | NavigateSolution navigateSolution = new NavigateSolution(); |
| | | List<List<NavigateNode>> stationMap = navigateSolution.getStationMap(); |
| | | |
| | | NavigateNode startNode = navigateSolution.findStationNavigateNode(stationMap, startStationId); |
| | | if (startNode == null){ |
| | | throw new CoolException("未找到该 起点 对应的节点"); |
| | | } |
| | | |
| | | NavigateNode endNode = navigateSolution.findStationNavigateNode(stationMap, endStationId); |
| | | if (endNode == null){ |
| | | throw new CoolException("未找到该 终点 对应的节点"); |
| | | } |
| | | |
| | | NavigateNode res_node = navigateSolution.astarSearchJava(stationMap, startNode, endNode); |
| | | if (res_node == null) { |
| | | throw new CoolException("未找到该路径"); |
| | | } |
| | | |
| | | ArrayList<NavigateNode> list = new ArrayList<>(); |
| | | // 使用 visited 集合防止父链出现环导致死循环,同时设置安全步数上限 |
| | | HashSet<NavigateNode> visited = new HashSet<>(); |
| | | int maxSteps = stationMap.size() * stationMap.get(0).size() + 5; // 安全上限 |
| | | int steps = 0; |
| | | while (res_node != null && visited.add(res_node) && steps++ < maxSteps) { |
| | | list.add(res_node); |
| | | res_node = res_node.getFather();//迭代操作 |
| | | } |
| | | if (steps >= maxSteps) { |
| | | throw new CoolException("路径回溯超出安全上限,疑似存在父链循环"); |
| | | } |
| | | Collections.reverse(list); |
| | | //将每个节点里面的fatherNode至为null(方便后续计算时父节点过多导致显示的节点太多) |
| | | for (NavigateNode navigateNode : list) { |
| | | //父节点设置为null,不影响计算结果,不影响后续操作。 |
| | | //此操作仅为后续排查处理提供视觉方便。 |
| | | navigateNode.setFather(null); |
| | | } |
| | | |
| | | //去重 |
| | | HashSet<Integer> set = new HashSet<>(); |
| | | List<NavigateNode> fitlerList = new ArrayList<>(); |
| | | for(NavigateNode navigateNode : list){ |
| | | JSONObject valuObject = JSON.parseObject(navigateNode.getNodeValue()); |
| | | if(set.add(valuObject.getInteger("stationId"))){ |
| | | fitlerList.add(navigateNode); |
| | | } |
| | | } |
| | | |
| | | return fitlerList; |
| | | } |
| | | |
| | | } |
| | |
| | | import com.zy.core.cache.SlaveConnection; |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.thread.impl.ZySiemensCrnThread; |
| | | import com.zy.core.thread.impl.ZyStationThread; |
| | | |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Async; |
| | |
| | | SlaveConnection.put(SlaveType.Crn, deviceConfig.getDeviceNo(), thread); |
| | | } |
| | | |
| | | News.info("初始化输送站........................................................"); |
| | | List<DeviceConfig> devpList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() |
| | | .eq("device_type", String.valueOf(SlaveType.Devp))); |
| | | for (DeviceConfig deviceConfig : devpList) { |
| | | ThreadHandler thread = null; |
| | | if (deviceConfig.getThreadImpl().equals("ZyStationThread")) { |
| | | thread = new ZyStationThread(deviceConfig, redisUtil); |
| | | } else { |
| | | throw new CoolException("未知的线程实现"); |
| | | } |
| | | |
| | | new Thread(thread).start(); |
| | | SlaveConnection.put(SlaveType.Devp, deviceConfig.getDeviceNo(), thread); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | package com.zy.core.model.protocol; |
| | | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | public class StationProtocol { |
| | | |
| | | // 站点编号 |
| | | private Integer stationId; |
| | | |
| | | // ---------------------------------------------------------------- |
| | | // 工作号 |
| | | private Integer taskNo = 0; |
| | | |
| | | // ---------------------------------------------------------------- |
| | | // 目标站 |
| | | private Integer targetStaNo; |
| | | |
| | | // ---------------------------------------------------------------- |
| | | // 自动 |
| | | private boolean autoing; |
| | | |
| | | // 有物 |
| | | private boolean loading; |
| | | |
| | | // 可入 |
| | | private boolean inEnable; |
| | | |
| | | // 可出 |
| | | private boolean outEnable; |
| | | |
| | | // 空板信号 |
| | | private boolean emptyMk; |
| | | |
| | | // 满托盘 |
| | | private boolean fullPlt; |
| | | |
| | | // 托盘高度 |
| | | private Integer palletHeight; |
| | | |
| | | //报警 |
| | | private Integer error; |
| | | |
| | | //条码 |
| | | private String barcode; |
| | | |
| | | @Override |
| | | public StationProtocol clone() { |
| | | try { |
| | | return (StationProtocol) super.clone(); |
| | | } catch (CloneNotSupportedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | } |
| | |
| | | // 满托盘 |
| | | private boolean fullPlt; |
| | | |
| | | // 锁定标记 |
| | | private boolean pakMk = true; |
| | | |
| | | // 托盘高度 |
| | | private Integer palletHeight; |
| | | |
| | |
| | | package com.zy.core.network.fake; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.asrs.entity.DeviceConfig; |
| | | import com.zy.common.model.NavigateNode; |
| | | import com.zy.common.utils.NavigateUtils; |
| | | import com.zy.core.model.CommandResponse; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.network.api.ZyStationConnectApi; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | import java.util.Collections; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | import java.util.concurrent.ExecutorService; |
| | |
| | | */ |
| | | public class ZyStationFakeConnect implements ZyStationConnectApi { |
| | | |
| | | private ZyStationStatusEntity status; |
| | | private List<ZyStationStatusEntity> statusList = new ArrayList<>(); |
| | | private final DeviceConfig deviceConfig; |
| | | private final ExecutorService executor = Executors.newSingleThreadExecutor(); |
| | | // 允许并行执行多个命令任务(固定线程池)。如需更高并发可调整大小。 |
| | | private final ExecutorService executor = Executors |
| | | .newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors())); |
| | | |
| | | public ZyStationFakeConnect(DeviceConfig deviceConfig) { |
| | | this.deviceConfig = deviceConfig; |
| | | this.status = JSON.parseObject(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class); |
| | | if (this.status == null) { |
| | | this.status = new ZyStationStatusEntity(); |
| | | this.status.setStationId(deviceConfig.getDeviceNo()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public boolean disconnect() { |
| | | executor.shutdownNow(); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public List<ZyStationStatusEntity> getStatus() { |
| | | return Collections.singletonList(status); |
| | | if (this.statusList.isEmpty()) { |
| | | this.statusList = JSON.parseArray(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class); |
| | | |
| | | for (ZyStationStatusEntity status : this.statusList) { |
| | | status.setAutoing(true);// 模拟自动运行 |
| | | status.setLoading(false);// 模拟有物 |
| | | status.setInEnable(true);// 模拟可入 |
| | | status.setOutEnable(true);// 模拟可出 |
| | | status.setEmptyMk(false);// 模拟空板信号 |
| | | status.setFullPlt(false);// 模拟满托盘 |
| | | status.setPalletHeight(0);// 模拟托盘高度为0 |
| | | status.setError(0);// 模拟无报警 |
| | | status.setBarcode("");// 模拟无条码 |
| | | } |
| | | } |
| | | |
| | | return this.statusList; |
| | | } |
| | | |
| | | @Override |
| | | public CommandResponse sendCommand(StationCommand command) { |
| | | CommandResponse response = new CommandResponse(false); |
| | | executor.submit(() -> handleCommand(command)); |
| | | response.setResult(true); |
| | | return response; |
| | | executor.submit(() -> { |
| | | try { |
| | | handleCommand(command); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | }); |
| | | return new CommandResponse(true, "命令已受理(异步执行)"); |
| | | } |
| | | |
| | | private void handleCommand(StationCommand command) { |
| | | // 简单的模拟:设置工作号和目标站,并模拟有物/可入/可出状态切换 |
| | | this.status.setTaskNo(command.getTaskNo()); |
| | | this.status.setTargetStaNo(command.getTargetStaNo()); |
| | | NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class); |
| | | if (navigateUtils == null) { |
| | | return; |
| | | } |
| | | |
| | | // 模拟到站过程 |
| | | this.status.setAutoing(true); |
| | | this.status.setLoading(true); |
| | | Integer taskNo = command.getTaskNo(); |
| | | Integer stationId = command.getStationId(); |
| | | Integer targetStationId = command.getTargetStaNo(); |
| | | |
| | | List<NavigateNode> navigateNodes = null; |
| | | |
| | | try { |
| | | navigateNodes = navigateUtils.calcByStationId(stationId, targetStationId); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | if (navigateNodes == null) { |
| | | return; |
| | | } |
| | | |
| | | Integer lastStationId = null; |
| | | for (int i = 0; i < navigateNodes.size(); i++) { |
| | | NavigateNode navigateNode = navigateNodes.get(i); |
| | | JSONObject valueObject = JSON.parseObject(navigateNode.getNodeValue()); |
| | | Integer currentStationId = valueObject.getInteger("stationId"); |
| | | ZyStationStatusEntity status = statusList.stream() |
| | | .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); |
| | | if (status == null) { |
| | | continue; |
| | | } |
| | | |
| | | try { |
| | | while (true) { |
| | | ZyStationStatusEntity nextStatus = statusList.stream() |
| | | .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); |
| | | if (nextStatus == null) { |
| | | continue; |
| | | } |
| | | |
| | | if (nextStatus.getTaskNo() == 0) { |
| | | break; |
| | | } |
| | | |
| | | sleep(100); |
| | | } |
| | | } catch (Exception e) { |
| | | continue; |
| | | } |
| | | |
| | | synchronized (status) { |
| | | status.setTaskNo(taskNo); |
| | | status.setTargetStaNo(targetStationId); |
| | | status.setLoading(true); |
| | | } |
| | | |
| | | if (lastStationId != null) { |
| | | Integer finalLastStationId = lastStationId; |
| | | ZyStationStatusEntity lastStatus = statusList.stream() |
| | | .filter(item -> item.getStationId().equals(finalLastStationId)).findFirst().orElse(null); |
| | | if (lastStatus != null) { |
| | | synchronized (lastStatus) { |
| | | lastStatus.setTaskNo(0); |
| | | lastStatus.setTargetStaNo(0); |
| | | lastStatus.setLoading(false); |
| | | } |
| | | } |
| | | } |
| | | lastStationId = currentStationId; |
| | | sleep(1000); |
| | | } |
| | | |
| | | // 模拟放下托盘 |
| | | this.status.setInEnable(true); |
| | | this.status.setOutEnable(false); |
| | | sleep(1000); |
| | | |
| | | // 完成任务,复位状态 |
| | | this.status.setLoading(false); |
| | | this.status.setAutoing(false); |
| | | this.status.setTaskNo(0); |
| | | this.status.setInEnable(false); |
| | | this.status.setOutEnable(true); |
| | | sleep(10000); |
| | | if (lastStationId != null) { |
| | | Integer finalLastStationId = lastStationId; |
| | | ZyStationStatusEntity lastStatus = statusList.stream() |
| | | .filter(item -> item.getStationId().equals(finalLastStationId)).findFirst().orElse(null); |
| | | if (lastStatus != null) { |
| | | synchronized (lastStatus) { |
| | | lastStatus.setTaskNo(0); |
| | | lastStatus.setTargetStaNo(0); |
| | | lastStatus.setLoading(false); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void sleep(long ms) { |
| | |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.network.api.ZyStationConnectApi; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | |
| | | import com.zy.core.ThreadHandler; |
| | | import com.zy.core.model.CommandResponse; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import java.util.List; |
| | | |
| | | public interface StationThread extends ThreadHandler{ |
| | | |
| | | List<ZyStationStatusEntity> getStatus(); |
| | | List<StationProtocol> getStatus(); |
| | | |
| | | StationCommand getMoveCommand(); |
| | | StationCommand getMoveCommand(Integer taskNo, Integer stationId, Integer targetStationId, Integer palletSize); |
| | | |
| | | CommandResponse sendCommand(StationCommand command); |
| | | |
| | |
| | | package com.zy.core.thread.impl; |
| | | |
| | | import HslCommunication.Profinet.Siemens.SiemensPLCS; |
| | | import HslCommunication.Profinet.Siemens.SiemensS7Net; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.service.BasDevpService; |
| | | import com.zy.core.network.DeviceConnectPool; |
| | | import com.zy.core.thread.StationThread; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.core.common.DateUtils; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.asrs.entity.DeviceConfig; |
| | | import com.zy.asrs.entity.DeviceDataLog; |
| | | import com.zy.asrs.service.DeviceDataLogService; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.network.ZyStationConnectDriver; |
| | | import com.zy.core.cache.MessageQueue; |
| | | import com.zy.core.cache.OutputQueue; |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.model.CommandResponse; |
| | | import com.zy.core.model.Task; |
| | | import com.zy.core.model.command.StationCommand; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | |
| | | import java.text.MessageFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | import lombok.Data; |
| | |
| | | @Slf4j |
| | | public class ZyStationThread implements Runnable, StationThread { |
| | | |
| | | private List<StationProtocol> statusList = new ArrayList<>(); |
| | | private DeviceConfig deviceConfig; |
| | | private RedisUtil redisUtil; |
| | | private ZyStationConnectDriver zyStationConnectDriver; |
| | | private long deviceDataLogTime = System.currentTimeMillis(); |
| | | |
| | | public ZyStationThread(DeviceConfig deviceConfig, RedisUtil redisUtil) { |
| | | this.deviceConfig = deviceConfig; |
| | |
| | | } |
| | | |
| | | @Override |
| | | @SuppressWarnings("InfiniteLoopStatement") |
| | | public void run() { |
| | | this.connect(); |
| | | while (true) { |
| | | try { |
| | | int step = 1; |
| | | Task task = MessageQueue.poll(SlaveType.Devp, deviceConfig.getDeviceNo()); |
| | | if (task != null) { |
| | | step = task.getStep(); |
| | | } |
| | | switch (step) { |
| | | // 读数据 |
| | | case 1: |
| | | readStatus(); |
| | | break; |
| | | case 2: |
| | | sendCommand((StationCommand) task.getData()); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | Thread.sleep(200); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void readStatus() { |
| | | if (zyStationConnectDriver == null) { |
| | | return; |
| | | } |
| | | |
| | | if(statusList.isEmpty()) { |
| | | BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); |
| | | if (basDevpService == null) { |
| | | return; |
| | | } |
| | | |
| | | BasDevp basDevp = basDevpService |
| | | .selectOne(new EntityWrapper<BasDevp>().eq("devp_no", deviceConfig.getDeviceNo())); |
| | | if (basDevp == null) { |
| | | return; |
| | | } |
| | | |
| | | List<ZyStationStatusEntity> list = JSONObject.parseArray(basDevp.getStationList(), ZyStationStatusEntity.class); |
| | | for (ZyStationStatusEntity entity : list) { |
| | | StationProtocol stationProtocol = new StationProtocol(); |
| | | stationProtocol.setStationId(entity.getStationId()); |
| | | statusList.add(stationProtocol); |
| | | } |
| | | } |
| | | |
| | | List<ZyStationStatusEntity> zyStationStatusEntities = zyStationConnectDriver.getStatus(); |
| | | for (ZyStationStatusEntity statusEntity : zyStationStatusEntities) { |
| | | for (StationProtocol stationProtocol : statusList) { |
| | | if(stationProtocol.getStationId().equals(statusEntity.getStationId())) { |
| | | stationProtocol.setTaskNo(statusEntity.getTaskNo()); |
| | | stationProtocol.setTargetStaNo(statusEntity.getTargetStaNo()); |
| | | stationProtocol.setAutoing(statusEntity.isAutoing()); |
| | | stationProtocol.setLoading(statusEntity.isLoading()); |
| | | stationProtocol.setInEnable(statusEntity.isInEnable()); |
| | | stationProtocol.setOutEnable(statusEntity.isOutEnable()); |
| | | stationProtocol.setEmptyMk(statusEntity.isEmptyMk()); |
| | | stationProtocol.setFullPlt(statusEntity.isFullPlt()); |
| | | stationProtocol.setPalletHeight(statusEntity.getPalletHeight()); |
| | | stationProtocol.setError(statusEntity.getError()); |
| | | stationProtocol.setBarcode(statusEntity.getBarcode()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); |
| | | |
| | | if (System.currentTimeMillis() - deviceDataLogTime > 1000 * 1) { |
| | | //采集时间超过1s,保存一次数据记录 |
| | | //保存数据记录 |
| | | DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class); |
| | | DeviceDataLog deviceDataLog = new DeviceDataLog(); |
| | | deviceDataLog.setOriginData(JSON.toJSONString(zyStationStatusEntities)); |
| | | deviceDataLog.setWcsData(JSON.toJSONString(statusList)); |
| | | deviceDataLog.setType(String.valueOf(SlaveType.Devp)); |
| | | deviceDataLog.setDeviceNo(deviceConfig.getDeviceNo()); |
| | | deviceDataLog.setCreateTime(new Date()); |
| | | deviceDataLogService.insert(deviceDataLog); |
| | | |
| | | //更新采集时间 |
| | | deviceDataLogTime = System.currentTimeMillis(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean connect() { |
| | | SiemensS7Net siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200, deviceConfig.getIp()); |
| | | zyStationConnectDriver = new ZyStationConnectDriver(siemensS7Net, deviceConfig); |
| | | new Thread(zyStationConnectDriver).start(); |
| | | DeviceConnectPool.put(SlaveType.Devp, deviceConfig.getDeviceNo(), zyStationConnectDriver); |
| | | return true; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<ZyStationStatusEntity> getStatus() { |
| | | if (zyStationConnectDriver == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return zyStationConnectDriver.getStatus(); |
| | | public List<StationProtocol> getStatus() { |
| | | return statusList; |
| | | } |
| | | |
| | | @Override |
| | | public StationCommand getMoveCommand() { |
| | | return null; |
| | | public StationCommand getMoveCommand(Integer taskNo, Integer stationId, Integer targetStationId, Integer palletSize) { |
| | | StationCommand stationCommand = new StationCommand(); |
| | | stationCommand.setTaskNo(taskNo); |
| | | stationCommand.setStationId(stationId); |
| | | stationCommand.setTargetStaNo(targetStationId); |
| | | stationCommand.setPalletSize(palletSize); |
| | | return stationCommand; |
| | | } |
| | | |
| | | @Override |
| | | public CommandResponse sendCommand(StationCommand command) { |
| | | return new CommandResponse(true); |
| | | CommandResponse commandResponse = zyStationConnectDriver.sendCommand(command); |
| | | return commandResponse; |
| | | } |
| | | |
| | | @Override |
| | | public void run() { |
| | | } |
| | | } |
| New file |
| | |
| | | Vue.component("devp-card", { |
| | | template: ` |
| | | <div> |
| | | <div style="display: flex;margin-bottom: 10px;"> |
| | | <div style="width: 100%;">输送监控</div> |
| | | <div style="width: 100%;text-align: right;display: flex;"><el-input size="mini" v-model="searchStationId" placeholder="请输入站号"></el-input><el-button @click="getDevpStateInfo" size="mini">查询</el-button></div> |
| | | </div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <div style="margin-bottom: 5px;"> |
| | | <el-button v-if="showControl" @click="openControl" size="mini">关闭控制中心</el-button> |
| | | <el-button v-else @click="openControl" size="mini">打开控制中心</el-button> |
| | | </div> |
| | | <div v-if="showControl" style="display: flex;justify-content: space-between;flex-wrap: wrap;"> |
| | | <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.stationId" placeholder="站号"></el-input></div> |
| | | <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.taskNo" placeholder="工作号"></el-input></div> |
| | | <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.targetStationId" placeholder="目标站"></el-input></div> |
| | | <div style="margin-bottom: 10px;"><el-button @click="controlCommand()" size="mini">下发</el-button></div> |
| | | </div> |
| | | </div> |
| | | <el-collapse v-model="activeNames"> |
| | | <el-collapse-item v-for="(item) in stationList" :name="item.stationId"> |
| | | <template slot="title"> |
| | | <div style="width: 100%;display: flex;"> |
| | | <div style="width: 50%;">{{ item.stationId }}站</div> |
| | | <div style="width: 50%;text-align: right;"> |
| | | <el-tag v-if="item.autoing" type="success" size="small">自动</el-tag> |
| | | <el-tag v-else type="warning" size="small">手动</el-tag> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <el-descriptions border direction="vertical"> |
| | | <el-descriptions-item label="编号">{{ item.stationId }}</el-descriptions-item> |
| | | <el-descriptions-item label="工作号">{{ item.taskNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="目标站">{{ item.targetStaNo }}</el-descriptions-item> |
| | | <el-descriptions-item label="模式">{{ item.autoing ? '自动' : '手动' }}</el-descriptions-item> |
| | | <el-descriptions-item label="有物">{{ item.loading ? '有' : '无' }}</el-descriptions-item> |
| | | <el-descriptions-item label="可入">{{ item.inEnable ? 'Y' : 'N' }}</el-descriptions-item> |
| | | <el-descriptions-item label="可出">{{ item.outEnable ? 'Y' : 'N' }}</el-descriptions-item> |
| | | <el-descriptions-item label="空板信号">{{ item.emptyMk ? 'Y' : 'N' }}</el-descriptions-item> |
| | | <el-descriptions-item label="满板信号">{{ item.fullPlt ? 'Y' : 'N' }}</el-descriptions-item> |
| | | <el-descriptions-item label="托盘高度">{{ item.palletHeight }}</el-descriptions-item> |
| | | <el-descriptions-item label="条码">{{ item.barcode }}</el-descriptions-item> |
| | | <el-descriptions-item label="故障代码">{{ item.error }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | `, |
| | | props: ["param"], |
| | | data() { |
| | | return { |
| | | stationList: [], |
| | | activeNames: "", |
| | | searchStationId: "", |
| | | showControl: true, |
| | | controlParam: { |
| | | stationId: "", |
| | | taskNo: "", |
| | | targetStationId: "", |
| | | }, |
| | | }; |
| | | }, |
| | | created() { |
| | | setInterval(() => { |
| | | this.getDevpStateInfo(); |
| | | }, 1000); |
| | | }, |
| | | watch: { |
| | | param: { |
| | | handler(newVal, oldVal) { |
| | | if (newVal.stationId != 0) { |
| | | this.activeNames = newVal.stationId; |
| | | this.searchStationId = newVal.stationId; |
| | | } |
| | | }, |
| | | deep: true, // 深度监听嵌套属性 |
| | | immediate: true, // 立即触发一次(可选) |
| | | }, |
| | | }, |
| | | methods: { |
| | | getDevpStateInfo() { |
| | | let that = this; |
| | | $.ajax({ |
| | | url: baseUrl + "/console/latest/data/station", |
| | | headers: { |
| | | token: localStorage.getItem("token"), |
| | | }, |
| | | method: "post", |
| | | success: (res) => { |
| | | // 堆垛机信息表获取 |
| | | if (res.code == 200) { |
| | | let list = res.data; |
| | | |
| | | if (that.searchStationId == "") { |
| | | that.stationList = list; |
| | | } else { |
| | | let tmp = []; |
| | | list.forEach((item) => { |
| | | if (item.stationId == that.searchStationId) { |
| | | tmp.push(item); |
| | | } |
| | | }); |
| | | that.stationList = tmp; |
| | | } |
| | | } |
| | | }, |
| | | }); |
| | | }, |
| | | openControl() { |
| | | this.showControl = !this.showControl; |
| | | }, |
| | | controlCommand() { |
| | | let that = this; |
| | | //下发命令 |
| | | $.ajax({ |
| | | url: baseUrl + "/station/command/move", |
| | | headers: { |
| | | token: localStorage.getItem("token"), |
| | | }, |
| | | contentType: "application/json", |
| | | method: "post", |
| | | data: JSON.stringify(that.controlParam), |
| | | success: (res) => { |
| | | if (res.code == 200) { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: "success", |
| | | }); |
| | | } else { |
| | | that.$message({ |
| | | message: res.msg, |
| | | type: "warning", |
| | | }); |
| | | } |
| | | }, |
| | | }); |
| | | }, |
| | | }, |
| | | }); |
| | |
| | | </div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <div style="margin-bottom: 5px;"> |
| | | <el-button @click="openControl" size="mini">控制中心</el-button> |
| | | <el-button v-if="showControl" @click="openControl" size="mini">关闭控制中心</el-button> |
| | | <el-button v-else @click="openControl" size="mini">打开控制中心</el-button> |
| | | </div> |
| | | <div v-if="showControl" style="display: flex;justify-content: space-between;flex-wrap: wrap;"> |
| | | <div style="margin-bottom: 10px;width: 33%;"><el-input size="mini" v-model="controlParam.crnNo" placeholder="堆垛机号"></el-input></div> |
| | |
| | | crnList: [], |
| | | activeNames: "", |
| | | searchCrnNo: "", |
| | | showControl: true, |
| | | showControl: false, |
| | | controlParam: { |
| | | crnNo: "", |
| | | sourceLocNo: "", |
| | |
| | | <el-tab-pane label="堆垛机" name="crn"> |
| | | <watch-crn-card :param="crnParam"></watch-crn-card> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="输送线" name="devp">输送线</el-tab-pane> |
| | | <el-tab-pane label="输送站" name="devp"> |
| | | <devp-card :param="devpParam"></devp-card> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="RGV" name="rgv">RGV</el-tab-pane> |
| | | <el-tab-pane label="地图配置" name="mapSetting"> |
| | | <map-setting-card :param="mapSettingParam"></map-setting-card> |
| | |
| | | <div class="shelf">{{col.shelfIdx}}</div> |
| | | </div> |
| | | <div v-else-if="col.type == 'devp'"> |
| | | <div class="site" :style="{height: col.rowPx}" :id="'site-' + col.value" @click="openSite(col.value)">{{col.value}}</div> |
| | | <div class="site" :style="{height: col.rowPx}" :id="'site-' + getStationId(col.value)" @click="openSite(getStationId(col.value))">{{getStationId(col.value)}}</div> |
| | | </div> |
| | | <div v-else-if="col.type == 'rgv'" style="position: relative;"> |
| | | <div class="rgv-item" v-if="getDeviceNo(col.value) != -1" :style="{width: col.width}" :id="'rgv-' + getDeviceNo(col.value)" @click="openRgv(getDeviceNo(col.value))">{{getDeviceNo(col.value)}}</div> |
| | |
| | | </div> |
| | | |
| | | <script src="../../components/WatchCrnCard.js"></script> |
| | | <script src="../../components/DevpCard.js"></script> |
| | | <script src="../../components/MapSettingCard.js"></script> |
| | | <script> |
| | | var app = new Vue({ |
| | |
| | | }, |
| | | mapSettingParam: { |
| | | zoom: 70 |
| | | }, |
| | | devpParam: { |
| | | stationId: 0 |
| | | } |
| | | }, |
| | | created() { |
| | |
| | | this.getMap() |
| | | this.getSystemRunningStatus() //获取系统运行状态 |
| | | |
| | | // this.consoleInterval = setInterval(() => { |
| | | // this.getCrnInfo() //获取堆垛机数据 |
| | | // this.getSiteInfo() //获取输送站点数据 |
| | | // this.getRgvInfo() //获取RGV数据 |
| | | // }, 1000) |
| | | this.consoleInterval = setInterval(() => { |
| | | this.getCrnInfo() //获取堆垛机数据 |
| | | this.getSiteInfo() //获取输送站点数据 |
| | | this.getRgvInfo() //获取RGV数据 |
| | | }, 1000) |
| | | }, |
| | | //获取地图数据 |
| | | getMap() { |
| | |
| | | let colPx = 35; |
| | | |
| | | $.ajax({ |
| | | url: "./test.json", |
| | | url: baseUrl + "/basMap/lev/1/auth", |
| | | headers: { |
| | | 'token': localStorage.getItem('token') |
| | | }, |
| | | method: "get", |
| | | success: (res) => { |
| | | let data = res.data; |
| | |
| | | }) |
| | | }, |
| | | openSite(id) { |
| | | this.siteWindow = true; //打开站点信息弹窗 |
| | | $(".detailed").empty(); |
| | | $('.detailed').append(id + '站点详细信息'); |
| | | $.ajax({ |
| | | url: baseUrl + "/console/site/detail", |
| | | headers: { |
| | | 'token': localStorage.getItem('token') |
| | | }, |
| | | data: { |
| | | siteId: id |
| | | }, |
| | | method: 'post', |
| | | success: function(res) { |
| | | for (var val in res.data) { |
| | | var find = $("#siteWindow").find(":input[name='" + val + "']"); |
| | | if (find[0].type === 'text') { |
| | | find.val(res.data[val]); |
| | | } else if (find[0].type === 'checkbox') { |
| | | find.attr("checked", res.data[val] === 'Y'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | }) |
| | | this.devpParam.stationId = id; |
| | | }, |
| | | getSiteInfo() { |
| | | //获取输送站点数据 |
| | | $.ajax({ |
| | | url: baseUrl + "/console/latest/data/site", |
| | | url: baseUrl + "/console/latest/data/station", |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | console.log(res) |
| | | if (res.code === 200) { |
| | | var sites = res.data; |
| | | for (var i = 0; i < sites.length; i++){ |
| | | var siteEl = $("#site-"+sites[i].siteId); |
| | | siteEl.attr("class", "site " + sites[i].siteStatus); |
| | | if (sites[i].workNo != null && sites[i].workNo>0) { |
| | | siteEl.html(sites[i].siteId + "[" + sites[i].workNo + "]"); |
| | | var siteEl = $("#site-"+sites[i].stationId); |
| | | siteEl.attr("class", "site " + sites[i].stationStatus); |
| | | if (sites[i].taskNo != null && sites[i].taskNo>0) { |
| | | siteEl.html(sites[i].stationId + "[" + sites[i].taskNo + "]"); |
| | | } else { |
| | | siteEl.html(sites[i].siteId); |
| | | siteEl.html(sites[i].stationId); |
| | | } |
| | | } |
| | | } else if (res.code === 403) { |
| | |
| | | return -1; |
| | | } |
| | | }, |
| | | getStationId(obj) { |
| | | if (this.isJson(obj)) { |
| | | let data = JSON.parse(obj) |
| | | if (data.stationId == null || data.stationId == undefined) { |
| | | return -1; |
| | | } |
| | | return data.stationId; |
| | | }else { |
| | | return -1; |
| | | } |
| | | }, |
| | | getTrackSiteNo(obj) { |
| | | if (this.isJson(obj)) { |
| | | let data = JSON.parse(obj) |