自动化立体仓库 - WCS系统
Junjie
2023-07-19 c605b435cb4be68de70c822162a96e9a78f45a88
src/main/java/com/zy/core/thread/LiftThread.java
@@ -5,29 +5,28 @@
import HslCommunication.Core.Types.OperateResultExOne;
import HslCommunication.ModBus.ModbusTcpNet;
import com.alibaba.fastjson.JSON;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.RadixTools;
import com.core.common.SpringUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasLift;
import com.zy.asrs.entity.BasLiftOpt;
import com.zy.asrs.entity.BasShuttle;
import com.zy.asrs.entity.BasShuttleOpt;
import com.zy.asrs.service.BasLiftOptService;
import com.zy.asrs.service.BasLiftService;
import com.zy.asrs.service.BasShuttleOptService;
import com.zy.asrs.service.BasShuttleService;
import com.zy.common.utils.CommonUtils;
import com.zy.common.utils.RedisUtil;
import com.zy.core.DevpThread;
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.cache.SlaveConnection;
import com.zy.core.enums.*;
import com.zy.core.model.LiftSlave;
import com.zy.core.model.Task;
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.StaProtocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -66,7 +65,7 @@
                switch (step) {
                    // 读数据
                    case 1:
                        readStatus();
                        read();
                        break;
                    // 写入数据
                    case 2:
@@ -112,9 +111,31 @@
        modbusTcpNet.ConnectClose();
    }
    private void read() {
        try {
            readStatus();
            //提升机处于运行状态,将标记置为true
            if (liftProtocol.getRunning()) {
                liftProtocol.setPakMk(true);
            }
            //提升机处于未运行、就绪、标记true、有任务号
            if (!liftProtocol.getRunning()
                    && liftProtocol.getPakMk()
                    && liftProtocol.getTaskNo() != 0) {
                //还有未完成的命令
                executeWork(liftProtocol.getTaskNo());
            }
        } catch (Exception e) {
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】提升机plc状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            initLift();
        }
    }
    private void readStatus() {
        try {
            OperateResultExOne<byte[]> result = modbusTcpNet.Read("29", (short) 50);
            OperateResultExOne<byte[]> result = modbusTcpNet.Read("41117", (short) 50);
            if (result.IsSuccess) {
                if (null == liftProtocol) {
                    liftProtocol = new LiftProtocol();
@@ -128,63 +149,53 @@
                liftProtocol.setLiftLock(CommonUtils.shortToBoolean(modbusTcpNet.getByteTransform().TransInt16(content, 0)));
                //位置到达反馈
                liftProtocol.setPositionArrivalFeedback(modbusTcpNet.getByteTransform().TransInt16(content,2));
                //准备就绪
                liftProtocol.setReady(CommonUtils.shortToBoolean(modbusTcpNet.getByteTransform().TransInt16(content,4)));
                //运行中
                liftProtocol.setRunning(CommonUtils.shortToBoolean(modbusTcpNet.getByteTransform().TransInt16(content,6)));
                //联机/单机
                liftProtocol.setMode(CommonUtils.shortToBoolean(modbusTcpNet.getByteTransform().TransInt16(content,8)));
                //以下参数并未进行调整(需要后续针对实机进行获取和调试)
                byte b1 = modbusTcpNet.getByteTransform().TransByte(content, 5);
                byte b2 = modbusTcpNet.getByteTransform().TransByte(content, 4);
                int[] datas1 = CommonUtils.byteToBits(b1);
                int[] datas2 = CommonUtils.byteToBits(b2);
                //准备就绪
                liftProtocol.setReady(CommonUtils.intToBoolean(datas1[0]));
                //运行中
                liftProtocol.setRunning(CommonUtils.intToBoolean(datas1[1]));
                //联机/单机
                liftProtocol.setMode(CommonUtils.intToBoolean(datas1[2]));
                //输送线前端光电有货
                liftProtocol.setLineFrontHasStock(modbusTcpNet.getByteTransform().TransBool(content,10));
                liftProtocol.setLineFrontHasStock(CommonUtils.intToBoolean(datas1[3]));
                //输送线正转反馈
                liftProtocol.setForwardRotationFeedback(modbusTcpNet.getByteTransform().TransBool(content,12));
                liftProtocol.setForwardRotationFeedback(CommonUtils.intToBoolean(datas1[4]));
                //输送线反转反馈
                liftProtocol.setReverseFeedback(modbusTcpNet.getByteTransform().TransBool(content,14));
                liftProtocol.setReverseFeedback(CommonUtils.intToBoolean(datas1[5]));
                //输送线电机过载
                liftProtocol.setMotorOverload(modbusTcpNet.getByteTransform().TransBool(content,16));
                liftProtocol.setMotorOverload(CommonUtils.intToBoolean(datas1[6]));
                //输送线末端光电有货
                liftProtocol.setLineEndHasStock(modbusTcpNet.getByteTransform().TransBool(content,18));
                liftProtocol.setLineEndHasStock(CommonUtils.intToBoolean(datas1[7]));
                //进输送线卡托盘报警
                liftProtocol.setInConveyLineCardTrayAlarm(modbusTcpNet.getByteTransform().TransBool(content,20));
                liftProtocol.setInConveyLineCardTrayAlarm(CommonUtils.intToBoolean(datas2[0]));
                //出输送线卡托盘报警
                liftProtocol.setOutConveyLineCardTrayAlarm(modbusTcpNet.getByteTransform().TransBool(content,22));
                liftProtocol.setOutConveyLineCardTrayAlarm(CommonUtils.intToBoolean(datas2[1]));
                //平台位置偏差报警
                liftProtocol.setPlatPositionDeviationAlarm(modbusTcpNet.getByteTransform().TransBool(content,24));
                liftProtocol.setPlatPositionDeviationAlarm(CommonUtils.intToBoolean(datas2[2]));
                //平台扭矩偏差报警
                liftProtocol.setPlatTorqueDeviationAlarm(modbusTcpNet.getByteTransform().TransBool(content,26));
                liftProtocol.setPlatTorqueDeviationAlarm(CommonUtils.intToBoolean(datas2[3]));
                //平台四向车检测
                liftProtocol.setPlatShuttleCheck(modbusTcpNet.getByteTransform().TransBool(content,28));
                liftProtocol.setPlatShuttleCheck(CommonUtils.intToBoolean(datas2[4]));
                //未就绪状态
                liftProtocol.setNotReady(modbusTcpNet.getByteTransform().TransInt16(content,30));
                liftProtocol.setNotReady(modbusTcpNet.getByteTransform().TransInt16(content,6));
                //伺服1错误
                liftProtocol.setServoError1(modbusTcpNet.getByteTransform().TransInt16(content,32));
                liftProtocol.setServoError1(modbusTcpNet.getByteTransform().TransInt16(content,8));
                //伺服2错误
                liftProtocol.setServoError2(modbusTcpNet.getByteTransform().TransInt16(content,34));
                liftProtocol.setServoError2(modbusTcpNet.getByteTransform().TransInt16(content,10));
                //伺服3错误
                liftProtocol.setServoError3(modbusTcpNet.getByteTransform().TransInt16(content,36));
                liftProtocol.setServoError3(modbusTcpNet.getByteTransform().TransInt16(content,12));
                //伺服4错误
                liftProtocol.setServoError4(modbusTcpNet.getByteTransform().TransInt16(content,38));
                liftProtocol.setServoError4(modbusTcpNet.getByteTransform().TransInt16(content,14));
                //提升机实际速度反馈
                liftProtocol.setLiftActualSpeed(modbusTcpNet.getByteTransform().TransInt16(content,40));
                liftProtocol.setLiftActualSpeed(modbusTcpNet.getByteTransform().TransInt16(content,16));
                ///读取提升机状态-end
                //小车处于运行状态,将标记置为true
                if (liftProtocol.getRunning()) {
                    liftProtocol.setPakMk(true);
                }
                //提升机处于锁定、未运行、就绪、标记true、有任务号
                if (liftProtocol.getLiftLock()
                        && !liftProtocol.getRunning()
                        && liftProtocol.getReady()
                        && liftProtocol.getPakMk()
                        && liftProtocol.getTaskNo() != 0) {
                    //还有未完成的命令
                    executeWork(liftProtocol.getTaskNo());
                }
                //将提升机状态保存至数据库
                BasLiftService liftService = SpringUtils.getBean(BasLiftService.class);
@@ -242,6 +253,54 @@
        }
        command.setLiftNo(slave.getId().shortValue());
        short[] array = getCommandArr(command);//获取命令报文
        try {
            Thread.sleep(1000);//命令下发前休眠1s
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        OperateResult result = modbusTcpNet.Write("41088", array);
        if (result != null && result.IsSuccess) {
            News.info("提升机命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            try {
                Thread.sleep(1000);//命令下发后休眠
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (int i = 0; i < 5; i++) {
                if (command.getRun().intValue() == 4 || command.getRun().intValue() == 5) {
                    break;//系统复位和链条停止转动不需要重发
                }
                readStatus();//重新读取状态
                if (liftProtocol.getRunning()) {
                    break;
                }
                //判断是否运行中,如不运行,重新下发命令
                result = modbusTcpNet.Write("41088", array);
                News.info("提升机命令下发[id:{}] >>>>> {},次数:{}", slave.getId(), JSON.toJSON(command), i);
                OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2},次数:{}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command), i));
                try {
                    Thread.sleep(3000);//命令下发后休眠
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            return true;
        } else {
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】写入提升机plc数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}],次数:{}", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("写入提升机plc数据失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            return false;
        }
    }
    //获取命令报文
    private short[] getCommandArr(LiftCommand command) {
        // 开始任务
        short[] array = new short[30];
        //开始运行
@@ -266,21 +325,23 @@
            //四层高度设定
            array[5] = command.getHeight4();
        }
        if (command.getHeight5() != null) {
            //四层高度设定
            array[6] = command.getHeight5();
        }
        if (command.getLiftLockShortValue() != null) {
            //提升机锁定
            array[29] = command.getLiftLockShortValue();
        }
        OperateResult result = modbusTcpNet.Write("0", array);;
        if (result != null && result.IsSuccess) {
            News.info("提升机命令下发[id:{}] >>>>> {}", slave.getId(), JSON.toJSON(command));
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] >>>>> 命令下发: {2}", DateUtils.convert(new Date()), slave.getId(), JSON.toJSON(command)));
            return true;
        } else {
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】写入提升机plc数据失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), slave.getId(), slave.getIp(), slave.getPort()));
            News.error("写入提升机plc数据失败 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
            return false;
        if (array[2] == 0) {
            // 开始任务
            short[] tmp = new short[2];
            tmp[0] = array[0];
            tmp[1] = array[1];
            array = tmp;
        }
        return array;
    }
    //分配任务
@@ -296,19 +357,25 @@
            }
            liftProtocol.setTaskNo(assignCommand.getTaskNo());
            switch (assignCommand.getTaskMode()) {
                case 1://上升一层
                    command = getLiftUpDownCommand(++lev);//获取提升机上升下降命令
                case 1://移动提升机
                    command = getLiftUpDownCommand(assignCommand.getLev());//获取提升机上升下降命令
                    break;
                case 2://下降一层
                    command = getLiftUpDownCommand(--lev);//获取提升机上升下降命令
                case 3://无货正转
                    command = getLiftTurnCommand(3);//获取提升机转动命令
                    break;
                case 3://有货正转
                case 4://无货反转
                    command = getLiftTurnCommand(4);//获取提升机转动命令
                    break;
                case 5://有货正转
                    command = getLiftTurnCommand(1);//获取提升机转动命令
                    break;
                case 4://有货反转
                case 6://有货反转
                    command = getLiftTurnCommand(2);//获取提升机转动命令
                    break;
                case 5://复位
                case 7://链条停止
                    command = getLiftTurnCommand(5);//获取提升机转动命令
                    break;
                case 0://复位
                    command = getResetCommand();//获取复位命令
                    break;
                default:
@@ -337,9 +404,6 @@
            return false;
        }
        //将标记置为false(防止重发)
        liftProtocol.setPakMk(false);
        Object o = redisUtil.get("lift_wrk_no_" + wrkNo);
        if (o == null) {
            return false;
@@ -352,14 +416,92 @@
        int size = commands.size();
        LiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        if (commandStep != 0) {
            //判断上一条指令是否完成
            LiftCommand command = commands.get(commandStep - 1);
            if (command.getRun().intValue() == 1) {
                //提升机升降命令
                if (command.getDistPosition().intValue() == liftProtocol.getPositionArrivalFeedback().intValue()) {
                    //提升机目标楼层和实际楼层相同,则认定命令完成
                    command.setComplete(true);
                }
            } else if (command.getRun().intValue() == 2 || command.getRun().intValue() == 3) {
                //无货正转,有货正转
                if (!liftProtocol.getForwardRotationFeedback()) {
                    //输送线正转反馈不在运行中,认定命令完成
                    command.setComplete(true);
                }
            } else if (command.getRun().intValue() == 6 || command.getRun().intValue() == 7) {
                //有货反转,无货反转
                if (!liftProtocol.getReverseFeedback()) {
                    //输送线反转反馈不在运行中,认定命令完成
                    command.setComplete(true);
                }
            } else if (command.getRun().intValue() == 4) {
                //输送线停止
                if (!liftProtocol.getForwardRotationFeedback() && !liftProtocol.getReverseFeedback()) {
                    //输送线正转反转都不在运行中,认定命令完成
                    command.setComplete(true);
                }
            }
            //任务数据保存到redis
            redisUtil.set("lift_wrk_no_" + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
            if (!command.getComplete()) {
                //上一条任务未完成,禁止下发命令
                return false;
            }
        }
        //取出命令
        LiftCommand command = commands.get(commandStep);
        if (command.getOperaStaNo() != null && command.getDevpId() != null) {
            //站点和输送线ID不为null,需要下发站点指令调度指定站点进行链条转动
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, command.getDevpId());
            StaProtocol staProtocol = devpThread.getStation().get(command.getOperaStaNo().intValue());
            if (!staProtocol.isLiftArrival()) {//链条转动条件,需要有提升机到位信号
                liftProtocol.setPakMk(true);
                return false;
            }
            staProtocol.setWorkNo(wrkNo);//设置任务号
            if (command.getStaNo() != null) {
                staProtocol.setStaNo(command.getStaNo());//设置目标站
            }
            if (command.getRotationDire() != null) {
                staProtocol.setRotationDire(command.getRotationDire());//站点链条转动信号
            }
            Integer devpId = command.getDevpId();
            boolean result1 = MessageQueue.offer(SlaveType.Devp, devpId, new Task(3, staProtocol));//下发命令使输送线链条运转
        }
        //下发命令
        if (!write(command)) {
            News.error("提升机命令下发失败,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
            return false;
        }else {
            News.info("提升机命令下发成功,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
            liftProtocol.setWrkTime(new Date());//更新工作时间
            //将标记置为false(防止重发)
            liftProtocol.setPakMk(false);
            //保存数据到数据库做流水
            BasLiftOptService liftOptService = SpringUtils.getBean(BasLiftOptService.class);
            if (liftOptService != null) {
                short[] commandArr = getCommandArr(command);//获取命令报文
                BasLiftOpt opt = new BasLiftOpt(
                        redisCommand.getWrkNo().intValue(),
                        redisCommand.getLiftNo().intValue(),
                        new Date(),
                        null,
                        null,
                        null,
                        JSON.toJSONString(command),
                        JSON.toJSONString(commandArr)
                );
                liftOptService.insert(opt);
            }
            //判断数据是否执行完成
            if (commandStep < size - 1) {
@@ -371,43 +513,12 @@
                redisUtil.set("lift_wrk_no_" + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
            }else {
                //已执行完成
                //保存数据到数据库做流水
                BasLiftOptService liftOptService = SpringUtils.getBean(BasLiftOptService.class);
                if (liftOptService != null) {
                    BasLiftOpt opt = new BasLiftOpt(
                            redisCommand.getWrkNo().intValue(),
                            redisCommand.getLiftNo().intValue(),
                            new Date(),
                            null,
                            null,
                            null,
                            JSON.toJSONString(assignCommand)
                    );
                    liftOptService.insert(opt);
                }
                //删除redis
                redisUtil.del("lift_wrk_no_" + redisCommand.getWrkNo());
                if (assignCommand.getAuto()) {
                    //对主线程抛出等待确认状态waiting
                    liftProtocol.setProtocolStatus(LiftProtocolStatusType.WAITING);
                    News.info("提升机任务执行完成等待确认中,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
                }else {
                    //手动模式不抛出等待状态
                    liftProtocol.setTaskNo((short) 0);
                    liftProtocol.setShuttleNo((short) 0);
                    liftProtocol.setProtocolStatus(LiftProtocolStatusType.IDLE);
                    liftProtocol.setPakMk(true);
                    liftProtocol.setSecurityMk(false);
                    News.info("提升机手动任务执行完成,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
                }
                //下发一条提升机解锁命令
                LiftCommand unlockCommand = getUnlockCommand(command.getLiftNo());
                if (write(unlockCommand)) {
                    News.info("提升机状态已解锁,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
                }
                //对主线程抛出等待确认状态waiting
                liftProtocol.setProtocolStatus(LiftProtocolStatusType.WAITING);
                News.info("提升机任务执行下发完成等待执行结束,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
            }
        }
@@ -417,7 +528,7 @@
    /**
     * 获取提升机解锁命令
     */
    private LiftCommand getUnlockCommand(Short liftNo) {
    public LiftCommand getUnlockCommand(Short liftNo) {
        LiftCommand command = new LiftCommand();
        command.setRun((short) 0);
        command.setLiftNo(liftNo);
@@ -428,9 +539,9 @@
    /**
     * 获取复位命令
     */
    private LiftCommand getResetCommand() {
    public LiftCommand getResetCommand() {
        LiftCommand command = new LiftCommand();
        command.setRun((short) 0);
        command.setRun((short) 5);
        command.setLiftLock(false);
        return command;
    }
@@ -438,19 +549,88 @@
    /**
     * 获取提升机上升下降命令
     */
    private LiftCommand getLiftUpDownCommand(Short lev) {
    public LiftCommand getLiftUpDownCommand(Integer lev) {
        LiftCommand command = new LiftCommand();
        command.setRun((short) 1);//升降
        command.setDistPosition(lev);
        Short position = LiftLevType.getRealLev(lev);//获取提升机实际楼层数值
        command.setDistPosition(position);
//        command.setSpeed((short) 200);
//        command.setHeight2((short) 180);
//        command.setHeight3((short) 1645);
//        command.setHeight4((short) (2 * 1645));
//        command.setHeight5((short) (3 * 1645));
        return command;
    }
    /**
     * 获取提升机上升下降命令
     */
    public LiftCommand getLiftUpDownCommand(Short liftNo, Short taskNo, Integer lev) {
        LiftCommand command = new LiftCommand();
        Short position = LiftLevType.getRealLev(lev);//获取提升机实际楼层数值
        command.setRun((short) 1);//升降
        command.setLiftNo(liftNo);//提升机号
        command.setTaskNo(taskNo);//任务号
        command.setDistPosition(position);//目标楼层
//        command.setSpeed((short) 200);
//        command.setHeight2((short) 180);
//        command.setHeight3((short) 1645);
//        command.setHeight4((short) 3290);
//        command.setHeight5((short) 4945);
        return command;
    }
    /**
     * 获取提升机转动命令,direction:1=》有货正转,2=》有货反转,3=>无货正转,4=>无货反转
     */
    public LiftCommand getLiftTurnCommand(Integer direction) {
        LiftCommand command = new LiftCommand();
        Short run = 0;
        switch (direction) {
            case 1:
                run = 6;//有货正转
                break;
            case 2:
                run = 3;//有货反转
                break;
            case 3:
                run = 2;//无货正转
                break;
            case 4:
                run = 7;//无货反转
                break;
            case 5:
                run = 4;//链条停止
        }
        command.setRun(run);
        return command;
    }
    /**
     * 获取提升机转动命令,direction:1=》有货正转,2=》有货反转
     */
    private LiftCommand getLiftTurnCommand(Integer direction) {
    public LiftCommand getLiftTurnCommand(Short liftNo, Short taskNo, Integer direction) {
        LiftCommand command = new LiftCommand();
        command.setRun(direction == 1 ? (short) 6 : (short) 3);
        Short run = 0;
        switch (direction) {
            case 1:
                run = 6;//有货正转
                break;
            case 2:
                run = 3;//有货反转
                break;
            case 3:
                run = 2;//无货正转
                break;
            case 4:
                run = 7;//无货反转
                break;
            case 5:
                run = 4;//链条停止
        }
        command.setRun(run);
        command.setLiftNo(liftNo);//提升机号
        command.setTaskNo(taskNo);//任务号
        return command;
    }
@@ -458,6 +638,7 @@
     * 初始化提升机
     */
    private void initLift() {
        this.connect();
        if (null == liftProtocol) {
            liftProtocol = new LiftProtocol();
        }