package com.zy.core.thread.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.DateUtils; import com.core.common.SpringUtils; import com.zy.asrs.entity.*; import com.zy.asrs.service.BasDualCrnpOptService; import com.zy.asrs.service.BasDualCrnpService; import com.zy.asrs.utils.Utils; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.cache.MessageQueue; import com.zy.core.cache.OutputQueue; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.*; import com.zy.core.model.CommandResponse; import com.zy.core.model.StationObjModel; import com.zy.core.model.Task; import com.zy.core.model.command.DualCrnCommand; import com.zy.core.model.param.SendDualCrnCommandParam; import com.zy.core.model.protocol.DualCrnProtocol; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.network.DeviceConnectPool; import com.zy.core.network.ZyDualCrnConnectDriver; import com.zy.core.network.entity.ZyDualCrnStatusEntity; import com.zy.core.thread.DualCrnThread; import com.zy.core.thread.StationThread; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.text.MessageFormat; import java.util.*; import com.zy.asrs.entity.BasDualCrnpErrLog; import com.zy.asrs.service.BasDualCrnpErrLogService; /** * 双工位堆垛机线程 */ @Data @Slf4j public class ZySiemensDualCrnThread implements Runnable, DualCrnThread { private DeviceConfig deviceConfig; private RedisUtil redisUtil; private ZyDualCrnConnectDriver zyDualCrnConnectDriver; private DualCrnProtocol crnProtocol; private int deviceLogCollectTime = 200; public ZySiemensDualCrnThread(DeviceConfig deviceConfig, RedisUtil redisUtil) { this.deviceConfig = deviceConfig; this.redisUtil = redisUtil; } @Override @SuppressWarnings("InfiniteLoopStatement") public void run() { this.connect(); this.initCrn(); Thread readThread = new Thread(() -> { while (true) { try { deviceLogCollectTime = Utils.getDeviceLogCollectTime(); readStatus(); Thread.sleep(50); } catch (Exception e) { log.error("DualCrnThread Fail", e); } } }); readThread.start(); Thread processThread = new Thread(() -> { while (true) { try { int step = 1; Task task = MessageQueue.poll(SlaveType.DualCrn, deviceConfig.getDeviceNo()); if (task != null) { step = task.getStep(); } if (step == 2) { List commandList = (List) task.getData(); redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + crnProtocol.getCrnNo(), JSON.toJSONString(commandList, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24); } else if (step == 3) { sendCommand((DualCrnCommand) task.getData()); } Thread.sleep(100); } catch (Exception e) { log.error("DualCrnProcess Fail", e); } } }); processThread.start(); Thread commandThread = new Thread(() -> { while (true) { try { if(crnProtocol.getMode() != DualCrnModeType.AUTO.id) { continue; } if(crnProtocol.getAlarm() != 0) { continue; } // if (crnProtocol.getLoaded() == 1 && crnProtocol.getLoadedTwo() == 1) { // Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo()); // if (wait != null) { // redisUtil.del(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo()); // } // } Object commandListObj = redisUtil.get(RedisKeyType.DUAL_CRN_COMMAND_.key + crnProtocol.getCrnNo()); if (commandListObj == null) { continue; } List commandList = JSON.parseArray(commandListObj.toString(), SendDualCrnCommandParam.class); List newCommandList = new ArrayList<>(); for (SendDualCrnCommandParam commandParam : commandList) { SendDualCrnCommandParam processed = processStation(commandParam); if(processed != null) { newCommandList.add(processed); } } redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + crnProtocol.getCrnNo(), JSON.toJSONString(newCommandList, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24); Thread.sleep(100); } catch (Exception e) { log.error("DualCrnCommand Fail", e); } } }); commandThread.start(); } private SendDualCrnCommandParam processStation(SendDualCrnCommandParam commandParam) { Integer station = commandParam.getStation(); Integer idx = commandParam.getCommandIdx(); List commandList = commandParam.getCommands(); if (idx >= commandList.size()) { return commandParam; } DualCrnCommand dualCommand = commandList.get(idx); boolean send = false; if (station == 1) { if (crnProtocol.getStatus().equals(DualCrnStatusType.FETCH_COMPLETE.id) || crnProtocol.getStatus().equals(DualCrnStatusType.IDLE.id) ) { send = true; } }else { if (crnProtocol.getStatusTwo().equals(DualCrnStatusType.FETCH_COMPLETE.id) || crnProtocol.getStatusTwo().equals(DualCrnStatusType.IDLE.id) ) { send = true; } } if (idx == 0) { if(send) { idx++; commandParam.setCommandIdx(idx); sendCommand(dualCommand); redisUtil.set(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo(), "lock", 5); } return commandParam; }else { if (dualCommand.getTaskMode() == DualCrnTaskModeType.PUT.id.shortValue()) { //等待下一个任务 Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo()); if (wait != null) { return commandParam; } Integer taskNo = dualCommand.getTaskNo(); Object outTaskStationInfoObj = redisUtil.get(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + taskNo); if (outTaskStationInfoObj != null) { //检测出口站是否可执行放货动作 StationObjModel stationObjModel = JSON.parseObject(outTaskStationInfoObj.toString(), StationObjModel.class); StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo()); if (stationThread == null) { return commandParam; } Map statusMap = stationThread.getStatusMap(); StationProtocol stationProtocol = statusMap.get(stationObjModel.getStationId()); if (stationProtocol == null) { return commandParam; } if (!stationProtocol.isAutoing()) { return commandParam; } if (stationProtocol.isLoading()) { return commandParam; } if (stationProtocol.getTaskNo() > 0) { return commandParam; } } } if(send) { idx++; commandParam.setCommandIdx(idx); sendCommand(dualCommand); } return commandParam; } } /** * 初始化堆垛机状态 */ private void initCrn() { if (null == crnProtocol) { crnProtocol = new DualCrnProtocol(); crnProtocol.setCrnNo(deviceConfig.getDeviceNo()); } crnProtocol.setMode(-1); //工位1 crnProtocol.setTaskNo(0); crnProtocol.setStatus(-1); crnProtocol.setBay(0); crnProtocol.setLevel(0); crnProtocol.setForkPos(-1); crnProtocol.setLoaded(0); crnProtocol.setWalkPos(0); crnProtocol.setLiftPos(0); //工位2 crnProtocol.setTaskNoTwo(0); crnProtocol.setStatusTwo(-1); crnProtocol.setBayTwo(0); crnProtocol.setLevelTwo(0); crnProtocol.setForkPosTwo(-1); crnProtocol.setLoadedTwo(0); crnProtocol.setWalkPosTwo(0); crnProtocol.setLiftPosTwo(0); crnProtocol.setAlarm(0); crnProtocol.setXSpeed(0D); crnProtocol.setYSpeed(0D); crnProtocol.setZSpeed(0D); crnProtocol.setXDistance(0D); crnProtocol.setYDistance(0D); crnProtocol.setXDuration(0D); crnProtocol.setYDuration(0D); BasDualCrnpService basDualCrnpService = null; try { basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class); }catch (Exception e){ } if (basDualCrnpService != null) { BasDualCrnp basDualCrnp = basDualCrnpService.selectOne(new EntityWrapper().eq("crn_no", deviceConfig.getDeviceNo())); if(basDualCrnp == null) { basDualCrnp = new BasDualCrnp(); basDualCrnp.setCrnNo(deviceConfig.getDeviceNo()); basDualCrnp.setStatus(1); basDualCrnp.setInEnable("N"); basDualCrnp.setOutEnable("N"); basDualCrnp.setMaxInTask(5); basDualCrnp.setMaxOutTask(5); basDualCrnp.setCreateTime(new Date()); basDualCrnpService.insert(basDualCrnp); } } } @Override public boolean connect() { zyDualCrnConnectDriver = new ZyDualCrnConnectDriver(deviceConfig); zyDualCrnConnectDriver.start(); DeviceConnectPool.put(SlaveType.Crn, deviceConfig.getDeviceNo(), zyDualCrnConnectDriver); return true; } /** * 读取状态 */ private void readStatus(){ ZyDualCrnStatusEntity crnStatus = zyDualCrnConnectDriver.getStatus(); if (crnStatus == null) { OutputQueue.DUAL_CRN.offer(MessageFormat.format("【{0}】读取双工位堆垛机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), deviceConfig.getDeviceNo(), deviceConfig.getIp(), deviceConfig.getPort())); return; } crnProtocol.setMode(crnStatus.getMode()); //工位1 crnProtocol.setTaskNo(crnStatus.getTaskNo()); crnProtocol.setStatus(crnStatus.getStatus()); crnProtocol.setForkPos(crnStatus.getForkPos()); crnProtocol.setLoaded(crnStatus.getLoaded()); crnProtocol.setTaskReceive(crnStatus.getTaskReceive()); //工位2 crnProtocol.setTaskNoTwo(crnStatus.getTaskNoTwo()); crnProtocol.setStatusTwo(crnStatus.getStatusTwo()); crnProtocol.setForkPosTwo(crnStatus.getForkPosTwo()); crnProtocol.setLoadedTwo(crnStatus.getLoadedTwo()); crnProtocol.setTaskReceiveTwo(crnStatus.getTaskReceiveTwo()); crnProtocol.setBay(crnStatus.getBay()); crnProtocol.setLevel(crnStatus.getLevel()); crnProtocol.setWalkPos(crnStatus.getWalkPos()); crnProtocol.setLiftPos(crnStatus.getLiftPos()); 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()); crnProtocol.setGoodsType(crnStatus.getGoodsType()); crnProtocol.setBarcode(crnStatus.getBarcode()); OutputQueue.DUAL_CRN.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); if (crnProtocol.getAlarm() > 0) { crnProtocol.setLastCommandTime(-1L); } if (crnProtocol.getAlarm() == 0 && crnProtocol.getLastCommandTime() == -1) { crnProtocol.setLastCommandTime(System.currentTimeMillis()); } if (System.currentTimeMillis() - crnProtocol.getDeviceDataLog() > deviceLogCollectTime) { //保存数据记录 DeviceDataLog deviceDataLog = new DeviceDataLog(); deviceDataLog.setOriginData(JSON.toJSONString(crnStatus)); deviceDataLog.setWcsData(JSON.toJSONString(crnProtocol)); deviceDataLog.setType(String.valueOf(SlaveType.DualCrn)); deviceDataLog.setDeviceNo(crnProtocol.getCrnNo()); deviceDataLog.setCreateTime(new Date()); redisUtil.set(RedisKeyType.DEVICE_LOG_KEY.key + System.currentTimeMillis(), deviceDataLog, 60 * 60 * 24); //更新采集时间 crnProtocol.setDeviceDataLog(System.currentTimeMillis()); } try { BasDualCrnpErrLogService errLogService = SpringUtils.getBean(BasDualCrnpErrLogService.class); if (errLogService != null) { String errFlagKey = RedisKeyType.DEVICE_ERR_ACTIVE_DUAL_CRN.key + crnProtocol.getCrnNo(); Object active = redisUtil.get(errFlagKey); if (crnProtocol.getAlarm() != null && crnProtocol.getAlarm() > 0) { if (active == null) { BasDualCrnpErrLog log = new BasDualCrnpErrLog(); Integer wrkNo = (crnProtocol.getTaskNo() != null && crnProtocol.getTaskNo() > 0) ? crnProtocol.getTaskNo() : crnProtocol.getTaskNoTwo(); log.setWrkNo(wrkNo); log.setStartTime(new Date()); log.setCrnNo(crnProtocol.getCrnNo()); log.setBarcode(crnProtocol.getBarcode()); log.setErrCode(crnProtocol.getAlarm()); log.setStatus(1); log.setCreateTime(new Date()); log.setSystemStatus(JSON.toJSONString(crnProtocol)); errLogService.insert(log); if (log.getId() != null) { redisUtil.set(errFlagKey, log.getId(), 60 * 60 * 24); } } } else { if (active != null) { Long id = Long.valueOf(String.valueOf(active)); BasDualCrnpErrLog update = new BasDualCrnpErrLog(); update.setId(id); update.setEndTime(new Date()); update.setStatus(2); update.setUpdateTime(new Date()); errLogService.updateById(update); redisUtil.del(errFlagKey); } } } } catch (Exception ignore) {} } @Override public void close() { if (zyDualCrnConnectDriver != null) { zyDualCrnConnectDriver.close(); } } @Override public DualCrnProtocol getStatus() { return this.crnProtocol; } @Override public DualCrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo, Integer station) { DualCrnCommand crnCommand = new DualCrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo); // 工作号 crnCommand.setTaskMode(DualCrnTaskModeType.TRANSFER.id); // 任务模式: 取放货 crnCommand.setSourcePosX(Utils.getRow(sourceLocNo)); // 源库位排 crnCommand.setSourcePosY(Utils.getBay(sourceLocNo)); // 源库位列 crnCommand.setSourcePosZ(Utils.getLev(sourceLocNo)); // 源库位层 crnCommand.setDestinationPosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setDestinationPosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setStation(station);//工位 crnCommand.setCommand(1); // 任务确认 return crnCommand; } @Override public DualCrnCommand getPickCommand(String targetLocNo, Integer taskNo, Integer crnNo, Integer station) { DualCrnCommand crnCommand = new DualCrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo); // 工作号 crnCommand.setTaskMode(DualCrnTaskModeType.PICK.id); // 任务模式: 取货 crnCommand.setSourcePosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setSourcePosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setSourcePosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setDestinationPosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setDestinationPosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setStation(station);//工位 crnCommand.setCommand(1); // 任务确认 return crnCommand; } @Override public DualCrnCommand getPutCommand(String targetLocNo, Integer taskNo, Integer crnNo, Integer station) { DualCrnCommand crnCommand = new DualCrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo); // 工作号 crnCommand.setTaskMode(DualCrnTaskModeType.PUT.id); // 任务模式: 放货 crnCommand.setSourcePosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setSourcePosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setSourcePosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setDestinationPosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setDestinationPosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setStation(station);//工位 crnCommand.setCommand(1); // 任务确认 return crnCommand; } @Override public DualCrnCommand getMoveCommand(String targetLocNo, Integer taskNo, Integer crnNo) { DualCrnCommand crnCommand = new DualCrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(taskNo); // 工作号 crnCommand.setTaskMode(DualCrnTaskModeType.MOVE.id); // 任务模式: 堆垛机移动 crnCommand.setSourcePosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setSourcePosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setSourcePosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setDestinationPosX(Utils.getRow(targetLocNo)); // 目标库位排 crnCommand.setDestinationPosY(Utils.getBay(targetLocNo)); // 目标库位列 crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo)); // 目标库位层 crnCommand.setCommand(1); // 任务确认 return crnCommand; } @Override public DualCrnCommand getResetCommand(Integer crnNo, Integer station) { DualCrnCommand crnCommand = new DualCrnCommand(); crnCommand.setCrnNo(crnNo); // 堆垛机编号 crnCommand.setTaskNo(0); // 工作号 crnCommand.setTaskMode(DualCrnTaskModeType.CONFIRM.id); // 任务模式: 确认 crnCommand.setSourcePosX(0); // 源库位排 crnCommand.setSourcePosY(0); // 源库位列 crnCommand.setSourcePosZ(0); // 源库位层 crnCommand.setDestinationPosX(0); // 目标库位排 crnCommand.setDestinationPosY(0); // 目标库位列 crnCommand.setDestinationPosZ(0); // 目标库位层 crnCommand.setStation(station);//工位 crnCommand.setCommand(1); // 任务确认 return crnCommand; } @Override public CommandResponse sendCommand(DualCrnCommand command) { this.crnProtocol.setLastCommandTime(System.currentTimeMillis()); CommandResponse response = null; try { response = zyDualCrnConnectDriver.sendCommand(command); return response; } finally { String sourceLocNo = Utils.getLocNo(command.getSourcePosX(), command.getSourcePosY(), command.getSourcePosZ()); String targetLocNo = Utils.getLocNo(command.getDestinationPosX(), command.getDestinationPosY(), command.getDestinationPosZ()); BasDualCrnpOptService bean = SpringUtils.getBean(BasDualCrnpOptService.class); ZyDualCrnStatusEntity statusEntity = zyDualCrnConnectDriver.getStatus(); BasDualCrnpOpt basDualCrnpOpt = new BasDualCrnpOpt( command.getTaskNo().intValue(), command.getCrnNo(), new Date(), String.valueOf(command.getTaskMode()), sourceLocNo, targetLocNo, null, null, null, JSON.toJSONString(command), JSON.toJSONString(statusEntity), 1, JSON.toJSONString(response) ); if (bean != null) { bean.insert(basDualCrnpOpt); } } } }