src/main/java/com/zy/asrs/controller/ConsoleController.java
@@ -1,12 +1,36 @@ 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.param.SystemSwitchParam; import com.zy.asrs.domain.vo.CrnDetailVo; import com.zy.asrs.domain.vo.CrnLatestDataVo; import com.zy.asrs.entity.BasCrnpErr; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.service.BasCrnpErrService; 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.properties.SystemProperties; import com.zy.core.thread.CrnThread; import com.zy.core.thread.impl.ZySiemensCrnThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.*; /** * 主控图接口 @@ -16,6 +40,13 @@ @RestController @RequestMapping("/console") public class ConsoleController { @Autowired private DeviceConfigService deviceConfigService; @Autowired private WrkMastService wrkMastService; @Autowired private BasCrnpErrService basCrnpErrService; @PostMapping("/system/running/status") @ManagerAuth(memo = "系统运行状态") @@ -42,4 +73,158 @@ 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/crn") @ManagerAuth(memo = "堆垛机实时数据") public R crnLatestData(){ List<CrnLatestDataVo> vos = new ArrayList<>(); List<DeviceConfig> crnList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Crn))); for (DeviceConfig deviceConfig : crnList) { // 获取堆垛机信息 CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, deviceConfig.getDeviceNo()); if (crnThread == null) { continue; } CrnProtocol crnProtocol = crnThread.getStatus(); if (crnProtocol == null) { continue; } CrnLatestDataVo vo = new CrnLatestDataVo(); vo.setCrnId(crnProtocol.getCrnNo()); // 堆垛机编号 vo.setOffset((double) new Random().nextInt(560)); // 堆垛机偏移量 vo.setBay(crnProtocol.getBay()); // 当前列 /** * 堆垛机状态判断 */ if (crnProtocol.getAlarm() > 0) { vo.setCrnStatus(CrnStatusType.MACHINE_ERROR); } else { if (crnProtocol.getTaskNo()>0) { WrkMast wrkMast = wrkMastService.selectById(crnProtocol.getTaskNo()); if (wrkMast != null) { vo.setCrnStatus(CrnStatusType.process(wrkMast.getIoType())); } else { 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); } } vos.add(vo); } return R.ok().add(vos); } // @PostMapping("/latest/data/rgv") // @ManagerAuth(memo = "RGV实时数据") // public R rgvLatestData(){ // List<RgvLatestDataVo> vos = new ArrayList<>(); // for (RgvSlave rgvSlave : slaveProperties.getRgv()) { // // 获取堆垛机信息 // RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgvSlave.getId()); // if (rgvThread == null) { // continue; // } // RgvProtocol rgvProtocol = rgvThread.getRgvProtocol(); // if (rgvProtocol == null) { // continue; // } // RgvLatestDataVo vo = new RgvLatestDataVo(); // vo.setRgvId(rgvProtocol.getRgvNo()); // RGV编号 // vo.setTrackSiteNo(String.valueOf(rgvProtocol.getRgvPos())); // vo.setRgvStatus(rgvProtocol.getStatusType()); // vos.add(vo); // // } // Object object = redisUtil.get("rgvLatestData"); // List<Object> siteLatestDataVos = JSON.parseArray(object.toString()); // return R.ok().add(siteLatestDataVos); // } // @PostMapping("/latest/data/barcode") // @ManagerAuth(memo = "条码扫描仪实时数据") // public R barcodeLatestData(){ // List<BarcodeDataVo> list = new ArrayList<>(); // for (Slave barcode : slaveProperties.getBarcode()) { // BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, barcode.getId()); // if (null == barcodeThread) { // continue; // } // BarcodeDataVo vo = new BarcodeDataVo(); // vo.setBarcodeId(barcode.getId()); // vo.setCodeValue(barcodeThread.getBarcode()); // list.add(vo); // } // return R.ok().add(list); // } @PostMapping("/crn/detail") @ManagerAuth(memo = "堆垛机设备数据详情") public R crnDetail(@RequestParam Integer crnNo){ if (Cools.isEmpty(crnNo)){ return R.parse(CodeRes.EMPTY); } CrnDetailVo vo = new CrnDetailVo(); DeviceConfig deviceConfig = deviceConfigService.selectOne(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Crn)) .eq("device_no", crnNo) ); if (deviceConfig == null) { return R.error("设备不存在"); } CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crnNo); CrnProtocol crnProtocol = crnThread.getStatus(); vo.setCrnNo(crnNo); vo.setWorkNo(crnProtocol.getTaskNo()); vo.setCrnStatus(crnProtocol.getStatusType().desc); if (crnProtocol.getAlarm() > 0) { BasCrnpErr crnError = basCrnpErrService.selectById(crnProtocol.getAlarm()); vo.setError(crnError == null ? "未知异常" : crnError.getErrName()); } if (crnProtocol.getTaskNo() > 0) { WrkMast wrkMast = wrkMastService.selectById(crnProtocol.getTaskNo()); if (wrkMast != null) { vo.setSourceStaNo(String.valueOf(wrkMast.getSourceStaNo())); vo.setStaNo(String.valueOf(wrkMast.getStaNo())); vo.setWrkSts(wrkMast.getWrkSts$()); // 工作状态 vo.setIoType(wrkMast.getIoType$()); // 入出库类型 vo.setSourceLocNo(wrkMast.getSourceLocNo$()); vo.setLocNo(wrkMast.getLocNo$()); vo.setCrnStatus(crnProtocol.getStatusType().desc); vo.setError(""); // todo } } return R.ok().add(vo); } } src/main/java/com/zy/asrs/domain/enums/CrnStatusType.java
New file @@ -0,0 +1,53 @@ package com.zy.asrs.domain.enums; /** * 堆垛机状态枚举 */ public enum CrnStatusType { // 入库 MACHINE_PAKIN("入库"), // 出库 MACHINE_PAKOUT("出库"), // 库到库 MACHINE_STOCK_MOVE("库到库"), // 站到站 MACHINE_SITE_MOVE("站到站"), // p to p MACHINE_P_MOVE("PToP"), // 异常 MACHINE_ERROR("异常"), // 自动 MACHINE_AUTO("自动"), // 非自动/手动 MACHINE_UN_AUTO("非自动"), ; private String desc; CrnStatusType(String desc){ this.desc = desc; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public static CrnStatusType process(Integer ioType){ if (ioType>100) { return MACHINE_PAKOUT; } else if (ioType < 100 && ioType!=3 && ioType!=6 && ioType!=11) { return MACHINE_PAKIN; } else if (ioType == 3) { return MACHINE_SITE_MOVE; } else if (ioType == 11) { return MACHINE_STOCK_MOVE; } else { return MACHINE_ERROR; } } } src/main/java/com/zy/asrs/domain/vo/CrnDetailVo.java
New file @@ -0,0 +1,42 @@ package com.zy.asrs.domain.vo; import lombok.Data; /** * 堆垛机详情视图对象 * Created by vincent on 2020-06-03 */ @Data public class CrnDetailVo { // 堆垛机号 private Integer crnNo; // 工作号 private Integer workNo; // 源站 private String sourceStaNo = ""; // 目标站 private String staNo = ""; // 工作状态 private String wrkSts = ""; // 出入类型 private String ioType = ""; // 源库位 private String sourceLocNo = ""; // 目标库位 private String locNo = ""; // 堆垛机状态 private String crnStatus = ""; // 异常 private String error = ""; } src/main/java/com/zy/asrs/domain/vo/CrnLatestDataVo.java
New file @@ -0,0 +1,28 @@ package com.zy.asrs.domain.vo; import com.zy.asrs.domain.enums.CrnStatusType; import lombok.Data; /** * 堆垛机最新数据视图对象 * Created by vincent on 2020-06-01 */ @Data public class CrnLatestDataVo { // 堆垛机编号 private Integer crnId; // 偏移量 private Double offset; // 当前列 private Integer bay; private CrnStatusType crnStatus; public String getCrnStatus(){ return crnStatus.toString().toLowerCase().replaceAll("_", "-"); } } src/main/java/com/zy/core/ServerBootstrap.java
@@ -1,11 +1,14 @@ package com.zy.core; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.exception.CoolException; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.service.DeviceConfigService; import com.zy.common.utils.RedisUtil; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.thread.impl.ZySiemensCrnThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; @@ -77,31 +80,20 @@ } private void initThread(){ // News.info("初始化堆垛机........................................................"); // List<DeviceConfig> crnList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() // .eq("device_type", String.valueOf(SlaveType.Crn))); // for (DeviceConfig deviceConfig : crnList) { // BasLift basLift = basLiftService.selectOne(new EntityWrapper<BasLift>().eq("lift_no", deviceConfig.getDeviceNo())); // if (basLift == null) { // throw new CoolException("未配置货叉提升机数据"); // } // // ThreadHandler thread = null; // if (deviceConfig.getThreadImpl().equals("ZyForkLiftThread")) { // thread = new ZyForkLiftThread(deviceConfig, basLift.getStationList$(), redisUtil); // } else { // throw new CoolException("未知的线程实现"); // } // // new Thread(thread).start(); // SlaveConnection.put(SlaveType.ForkLift, deviceConfig.getDeviceNo(), thread); // // if (deviceConfig.getFake() == 1) { // fakeDevices.add(deviceConfig); // }else { // allDevices.add(deviceConfig); // } // } News.info("初始化堆垛机........................................................"); List<DeviceConfig> crnList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>() .eq("device_type", String.valueOf(SlaveType.Crn))); for (DeviceConfig deviceConfig : crnList) { ThreadHandler thread = null; if (deviceConfig.getThreadImpl().equals("ZySiemensCrnThread")) { thread = new ZySiemensCrnThread(deviceConfig, redisUtil); } else { throw new CoolException("未知的线程实现"); } new Thread(thread).start(); SlaveConnection.put(SlaveType.Crn, deviceConfig.getDeviceNo(), thread); } } src/main/java/com/zy/core/cache/OutputQueue.java
@@ -9,11 +9,13 @@ */ public class OutputQueue { //四向穿梭车输出日志 public static ArrayBlockingQueue<String> SHUTTLE = new ArrayBlockingQueue<>(32); //提升机输出日志 public static ArrayBlockingQueue<String> LIFT = new ArrayBlockingQueue<>(32); //货叉提升机输出日志 public static ArrayBlockingQueue<String> FORKLIFT = new ArrayBlockingQueue<>(32); // 堆垛机输出日志 public static ArrayBlockingQueue<String> CRN = new ArrayBlockingQueue<>(32); // 输送线输出日志 public static ArrayBlockingQueue<String> DEVP = new ArrayBlockingQueue<>(32); // 条码器输出日志 public static ArrayBlockingQueue<JSONObject> BARCODE = new ArrayBlockingQueue<>(32); // rgv输出日志 public static ArrayBlockingQueue<String> RGV = new ArrayBlockingQueue<>(32); } src/main/java/com/zy/core/enums/CrnTaskModeType.java
New file @@ -0,0 +1,46 @@ package com.zy.core.enums; public enum CrnTaskModeType { NONE(0), // 无 PAKIN(1), // 入库 PAKOUT(2), // 出库 LOC_MOVE(3), // 库位移转 X_MOVE(4), // 站位移转 Y_MOVE(5), // 站位移转 XY_MOVE(6), // 站位移转 CRN_MOVE(7), // 堆垛机移动XYZ BACK_ORIGIN(8), // 回反原点 CLEAR(9), // 清错 ; public Integer id; CrnTaskModeType(Integer id) { this.id = id; } public static CrnTaskModeType get(Integer id) { if (null == id) { return null; } for (CrnTaskModeType type : CrnTaskModeType.values()) { if (type.id.equals(id)) { return type; } } return null; } public static CrnTaskModeType get(CrnTaskModeType type) { if (null == type) { return null; } for (CrnTaskModeType crnTaskModeType : CrnTaskModeType.values()) { if (crnTaskModeType == type) { return crnTaskModeType; } } return null; } } src/main/java/com/zy/core/model/command/CrnCommand.java
New file @@ -0,0 +1,68 @@ package com.zy.core.model.command; import lombok.Data; /** * 堆垛机命令报文 * Created by vincent on 2020/8/11 */ @Data public class CrnCommand { // 堆垛机号 private Integer crnNo = 0; // 任务完成确认位 private Short ackFinish = 0; // 任务号 private Short taskNo = 0; /** * 任务模式: * 0 = 无 * 1 = 入库 源和目标都发 * 2 = 出库 源和目标都发 * 3 = 库位移转 源和目标都发 * 4 = 站位移转 源和目标都发 * 5 = 回原点 不用发 * 6 = 去反原点 目标发 * 7 = 坐标移行 取货发 * 90 = 设置时间 * 99 = 取消当前任务 */ private Short taskMode = 0; // 源位置排号 private Short sourcePosX = 0; // 源位置列号 private Short sourcePosY = 0; // 源位置层号 private Short sourcePosZ = 0; // 源站 private Short sourceStaNo = 0; // 源巷道 private Short sourceLane = 0; // 目标位置排号 private Short destinationPosX = 0; // 目标位置列号 private Short destinationPosY = 0; // 目标位置层号 private Short destinationPosZ = 0; // 目标站 private Short destinationStaNo = 0; // 目标巷道 private Short destinationLane = 0; // 任务确认 0:未确认 1:已确认 private Short command = 0; } src/main/java/com/zy/core/model/protocol/CrnProtocol.java
@@ -24,11 +24,6 @@ public CrnModeType modeType; /** * 1 = 急停 */ public Integer eStop; /** * 异常码 */ public Integer alarm; @@ -110,37 +105,37 @@ /** * X行走线速度m/min */ private Float xSpeed; private Integer xSpeed; /** * Y行走线速度m/min */ private Float ySpeed; private Integer ySpeed; /** * Z行走线速度m/min */ private Float zSpeed; private Integer zSpeed; /** * 堆垛机累计走行距离km */ public Float xDistance; public Integer xDistance; /** * 堆垛机累计升降距离km */ public Float yDistance; public Integer yDistance; /** * 堆垛机累计走行时长h */ public Float xDuration; public Integer xDuration; /** * 堆垛机累计升降时长h */ public Float yDuration; public Integer yDuration; /** * 最近一次入出库类型 src/main/java/com/zy/core/network/DeviceConnectPool.java
New file @@ -0,0 +1,36 @@ package com.zy.core.network; import com.zy.core.ThreadHandler; import com.zy.core.enums.SlaveType; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class DeviceConnectPool { private static final String _LINK = "_"; private static final Map<String, ThreadHandler> conContain = new ConcurrentHashMap<>(); public static void put(SlaveType type, Integer id, ThreadHandler thread) { String key = toKey(type, id); remove(type, id); conContain.put(key, thread); } public static ThreadHandler get(SlaveType type, Integer id) { return conContain.get(toKey(type, id)); } public static void remove(SlaveType type, Integer id) { Object object = get(type, id); if (null == object) { return; } conContain.remove(toKey(type, id)); } private static String toKey(SlaveType type, Integer id){ return type.toString() + _LINK + id; } } src/main/java/com/zy/core/network/ZyCrnConnectThread.java
New file @@ -0,0 +1,69 @@ package com.zy.core.network; import HslCommunication.Profinet.Siemens.SiemensS7Net; import com.zy.asrs.entity.DeviceConfig; import com.zy.core.ThreadHandler; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.CrnCommand; import com.zy.core.network.api.ZyCrnConnectApi; import com.zy.core.network.entity.ZyCrnStatusEntity; import com.zy.core.network.real.ZyCrnRealConnect; import lombok.extern.slf4j.Slf4j; @Slf4j public class ZyCrnConnectThread implements ThreadHandler{ private boolean connected = false; private SiemensS7Net siemensNet; private DeviceConfig deviceConfig; private ZyCrnConnectApi zyCrnConnectApi; public ZyCrnConnectThread(SiemensS7Net siemensS7Net, DeviceConfig deviceConfig) { this.siemensNet = siemensS7Net; this.deviceConfig = deviceConfig; } @Override @SuppressWarnings("InfiniteLoopStatement") public void run() { while (true) { try { if (!connected) { connect(); } Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } @Override public boolean connect() { if (deviceConfig.getFake() == 0) { zyCrnConnectApi = new ZyCrnRealConnect(siemensNet, deviceConfig); } boolean connect = zyCrnConnectApi.connect(); connected = connect; return connect; } @Override public void close() { zyCrnConnectApi.disconnect(); zyCrnConnectApi = null; connected = false; } public ZyCrnStatusEntity getStatus() { return zyCrnConnectApi.getStatus(); } public CommandResponse sendCommand(CrnCommand command) { return zyCrnConnectApi.sendCommand(command); } } src/main/java/com/zy/core/network/api/ZyCrnConnectApi.java
New file @@ -0,0 +1,17 @@ package com.zy.core.network.api; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.CrnCommand; import com.zy.core.network.entity.ZyCrnStatusEntity; public interface ZyCrnConnectApi { boolean connect(); boolean disconnect(); ZyCrnStatusEntity getStatus();//设备状态 CommandResponse sendCommand(CrnCommand command);//下发命令 } src/main/java/com/zy/core/network/entity/ZyCrnStatusEntity.java
New file @@ -0,0 +1,125 @@ package com.zy.core.network.entity; import lombok.Data; @Data public class ZyCrnStatusEntity { /** * 堆垛机号 */ private Integer crnNo; /** * 1 = 手动模式 * 2 = 自动模式 * 3 = 电脑模式 */ public Integer mode; /** * 异常码 */ public Integer alarm; /** * 任务号 */ public Integer taskNo = 0; /** * 堆垛机当前状态 * 0:空闲,无任务 * 1:取货定位中 * 2:取货中 * 3:取货完成,放货定位中 * 4:放货中 * 5:回原点中 * 6:反原点 * 7:库位移位 * 90:任务完成等待WCS确认 * 99:报警 */ public Integer status; /** * 堆垛机当前列号 */ public Integer bay; /** * 堆垛机当前层号 */ public Integer level; /** * 当前货叉位置 * 0 = 货叉原位 * 1 = 货叉在左侧 * 2 = 货叉在右侧 */ public Integer forkPos; /** * 当前载货台位置 * 0 = 下定位 * 1 = 上定位 */ public Integer liftPos; /** * 走行在定位 * 0 = 在定位 * 1 = 不在定位 */ public Integer walkPos; /** * 载货台有物 */ public Integer loaded; /** * X行走线速度m/min */ private Integer xSpeed; /** * Y行走线速度m/min */ private Integer ySpeed; /** * Z行走线速度m/min */ private Integer zSpeed; /** * 堆垛机累计走行距离km */ public Integer xDistance; /** * 堆垛机累计升降距离km */ public Integer yDistance; /** * 堆垛机累计走行时长h */ public Integer xDuration; /** * 堆垛机累计升降时长h */ public Integer yDuration; private Integer temp1; private Integer temp2; private Integer temp3; private Integer temp4; } src/main/java/com/zy/core/network/real/ZyCrnRealConnect.java
New file @@ -0,0 +1,231 @@ package com.zy.core.network.real; import HslCommunication.Core.Types.OperateResult; import HslCommunication.Core.Types.OperateResultExOne; import HslCommunication.Profinet.Siemens.SiemensS7Net; import com.alibaba.fastjson.JSON; import com.core.common.DateUtils; import com.core.common.SpringUtils; import com.zy.asrs.entity.BasCrnpOpt; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.service.BasCrnpOptService; import com.zy.asrs.utils.Utils; import com.zy.core.News; import com.zy.core.cache.OutputQueue; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.CrnCommand; import com.zy.core.network.api.ZyCrnConnectApi; import com.zy.core.network.entity.ZyCrnStatusEntity; import java.text.MessageFormat; import java.util.Date; public class ZyCrnRealConnect implements ZyCrnConnectApi { private SiemensS7Net siemensNet; private DeviceConfig deviceConfig; public ZyCrnRealConnect(SiemensS7Net siemensS7Net, DeviceConfig deviceConfig) { this.siemensNet = siemensS7Net; this.deviceConfig = deviceConfig; } public boolean connect() { boolean connected = false; OperateResult connect = siemensNet.ConnectServer(); if(connect.IsSuccess){ connected = true; OutputQueue.CRN.offer(MessageFormat.format( "【{0}】堆垛机plc连接成功 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.info("SiemensCrn"+" - 1"+" - 堆垛机plc连接成功 ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } else { OutputQueue.CRN.offer(MessageFormat.format("【{0}】堆垛机plc连接失败!!! ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.error("SiemensCrn"+" - 2"+" - 堆垛机plc连接失败!!! ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } // siemensNet.ConnectClose(); return connected; } @Override public boolean disconnect() { siemensNet.ConnectClose(); return true; } @Override public ZyCrnStatusEntity getStatus() { try { OperateResultExOne<byte[]> result = siemensNet.Read("DB101.0", (short) 56); if (result.IsSuccess) { ZyCrnStatusEntity crnStatus = new ZyCrnStatusEntity(); crnStatus.setCrnNo(deviceConfig.getDeviceNo()); crnStatus.setMode((int) siemensNet.getByteTransform().TransInt16(result.Content, 0)); crnStatus.setTaskNo((int) siemensNet.getByteTransform().TransInt16(result.Content, 2)); crnStatus.setStatus((int) siemensNet.getByteTransform().TransInt16(result.Content, 4)); crnStatus.setBay((int) siemensNet.getByteTransform().TransInt16(result.Content, 6)); crnStatus.setLevel((int) siemensNet.getByteTransform().TransInt16(result.Content, 8)); crnStatus.setForkPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 10)); crnStatus.setLiftPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 12)); crnStatus.setWalkPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 14)); crnStatus.setLoaded((int) siemensNet.getByteTransform().TransInt16(result.Content, 16)); crnStatus.setAlarm((int) siemensNet.getByteTransform().TransInt16(result.Content, 18)); crnStatus.setTemp1((int) siemensNet.getByteTransform().TransInt16(result.Content, 20)); crnStatus.setTemp2((int) siemensNet.getByteTransform().TransInt16(result.Content, 22)); crnStatus.setTemp3((int) siemensNet.getByteTransform().TransInt16(result.Content, 24)); crnStatus.setTemp4((int) siemensNet.getByteTransform().TransInt16(result.Content, 26)); crnStatus.setXSpeed((int) siemensNet.getByteTransform().TransInt16(result.Content, 28)); crnStatus.setYSpeed((int) siemensNet.getByteTransform().TransInt16(result.Content, 32)); crnStatus.setZSpeed((int) siemensNet.getByteTransform().TransInt16(result.Content, 36)); crnStatus.setXDistance((int) siemensNet.getByteTransform().TransInt16(result.Content, 40)); crnStatus.setYDistance((int) siemensNet.getByteTransform().TransInt16(result.Content, 44)); crnStatus.setXDuration((int) siemensNet.getByteTransform().TransInt16(result.Content, 48)); crnStatus.setYDuration((int) siemensNet.getByteTransform().TransInt16(result.Content, 52)); return crnStatus; } else { OutputQueue.CRN.offer(MessageFormat.format("【{0}】读取堆垛机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.error("SiemensCrn"+" - 4"+" - 读取堆垛机plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } } catch (Exception e) { e.printStackTrace(); OutputQueue.CRN.offer(MessageFormat.format("【{0}】读取堆垛机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.error("SiemensCrn"+" - 5"+" - 读取堆垛机plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); } return null; } @Override public CommandResponse sendCommand(CrnCommand command) { CommandResponse response = new CommandResponse(false); try { if (null == command) { News.error("堆垛机写入命令为空"); response.setMessage("堆垛机写入命令为空"); return response; } int writeAck = 0; boolean ackResult = false; do { OperateResult resultAck = siemensNet.Write("DB100.0", (short) 0); if (resultAck.IsSuccess) { Thread.sleep(200); OperateResultExOne<byte[]> resultRead = siemensNet.Read("DB100.0", (short) 2); short ack = siemensNet.getByteTransform().TransInt16(resultRead.Content, 0); if (ack != 0) { writeAck++; } else { News.info("堆垛机命令下发[id:{}] >>>>> {}", command.getCrnNo(), "ack复位完成"); ackResult = true; break; } } } while (writeAck < 5); if (!ackResult) { response.setMessage("堆垛机命令下发[id:{}] >>>>> {}" + command.getCrnNo() + "ack复位失败"); return response; } short[] array = new short[10]; array[0] = command.getAckFinish(); array[1] = command.getTaskNo(); array[2] = command.getTaskMode(); array[3] = command.getSourcePosX(); array[4] = command.getSourcePosY(); array[5] = command.getSourcePosZ(); array[6] = command.getDestinationPosX(); array[7] = command.getDestinationPosY(); array[8] = command.getDestinationPosZ(); array[9] = command.getCommand(); OperateResult result = null; int idx = 0; do { OperateResultExOne<byte[]> resultRead = siemensNet.Read("DB100.0", (short) 20); if (resultRead.IsSuccess) { if (command.getAckFinish() == 0) { short taskNo = siemensNet.getByteTransform().TransInt16(resultRead.Content, 2); short taskMode = siemensNet.getByteTransform().TransInt16(resultRead.Content, 4); short sourcePosX = siemensNet.getByteTransform().TransInt16(resultRead.Content, 6); short sourcePosY = siemensNet.getByteTransform().TransInt16(resultRead.Content, 8); short sourcePosZ = siemensNet.getByteTransform().TransInt16(resultRead.Content, 10); short destinationPosX = siemensNet.getByteTransform().TransInt16(resultRead.Content, 12); short destinationPosY = siemensNet.getByteTransform().TransInt16(resultRead.Content, 14); short destinationPosZ = siemensNet.getByteTransform().TransInt16(resultRead.Content, 16); if (taskNo == 0 || taskMode == 0 || sourcePosX == 0 || sourcePosY == 0 || sourcePosZ == 0 || destinationPosX == 0 || destinationPosY == 0 || destinationPosZ == 0) { result = siemensNet.Write("DB100.0", array); } else { break; } } else { short ackFinish = siemensNet.getByteTransform().TransInt16(resultRead.Content, 0); if (ackFinish != command.getAckFinish()) { result = siemensNet.Write("DB100.0", array); } else { break; } } } idx++; Thread.sleep(500L); } while (idx < 5); if (command.getAckFinish() == 0) { short commandFinish = 1; int i = 0; do { OperateResultExOne<byte[]> resultRead = siemensNet.Read("DB100.0", (short) 4); OperateResultExOne<byte[]> resultReadConfirm = siemensNet.Read("DB100.18", (short) 2); if (resultRead.IsSuccess && resultReadConfirm.IsSuccess) { short taskNo = siemensNet.getByteTransform().TransInt16(resultRead.Content, 2); short confirm = siemensNet.getByteTransform().TransInt16(resultReadConfirm.Content, 0); if (taskNo != 0 && confirm == 0) { result = siemensNet.Write("DB100.18", commandFinish); } } i++; Thread.sleep(500L); } while (i < 5); } if (result != null && result.IsSuccess) { News.info("SiemensCrn" + " - 7" + " - 堆垛机命令下发[id:{}] >>>>> {}", command.getCrnNo(), JSON.toJSON(command)); OutputQueue.CRN.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), command.getCrnNo(), JSON.toJSON(command))); response.setResult(true); response.setMessage("命令下发成功"); } else { News.error("SiemensCrn" + " - 8" + " - 写入堆垛机plc数据失败 ===>> [id:{}]", command.getCrnNo()); OutputQueue.CRN.offer(MessageFormat.format("【{0}】写入堆垛机plc数据失败 ===>> [id:{1}]", DateUtils.convert(new Date()), command.getCrnNo())); response.setResult(false); response.setMessage("命令下发失败"); } return response; } catch (Exception e) { e.printStackTrace(); }finally { String sourceLocNo = Utils.getLocNo(command.getSourcePosX(), command.getSourcePosY(), command.getSourcePosZ()); String targetLocNo = Utils.getLocNo(command.getDestinationPosX(), command.getDestinationPosY(), command.getDestinationPosZ()); // 日志记录 BasCrnpOptService bean = SpringUtils.getBean(BasCrnpOptService.class); BasCrnpOpt basCrnpOpt = new BasCrnpOpt( command.getTaskNo().intValue(), // 任务号 command.getCrnNo(), // 堆垛机[非空] new Date(), // 下发时间 String.valueOf(command.getTaskMode()), // 模式 sourceLocNo, //源库位 targetLocNo, //目标库位 null, // 修改时间 null, // 修改人员 null, // 备注 JSON.toJSONString(command), // 指令 JSON.toJSONString(command), // 系统状态 1, // 下发状态{0:未下发,1:已下发} JSON.toJSONString(response) // 响应 ); bean.insert(basCrnpOpt); } return response; } } src/main/java/com/zy/core/thread/CrnThread.java
@@ -1,10 +1,20 @@ package com.zy.core.thread; import com.zy.core.ThreadHandler; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.CrnCommand; import com.zy.core.model.protocol.CrnProtocol; public interface CrnThread extends ThreadHandler { CrnProtocol getCrnProtocol(); CrnProtocol getStatus(); CrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo);//取放货 CrnCommand getMoveCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo);//移动 CrnCommand getResetCommand(Integer crnNo);//复位 CommandResponse sendCommand(CrnCommand command);//下发命令 } src/main/java/com/zy/core/thread/ShuttleThread.java
File was deleted src/main/java/com/zy/core/thread/impl/NyShuttleThread.java
File was deleted src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java
New file @@ -0,0 +1,254 @@ package com.zy.core.thread.impl; import HslCommunication.Profinet.Siemens.SiemensPLCS; import HslCommunication.Profinet.Siemens.SiemensS7Net; 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.asrs.utils.Utils; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.ThreadHandler; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.OutputQueue; import com.zy.core.enums.CrnTaskModeType; import com.zy.core.enums.SlaveType; import com.zy.core.model.CommandResponse; import com.zy.core.model.Task; import com.zy.core.model.command.CrnCommand; import com.zy.core.model.protocol.CrnProtocol; import com.zy.core.network.DeviceConnectPool; import com.zy.core.network.ZyCrnConnectThread; import com.zy.core.network.entity.ZyCrnStatusEntity; import com.zy.core.thread.CrnThread; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.text.MessageFormat; import java.util.Date; /** * 堆垛机线程 * Created by vincent on 2020/8/4 */ @Data @Slf4j public class ZySiemensCrnThread implements Runnable, CrnThread { private DeviceConfig deviceConfig; private RedisUtil redisUtil; private ZyCrnConnectThread zyCrnConnectThread; private CrnProtocol crnProtocol; private boolean resetFlag = false; public ZySiemensCrnThread(DeviceConfig deviceConfig, RedisUtil redisUtil) { this.deviceConfig = deviceConfig; this.redisUtil = redisUtil; } @Override @SuppressWarnings("InfiniteLoopStatement") public void run() { this.connect(); this.initCrn(); while (true) { try { int step = 1; Task task = MessageQueue.poll(SlaveType.Crn, deviceConfig.getDeviceNo()); if (task != null) { step = task.getStep(); } switch (step) { // 读数据 case 1: readStatus(); break; default: break; } Thread.sleep(200); } catch (Exception e) { // e.printStackTrace(); } } } /** * 初始化堆垛机状态 */ private void initCrn() { if (null == crnProtocol) { crnProtocol = new CrnProtocol(); crnProtocol.setCrnNo(deviceConfig.getDeviceNo()); } crnProtocol.setMode(-1); crnProtocol.setTaskNo(0); crnProtocol.setStatus(-1); crnProtocol.setBay(0); crnProtocol.setLevel(0); crnProtocol.setForkPos(-1); crnProtocol.setLiftPos(-1); crnProtocol.setWalkPos(0); crnProtocol.setLoaded(0); crnProtocol.setAlarm(0); crnProtocol.setXSpeed(0); crnProtocol.setYSpeed(0); crnProtocol.setZSpeed(0); crnProtocol.setXDistance(0); crnProtocol.setYDistance(0); crnProtocol.setXDuration(0); crnProtocol.setYDuration(0); } @Override public boolean connect() { SiemensS7Net siemensS7Net = new SiemensS7Net(SiemensPLCS.S1200, deviceConfig.getIp()); ThreadHandler thread = new ZyCrnConnectThread(siemensS7Net, deviceConfig); new Thread(thread).start(); DeviceConnectPool.put(SlaveType.Crn, deviceConfig.getDeviceNo(), thread); return true; } /** * 读取状态 */ private void readStatus(){ ZyCrnStatusEntity crnStatus = zyCrnConnectThread.getStatus(); if (crnStatus == null) { OutputQueue.CRN.offer(MessageFormat.format("【{0}】读取堆垛机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); News.error("SiemensCrn"+" - 5"+" - 读取堆垛机plc状态信息失败 ===>> [id:{}] [ip:{}] [port:{}]", deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort()); return; } crnProtocol.setMode(crnStatus.getMode()); crnProtocol.setTaskNo(crnStatus.getTaskNo()); crnProtocol.setStatus(crnStatus.getStatus()); crnProtocol.setBay(crnStatus.getBay()); crnProtocol.setLevel(crnStatus.getLevel()); crnProtocol.setForkPos(crnStatus.getForkPos()); crnProtocol.setLiftPos(crnStatus.getLiftPos()); crnProtocol.setWalkPos(crnStatus.getWalkPos()); crnProtocol.setLoaded(crnStatus.getLoaded()); crnProtocol.setAlarm(crnStatus.getAlarm()); crnProtocol.setTemp1(crnStatus.getTemp1()); crnProtocol.setTemp2(crnStatus.getTemp2()); crnProtocol.setTemp3(crnStatus.getTemp3()); crnProtocol.setTemp4(crnStatus.getTemp4()); crnProtocol.setXSpeed(crnStatus.getXSpeed()); crnProtocol.setYSpeed(crnStatus.getYSpeed()); crnProtocol.setZSpeed(crnStatus.getZSpeed()); crnProtocol.setXDistance(crnStatus.getXDistance()); crnProtocol.setYDistance(crnStatus.getYDistance()); crnProtocol.setXDuration(crnStatus.getXDuration()); crnProtocol.setYDuration(crnStatus.getYDuration()); OutputQueue.CRN.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); // // 复位信号 // if (!Cools.isEmpty(crnProtocol.getStatusType()) && crnProtocol.getStatusType().equals(CrnStatusType.WAITING)) { // if (resetFlag) { // if(crnProtocol.getTaskNo()==9999){ // backHpFlag = false; // } // CrnCommand crnCommand = new CrnCommand(); // crnCommand.setAckFinish((short)1); // if (write(crnCommand)) { // resetFlag = false; // } // } // } if (crnProtocol.getAlarm() > 0) { crnProtocol.setLastCommandTime(-1L); } if (crnProtocol.getAlarm() == 0 && crnProtocol.getLastCommandTime() == -1) { crnProtocol.setLastCommandTime(System.currentTimeMillis()); } if (System.currentTimeMillis() - crnProtocol.getDeviceDataLog() > 1000 * 1) { //采集时间超过1s,保存一次数据记录 //保存数据记录 DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class); DeviceDataLog deviceDataLog = new DeviceDataLog(); deviceDataLog.setOriginData(JSON.toJSONString(crnStatus)); deviceDataLog.setWcsData(JSON.toJSONString(crnProtocol)); deviceDataLog.setType(String.valueOf(SlaveType.Crn)); deviceDataLog.setDeviceNo(crnProtocol.getCrnNo()); deviceDataLog.setCreateTime(new Date()); deviceDataLogService.insert(deviceDataLog); //更新采集时间 crnProtocol.setDeviceDataLog(System.currentTimeMillis()); } } @Override public void close() { zyCrnConnectThread.close(); } @Override public CrnProtocol getStatus() { return this.crnProtocol; } @Override public CrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo) { CrnCommand crnCommand = new CrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo.shortValue()); // 工作号 crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE.id.shortValue()); // 任务模式: 库位移转 crnCommand.setSourcePosX((short) Utils.getRow(sourceLocNo)); // 源库位排 crnCommand.setSourcePosY((short) Utils.getBay(sourceLocNo)); // 源库位列 crnCommand.setSourcePosZ((short) Utils.getLev(sourceLocNo)); // 源库位层 crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setCommand((short) 1); // 任务确认 return crnCommand; } @Override public CrnCommand getMoveCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo) { CrnCommand crnCommand = new CrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo.shortValue()); // 工作号 crnCommand.setAckFinish((short) 0); // 任务完成确认位 crnCommand.setTaskMode(CrnTaskModeType.CRN_MOVE.id.shortValue()); // 任务模式: 堆垛机移动 crnCommand.setSourcePosX((short) Utils.getRow(sourceLocNo)); // 源库位排 crnCommand.setSourcePosY((short) Utils.getBay(sourceLocNo)); // 源库位列 crnCommand.setSourcePosZ((short) Utils.getLev(sourceLocNo)); // 源库位层 crnCommand.setDestinationPosX((short) 0); // 目标库位排 crnCommand.setDestinationPosY((short) 0); // 目标库位列 crnCommand.setDestinationPosZ((short) 0); // 目标库位层 crnCommand.setCommand((short) 1); // 任务确认 return crnCommand; } @Override public CrnCommand getResetCommand(Integer crnNo) { CrnCommand crnCommand = new CrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo((short) 0); // 工作号 crnCommand.setAckFinish((short) 1); // 任务完成确认位 crnCommand.setTaskMode(CrnTaskModeType.NONE.id.shortValue()); // 任务模式 crnCommand.setSourcePosX((short)0); // 源库位排 crnCommand.setSourcePosY((short)0); // 源库位列 crnCommand.setSourcePosZ((short)0); // 源库位层 crnCommand.setDestinationPosX((short)0); // 目标库位排 crnCommand.setDestinationPosY((short)0); // 目标库位列 crnCommand.setDestinationPosZ((short)0); // 目标库位层 crnCommand.setCommand((short) 1); // 任务确认 return crnCommand; } @Override public synchronized CommandResponse sendCommand(CrnCommand command) { this.crnProtocol.setLastCommandTime(System.currentTimeMillis()); return zyCrnConnectThread.sendCommand(command); } } src/main/webapp/views/lift.html
File was deleted src/main/webapp/views/lift_old.html
File was deleted src/main/webapp/views/shuttle.html
File was deleted src/main/webapp/views/shuttle2.html
File was deleted src/main/webapp/views/shuttleNew.html
File was deleted src/main/webapp/views/shuttle_zs.html
File was deleted src/main/webapp/views/trafficControl.html
File was deleted