自动化立体仓库 - WCS系统
Junjie
2023-06-17 928bc386bea03b9d3157e6d66dcb7afc843e9964
src/main/java/com/zy/core/thread/ShuttleThread.java
@@ -8,19 +8,11 @@
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasDevp;
import com.zy.asrs.entity.BasShuttle;
import com.zy.asrs.entity.BasShuttleOpt;
import com.zy.asrs.entity.LocMast;
import com.zy.asrs.service.BasDevpService;
import com.zy.asrs.service.BasShuttleOptService;
import com.zy.asrs.service.BasShuttleService;
import com.zy.asrs.service.LocMastService;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.NavigateNode;
import com.zy.common.utils.CommonUtils;
import com.zy.common.utils.NavigatePositionConvert;
import com.zy.common.utils.NavigateUtils;
import com.zy.common.utils.RedisUtil;
import com.zy.common.utils.*;
import com.zy.core.News;
import com.zy.core.ThreadHandler;
import com.zy.core.cache.MessageQueue;
@@ -32,6 +24,7 @@
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.ShuttleProtocol;
import com.zy.core.model.protocol.StaProtocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -136,7 +129,7 @@
                //电池电量百分比
                shuttleProtocol.setBatteryPower(modbusTcpNet.getByteTransform().TransInt16(content,4));
                //电池温度
                shuttleProtocol.setBatteryTemp(modbusTcpNet.getByteTransform().TransInt16(content,6));
                shuttleProtocol.setBatteryTemp(modbusTcpNet.getByteTransform().TransUInt16(content, 6));
                //错误编号
                shuttleProtocol.setErrorCode(modbusTcpNet.getByteTransform().TransInt16(content,8));
                //Plc输出状态IO
@@ -157,7 +150,7 @@
                //读到的二维码Y方向偏移量
                shuttleProtocol.setCodeOffsetY(modbusTcpNet.getByteTransform().TransInt16(content,20));
                //当前的电压值
                shuttleProtocol.setCurrentVoltage(modbusTcpNet.getByteTransform().TransInt16(content,22));
                shuttleProtocol.setCurrentVoltage(modbusTcpNet.getByteTransform().TransUInt16(content, 22));
                //当前的模拟量值
                shuttleProtocol.setCurrentAnalogValue(modbusTcpNet.getByteTransform().TransInt16(content,24));
                //当前的升降伺服速度
@@ -176,18 +169,18 @@
                    shuttleProtocol.setPakMk(true);
                }
                if (shuttleProtocol.getErrorCode() != 0 && shuttleProtocol.getProtocolStatusType() == ShuttleProtocolStatusType.WORKING) {
                    //出现错误
                    resetAndTryFix(shuttleProtocol.getTaskNo());
                }
                if(shuttleProtocol.getProtocolStatusType() == ShuttleProtocolStatusType.FIXING
                        && shuttleProtocol.getTaskNo() != 0
                        && shuttleProtocol.getBusyStatusType() == ShuttleStatusType.IDLE){
                    //处于故障修复状态
                    //执行下一步指令
                    executeWork(shuttleProtocol.getTaskNo());
                }
//                if (shuttleProtocol.getErrorCode() != 0 && shuttleProtocol.getProtocolStatusType() == ShuttleProtocolStatusType.WORKING) {
//                    //出现错误
//                    resetAndTryFix(shuttleProtocol.getTaskNo());
//                }
//
//                if(shuttleProtocol.getProtocolStatusType() == ShuttleProtocolStatusType.FIXING
//                        && shuttleProtocol.getTaskNo() != 0
//                        && shuttleProtocol.getBusyStatusType() == ShuttleStatusType.IDLE){
//                    //处于故障修复状态
//                    //执行下一步指令
//                    executeWork(shuttleProtocol.getTaskNo());
//                }
                //四向穿梭车空闲、有任务、标记为true、存在任务指令,需要执行任务的下一条指令
                if (shuttleProtocol.getBusyStatusType() == ShuttleStatusType.IDLE
@@ -197,22 +190,22 @@
                    executeWork(shuttleProtocol.getTaskNo());
                }
                //检测是否有提升机锁定标记,有则检测提升机是否到位,是否能走下一步命令
                if (shuttleProtocol.getBusyStatusType() == ShuttleStatusType.IDLE
                        && shuttleProtocol.getTaskNo() != 0) {
                    Object o = redisUtil.get("wrk_no_" + shuttleProtocol.getTaskNo());
                    if (o != null) {
                        ShuttleRedisCommand redisCommand = JSON.parseObject(o.toString(), ShuttleRedisCommand.class);
                        if (redisCommand.getLiftSecurityMk()) {
                            //执行下一步指令
                            executeWork(shuttleProtocol.getTaskNo());
                        }
                    }
                }
//                //检测是否有提升机锁定标记,有则检测提升机是否到位,是否能走下一步命令
//                if (shuttleProtocol.getBusyStatusType() == ShuttleStatusType.IDLE
//                        && shuttleProtocol.getTaskNo() != 0) {
//                    Object o = redisUtil.get("shuttle_wrk_no_" + shuttleProtocol.getTaskNo());
//                    if (o != null) {
//                        ShuttleRedisCommand redisCommand = JSON.parseObject(o.toString(), ShuttleRedisCommand.class);
//                        if (redisCommand.getLiftSecurityMk()) {
//                            //执行下一步指令
//                            executeWork(shuttleProtocol.getTaskNo());
//                        }
//                    }
//                }
                //将四向穿梭车状态保存至数据库
                BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class);
                BasShuttle basShuttle = shuttleService.selectById(shuttleProtocol.getShuttleNo());
                BasShuttle basShuttle = shuttleService.selectById(slave.getId());
                if (basShuttle == null) {
                    basShuttle = new BasShuttle();
                    //四向穿梭车号
@@ -393,10 +386,28 @@
    //分配任务
    private void assignWork(ShuttleAssignCommand assignCommand) {
        ShuttleRedisCommand redisCommand = new ShuttleRedisCommand();
        if (!assignCommand.getAuto()) {
            List<NavigateNode> allNode = new ArrayList<>();
            List<ShuttleCommand> commands = new ArrayList<>();
            ShuttleCommand command = new ShuttleCommand();
            LocMastService locMastService = SpringUtils.getBean(LocMastService.class);
            BasShuttleService shuttleService = SpringUtils.getBean(BasShuttleService.class);
            NavigateMapData navigateMapData;
            //获取小车移动速度
            BasShuttle basShuttle = shuttleService.selectById(slave.getId());
            Integer runSpeed = 1000;
            if (basShuttle != null) {
                Integer runSpeed1 = basShuttle.getRunSpeed();
                if (runSpeed1 != null) {
                    runSpeed = runSpeed1;
                }
            }
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, 1);
            LiftProtocol liftProtocol = liftThread.getLiftProtocol();
            switch (assignCommand.getTaskMode()) {
                case 1://入库
                case 2://出库
@@ -404,231 +415,208 @@
                    //计算小车起点到中点所需命令
                    LocMast currentLocMast = locMastService.queryByQrCode(shuttleProtocol.getCurrentCode().toString());
                    List<NavigateNode> firstMastResult = NavigateUtils.calc(currentLocMast.getLocNo(), assignCommand.getSourceLocNo(), ShuttleTaskModeType.PAK_IN.id);
                    if (firstMastResult != null) {
                        allNode.addAll(firstMastResult);//将节点进行保存
                        //获取分段路径
                        ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(firstMastResult);
                        //将每一段路径分成command指令
                        for (ArrayList<NavigateNode> nodes : data) {
                            //开始路径
                            NavigateNode startPath = nodes.get(0);
                            //中间路径
                            NavigateNode middlePath = nodes.get(nodes.size() - 2);
                            //目标路径
                            NavigateNode endPath = nodes.get(nodes.size() - 1);
                            Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离
                            Integer middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes);//计算中间点到目标点行走距离
                            ShuttleCommand command1 = new ShuttleCommand();
                            command1.setCommandWord((short) 1);
                            command1.setStartCodeNum(NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), 1));
                            command1.setMiddleCodeNum((short) 1);
                            command1.setDistCodeNum(NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), 1));
                            command1.setStartToDistDistance(allDistance);
                            command1.setRunDirection(ShuttleRunDirection.get(startPath.getDirection()).id);
                            command1.setForceMoveDistance(0);
                            command1.setIOControl((short) 0);
                            command1.setRunSpeed((short) 1000);
                            command1.setCommandEnd((short) 1);
                            commands.add(command1);
                            //正常移动命令
                            Short startCode = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ());//开始二维码
                            Short middleCode = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ());//目标二维码
                            Short distCode = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ());//目标二维码
                            commands.add(getMoveCommand(startCode, distCode, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id, middleCode, middleToDistDistance, runSpeed));
                        }
                        //托盘顶升
                        ShuttleCommand command2 = new ShuttleCommand();
                        command2.setCommandWord((short) 2);
                        command2.setStartCodeNum((short) 0);
                        command2.setMiddleCodeNum((short) 0);
                        command2.setDistCodeNum((short) 0);
                        command2.setStartToDistDistance(0);
                        command2.setMiddleToDistDistance(0);
                        command2.setRunDirection((short) 0);
                        command2.setForceMoveDistance(0);
                        command2.setPalletLift((short) 1);
                        command2.setRunSpeed((short) 0);
                        command2.setCommandEnd((short) 1);
                        commands.add(command2);
                        commands.add(getPalletCommand((short) 1));
                    }else {
                        //没有计算到路径,可能存在小车位置就是起点位置
                        if (currentLocMast.getLocNo().equals(assignCommand.getSourceLocNo())) {
                            //小车位置就是起点位置,无需移动,直接顶升
                            //托盘顶升
                            ShuttleCommand command2 = new ShuttleCommand();
                            command2.setCommandWord((short) 2);
                            command2.setStartCodeNum((short) 0);
                            command2.setMiddleCodeNum((short) 0);
                            command2.setDistCodeNum((short) 0);
                            command2.setStartToDistDistance(0);
                            command2.setMiddleToDistDistance(0);
                            command2.setRunDirection((short) 0);
                            command2.setForceMoveDistance(0);
                            command2.setPalletLift((short) 1);
                            command2.setRunSpeed((short) 0);
                            command2.setCommandEnd((short) 1);
                            commands.add(command2);
                            commands.add(getPalletCommand((short) 1));
                        }
                    }
                    //计算中点到终点路径
                    List<NavigateNode> secMastResult = NavigateUtils.calc(assignCommand.getSourceLocNo(), assignCommand.getLocNo(), ShuttleTaskModeType.PAK_IN.id);
                    if (secMastResult != null) {
                        allNode.addAll(secMastResult);//将节点进行保存
                        //获取分段路径
                        ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(secMastResult);
                        //将每一段路径分成command指令
                        for (ArrayList<NavigateNode> nodes : data) {
                            //开始路径
                            NavigateNode startPath = nodes.get(0);
                            //中间路径
                            NavigateNode middlePath = nodes.get(nodes.size() - 2);
                            //目标路径
                            NavigateNode endPath = nodes.get(nodes.size() - 1);
                            Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离
                            Integer middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes);//计算中间点到目标点行走距离
                            ShuttleCommand command1 = new ShuttleCommand();
                            command1.setCommandWord((short) 1);
                            command1.setStartCodeNum(NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), 1));
                            command1.setMiddleCodeNum((short) 1);
                            command1.setDistCodeNum(NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), 1));
                            command1.setStartToDistDistance(allDistance);
                            command1.setRunDirection(ShuttleRunDirection.get(startPath.getDirection()).id);
                            command1.setForceMoveDistance(0);
                            command1.setIOControl((short) 0);
                            command1.setRunSpeed((short) 1000);
                            command1.setCommandEnd((short) 1);
                            commands.add(command1);
                            //正常移动命令
                            Short startCode = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ());//开始二维码
                            Short middleCode = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ());//中间二维码
                            Short distCode = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ());//目标二维码
                            commands.add(getMoveCommand(startCode, distCode, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id, middleCode, middleToDistDistance, runSpeed));
                        }
                        //托盘下降
                        ShuttleCommand command2 = new ShuttleCommand();
                        command2.setCommandWord((short) 2);
                        command2.setStartCodeNum((short) 0);
                        command2.setMiddleCodeNum((short) 0);
                        command2.setDistCodeNum((short) 0);
                        command2.setStartToDistDistance(0);
                        command2.setMiddleToDistDistance(0);
                        command2.setRunDirection((short) 0);
                        command2.setForceMoveDistance(0);
                        command2.setPalletLift((short) 2);
                        command2.setRunSpeed((short) 0);
                        command2.setCommandEnd((short) 1);
                        commands.add(command2);
                        commands.add(getPalletCommand((short) 2));
                    }
                    navigateMapData = new NavigateMapData(Utils.getLev(currentLocMast.getLocNo()));
                    if (firstMastResult != null) {
                        //所使用的路径进行锁定禁用
                        navigateMapData.writeNavigateNodeToRedisMap(firstMastResult, true);////所使用的路径进行锁定禁用
                    }
                    if (secMastResult != null) {
                        navigateMapData.writeNavigateNodeToRedisMap(secMastResult, true);////所使用的路径进行锁定禁用
                    }
                    break;
                case 3://托盘顶升
                case 4://托盘下降
                    command.setCommandWord((short) 2);
                    command.setStartCodeNum((short) 0);
                    command.setMiddleCodeNum((short) 0);
                    command.setDistCodeNum((short) 0);
                    command.setStartToDistDistance(0);
                    command.setMiddleToDistDistance(0);
                    command.setRunDirection((short) 0);
                    command.setForceMoveDistance(0);
                    command.setPalletLift(assignCommand.getTaskMode() == 3 ? (short)1 : (short)2);
                    command.setRunSpeed((short) 0);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                    commands.add(getPalletCommand(assignCommand.getTaskMode() == 3 ? (short) 1 : (short) 2));
                    break;
                case 5://强制左移
                    commands.add(getForceMoveCommand((short) 2));
                    break;
                case 6://强制右移
                    commands.add(getForceMoveCommand((short) 1));
                    break;
                case 7://强制上移
                    commands.add(getForceMoveCommand((short) 3));
                    break;
                case 8://强制下移
                    command.setCommandWord((short) 3);
                    command.setStartCodeNum((short) 0);
                    command.setMiddleCodeNum((short) 0);
                    command.setDistCodeNum((short) 0);
                    command.setStartToDistDistance(600);
                    command.setRunDirection((short) (assignCommand.getTaskMode() - 4));
                    command.setForceMoveDistance(600);
                    command.setIOControl((short) 0);
                    command.setCommandEnd((short) 1);
                    command.setRunSpeed((short) 1000);
                    commands.add(command);
                    commands.add(getForceMoveCommand((short) 4));
                    break;
                case 9://状态复位
                    command.setCommandWord((short) 6);
                    command.setStartCodeNum((short) 0);
                    command.setMiddleCodeNum((short) 0);
                    command.setDistCodeNum((short) 0);
                    command.setStartToDistDistance(0);
                    command.setMiddleToDistDistance(0);
                    command.setRunDirection((short) 0);
                    command.setPalletLift((short) 0);
                    command.setPalletLift((short) 0);
                    command.setForceMoveDistance(0);
                    command.setChargeSwitch((short) 0);
                    command.setIOControl((short) 0);
                    command.setRunSpeed((short) 0);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                    ShuttleCommand reset = getResetCommand();
                    commands.add(reset);
                    break;
                case 10://向正方向(左)寻库位
                    command.setCommandWord((short) 4);
                    command.setRunDirection((short) 1);
                    command.setStartToDistDistance(3000);
                    command.setRunSpeed((short) 1000);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                case 10://正方向(右)寻库位
                    commands.add(getFindLocCommand((short) 1));
                    break;
                case 11://向负方向(右)寻库位
                    command.setCommandWord((short) 4);
                    command.setRunDirection((short) 2);
                    command.setStartToDistDistance(3000);
                    command.setRunSpeed((short) 1000);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                case 11://负方向(左)寻库位
                    commands.add(getFindLocCommand((short) 2));
                    break;
                case 12://向正方向(前)寻库位
                    command.setCommandWord((short) 4);
                    command.setRunDirection((short) 4);
                    command.setStartToDistDistance(3000);
                    command.setRunSpeed((short) 1000);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                    commands.add(getFindLocCommand((short) 4));
                    break;
                case 13://向负方向(后)寻库位
                    command.setCommandWord((short) 4);
                    command.setRunDirection((short) 3);
                    command.setStartToDistDistance(3000);
                    command.setRunSpeed((short) 1000);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                    commands.add(getFindLocCommand((short) 3));
                    break;
                case 14://移动到目标库位
                    LocMast locMast = locMastService.queryByQrCode(shuttleProtocol.getCurrentCode().toString());
                    String startQr = shuttleProtocol.getCurrentCode().toString();//起始位置
                    //如果穿梭车在提升机内,移动时需要先下发出提升机命令
                    if (liftProtocol.getBarcode().intValue() == shuttleProtocol.getCurrentCode().intValue()) {
                        //穿梭车出提升机
                        Short liftArrival = liftProtocol.getPositionArrivalFeedback();//提升机位置反馈
                        String liftSiteLocNo = Utils.liftArrivalToOutInStaLocNo(liftArrival);
                        LocMast locMast1 = locMastService.selectById(liftSiteLocNo);
                        ShuttleCommand moveCommand = getMoveCommand(liftProtocol.getBarcode(), Short.parseShort(locMast1.getQrCodeValue()), 1400, ShuttleRunDirection.BOTTOM.id, liftProtocol.getBarcode(), 1400, runSpeed);
                        commands.add(moveCommand);
                        //起始位置修改为提升机口站点位置
                        startQr = locMast1.getQrCodeValue();
                    }
                    LocMast locMast = locMastService.queryByQrCode(startQr);
                    List<NavigateNode> result = NavigateUtils.calc(locMast.getLocNo(), assignCommand.getLocNo(), ShuttleTaskModeType.PAK_IN.id);
                    if (result != null) {
                        //所使用的路径进行锁定禁用
                        navigateMapData = new NavigateMapData(Utils.getLev(locMast.getLocNo()));
                        navigateMapData.writeNavigateNodeToRedisMap(result, true);////所使用的路径进行锁定禁用
                        allNode.addAll(result);//将节点进行保存
                        //获取分段路径
                        ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(result);
                        //将每一段路径分成command指令
                        for (ArrayList<NavigateNode> nodes : data) {
                            //开始路径
                            NavigateNode startPath = nodes.get(0);
                            //中间路径
                            NavigateNode middlePath = nodes.get(nodes.size() - 2);
                            //目标路径
                            NavigateNode endPath = nodes.get(nodes.size() - 1);
                            Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离
                            LocMast distLocMast = locMastService.queryByLoc(assignCommand.getLocNo());
                            String qrCodeValue = distLocMast.getQrCodeValue();
                            command.setCommandWord((short) 1);
                            command.setStartCodeNum(shuttleProtocol.getCurrentCode());
                            command.setMiddleCodeNum((short) 1);
                            command.setDistCodeNum((short) Integer.parseInt(qrCodeValue));
                            command.setStartToDistDistance(allDistance);
                            command.setRunSpeed((short) 1000);
                            command.setRunDirection(ShuttleRunDirection.get(startPath.getDirection()).id);
                            command.setForceMoveDistance(0);
                            command.setIOControl((short) 0);
                            command.setCommandEnd((short) 1);
                            commands.add(command);
                            Integer middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes);//计算中间点到目标点行走距离
                            Short startCode = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ());//开始二维码
                            Short middleCode = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ());//中间二维码
                            Short distCode = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ());//目标二维码
                            //正常移动命令
                            commands.add(getMoveCommand(startCode, distCode, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id, middleCode, middleToDistDistance, runSpeed));
                        }
                    }
                    break;
                case 15://充电开关
                    command.setCommandWord((short) 8);
                    command.setIOControl((short) 4);
                    command.setCommandEnd((short) 1);
                    commands.add(command);
                    commands.add(getChargeSwitchCommand());
                    break;
                case 16://移动到提升机
                    LocMast locMast1 = locMastService.queryByQrCode(shuttleProtocol.getCurrentCode().toString());
                    int lev = Utils.getLev(locMast1.getLocNo());//穿梭车当前高度
                    String liftSiteLocNo = Utils.levToOutInStaLocNo(lev);//当前楼层站点库位号
                    LocMast liftSitelocMast = locMastService.selectById(liftSiteLocNo);
                    List<NavigateNode> result1 = NavigateUtils.calc(locMast1.getLocNo(), liftSiteLocNo, ShuttleTaskModeType.PAK_IN.id);
                    Short endStartCode = null;
                    if (result1 != null) {
                        //所使用的路径进行锁定禁用
                        navigateMapData = new NavigateMapData(Utils.getLev(locMast1.getLocNo()));
                        navigateMapData.writeNavigateNodeToRedisMap(result1, true);////所使用的路径进行锁定禁用
                        allNode.addAll(result1);//将节点进行保存
                        //获取分段路径
                        ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(result1);
                        //将每一段路径分成command指令
                        for (ArrayList<NavigateNode> nodes : data) {
                            //开始路径
                            NavigateNode startPath = nodes.get(0);
                            //中间路径
                            NavigateNode middlePath = nodes.get(nodes.size() - 2);
                            //目标路径
                            NavigateNode endPath = nodes.get(nodes.size() - 1);
                            Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离
                            Integer middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes);//计算中间点到目标点行走距离
                            Short startCode = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ());//开始二维码
                            Short middleCode = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ());//中间二维码
                            Short distCode = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ());//目标二维码
                            endStartCode = distCode;
                            //正常移动命令
                            commands.add(getMoveCommand(startCode, distCode, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id, middleCode, middleToDistDistance, runSpeed));
                        }
                    }
                    if (endStartCode == null && shuttleProtocol.getCurrentCode() == Short.parseShort(liftSitelocMast.getQrCodeValue())) {
                        //穿梭车已经在提升机站点口
                        endStartCode = shuttleProtocol.getCurrentCode();
                    }
                    //增加移动进提升机命令
                    ShuttleCommand moveCommand = getMoveCommand(endStartCode, liftProtocol.getBarcode(), 1400, ShuttleRunDirection.TOP.id, endStartCode, 1400, runSpeed);
                    commands.add(moveCommand);
                    break;
                default:
            }
            assignCommand.setCommands(commands);
            assignCommand.setNodes(allNode);//当前任务所占用的节点list
        }
        ShuttleRedisCommand redisCommand = new ShuttleRedisCommand();
        redisCommand.setShuttleNo(assignCommand.getShuttleNo());//四向穿梭车号
        redisCommand.setWrkNo(assignCommand.getTaskNo());//工作号
        redisCommand.setCommandStep(0);//命令执行步序
@@ -638,7 +626,7 @@
        shuttleProtocol.setAssignCommand(assignCommand);
        shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.WORKING);
        //任务数据保存到redis
        redisUtil.set("wrk_no_" + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand));
        redisUtil.set("shuttle_wrk_no_" + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand));
        //执行下发任务
        executeWork(assignCommand.getTaskNo());
    }
@@ -650,7 +638,7 @@
            return false;
        }
        Object o = redisUtil.get("wrk_no_" + wrkNo);
        Object o = redisUtil.get("shuttle_wrk_no_" + wrkNo);
        if (o == null) {
            return false;
        }
@@ -683,7 +671,7 @@
                    commandStep--;
                    redisCommand.setCommandStep(commandStep);
                    //任务数据保存到redis
                    redisUtil.set("wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
                    redisUtil.set("shuttle_wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
                    shuttleProtocol.setPakMk(true);
                    return true;
                }else {
@@ -731,7 +719,7 @@
                errorCommands.remove(0);
                redisCommand.setErrorCommands(errorCommands);
                //任务数据保存到redis
                redisUtil.set("wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
                redisUtil.set("shuttle_wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
                return true;
            }
        }
@@ -755,12 +743,57 @@
            }
        }
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, 1);
        LiftProtocol liftProtocol = liftThread.getLiftProtocol();
        //判断小车当前二维码是否为提升机二维码
        if (shuttleProtocol.getCurrentCode().intValue() == liftProtocol.getBarcode().intValue()) {
            //小车当前命令起始位置就是提升机二维码,说明小车需要向提升机外移动,则需要判断状态是否满足
            if (command.getStartCodeNum().intValue() == liftProtocol.getBarcode().intValue()){
                //提升机是否空闲,提升机是否到达目标楼层,目标楼层是否给出提升机到位信号位
                if (!liftProtocol.isIdle()) {
                    return false;//提升机忙,禁止下发命令
                }
                Short distCodeNum = command.getDistCodeNum();//目标二维码
                BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class);
                BasDevp basDevp = basDevpService.queryByQrCode(distCodeNum.intValue());//目标站点
                if (basDevp == null) {
                    return false;//找不到目标站,禁止下发命令
                }
                int lev = Utils.getLev(basDevp.getLocNo());//目标二维码所在楼层
                int liftLev = liftProtocol.getLev().intValue();//提升机所在楼层
                if (liftLev != lev) {
                    return false;//提升机不在目标楼层,禁止下发命令
                }
                //获取目标站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, 1);
                StaProtocol staProtocol = devpThread.getStation().get(basDevp.getDevNo());
                if (staProtocol == null) {
                    return false;//站点信息不存在,禁止下发命令
                }
                if (!staProtocol.isLiftArrival()) {
                    return false;//站点提升机到位信号false,禁止下发命令
                }
            }
        }
        //下发命令
        if (!write(command)) {
            News.error("四向穿梭车命令下发失败,穿梭车号={},任务数据={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command));
            return false;
        } else {
            News.info("四向穿梭车命令下发成功,穿梭车号={},任务数据={}", shuttleProtocol.getShuttleNo(), JSON.toJSON(command));
            try {
                Thread.sleep(1000);//命令下发完后休眠1s
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //判断数据是否执行完成
            if (commandStep < size - 1) {
@@ -769,7 +802,7 @@
                commandStep++;
                redisCommand.setCommandStep(commandStep);
                //任务数据保存到redis
                redisUtil.set("wrk_no_" + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
                redisUtil.set("shuttle_wrk_no_" + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
            }else {
                //已执行完成
                //保存数据到数据库做流水
@@ -792,15 +825,20 @@
                if (redisCommand.getLiftSecurityMk()) {
                    //曾锁定过提升机,需要进行解锁
                    LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, 1);
                    LiftProtocol liftProtocol = liftThread.getLiftProtocol();
                    if (liftProtocol != null) {
                        liftProtocol.setSecurityMk(false);
                    }
                }
                String locNo = shuttleProtocol.getLocNo() == null ? shuttleProtocol.getSourceLocNo() : shuttleProtocol.getLocNo();
                if (locNo != null) {
                    //解除锁定的库位路径
                    NavigateMapData navigateMapData = new NavigateMapData(Utils.getLev(locNo));
                    navigateMapData.writeNavigateNodeToRedisMap(redisCommand.getAssignCommand().getNodes(), false);
                }
                //删除redis
                redisUtil.del("wrk_no_" + redisCommand.getWrkNo());
                redisUtil.del("shuttle_wrk_no_" + redisCommand.getWrkNo());
                if (!assignCommand.getAuto()) {
                    //手动模式不抛出等待状态,直接复位
@@ -836,7 +874,17 @@
            return false;
        }
        Object o = redisUtil.get("wrk_no_" + wrkNo);
        //拿到提升机线程
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, 1);
        if (liftThread == null) {
            return false;
        }
        LiftProtocol liftProtocol = liftThread.getLiftProtocol();
        if (liftProtocol == null) {
            return false;
        }
        Object o = redisUtil.get("shuttle_wrk_no_" + wrkNo);
        if (o == null) {
            return false;
        }
@@ -846,6 +894,21 @@
        //检测是否存在提升机口的指令
        List<ShuttleCommand> commands = redisCommand.getAssignCommand().getCommands();
        if (commands.size() > 0) {
            if (commands.get(commandStep).getCommandWord() != 1) {
                //不是行走命令,直接放行
                return true;
            }
            if (commands.get(0).getStartCodeNum() == null) {
                return false;
            }
            //命令起始位置就是提升机二维码,则不进行校验
            if (commands.get(0).getStartCodeNum().intValue() == liftProtocol.getBarcode().intValue()) {
                return true;
            }
        }
        BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class);
        ArrayList<Short> qrCodeValues = new ArrayList<>();
        for (BasDevp basDevp : basDevpService.selectList(null)) {
@@ -855,13 +918,18 @@
        //遍历所有指令,判断是否有到提升机口的指令,并获取到达该提升机口所需步序
        int step = 0;
        Integer siteNo = null;//站点号
        ShuttleCommand command = null;
        for (int i = 1; i < commands.size(); i++) {
        for (int i = 0; i < commands.size(); i++) {
            command = commands.get(i);
            if (qrCodeValues.contains(command.getDistCodeNum())) {
                //存在
                step = i + 1;
                break;
            for (Short qrCodeValue : qrCodeValues) {
                if (qrCodeValue.intValue() == command.getDistCodeNum().intValue()) {
                    //存在
                    step = i + 1;
                    BasDevp basDevp = basDevpService.queryByQrCode(qrCodeValue.intValue());
                    siteNo = basDevp.getDevNo();
                    break;
                }
            }
        }
@@ -876,65 +944,48 @@
            return true;
        }
        //拿到提升机线程
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, 1);
        if (liftThread == null) {
            return false;
        }
        LiftProtocol liftProtocol = liftThread.getLiftProtocol();
        if (liftProtocol == null) {
            return false;
        }
        //获取四向穿梭车当前楼层
        String shuttleLocNo = shuttleProtocol.getCurrentLocNo();//二维码对应库位号
        Integer shuttleLocNoLev = Integer.parseInt(shuttleLocNo.substring(shuttleLocNo.length() - 2, shuttleLocNo.length()));//库位号对应层高
        Integer shuttleLocNoLev = shuttleLocNo == null ? 0 : Utils.getLev(shuttleLocNo);//库位号对应层高
        //程序走到这,表示提升机可能一直就在当前层,可能经过了移动到达了该层
        if (liftProtocol.getProtocolStatusType() == LiftProtocolStatusType.WAITING) {
            //提升机等待确认
            //设置提升机为空闲状态
            liftProtocol.setProtocolStatus(LiftProtocolStatusType.IDLE);
            //任务号清零
            liftProtocol.setTaskNo((short) 0);
            //标记复位
            liftProtocol.setPakMk(true);
            //任务指令清零
            liftProtocol.setAssignCommand(null);
            //提升机解锁
            liftProtocol.setLiftLock(false);
        //判断穿梭车和提升机是否在目标楼层
        if (shuttleLocNoLev >= 2) {
            shuttleLocNoLev++;
        }
        //判断提升机是否在目标楼层
        if (liftProtocol.getLev().intValue() == shuttleLocNoLev) {
            //同一层,直接放行
            return true;
        //判断输送线站点是否给出提升机到位信号
        if (siteNo != null) {
            SiemensDevpThread siemensDevpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, 1);
            StaProtocol staProtocol = siemensDevpThread.getStation().get(siteNo);
            if (staProtocol.isLiftArrival()
                && liftProtocol.getPositionArrivalFeedback$() == shuttleLocNoLev) {
                //输送线反馈提升机到位且提升机楼层反馈为同一层,直接放行
                return true;
            }
        }
        //提升机和穿梭车处于不同楼层,需要进行调度
        if (!liftProtocol.isIdle()) {
            //提升机不是空闲
        if (liftProtocol.getRunning()) {
            //提升机运行中,禁止下发
            return false;
        }
        if (redisCommand.getLiftSecurityMk()) {
            //已经执行过提升机命令,禁止下发
            return false;
        }
        //给提升机分配任务
        liftProtocol.setLiftLock(true);//锁定提升机
        liftProtocol.setTaskNo(shuttleProtocol.getTaskNo());//设置任务号
        liftProtocol.setShuttleNo(shuttleProtocol.getShuttleNo());//设置四向穿梭车号
        liftProtocol.setProtocolStatus(LiftProtocolStatusType.WORKING);//设置提升机状态为工作中
        liftProtocol.setSecurityMk(true);//标记置为true,防止其他任务占用当前提升机
        redisCommand.setLiftSecurityMk(true);//标记置为true,防止其他任务占用当前提升机
        //任务数据保存到redis
        redisUtil.set("wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
        redisUtil.set("shuttle_wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
        //命令list
        ArrayList<LiftCommand> liftCommands = new ArrayList<>();
        LiftCommand liftCommand = new LiftCommand();
        liftCommand.setLiftNo(liftProtocol.getLiftNo());//提升机号
        liftCommand.setTaskNo(liftProtocol.getTaskNo());//任务号
        liftCommand.setRun((short) 1);//升降
        liftCommand.setDistPosition(shuttleLocNoLev.shortValue());//目标楼层(穿梭车所在楼层)
        liftCommand.setLiftLock(true);//锁定提升机
        LiftCommand liftCommand = liftThread.getLiftUpDownCommand(liftProtocol.getLiftNo(), liftProtocol.getTaskNo(), shuttleLocNoLev);
        liftCommands.add(liftCommand);//将命令添加进list
        LiftAssignCommand liftAssignCommand = new LiftAssignCommand();
@@ -956,7 +1007,7 @@
            return false;
        }
        Object o = redisUtil.get("wrk_no_" + wrkNo);
        Object o = redisUtil.get("shuttle_wrk_no_" + wrkNo);
        if (o == null) {
            return false;
        }
@@ -974,29 +1025,13 @@
        ShuttleCommand command = commands.get(commandStep - 1);
        //复位命令
        ShuttleCommand resetCommand = new ShuttleCommand();
        resetCommand.setCommandWord((short) 6);
        resetCommand.setStartCodeNum((short) 0);
        resetCommand.setMiddleCodeNum((short) 0);
        resetCommand.setDistCodeNum((short) 0);
        resetCommand.setStartToDistDistance(0);
        resetCommand.setMiddleToDistDistance(0);
        resetCommand.setRunDirection((short) 0);
        resetCommand.setPalletLift((short) 0);
        resetCommand.setPalletLift((short) 0);
        resetCommand.setForceMoveDistance(0);
        resetCommand.setChargeSwitch((short) 0);
        resetCommand.setIOControl((short) 0);
        resetCommand.setRunSpeed((short) 0);
        resetCommand.setCommandEnd((short) 1);
        ShuttleCommand resetCommand = getResetCommand();
        list.add(resetCommand);
        //车辆空闲,等待写入找库位命令
        //找库位命令
        ShuttleCommand searchCommand = new ShuttleCommand();
        searchCommand.setCommandWord((short) 4);
        short direction = 1;
        switch (command.getRunDirection()) {
        switch (command.getRunDirection()) {//转换运行方向
            case 1:
                direction = 2;
                break;
@@ -1012,11 +1047,8 @@
            default:
                direction = 1;
        }
        searchCommand.setRunDirection(direction);//运行方向
        searchCommand.setStartToDistDistance(1200);
        searchCommand.setRunSpeed((short) 1000);
        searchCommand.setCommandEnd((short) 1);
        //找库位命令
        ShuttleCommand searchCommand = getFindLocCommand(direction, 1200, (short) 1000);
        list.add(searchCommand);
        //移动车辆,需要在执行完寻找定位点后再执行
@@ -1027,11 +1059,143 @@
        redisCommand.setErrorCommands(list);
        //任务数据保存到redis
        redisUtil.set("wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
        redisUtil.set("shuttle_wrk_no_" + wrkNo, JSON.toJSONString(redisCommand));
        shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.FIXING);
        return true;
    }
    /**
     * 获取托盘顶升命令
     * @param lift 1顶升,2下降
     */
    public ShuttleCommand getPalletCommand(Short lift) {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 2);
        command.setStartCodeNum((short) 0);
        command.setMiddleCodeNum((short) 0);
        command.setDistCodeNum((short) 0);
        command.setStartToDistDistance(0);
        command.setMiddleToDistDistance(0);
        command.setRunDirection((short) 0);
        command.setForceMoveDistance(0);
        command.setPalletLift(lift);
        command.setRunSpeed((short) 0);
        command.setCommandEnd((short) 1);
        return command;
    }
    /**
     * 正常移动命令,默认移动速度1000
     */
    public ShuttleCommand getMoveCommand(Short startCodeNum, Short distCodeNum, Integer startToDistDistance, Short runDirection, Short middleCodeNum, Integer middleToDistDistance) {
        return getMoveCommand(startCodeNum, distCodeNum, startToDistDistance, runDirection, middleCodeNum, middleToDistDistance, 1000);
    }
    /**
     * 正常移动命令
     */
    public ShuttleCommand getMoveCommand(Short startCodeNum, Short distCodeNum, Integer startToDistDistance, Short runDirection, Short middleCodeNum, Integer middleToDistDistance, Integer runSpeed) {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 1);
        command.setStartCodeNum(startCodeNum);
        command.setMiddleCodeNum(middleCodeNum);
        command.setDistCodeNum(distCodeNum);
        command.setStartToDistDistance(startToDistDistance);
        command.setMiddleToDistDistance(middleToDistDistance);
        command.setRunDirection(runDirection);
        command.setForceMoveDistance(0);
        command.setIOControl((short) 0);
        command.setRunSpeed(runSpeed.shortValue());
        command.setCommandEnd((short) 1);
        return command;
    }
    /**
     * 强制移动命令
     * @param direction 移动方向 1左移,2右移,3前移,4后移
     */
    public ShuttleCommand getForceMoveCommand(Short direction) {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 3);
        command.setStartCodeNum((short) 0);
        command.setMiddleCodeNum((short) 0);
        command.setDistCodeNum((short) 0);
        command.setStartToDistDistance(600);
        command.setRunDirection(direction);
        command.setForceMoveDistance(600);
        command.setIOControl((short) 0);
        command.setCommandEnd((short) 1);
        command.setRunSpeed((short) 1000);
        return command;
    }
    /**
     * 状态复位命令
     */
    public ShuttleCommand getResetCommand() {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 6);
        command.setStartCodeNum((short) 0);
        command.setMiddleCodeNum((short) 0);
        command.setDistCodeNum((short) 0);
        command.setStartToDistDistance(0);
        command.setMiddleToDistDistance(0);
        command.setRunDirection((short) 0);
        command.setPalletLift((short) 0);
        command.setPalletLift((short) 0);
        command.setForceMoveDistance(0);
        command.setChargeSwitch((short) 0);
        command.setIOControl((short) 0);
        command.setRunSpeed((short) 0);
        command.setCommandEnd((short) 1);
        return command;
    }
    /**
     * 获取寻库位命令
     * @param direction 1:向正方向(左)寻库位,2:向负方向(右)寻库位,3:向负方向(后)寻库位,4:向正方向(前)寻库位
     */
    public ShuttleCommand getFindLocCommand(Short direction, Integer startToDistance, Short runSpeed) {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 4);
        command.setRunDirection(direction);
        command.setStartToDistDistance(startToDistance);
        command.setRunSpeed((short) runSpeed);
        command.setCommandEnd((short) 1);
        return command;
    }
    /**
     * 获取寻库位命令,默认移动距离3000,运行速度1000
     * @param direction 1:向正方向(左)寻库位,2:向负方向(右)寻库位,3:向负方向(后)寻库位,4:向正方向(前)寻库位
     */
    public ShuttleCommand getFindLocCommand(Short direction) {
        return getFindLocCommand(direction, 3000, (short) 1000);
    }
    /**
     * 获取充电开关命令
     */
    public ShuttleCommand getChargeSwitchCommand() {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 5);
        command.setChargeSwitch((short) 1);
        command.setCommandEnd((short) 1);
        return command;
    }
    /**
     * charge:1=>开始充电,2=>断开充电
     */
    public ShuttleCommand getChargeSwitchCommand(Short charge) {
        ShuttleCommand command = new ShuttleCommand();
        command.setCommandWord((short) 5);//充电
        command.setShuttleNo(shuttleProtocol.getShuttleNo());
        command.setChargeSwitch(charge);//开始充电
        command.setCommandEnd((short) 1);
        return command;
    }
    /******************************************************************************************/
    /**************************************** 测试专用 *****************************************/
    /*****************************************************************************************/