#
Junjie
17 小时以前 b63790fa580ea78777f16bff6bc79373d675dd10
#
10个文件已修改
3个文件已添加
683 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/service/impl/ForkMainServiceImpl.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java 164 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/NavigateSolution.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/MainProcess.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/action/LiftAction.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/dispatcher/ForkLiftDispatchUtils.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/dispatcher/LiftDispatchUtils.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/dispatcher/ShuttleDispatchUtils.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/LiftDeviceStatusType.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/WrkIoType.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/protocol/LiftProtocol.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/NyLiftThread.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/lift.html 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/ForkMainServiceImpl.java
@@ -15,11 +15,13 @@
import com.zy.core.action.ForkLiftAction;
import com.zy.core.action.ShuttleAction;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.dispatcher.ForkLiftDispatchUtils;
import com.zy.core.dispatcher.ShuttleDispatchUtils;
import com.zy.core.enums.*;
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.ForkLiftProtocol;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.model.protocol.ShuttleProtocol;
import com.zy.core.thread.ForkLiftThread;
import com.zy.core.thread.ShuttleThread;
@@ -35,7 +37,6 @@
/**
 * 立体仓库WCS系统主流程业务
 * Created by vincent on 2020/8/6
 */
@Slf4j
@Service("forkMainService")
@@ -62,8 +63,6 @@
    @Autowired
    private ConfigService configService;
    @Autowired
    private NavigateMapUtils navigateMapUtils;
    @Autowired
    private NavigateMapData navigateMapData;
    @Autowired
    private NavigateUtils navigateUtils;
@@ -79,6 +78,8 @@
    private BasShuttleChargeService basShuttleChargeService;
    @Autowired
    private DeviceConfigService deviceConfigService;
    @Autowired
    private ForkLiftDispatchUtils forkLiftDispatchUtils;
    /**
     * 初始化实时地图
@@ -897,7 +898,7 @@
                            News.error("提升机已确认且任务完成状态,复位失败,但未找到工作档。提升机号={},工作号={}", forkLiftProtocol.getLiftNo(), forkLiftProtocol.getWrkNo());
                        }
                    }else {
                        boolean checkPreviewDispatchForkLift = commonService.checkWorkNoContainMk(forkLiftProtocol.getWrkNo(), WrkIoType.FORKLIFT_MOVE.id);
                        boolean checkPreviewDispatchForkLift = commonService.checkWorkNoContainMk(forkLiftProtocol.getWrkNo(), WrkIoType.PREVIEW_LIFT_MOVE.id);
                        if (checkPreviewDispatchForkLift) {
                            //属于提升机预调度移动任务
                            //无工作档支撑,直接确认完成
@@ -1490,24 +1491,25 @@
                return false;
            }
            //获取源输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            //搜索最近且无故障提升机
            ForkLiftStaProtocol recentLiftStation = forkLiftDispatchUtils.getRecentLiftStation(shuttleProtocol.getShuttleNo(), Utils.getLev(wrkMast.getLocNo()));
            if(recentLiftStation == null) {
                News.info("{}号小车,{}目标库位,没有可用空闲输送站点", shuttleProtocol.getShuttleNo(), wrkMast.getLocNo());
                return false;
            }
            if (liftSta.getHasTray()) {
            if (recentLiftStation.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
            if (recentLiftStation.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在小车", wrkMast.getWrkNo());
                return false;
            }
            //获取目标输送站
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByLev(recentLiftStation.getLiftNo(), Utils.getLev(wrkMast.getLocNo()));
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
@@ -1529,7 +1531,7 @@
            assignCommand.setAuto(true);//自动模式
            //计算近点位置
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), recentLiftStation.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            if (endLocation == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车近点位置计算失败", wrkMast.getWrkNo());
                return false;
@@ -1554,6 +1556,8 @@
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_NEARBY.sts);//小车移动到提升机中  301.生成小车移库任务 ==> 302.小车移动至近点中
            wrkMast.setSourceStaNo(recentLiftStation.getStaNo());
            wrkMast.setStaNo(liftStaTarget.getStaNo());
            wrkMast.setModiTime(now);
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
@@ -2000,7 +2004,7 @@
            }
            //移动
            int workNo = commonService.getWorkNo(WrkIoType.FORKLIFT_MOVE.id);//获取任务号
            int workNo = commonService.getWorkNo(WrkIoType.PREVIEW_LIFT_MOVE.id);//获取任务号
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getMoveCommand(workNo, forkLiftProtocol.getLev(), Utils.getLev(wrkMast.getSourceLocNo()));
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -15,6 +15,7 @@
import com.zy.core.action.LiftAction;
import com.zy.core.action.ShuttleAction;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.dispatcher.LiftDispatchUtils;
import com.zy.core.dispatcher.ShuttleDispatchUtils;
import com.zy.core.enums.*;
import com.zy.core.model.command.*;
@@ -57,8 +58,6 @@
    @Autowired
    private ConfigService configService;
    @Autowired
    private NavigateMapUtils navigateMapUtils;
    @Autowired
    private NavigateMapData navigateMapData;
    @Autowired
    private NavigateUtils navigateUtils;
@@ -74,6 +73,8 @@
    private BasShuttleChargeService basShuttleChargeService;
    @Autowired
    private DeviceConfigService deviceConfigService;
    @Autowired
    private LiftDispatchUtils liftDispatchUtils;
    /**
     * 初始化实时地图
@@ -568,9 +569,9 @@
    }
    /**
     * 货叉提升机任务
     * 提升机任务
     */
    public synchronized void forkLiftIoExecute() {
    public synchronized void liftIoExecute() {
        try {
            //搜索是否有待处理的任务
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
@@ -844,61 +845,63 @@
    }
    /**
     * 货叉提升机任务完成
     * 提升机任务完成
     */
    public synchronized void forkLiftFinished() {
    public synchronized void liftFinished() {
        try {
            List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .eq("device_type", String.valueOf(SlaveType.ForkLift)));
            for (DeviceConfig device : forkliftList) {
            List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .eq("device_type", String.valueOf(SlaveType.Lift)));
            for (DeviceConfig device : liftList) {
                //获取提升机信息
                ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, device.getDeviceNo());
                if(forkLiftThread == null) {
                LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
                if(liftThread == null) {
                    continue;
                }
                ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
                if (forkLiftProtocol == null) {
                LiftProtocol liftProtocol = liftThread.getStatus();
                if (liftProtocol == null) {
                    continue;
                }
                //提升机为等待确认且空闲
                if (forkLiftProtocol.getProtocolStatus() == ForkLiftProtocolStatusType.WAITING.id
                        && forkLiftProtocol.getWrkNo() != 0
                if (liftProtocol.getProtocolStatus() == LiftProtocolStatusType.WAITING.id
                        && liftProtocol.getTaskNo() != 0
                ) {
                    //将任务档标记为完成
                    WrkMast wrkMast = wrkMastService.selectByWorkNo(forkLiftProtocol.getWrkNo());
                    WrkMast wrkMast = wrkMastService.selectByWorkNo(liftProtocol.getTaskNo());
                    if (wrkMast != null) {
                        if (wrkMast.getWrkSts() == WrkStsType.INBOUND_LIFT_RUN.sts) {
                            //3.提升机搬运中 ==> 4.提升机搬运完成
                            wrkMast.setWrkSts(WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts);
                            wrkMast.setLiftNo(null);//释放提升机
                            forkLiftThread.setSyncTaskNo(0);
                        }else if (wrkMast.getWrkSts() == WrkStsType.MOVE_NEARBY_COMPLETE.sts) {
                            //303.小车移动至近点完成 -- 调度提升机到小车层
                        } else if (wrkMast.getWrkSts() == WrkStsType.OUTBOUND_LIFT_RUN.sts) {
                            //104.提升机搬运中 ==> 109.出库完成
                            //304.提升机搬运中 ==> 109.出库完成
                            wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts);
                            wrkMast.setLiftNo(null);//释放提升机
                            forkLiftThread.setSyncTaskNo(0);
                            redisUtil.set(RedisKeyType.FORK_LIFT_PUT_COMPLETE.key + forkLiftProtocol.getLiftNo(), wrkMast.getWmsWrkNo(), 60 * 3);
                        } else if (wrkMast.getWrkSts() == WrkStsType.MOVE_LIFT_RUN.sts) {
                            //306.提升机搬运中 ==> 307.提升机搬运完成
                            wrkMast.setWrkSts(WrkStsType.MOVE_LIFT_RUN_COMPLETE.sts);
                            forkLiftThread.setSyncTaskNo(0);
                        } else {
                            News.error("提升机确认失败,提升机号={},工作号={}", liftProtocol.getLiftNo(), liftProtocol.getTaskNo());
                            return;
                        }
                        wrkMast.setModiTime(new Date());
                        if (wrkMastService.updateById(wrkMast)) {
                            forkLiftThread.reset();
                            News.info("提升机已确认且任务完成状态。提升机号={}", forkLiftProtocol.getLiftNo());
                            liftThread.reset();
                            News.info("提升机已确认且任务完成状态。提升机号={}", liftProtocol.getLiftNo());
                        } else {
                            News.error("提升机已确认且任务完成状态,复位失败,但未找到工作档。提升机号={},工作号={}", forkLiftProtocol.getLiftNo(), forkLiftProtocol.getWrkNo());
                            News.error("提升机已确认且任务完成状态,复位失败,但未找到工作档。提升机号={},工作号={}", liftProtocol.getLiftNo(), liftProtocol.getTaskNo());
                        }
                    }else {
                        boolean checkPreviewDispatchForkLift = commonService.checkWorkNoContainMk(forkLiftProtocol.getWrkNo(), WrkIoType.FORKLIFT_MOVE.id);
                        boolean checkPreviewDispatchForkLift = commonService.checkWorkNoContainMk(liftProtocol.getTaskNo(), WrkIoType.PREVIEW_LIFT_MOVE.id);
                        if (checkPreviewDispatchForkLift) {
                            //属于提升机预调度移动任务
                            //无工作档支撑,直接确认完成
                            forkLiftThread.setSyncTaskNo(0);
                            forkLiftThread.reset();
                            News.info("已确认提升机预调度移动任务。提升机号={}", forkLiftProtocol.getLiftNo());
                            liftThread.setSyncTaskNo(0);
                            liftThread.reset();
                            News.info("已确认提升机预调度移动任务。提升机号={}", liftProtocol.getLiftNo());
                        }
                    }
                }
@@ -1485,25 +1488,15 @@
                return false;
            }
            //获取源输送站
            LiftStaProtocol liftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在小车", wrkMast.getWrkNo());
            //搜索最近且无故障提升机
            LiftStaProtocol recentLiftStation = liftDispatchUtils.getRecentLiftStation(shuttleProtocol.getShuttleNo(), Utils.getLev(wrkMast.getLocNo()));
            if(recentLiftStation == null) {
                News.info("{}号小车,{}目标库位,没有可用空闲输送站点", shuttleProtocol.getShuttleNo(), wrkMast.getLocNo());
                return false;
            }
            //获取目标输送站
            LiftStaProtocol liftStaTarget = LiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
            if (liftStaTarget.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在小车", wrkMast.getWrkNo());
            LiftStaProtocol targetLiftSta = LiftUtils.getLiftStaByLev(recentLiftStation.getLiftNo(), Utils.getLev(wrkMast.getLocNo()));
            if(targetLiftSta == null) {
                return false;
            }
@@ -1514,7 +1507,7 @@
            assignCommand.setAuto(true);//自动模式
            //计算近点位置
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), recentLiftStation.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            if (endLocation == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车近点位置计算失败", wrkMast.getWrkNo());
                return false;
@@ -1523,6 +1516,8 @@
            //小车已在近点位置无需前往
            if (shuttleProtocol.getCurrentLocNo().equals(endLocation)) {
                wrkMast.setWrkSts(WrkStsType.MOVE_NEARBY_COMPLETE.sts);//小车移动到提升机中  301.生成小车移库任务 ==> 303.小车移动至近点完成
                wrkMast.setSourceStaNo(recentLiftStation.getStaNo());
                wrkMast.setStaNo(targetLiftSta.getStaNo());
                wrkMast.setModiTime(now);
                wrkMast.setSystemMsg("");//清空消息
                wrkMastService.updateById(wrkMast);
@@ -1539,6 +1534,8 @@
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_NEARBY.sts);//小车移动到提升机中  301.生成小车移库任务 ==> 302.小车移动至近点中
            wrkMast.setSourceStaNo(recentLiftStation.getStaNo());
            wrkMast.setStaNo(targetLiftSta.getStaNo());
            wrkMast.setModiTime(now);
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
@@ -1627,7 +1624,7 @@
                return false;
            }
            int targetLev = Utils.getLev(wrkMast.getLocNo());
            int targetLev = Utils.getLev(shuttleProtocol.getCurrentLocNo());
            if (liftProtocol.getLev() != targetLev) {
                //获取提升机命令
                LiftCommand liftCommand = liftThread.getMoveCommand(wrkMast.getWrkNo(), liftProtocol.getLev(), targetLev);
@@ -1639,7 +1636,7 @@
                assignCommand.setCommands(commands);
                assignCommand.setLiftNo(wrkMast.getLiftNo());
                assignCommand.setTaskNo(wrkMast.getWrkNo());
                assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id);
                assignCommand.setTaskMode(LiftTaskModeType.MOVE.id);
                //下发任务
                liftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机在{}层,提升机不在小车层,调度移动中", wrkMast.getWrkNo(), liftProtocol.getLev(), wrkMast.getLiftNo());
@@ -1724,7 +1721,7 @@
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(wrkMast.getLiftNo());
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id);
            assignCommand.setTaskMode(LiftTaskModeType.SHUTTLE_SWITCH.id);
            wrkMast.setWrkSts(WrkStsType.MOVE_LIFT_RUN.sts);//提升机搬运中  305.小车迁入提升机完成 ==> 306.提升机搬运中
            wrkMast.setSystemMsg("");//清空消息
@@ -1855,77 +1852,6 @@
            }
        }
        return true;
    }
    //自动切换出入库模式
    public void autoSwitchForkLiftIOMode() {
//        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
//                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
//        for (DeviceConfig device : forkliftList) {
//            Integer liftNo = device.getDeviceNo();
//            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
//            if (forkLiftThread == null) {
//                continue;
//            }
//            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
//            if (forkLiftProtocol == null) {
//                continue;
//            }
//
//            List<Integer> liftAllStaNo = ForkLiftUtils.getLiftAllStaNo(liftNo);
//            if (liftAllStaNo.isEmpty()) {
//                continue;
//            }
//
//            List<Integer> conveyorBindLiftAllStaNo = ForkLiftUtils.getConveyorBindLiftAllStaNo(liftNo);
//            if (conveyorBindLiftAllStaNo.isEmpty()) {
//                continue;
//            }
//
//            //获取入库任务
//            List<WrkMast> inWrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
//                    .in("sta_no", liftAllStaNo)
//                    .in("wrk_sts"
//                            , WrkStsType.NEW_INBOUND.sts
//                            , WrkStsType.INBOUND_DEVICE_RUN.sts
//                            , WrkStsType.INBOUND_LIFT_RUN.sts
//                            , WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts
//                            , WrkStsType.INBOUND_SHUTTLE_RUN.sts
//                            , WrkStsType.INBOUND_SHUTTLE_RUN_COMPLETE.sts
//                    ));
//
//            //获取出库任务
//            List<WrkMast> outWrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
//                    .in("sta_no", conveyorBindLiftAllStaNo)
//                    .in("wrk_sts"
//                            , WrkStsType.NEW_OUTBOUND.sts
//                            , WrkStsType.OUTBOUND_SHUTTLE_RUN.sts
//                            , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
//                            , WrkStsType.OUTBOUND_LIFT_RUN.sts
//                            , WrkStsType.OUTBOUND_LIFT_RUN_COMPLETE.sts
//                    ));
//
//            if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.NONE)) {
//                //未知模式
//                if (!inWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                } else if (!outWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.OUT);
//                }else {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                }
//            } else if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.IN)) {
//                //入库模式
//                if (inWrkMasts.isEmpty() && !outWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.OUT);
//                }
//            } else if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.OUT)) {
//                //出库模式
//                if (outWrkMasts.isEmpty() && !inWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                }
//            }
//        }
    }
}
src/main/java/com/zy/common/utils/NavigateSolution.java
@@ -205,7 +205,7 @@
                }
            }
            if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) {
            if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CONVEYOR.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) {
                //子轨和母轨、小车可走输送线、充电桩、提升机才能进行左右移动
                if (is_valid(x, y + 1)) {
                    NavigateNode node = new NavigateNode(x, y + 1);
@@ -233,7 +233,7 @@
                }
            }
            if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) {
            if (map[x][y] == MapNodeType.NORMAL_PATH.id || map[x][y] == MapNodeType.MAIN_PATH.id || map[x][y] == MapNodeType.CONVEYOR_CAR_GO.id || map[x][y] == MapNodeType.CONVEYOR.id || map[x][y] == MapNodeType.CHARGE.id || map[x][y] == MapNodeType.LIFT.id) {
                //子轨和母轨、小车可走输送线、充电桩、提升机才能进行上下移动
                if (is_valid(x + 1, y)) {
                    NavigateNode node = new NavigateNode(x + 1, y);
src/main/java/com/zy/core/MainProcess.java
@@ -66,10 +66,10 @@
//                    mainService.shuttleFinished();
                    //执行移库任务
                    mainService.shuttleLocMoveExecute();
                    //货叉提升机任务
                    mainService.forkLiftIoExecute();
                    //货叉提升机任务完成
                    mainService.forkLiftFinished();
                    //提升机任务
                    mainService.liftIoExecute();
                    //提升机任务完成
                    mainService.liftFinished();
                    //执行小车移动任务
                    mainService.shuttleMoveExecute();
                    // 异常信息记录
@@ -77,9 +77,6 @@
                    // 穿梭车 ===>> 小车电量检测充电
                    mainService.loopShuttleCharge();
                    mainService.executeShuttleCharge();
                    //自动切换出入库模式
                    mainService.autoSwitchForkLiftIOMode();
                    // 间隔
                    Thread.sleep(200);
src/main/java/com/zy/core/action/LiftAction.java
@@ -8,6 +8,7 @@
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.LiftProtocolStatusType;
import com.zy.core.enums.LiftTaskModeType;
import com.zy.core.enums.RedisKeyType;
import com.zy.core.enums.SlaveType;
@@ -121,6 +122,45 @@
            redisCommand.setCommandStep(commandStep);
            // 更新redis数据
            redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + taskNo, JSON.toJSONString(redisCommand));
        }else {
            if (!liftThread.isDeviceIdle()) {
                return false;
            }
            LiftCommand lastCommand = commands.get(commandStep - 1);
            if (lastCommand.getMode() == LiftTaskModeType.PICK_PUT.id) {
                if (liftProtocol.getLev() == lastCommand.getPut()) {
                    lastCommand.setComplete(true);
                }
            } else if (lastCommand.getMode() == LiftTaskModeType.SHUTTLE_SWITCH.id) {
                if (liftProtocol.getLev() == lastCommand.getPut()) {
                    lastCommand.setComplete(true);
                }
            } else if (lastCommand.getMode() == LiftTaskModeType.MOVE.id) {
                if (liftProtocol.getLev() == lastCommand.getPut()) {
                    lastCommand.setComplete(true);
                }
            }
            //任务数据保存到redis
            redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + redisCommand.getWrkNo(), JSON.toJSONString(redisCommand));
            if (!lastCommand.getComplete()) {
                //上一条任务未完成,禁止下发命令
                return false;
            }
            //判断是否为最后一条命令且命令执行完成,抛出等待确认状态
            LiftCommand endCommand = commands.get(commands.size() - 1);
            if (endCommand.getComplete()) {
                //已执行完成
                //删除redis
                redisUtil.del(RedisKeyType.LIFT_WORK_FLAG.key + redisCommand.getWrkNo());
                //对主线程抛出等待确认状态waiting
                liftThread.setProtocolStatus(LiftProtocolStatusType.WAITING);
                News.info("提升机任务执行下发完成执行结束,提升机号={},任务数据={}", redisCommand.getLiftNo(), JSON.toJSON(redisCommand));
            }
        }
        return true;
src/main/java/com/zy/core/dispatcher/ForkLiftDispatchUtils.java
New file
@@ -0,0 +1,127 @@
package com.zy.core.dispatcher;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.service.DeviceConfigService;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.NavigateNode;
import com.zy.common.model.enums.NavigationMapType;
import com.zy.common.utils.ForkLiftUtils;
import com.zy.common.utils.NavigateUtils;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.protocol.ForkLiftProtocol;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import com.zy.core.model.protocol.ShuttleProtocol;
import com.zy.core.thread.ForkLiftThread;
import com.zy.core.thread.ShuttleThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
 * 提升机调度工具
 */
@Component
public class ForkLiftDispatchUtils {
    @Autowired
    private DeviceConfigService deviceConfigService;
    @Autowired
    private NavigateUtils navigateUtils;
    /**
     * 获取穿梭车最近且空闲的提升机输送站点
     */
    public ForkLiftStaProtocol getRecentLiftStation(Integer shuttleNo, Integer targetLev) {
        //获取四向穿梭车线程
        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
        if (shuttleThread == null) {
            return null;
        }
        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
        if (shuttleProtocol == null) {
            return null;
        }
        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
        //获取小车同一楼层的站点
        ArrayList<ForkLiftStaProtocol> list = new ArrayList<>();
        int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车楼层
        for (DeviceConfig device : forkliftList) {
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, device.getDeviceNo());
            if (forkLiftThread == null) {
                continue;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                continue;
            }
            if (forkLiftProtocol.getErrorCode() > 0) {
                continue;
            }
            ForkLiftStaProtocol forkLiftStaProtocol = ForkLiftUtils.getLiftStaByLev(device.getDeviceNo(), lev);
            if (forkLiftStaProtocol == null) {
                continue;
            }
            //判断当前层是否无托盘
            if (forkLiftStaProtocol.getHasTray()) {
                continue;
            }
            if (forkLiftStaProtocol.getHasCar()) {
                continue;
            }
            //判断目标楼层站点是否无托盘
            ForkLiftStaProtocol targetLiftStaProtocol = ForkLiftUtils.getLiftStaByLev(device.getDeviceNo(), targetLev);
            if (targetLiftStaProtocol == null) {
                continue;
            }
            if (targetLiftStaProtocol.getHasTray()) {
                continue;//有托盘跳过
            }
            if (targetLiftStaProtocol.getHasCar()) {
                continue;
            }
            list.add(forkLiftStaProtocol);
        }
        if (list.isEmpty()) {
            return null;
        }
        String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车位置
        Integer recentAllDistance = 9999999;
        ForkLiftStaProtocol recentSta = null;//最近站点
        //搜索距离小车最近的站点
        for (ForkLiftStaProtocol forkLiftStaProtocol : list) {
            Integer staNo = forkLiftStaProtocol.getStaNo();//站点号
            String locNo = forkLiftStaProtocol.getLocNo();//站点库位号
            //当前穿梭车线程到目标地点距离
            List<NavigateNode> currentShuttlePath = navigateUtils.calc(currentLocNo, locNo, NavigationMapType.getMapTypes(NavigationMapType.NORMAL), Utils.getShuttlePoints(shuttleNo, Utils.getLev(currentLocNo)), null);//使用正常通道地图
            if (currentShuttlePath == null) {
                continue;
            }
            Integer currentAllDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离
            if (currentAllDistance < recentAllDistance) {
                //如果当前楼层的车路径更小,则更新最近站点
                recentSta = forkLiftStaProtocol;
                recentAllDistance = currentAllDistance;
            }
        }
        return recentSta;
    }
}
src/main/java/com/zy/core/dispatcher/LiftDispatchUtils.java
New file
@@ -0,0 +1,110 @@
package com.zy.core.dispatcher;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.service.DeviceConfigService;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.NavigateNode;
import com.zy.common.model.enums.NavigationMapType;
import com.zy.common.utils.LiftUtils;
import com.zy.common.utils.NavigateUtils;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.model.protocol.ShuttleProtocol;
import com.zy.core.thread.LiftThread;
import com.zy.core.thread.ShuttleThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
 * 提升机调度工具
 */
@Component
public class LiftDispatchUtils {
    @Autowired
    private DeviceConfigService deviceConfigService;
    @Autowired
    private NavigateUtils navigateUtils;
    /**
     * 获取穿梭车最近且无故障提升机输送站点
     */
    public LiftStaProtocol getRecentLiftStation(Integer shuttleNo, Integer targetLev) {
        //获取四向穿梭车线程
        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
        if (shuttleThread == null) {
            return null;
        }
        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
        if (shuttleProtocol == null) {
            return null;
        }
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        //获取小车同一楼层的站点
        ArrayList<LiftStaProtocol> list = new ArrayList<>();
        int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车楼层
        for (DeviceConfig device : liftList) {
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
            if (liftThread == null) {
                continue;
            }
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                continue;
            }
            if (liftProtocol.getErrorCode() > 0) {
                continue;
            }
            //判断目标楼层站点是否无托盘
            LiftStaProtocol targetLiftStaProtocol = LiftUtils.getLiftStaByLev(device.getDeviceNo(), targetLev);
            if (targetLiftStaProtocol == null) {
                continue;
            }
            //目标层有小车
            if (targetLiftStaProtocol.getHasCar()) {
                continue;
            }
            list.add(targetLiftStaProtocol);
        }
        if (list.isEmpty()) {
            return null;
        }
        String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车位置
        Integer recentAllDistance = 9999999;
        LiftStaProtocol recentSta = null;//最近站点
        //搜索距离小车最近的站点
        for (LiftStaProtocol liftStaProtocol : list) {
            Integer staNo = liftStaProtocol.getStaNo();//站点号
            String locNo = liftStaProtocol.getLocNo();//站点库位号
            //当前穿梭车线程到目标地点距离
            List<NavigateNode> currentShuttlePath = navigateUtils.calc(currentLocNo, locNo, NavigationMapType.getMapTypes(NavigationMapType.NORMAL), Utils.getShuttlePoints(shuttleNo, Utils.getLev(currentLocNo)), null);//使用正常通道地图
            if (currentShuttlePath == null) {
                continue;
            }
            Integer currentAllDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离
            if (currentAllDistance < recentAllDistance) {
                //如果当前楼层的车路径更小,则更新最近站点
                recentSta = liftStaProtocol;
                recentAllDistance = currentAllDistance;
            }
        }
        return recentSta;
    }
}
src/main/java/com/zy/core/dispatcher/ShuttleDispatchUtils.java
@@ -17,17 +17,13 @@
import com.zy.common.model.NavigateNode;
import com.zy.common.model.enums.NavigationMapType;
import com.zy.common.service.CommonService;
import com.zy.common.utils.ForkLiftUtils;
import com.zy.common.utils.NavigateUtils;
import com.zy.core.News;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.enums.WrkIoType;
import com.zy.core.enums.WrkStsType;
import com.zy.core.model.ForkLiftSlave;
import com.zy.core.model.ShuttleSlave;
import com.zy.core.model.protocol.*;
import com.zy.core.thread.ForkLiftThread;
import com.zy.core.thread.ShuttleThread;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
@@ -251,27 +247,6 @@
            }
        }
        Integer sourceStaNo = null;//小车换层源站点
        Integer staNo = null;//小车换层目标站点
        if (Utils.getLev(locNo) != Utils.getLev(shuttleProtocol.getCurrentLocNo())) {
            //目标库位和小车库位处于不同一楼层,需要通过提升机调度
            //获取穿梭车最近且空闲的提升机输送站点
            ForkLiftStaProtocol liftSta = this.getRecentLiftSta(shuttleNo, Utils.getLev(locNo));
            if (liftSta == null) {
                News.info("{}号小车,{}目标库位,没有可用空闲输送站点", shuttleNo, locNo);
                return false;//没有可用且空闲的输送站点
            }
            sourceStaNo = liftSta.getStaNo();//源站点
            ForkLiftStaProtocol targetLiftSta = ForkLiftUtils.getLiftStaByLev(liftSta.getLiftNo(), Utils.getLev(locNo));
            if (targetLiftSta == null) {
                News.info("{}号小车,{}目标库位,没有目标站点", shuttleNo, locNo);
                return false;//没有找到目标站点
            }
            //目标站点
            staNo = targetLiftSta.getStaNo();//目标站
        }
        // 获取工作号
        int workNo = commonService.getWorkNo(WrkIoType.SHUTTLE_MOVE.id);
        // 保存工作档
@@ -284,8 +259,6 @@
        wrkMast.setShuttleNo(shuttleNo);//穿梭车号
        wrkMast.setSourceLocNo(shuttleProtocol.getCurrentLocNo()); // 源库位 => 小车当前库位号
        wrkMast.setLocNo(locNo); // 目标库位
        wrkMast.setSourceStaNo(sourceStaNo);//源站
        wrkMast.setStaNo(staNo);//目标站
        wrkMast.setAppeTime(now);
        wrkMast.setModiTime(now);
        boolean res = wrkMastService.insert(wrkMast);
@@ -419,98 +392,6 @@
        return levCount < Integer.parseInt(config.getValue());
    }
    /**
     * 获取穿梭车最近且空闲的提升机输送站点
     */
    public ForkLiftStaProtocol getRecentLiftSta(Integer shuttleNo, Integer targetLev) {
        //获取四向穿梭车线程
        ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttleNo);
        if (shuttleThread == null) {
            return null;
        }
        ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
        if (shuttleProtocol == null) {
            return null;
        }
        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
        //获取小车同一楼层的站点
        ArrayList<ForkLiftStaProtocol> list = new ArrayList<>();
        int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());//小车楼层
        for (DeviceConfig device : forkliftList) {
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, device.getDeviceNo());
            if (forkLiftThread == null) {
                continue;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                continue;
            }
            if (!forkLiftThread.isIdle()) {
                continue;
            }
            ForkLiftStaProtocol forkLiftStaProtocol = ForkLiftUtils.getLiftStaByLev(device.getDeviceNo(), lev);
            if (forkLiftStaProtocol == null) {
                continue;
            }
            //判断当前层是否无托盘
            if (forkLiftStaProtocol.getHasTray()) {
                continue;
            }
            if (forkLiftStaProtocol.getHasCar()) {
                continue;
            }
            //判断目标楼层站点是否无托盘
            ForkLiftStaProtocol targetLiftStaProtocol = ForkLiftUtils.getLiftStaByLev(device.getDeviceNo(), targetLev);
            if (targetLiftStaProtocol == null) {
                continue;
            }
            if (targetLiftStaProtocol.getHasTray()) {
                continue;//有托盘跳过
            }
            if (targetLiftStaProtocol.getHasCar()) {
                continue;
            }
            list.add(forkLiftStaProtocol);
        }
        if (list.isEmpty()) {
            return null;
        }
        String currentLocNo = shuttleProtocol.getCurrentLocNo();//小车位置
        Integer recentAllDistance = 9999999;
        ForkLiftStaProtocol recentSta = null;//最近站点
        //搜索距离小车最近的站点
        for (ForkLiftStaProtocol forkLiftStaProtocol : list) {
            Integer staNo = forkLiftStaProtocol.getStaNo();//站点号
            String locNo = forkLiftStaProtocol.getLocNo();//站点库位号
            //当前穿梭车线程到目标地点距离
            List<NavigateNode> currentShuttlePath = navigateUtils.calc(currentLocNo, locNo, NavigationMapType.getMapTypes(NavigationMapType.NORMAL), Utils.getShuttlePoints(shuttleNo, Utils.getLev(currentLocNo)), null);//使用正常通道地图
            if (currentShuttlePath == null) {
                continue;
            }
            Integer currentAllDistance = navigateUtils.getOriginPathAllDistance(currentShuttlePath);//计算当前路径行走总距离
            if (currentAllDistance < recentAllDistance) {
                //如果当前楼层的车路径更小,则更新最近站点
                recentSta = forkLiftStaProtocol;
                recentAllDistance = currentAllDistance;
            }
        }
        return recentSta;
    }
    /**
src/main/java/com/zy/core/enums/LiftDeviceStatusType.java
New file
@@ -0,0 +1,42 @@
package com.zy.core.enums;
public enum LiftDeviceStatusType {
    NONE(-1, "离线"),
    IDLE(0, "空闲"),
    BUSY(1, "忙碌"),
    WAITING(98, "等待确认"),
    ERROR(99, "故障"),
    ;
    public Integer id;
    public String desc;
    LiftDeviceStatusType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static LiftDeviceStatusType get(Integer id) {
        if (null == id) {
            return NONE;
        }
        for (LiftDeviceStatusType type : LiftDeviceStatusType.values()) {
            if (type.id.equals(id)) {
                return type;
            }
        }
        return NONE;
    }
    public static LiftDeviceStatusType get(LiftDeviceStatusType type) {
        if (null == type) {
            return NONE;
        }
        for (LiftDeviceStatusType type2 : LiftDeviceStatusType.values()) {
            if (type2 == type) {
                return type2;
            }
        }
        return NONE;
    }
}
src/main/java/com/zy/core/enums/WrkIoType.java
@@ -9,7 +9,7 @@
    SHUTTLE_MOVE(200, "小车移动"),
    LOC_MOVE(201, "移库任务"),
    SHUTTLE_CHARGE(300, "小车充电"),
    FORKLIFT_MOVE(98, "提升机预调度移动任务"),
    PREVIEW_LIFT_MOVE(98, "提升机预调度移动任务"),
    MANUAL(99, "手动任务"),
    ;
src/main/java/com/zy/core/model/protocol/LiftProtocol.java
@@ -39,12 +39,22 @@
    /**
     * 任务状态
     */
    private Integer protocolStatus = LiftProtocolStatusType.NONE.id;
    private Integer protocolStatus = LiftProtocolStatusType.IDLE.id;
    /**
     * 任务状态枚举
     */
    private LiftProtocolStatusType protocolStatusType = LiftProtocolStatusType.NONE;
    private LiftProtocolStatusType protocolStatusType = LiftProtocolStatusType.IDLE;
    /**
     * 设备状态
     */
    private Integer deviceStatus = LiftDeviceStatusType.NONE.id;
    /**
     * 设备状态枚举
     */
    private LiftDeviceStatusType deviceStatusType = LiftDeviceStatusType.NONE;
    /**
     * 任务模式
@@ -222,6 +232,14 @@
        return LiftProtocolStatusType.get(this.protocolStatus).desc;
    }
    public String getDeviceStatus$() {
        if (this.deviceStatus == null) {
            return "";
        }
        return LiftDeviceStatusType.get(this.deviceStatus).desc;
    }
    public String getTaskMode$() {
        if (this.taskMode == null) {
            return "";
src/main/java/com/zy/core/thread/impl/NyLiftThread.java
@@ -160,7 +160,7 @@
            if (null == liftProtocol) {
                liftProtocol = new LiftProtocol();
                liftProtocol.setLiftNo(device.getDeviceNo());
                liftProtocol.setProtocolStatus(LiftProtocolStatusType.NONE);
                liftProtocol.setProtocolStatus(LiftProtocolStatusType.IDLE);
                InnerLiftExtend innerLiftExtend = new InnerLiftExtend();
                liftProtocol.setExtend(innerLiftExtend);
@@ -171,8 +171,8 @@
            liftProtocol.setModel(data.getInteger("model"));
            //PLC任务号
            liftProtocol.setPlcTaskNo(data.getInteger("plcTaskNo"));
            //任务状态
            liftProtocol.setProtocolStatus(data.getInteger("protocolStatus"));
            //设备状态
            liftProtocol.setDeviceStatus(data.getInteger("deviceStatus"));
            //任务模式
            liftProtocol.setTaskMode(data.getInteger("taskMode"));
            //取货数据
@@ -397,6 +397,8 @@
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            this.setSyncTaskNo(0);
            this.setProtocolStatus(LiftProtocolStatusType.IDLE);
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
@@ -422,7 +424,7 @@
        InnerLiftExtend extend = (InnerLiftExtend) this.liftProtocol.getExtend();
        boolean res = this.liftProtocol.getProtocolStatus() == LiftProtocolStatusType.IDLE.id
                && this.liftProtocol.getPlcTaskNo() == 0
//                && this.liftProtocol.getPlcTaskNo() == 0
                && this.liftProtocol.getTaskNo() == 0
                && this.liftProtocol.getModel() == 2
                && this.liftProtocol.getErrorCode() == 0
src/main/webapp/views/lift.html
@@ -114,6 +114,7 @@
                                <th class="py-3 px-4">工作号</th>
                                <th class="py-3 px-4">PLC工作号</th>
                                <th class="py-3 px-4">设备模式</th>
                                <th class="py-3 px-4">设备状态</th>
                                <th class="py-3 px-4">任务状态</th>
                                <th class="py-3 px-4">任务模式</th>
                                <th class="py-3 px-4">取货数据</th>
@@ -132,6 +133,7 @@
                                    <td class="py-3 px-4">{{ item.taskNo }}</td>
                                    <td class="py-3 px-4">{{ item.plcTaskNo }}</td>
                                    <td class="py-3 px-4">{{ item.model$ }}</td>
                                    <td class="py-3 px-4">{{ item.deviceStatus$ }}</td>
                                    <td class="py-3 px-4">{{ item.protocolStatus$ }}</td>
                                    <td class="py-3 px-4">{{ item.taskMode$ }}</td>
                                    <td class="py-3 px-4">{{ item.pick }}</td>