zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/kernel/command/ShuttleCommandService.java
@@ -1,102 +1,108 @@ //package com.zy.asrs.wcs.core.kernel.command; // //import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; //import com.zy.asrs.wcs.core.model.command.ShuttleAssignCommand; //import com.zy.asrs.wcs.core.model.command.ShuttleCommand; //import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; //import com.zy.asrs.wcs.core.model.enums.MotionStsType; //import com.zy.asrs.wcs.core.service.BasShuttleService; //import com.zy.asrs.wcs.core.service.LocService; //import com.zy.asrs.wcs.core.service.TaskService; //import com.zy.asrs.wcs.core.utils.NavigateMapUtils; //import com.zy.asrs.wcs.core.utils.RedisUtil; //import com.zy.asrs.wcs.rcs.cache.SlaveConnection; //import com.zy.asrs.wcs.rcs.entity.Motion; //import com.zy.asrs.wcs.rcs.model.enums.SlaveType; //import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; //import com.zy.asrs.wcs.rcs.service.MotionService; //import com.zy.asrs.wcs.rcs.thread.ShuttleThread; //import lombok.extern.slf4j.Slf4j; //import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.stereotype.Service; // //import java.util.ArrayList; //import java.util.List; //import java.util.Objects; //import java.util.Optional; // ///** // * Created by vincent on 2023/10/23 // */ //@Slf4j //@Service //public class ShuttleCommandService { // // public static final Integer SHUTTLE_ADDITION_COMMAND_SPEED = 500; // // @Autowired // private RedisUtil redisUtil; // @Autowired // private MotionService motionService; // @Autowired // private TaskService taskService; // @Autowired // private BasShuttleService basShuttleService; // @Autowired // private LocService locService; // @Autowired // private NavigateMapUtils navigateMapUtils; // // // 计算 // public Boolean accept(Motion motion) { // Integer deviceNo = Integer.parseInt(motion.getDevice()); // ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); // ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); // if (null == shuttleProtocol) { // return false; // } // if (!shuttleProtocol.getIdle()) {//设备不空闲 // return false; // } // if (!shuttleProtocol.getPakMk()) { // return false; // } // if (motionService.count(new LambdaQueryWrapper<Motion>() // .eq(Motion::getDeviceCtg, DeviceCtgType.SHUTTLE.val()) // .eq(Motion::getDevice, motion.getDevice()) // .eq(Motion::getMotionSts, MotionStsType.EXECUTING.val())) > 0) { // return false; // } // // ShuttleAssignCommand assignCommand = new ShuttleAssignCommand(); // assignCommand.setShuttleNo(deviceNo.shortValue()); // assignCommand.setTaskNo(motion.getWrkNo().shortValue()); // assignCommand.setSourceLocNo(motion.getOrigin()); // assignCommand.setLocNo(motion.getTarget()); // // List<ShuttleCommand> shuttleCommands = new ArrayList<>(); // ShuttleTaskModeType shuttleTaskModeType = null; // package com.zy.asrs.wcs.core.kernel.command; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.exception.CoolException; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.model.NavigateNode; import com.zy.asrs.wcs.core.model.command.ShuttleAssignCommand; import com.zy.asrs.wcs.core.model.command.ShuttleCommand; import com.zy.asrs.wcs.core.model.enums.*; import com.zy.asrs.wcs.core.service.BasShuttleService; import com.zy.asrs.wcs.core.service.LocService; import com.zy.asrs.wcs.core.service.TaskService; import com.zy.asrs.wcs.core.utils.*; import com.zy.asrs.wcs.rcs.News; import com.zy.asrs.wcs.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.rcs.entity.Motion; import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; import com.zy.asrs.wcs.rcs.service.MotionService; import com.zy.asrs.wcs.rcs.thread.ShuttleThread; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; /** * Created by vincent on 2023/10/23 */ @Slf4j @Service public class ShuttleCommandService { public static final Integer SHUTTLE_ADDITION_COMMAND_SPEED = 500; @Autowired private RedisUtil redisUtil; @Autowired private MotionService motionService; @Autowired private TaskService taskService; @Autowired private BasShuttleService basShuttleService; @Autowired private LocService locService; @Autowired private NavigateMapUtils navigateMapUtils; // 计算 public Boolean accept(Motion motion) { Integer deviceNo = Integer.parseInt(motion.getDevice()); ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); if (null == shuttleProtocol) { return false; } if (!shuttleProtocol.getIdle()) {//设备不空闲 return false; } if (!shuttleProtocol.getPakMk()) { return false; } if (motionService.count(new LambdaQueryWrapper<Motion>() .eq(Motion::getDeviceCtg, DeviceCtgType.SHUTTLE.val()) .eq(Motion::getDevice, motion.getDevice()) .eq(Motion::getMotionSts, MotionStsType.EXECUTING.val())) > 0) { return false; } ShuttleAssignCommand assignCommand = new ShuttleAssignCommand(); assignCommand.setShuttleNo(deviceNo.shortValue()); assignCommand.setTaskNo(motion.getWrkNo().shortValue()); assignCommand.setSourceLocNo(motion.getOrigin()); assignCommand.setLocNo(motion.getTarget()); List<ShuttleCommand> shuttleCommands = new ArrayList<>(); ShuttleTaskModeType shuttleTaskModeType = null; // SiemensLiftThread liftThread = null; // LiftProtocol liftProtocol = null; // // //判断小车状态 // if (shuttleProtocol.getBusyStatusType().equals(ShuttleStatusType.IDLE) // && shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE) // && shuttleProtocol.getTaskNo().intValue() != 0 // ) { // return false; // } // // switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))){ // case SHUTTLE_MOVE: // // 如果已经在当前条码则过滤 // if (String.valueOf(shuttleProtocol.getCurrentCode()).equals(locMastService.selectById(motion.getTarget()).getQrCodeValue())) { // return true; // } // shuttleCommands = this.shuttleAssignCommand(motion.getOrigin(), motion.getTarget(), NavigationMapType.NORMAL.id, assignCommand, shuttleThread); // shuttleTaskModeType = ShuttleTaskModeType.SHUTTLE_MOVE_LOC_NO; // break; //判断小车状态 if (shuttleProtocol.getIdle() && shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE) && shuttleProtocol.getTaskNo() != 0 ) { return false; } switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))){ case SHUTTLE_MOVE: // 如果已经在当前条码则过滤 if (String.valueOf(shuttleProtocol.getCurrentCode()).equals(locService.getOne(new LambdaQueryWrapper<Loc>() .eq(Loc::getLocNo, motion.getTarget()) .eq(Loc::getHostId, motion.getHostId())).getCode())) { return true; } shuttleCommands = this.shuttleAssignCommand(motion.getOrigin(), motion.getTarget(), NavigationMapType.NORMAL.id, assignCommand, shuttleThread); shuttleTaskModeType = ShuttleTaskModeType.SHUTTLE_MOVE_LOC_NO; break; // case SHUTTLE_MOVE_LIFT_PALLET://穿梭车顶升并移动 // shuttleCommands = this.shuttleAssignCommand(motion.getOrigin(), motion.getTarget(), NavigationMapType.DFX.id, assignCommand, shuttleThread); // shuttleTaskModeType = ShuttleTaskModeType.PAK_IN; @@ -345,76 +351,76 @@ // shuttleCommands.add(shuttleThread.getChargeSwitchCommand((short) 1)); // assignCommand.setCharge(Boolean.TRUE); // break; // default: // throw new CoolException(motion.getMotionCtgEl() + "没有指定任务作业流程!!!"); // } // // if (Cools.isEmpty(shuttleCommands)) { // return false; // } // // assert null != shuttleTaskModeType; // assignCommand.setTaskMode(shuttleTaskModeType.id.shortValue());//入出库模式 // assignCommand.setCommands(shuttleCommands); // // if (motion.getOrigin() != null && motion.getTarget() != null) { // //所使用的路径进行锁定禁用 // boolean lockResult = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(motion.getTarget()), shuttleProtocol.getShuttleNo().intValue(), assignCommand.getNodes(), true);//所使用的路径进行锁定禁用 // if (!lockResult) { // return false;//锁定失败 // } default: throw new CoolException(motion.getMotionCtgEl() + "没有指定任务作业流程!!!"); } if (Cools.isEmpty(shuttleCommands)) { return false; } assert null != shuttleTaskModeType; assignCommand.setTaskMode(shuttleTaskModeType.id.shortValue());//入出库模式 assignCommand.setCommands(shuttleCommands); if (motion.getOrigin() != null && motion.getTarget() != null) { //所使用的路径进行锁定禁用 boolean lockResult = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(motion.getTarget()), Integer.parseInt(shuttleProtocol.getShuttleNo()), assignCommand.getNodes(), true);//所使用的路径进行锁定禁用 if (!lockResult) { return false;//锁定失败 } // shuttleThread.assignWork(assignCommand); // }else { }else { // shuttleThread.assignWork(assignCommand); // } // // return Boolean.TRUE; // } // // public Boolean finish(Motion motion) { // Integer deviceNo = Integer.parseInt(motion.getDevice()); // ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); // ShuttleProtocol shuttleProtocol = shuttleThread.getShuttleProtocol(); // if (null == shuttleProtocol) { // return false; // } // // if (shuttleProtocol.getTaskNo() != 0 && shuttleProtocol.getTaskNo().intValue() != motion.getWrkNo()) { // return false; // } // // //充电任务 // if (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl())).equals(MotionCtgType.SHUTTLE_CHARGE_ON)) { // // 复位穿梭车 // shuttleProtocol.setTaskNo((short) 0); // shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE); // shuttleProtocol.setPakMk(true); // return true; // } // // if (!shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.WAITING) // && !shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.CHARGING_WAITING) // ) { // return false; // } // // if (shuttleProtocol.getBusyStatusType().equals(ShuttleStatusType.BUSY)) { // return false; // } // } return Boolean.TRUE; } public Boolean finish(Motion motion) { Integer deviceNo = Integer.parseInt(motion.getDevice()); ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); if (null == shuttleProtocol) { return false; } if (shuttleProtocol.getTaskNo() != 0 && shuttleProtocol.getTaskNo().intValue() != motion.getWrkNo()) { return false; } //充电任务 if (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl())).equals(MotionCtgType.SHUTTLE_CHARGE_ON)) { // 复位穿梭车 shuttleProtocol.setTaskNo(0); shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE); shuttleProtocol.setPakMk(true); return true; } if (!shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.WAITING) && !shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.CHARGING_WAITING) ) { return false; } if (!shuttleProtocol.getIdle()) { return false; } // SiemensLiftThread liftThread = null; // LiftProtocol liftProtocol = null; // // switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))){ // case SHUTTLE_MOVE: // case SHUTTLE_MOVE_LIFT_PALLET: // case SHUTTLE_MOVE_DOWN_PALLET: // case SHUTTLE_MOVE_TO_CONVEYOR: // case SHUTTLE_MOVE_FROM_CONVEYOR: // if (!shuttleProtocol.getCurrentLocNo().equals(motion.getTarget())) { // return false; // } // break; switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))){ case SHUTTLE_MOVE: case SHUTTLE_MOVE_LIFT_PALLET: case SHUTTLE_MOVE_DOWN_PALLET: case SHUTTLE_MOVE_TO_CONVEYOR: case SHUTTLE_MOVE_FROM_CONVEYOR: if (!shuttleProtocol.getCurrentLocNo().equals(motion.getTarget())) { return false; } break; // case SHUTTLE_MOVE_TO_LIFT: // case SHUTTLE_MOVE_FROM_LIFT: // case SHUTTLE_TRANSPORT_FROM_LIFT: @@ -451,73 +457,73 @@ // } // // break; // default: // break; // } // // // 复位穿梭车 // shuttleProtocol.setTaskNo((short) 0); // shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE); // shuttleProtocol.setPakMk(true); // // return true; // } // // public synchronized List<ShuttleCommand> shuttleAssignCommand(String startLocNo, String endLocNo, Integer mapType, ShuttleAssignCommand assignCommand, ShuttleThread shuttleThread) { // //获取小车移动速度 // Integer runSpeed = Optional.ofNullable(basShuttleService.selectById(assignCommand.getShuttleNo()).getRunSpeed()).orElse(1000); // // List<NavigateNode> nodeList = NavigateUtils.calc(startLocNo, endLocNo, mapType, Utils.getShuttlePoints(shuttleThread.getSlave().getId(), Utils.getLev(startLocNo))); // if (nodeList == null) { // News.error("{} dash {} can't find navigate path!", startLocNo, endLocNo); // return null; // } // List<NavigateNode> allNode = new ArrayList<>(nodeList); // // List<ShuttleCommand> commands = new ArrayList<>(); // //获取分段路径 // ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(nodeList); // //将每一段路径分成command指令 // for (ArrayList<NavigateNode> nodes : data) { // //开始路径 // NavigateNode startPath = nodes.get(0); // // //中间路径 // NavigateNode middlePath = null; // //通过xy坐标小车二维码 // Short middleCodeNum = null; // Integer middleToDistDistance = null;//计算中间点到目标点行走距离 // if (nodes.size() > 10) {//中段码传倒数第三个 // //中间路径 // middlePath = nodes.get(nodes.size() - 3); // //通过xy坐标小车二维码 // middleCodeNum = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ()); // middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes, middlePath);//计算中间点到目标点行走距离 // } else if (nodes.size() > 5) {//中段码传倒数第二个 // //中间路径 // middlePath = nodes.get(nodes.size() - 2); // //通过xy坐标小车二维码 // middleCodeNum = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ()); // middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes, middlePath);//计算中间点到目标点行走距离 // } // // //目标路径 // NavigateNode endPath = nodes.get(nodes.size() - 1); // Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离 // //通过xy坐标小车二维码 // Short startCodeNum = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ()); // //通过xy坐标小车二维码 // Short distCodeNum = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ()); // //获取移动命令 // ShuttleCommand command = shuttleThread.getMoveCommand(startCodeNum, distCodeNum, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id, middleCodeNum, middleToDistDistance, runSpeed); // command.setNodes(nodes);//将行走节点添加到每一步命令中 // commands.add(command); // } // // assignCommand.setNodes(allNode);//当前任务所占用的节点list // // return commands; // } // // //} default: break; } // 复位穿梭车 shuttleProtocol.setTaskNo(0); shuttleProtocol.setProtocolStatus(ShuttleProtocolStatusType.IDLE); shuttleProtocol.setPakMk(true); return true; } public synchronized List<ShuttleCommand> shuttleAssignCommand(String startLocNo, String endLocNo, Integer mapType, ShuttleAssignCommand assignCommand, ShuttleThread shuttleThread) { //获取小车移动速度 Integer runSpeed = Optional.ofNullable(basShuttleService.getById(assignCommand.getShuttleNo()).getRunSpeed()).orElse(1000); Long hostId = shuttleThread.getDevice().getHostId(); List<NavigateNode> nodeList = NavigateUtils.calc(startLocNo, endLocNo, mapType, Utils.getShuttlePoints(Integer.parseInt(shuttleThread.getDevice().getDeviceNo()), Utils.getLev(startLocNo))); if (nodeList == null) { News.error("{} dash {} can't find navigate path!", startLocNo, endLocNo); return null; } List<NavigateNode> allNode = new ArrayList<>(nodeList); List<ShuttleCommand> commands = new ArrayList<>(); //获取分段路径 ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(nodeList); //将每一段路径分成command指令 for (ArrayList<NavigateNode> nodes : data) { //开始路径 NavigateNode startPath = nodes.get(0); //中间路径 NavigateNode middlePath = null; //通过xy坐标小车二维码 String middleCodeNum = null; Integer middleToDistDistance = null;//计算中间点到目标点行走距离 if (nodes.size() > 10) {//中段码传倒数第三个 //中间路径 middlePath = nodes.get(nodes.size() - 3); //通过xy坐标小车二维码 middleCodeNum = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ(), hostId); middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes, middlePath);//计算中间点到目标点行走距离 } else if (nodes.size() > 5) {//中段码传倒数第二个 //中间路径 middlePath = nodes.get(nodes.size() - 2); //通过xy坐标小车二维码 middleCodeNum = NavigatePositionConvert.xyToPosition(middlePath.getX(), middlePath.getY(), middlePath.getZ(), hostId); middleToDistDistance = NavigateUtils.getMiddleToDistDistance(nodes, middlePath);//计算中间点到目标点行走距离 } //目标路径 NavigateNode endPath = nodes.get(nodes.size() - 1); Integer allDistance = NavigateUtils.getCurrentPathAllDistance(nodes);//计算当前路径行走总距离 //通过xy坐标小车二维码 String startCodeNum = NavigatePositionConvert.xyToPosition(startPath.getX(), startPath.getY(), startPath.getZ(), hostId); //通过xy坐标小车二维码 String distCodeNum = NavigatePositionConvert.xyToPosition(endPath.getX(), endPath.getY(), endPath.getZ(), hostId); //获取移动命令 ShuttleCommand command = shuttleThread.getMoveCommand(assignCommand.getTaskNo().intValue(), startCodeNum, distCodeNum, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id.intValue(), runSpeed); command.setNodes(nodes);//将行走节点添加到每一步命令中 commands.add(command); } assignCommand.setNodes(allNode);//当前任务所占用的节点list return commands; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/model/command/ShuttleCommand.java
@@ -14,99 +14,17 @@ /** * 四向穿梭车号 */ private Short shuttleNo = 0; private Integer shuttleNo; /** * 任务号 */ private Short taskNo = 0; private Integer taskNo = 0; /** * 作业类型 * 报文内容 */ private Short taskMode = 0; /** * 功能说明 * 0、空 * 1、正常移动 * 2、托盘顶升 * 3、强制移动 * 4、查找定位点 * 5、充电开关 * 6、系统复位 * 7、紧急停止 * 8、IO控制 * 9、行走电机强制移动(输入为脉冲指令) * 10、升降伺服强制移动(输入为脉冲指令) * 控制指令字 */ private Short commandWord; /** * 启始二维编号 */ private Short startCodeNum; /** * 中间二维编号 */ private Short middleCodeNum; /** * 目标二维编号 */ private Short distCodeNum; /** * 起点到目标点的距离长度 */ private Integer startToDistDistance; /** * 中间点到目标点的距离长度 */ private Integer middleToDistDistance; /** * 小车运行方向 */ private Short runDirection; /** * 托盘顶升 */ private Short palletLift; /** * 小车强制移动距离 */ private Integer forceMoveDistance; /** * 充电开关 */ private Short chargeSwitch; /** * 小车IO控制 */ private Short IOControl; /** * 小车运行速度 */ private Short runSpeed; /** * 小车雷达备用 */ private Short radarTmp; /** * 指令结束位 */ private Short commandEnd; private String body; /** * 命令是否完成,默认false未完成 zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/model/enums/MotionCtgType.java
New file @@ -0,0 +1,84 @@ package com.zy.asrs.wcs.core.model.enums; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.framework.exception.CoolException; import com.zy.asrs.wcs.rcs.entity.MotionCtg; import com.zy.asrs.wcs.rcs.service.MotionCtgService; import static com.zy.asrs.wcs.core.model.enums.DeviceCtgType.*; public enum MotionCtgType { // 输送线 -------------------------------------------- CONVEYOR_INBOUND(CONVEYOR), CONVEYOR_INBOUND_TO_LIFT(CONVEYOR), CONVEYOR_OUTBOUND(CONVEYOR), CONVEYOR_OUTBOUND_FROM_LIFT(CONVEYOR), // 堆垛机 -------------------------------------------- // 提升机 -------------------------------------------- LIFT_MOVE(LIFT), LIFT_WITH_GOODS(LIFT), LIFT_WITH_SHUTTLE(LIFT), LIFT_WITH_GOODS_AND_SHUTTLE(LIFT), LIFT_TRANSPORT_TO_CONVEYOR(LIFT), LIFT_MISSION_COMPLETE(LIFT), // 穿梭车 -------------------------------------------- SHUTTLE_MOVE(SHUTTLE), SHUTTLE_MOVE_LIFT_PALLET(SHUTTLE),//穿梭车顶升并移动 SHUTTLE_MOVE_DOWN_PALLET(SHUTTLE),//穿梭车移动并托盘下降 SHUTTLE_MOVE_FROM_LIFT(SHUTTLE), SHUTTLE_MOVE_TO_LIFT(SHUTTLE), SHUTTLE_MOVE_FROM_CONVEYOR(SHUTTLE), SHUTTLE_MOVE_TO_CONVEYOR(SHUTTLE), SHUTTLE_MOVE_FROM_LIFT_TO_CONVEYOR(SHUTTLE), SHUTTLE_TRANSPORT(SHUTTLE), SHUTTLE_TRANSPORT_FROM_LIFT(SHUTTLE), SHUTTLE_TRANSPORT_TO_LIFT(SHUTTLE), SHUTTLE_TRANSPORT_FROM_CONVEYOR(SHUTTLE), SHUTTLE_TRANSPORT_TO_CONVEYOR(SHUTTLE), SHUTTLE_CHARGE_ON(SHUTTLE), SHUTTLE_CHARGE_OFF(SHUTTLE), // AGV ---------------------------------------------- AGV_TRANSPORT(AGV), ; public DeviceCtgType deviceCtg; MotionCtgType(DeviceCtgType deviceCtg) { this.deviceCtg = deviceCtg; } public long val() { MotionCtgService service = SpringUtils.getBean(MotionCtgService.class); MotionCtg entity = service.selectByFlag(this.toString()); if (entity == null) { throw new CoolException("MotionCtgType Error!"); } return entity.getId(); } public static MotionCtgType get(String el) { for (MotionCtgType value : MotionCtgType.values()) { if (el.equals(value.toString())) { return value; } } return null; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/model/enums/ShuttleRunDirection.java
New file @@ -0,0 +1,63 @@ package com.zy.asrs.wcs.core.model.enums; /** * 四向穿梭车运行方向 */ public enum ShuttleRunDirection { TOP((short)2, "货物方向-"), BOTTOM((short)1, "货物方向+"), LEFT((short)3, "过道方向-"), RIGHT((short)4, "过道方向+"), ; public Short id; public String desc; ShuttleRunDirection(Short id, String desc) { this.id = id; this.desc = desc; } public static ShuttleRunDirection get(String direction) { if (null == direction) { return null; } if (direction.equals("top")) { return TOP; } else if (direction.equals("bottom")) { return BOTTOM; } else if (direction.equals("left")) { return LEFT; } else if (direction.equals("right")) { return RIGHT; }else { return null; } } public static ShuttleRunDirection get(Short id) { if (null == id) { return null; } for (ShuttleRunDirection type : ShuttleRunDirection.values()) { if (type.id.equals(id.shortValue())) { return type; } } return null; } public static ShuttleRunDirection get(ShuttleRunDirection type) { if (null == type) { return null; } for (ShuttleRunDirection shuttleRunDirection : ShuttleRunDirection.values()) { if (shuttleRunDirection == type) { return shuttleRunDirection; } } return null; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/model/enums/ShuttleTaskModeType.java
New file @@ -0,0 +1,63 @@ package com.zy.asrs.wcs.core.model.enums; public enum ShuttleTaskModeType { INIT(0, "初始"), // 初始 PAK_IN(1, "入库"), PAK_OUT(2, "出库"), PALLET_LIFT(3, "托盘顶升"), PALLET_DOWN(4, "托盘下降"), X_NEGATIVE(5, "X-方向"), X_POSITIVE(6, "X+方向"), Y_POSITIVE(7, "Y+方向"), Y_NEGATIVE(8, "Y-方向"), RESET(9, "状态复位"), SEARCH_LEFT(10, "正方向(右)寻库位"), SEARCH_RIGHT(11, "负方向(左)寻库位"), SEARCH_TOP(12, "负方向(前)寻库位"), SEARCH_BOTTOM(13, "负方向(后)寻库位"), MOVE_LOC_NO(14, "移动到目标库位"), CHARGE(15, "充电"), MOVE_LIFT(16, "移动到提升机"), AVOID(17, "避让任务"), TRANSPORT(18, "搬运任务"), SHUTTLE_MOVE_LOC_NO(19, "小车移库任务"), SHUTTLE_LOC_TO_LOC(20, "库位移转"), SHUTTLE_CONTROL(21, "小车管制"), SHUTTLE_CANCEL_CONTROL(22, "小车取消管制"), MOVE_LOC_NO_WRK_MAST(23, "移动到目标库位(生成移动任务)"), ; public Integer id; public String desc; ShuttleTaskModeType(Integer id, String desc) { this.id = id; this.desc = desc; } public static ShuttleTaskModeType get(Short id) { if (null == id) { return null; } for (ShuttleTaskModeType type : ShuttleTaskModeType.values()) { if (type.id.equals(id.intValue())) { return type; } } return null; } public static ShuttleTaskModeType get(ShuttleTaskModeType type) { if (null == type) { return null; } for (ShuttleTaskModeType shuttleTaskModeType : ShuttleTaskModeType.values()) { if (shuttleTaskModeType == type) { return shuttleTaskModeType; } } return null; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/NavigatePositionConvert.java
New file @@ -0,0 +1,112 @@ package com.zy.asrs.wcs.core.utils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.model.NavigateNode; import com.zy.asrs.wcs.core.service.LocService; /** * 库位编号和A*算法的xy轴转换工具类 */ public class NavigatePositionConvert { public static String xyToPosition(int x, int y, int z, Long hostId) { StringBuffer sb = new StringBuffer(); if (x < 10) { sb.append("0"); } sb.append(x); if (y < 10) { sb.append("00"); } else if (y < 100) { sb.append("0"); } sb.append(y); if (z < 10) { sb.append("0"); } sb.append(z); String position = sb.toString();//库位号 //库位号转小车二维码 LocService locMastService = SpringUtils.getBean(LocService.class); Loc locMast = locMastService.getOne(new LambdaQueryWrapper<Loc>() .eq(Loc::getLocNo, position) .eq(Loc::getHostId, hostId)); if (locMast == null) { // //当前库位号查不到,可能是站点库位号 // BasDevpService basDevpService = SpringUtils.getBean(BasDevpService.class); // BasDevp basDevp = basDevpService.queryByLocNo(position); // if (basDevp == null) { // return null; // } // return Short.parseShort(basDevp.getQrCodeValue()); return null; } return locMast.getCode(); } //坐标编号转xy轴 public static int[] positionToXY(String position) { int col = Integer.parseInt(position.substring(0, 2)); int row = Integer.parseInt(position.substring(2, 5)); int[] newPosition = coverPosition(col,row); //返回x和y // return new int[]{row, col}; return newPosition; } //WCS系统库位号转路径算法节点 public static NavigateNode locNoToNode(String locNo) { int col = Integer.parseInt(locNo.substring(0, 2)); int row = Integer.parseInt(locNo.substring(2, 5)); int[] newPosition = coverPosition(col,row); NavigateNode node = new NavigateNode(col, row); node.setZ(Utils.getLev(locNo)); return node; } //路径算法节点转WCS系统库位号 public static String nodeToLocNo(NavigateNode node) { return xyzToLocNo(node.getX(), node.getY(), node.getZ()); } //WCS坐标转WCS库位号 public static String xyzToLocNo(int x, int y, int z) { String locNo = Utils.getLocNo(x, y, z); return locNo; } //牛眼坐标转WCS库位号 public static String nyXyzToLocNo(int x, int y, int z) { int[] ints = NyXyzToWCSXyz(x, y, z); String locNo = Utils.getLocNo(ints[0],ints[1],ints[2]); return locNo; } //WCS系统坐标转牛眼坐标 public static int[] WCSXyzToNyXyz(int x, int y, int z) { //WCS系统Y轴 => 牛眼X轴转换公式 int x1 = Math.abs(y - 61) + 11; //WCS系统X轴 => 牛眼Y轴转换公式 int y1 = x + 10; return new int[]{x1, y1, z}; } //牛眼坐标转WCS系统坐标 public static int[] NyXyzToWCSXyz(int x, int y, int z) { //牛眼X轴 => WCS系统Y轴公式 int y1 = Math.abs(x - 11 - 61); //牛眼Y轴 => WCS系统X轴公式 int x1 = y - 10; return new int[]{x1, y1, z}; } public static int[] coverPosition(int col,int row) { return new int[]{col, row}; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/NavigateSolution.java
New file @@ -0,0 +1,217 @@ package com.zy.asrs.wcs.core.utils; import com.zy.asrs.wcs.core.model.NavigateNode; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; /** * 四向库核心 * A*算法实现类 */ public class NavigateSolution { // -1 -> 墙壁, 1 -> 起点 2 -> 终点 3-> 母轨 4->站点 int[][] map = {{}}; public NavigateSolution() { //载入地图 NavigateMapData mapData = new NavigateMapData(); int[][] data = mapData.getData(); this.map = data; } public NavigateSolution(Integer mapType, Integer lev, List<int[]> whitePoints, List<int[]> shuttlePoints) { //载入地图指定层高地图 NavigateMapData mapData = new NavigateMapData(lev); int[][] data = mapData.getDataFromRedis(mapType, whitePoints, shuttlePoints); if (data == null) { data = mapData.getData(mapType, whitePoints, shuttlePoints); } this.map = data; } public NavigateSolution(int[][] data) { this.map = data; } // Open表用优先队列 public PriorityQueue<NavigateNode> Open = new PriorityQueue<NavigateNode>(); //Close表用普通的数组 public ArrayList<NavigateNode> Close = new ArrayList<NavigateNode>(); //Exist表用来存放已经出现过的结点。 public ArrayList<NavigateNode> Exist = new ArrayList<NavigateNode>(); public NavigateNode astarSearch(NavigateNode start, NavigateNode end) { //把第一个开始的结点加入到Open表中 this.Open.add(start); //把出现过的结点加入到Exist表中 this.Exist.add(start); //主循环 while (Open.size() > 0) { //取优先队列顶部元素并且把这个元素从Open表中删除 NavigateNode current_node = Open.poll(); //将这个结点加入到Close表中 Close.add(current_node); //对当前结点进行扩展,得到一个四周结点的数组 ArrayList<NavigateNode> neighbour_node = extend_current_node(current_node); //对这个结点遍历,看是否有目标结点出现 for (NavigateNode node : neighbour_node) { // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) int gCost = calcNodeCost(current_node, node) * calcNodeExtraCost(current_node, node, end); if (node.getX() == end.getX() && node.getY() == end.getY()) {//找到目标结点就返回 //init_node操作把这个邻居结点的父节点设置为当前结点 //并且计算出G, F, H等值 node.init_node(current_node, end); return node; } //(对启发函数增加去拐点方案calcNodeExtraCost) if (is_exist(node)) { if (gCost < node.getG()) { node.setFather(current_node); node.setG(gCost); node.setF(node.getG() + node.getH()); } }else { //没出现过的结点加入到Open表中并且设置父节点 //进行计算对G, F, H 等值 node.init_node(current_node, end); node.setG(gCost); node.setH(calcNodeCost(node, end)); node.setF(node.getG() + node.getH()); Open.add(node); Exist.add(node); } } } //如果遍历完所有出现的结点都没有找到最终的结点,返回null return null; } public ArrayList<NavigateNode> extend_current_node(NavigateNode current_node) { //获取当前结点的x, y int x = current_node.getX(); int y = current_node.getY(); //如果当前结点的邻结点合法,就加入到neighbour_node ArrayList<NavigateNode> neighbour_node = new ArrayList<NavigateNode>(); // if (map[x][y] == 0 || map[x][y] == 3) { // //只有子轨和母轨才能进行左右移动 // if (is_valid(x, y + 1)) // { // Node node = new Node(x, y + 1); // neighbour_node.add(node); // } // if (is_valid(x, y - 1)) // { // Node node = new Node(x, y - 1); // neighbour_node.add(node); // } // } // // if (map[x][y] == 3) { // //只有母轨才能进行上下移动 // if (is_valid(x + 1, y)) // { // Node node = new Node(x + 1, y); // neighbour_node.add(node); // } // if (is_valid(x - 1, y)) // { // Node node = new Node(x -1, y); // neighbour_node.add(node); // } // } if (map[x][y] == 3) { //母轨才能进行左右移动 if (is_valid(x, y + 1)) { NavigateNode node = new NavigateNode(x, y + 1); neighbour_node.add(node); } if (is_valid(x, y - 1)) { NavigateNode node = new NavigateNode(x, y - 1); neighbour_node.add(node); } } if (map[x][y] == 0 || map[x][y] == 3 || map[x][y] == 4 || map[x][y] == 5) { //子轨和母轨、输送线、充电桩才能进行上下移动 if (is_valid(x + 1, y)) { NavigateNode node = new NavigateNode(x + 1, y); neighbour_node.add(node); } if (is_valid(x - 1, y)) { NavigateNode node = new NavigateNode(x -1, y); neighbour_node.add(node); } } return neighbour_node; } public boolean is_valid(int x, int y) { // 如果结点的位置小于0,则不合法 if (map[x][y] < 0) return false; for (NavigateNode node : Exist) { //如果结点出现过,不合法 if (node.getX() == x && node.getY() == y) { return false; } if (is_exist(new NavigateNode(x, y))) { return false; } } //以上情况都没有则合法 return true; } public boolean is_exist(NavigateNode node) { for (NavigateNode exist_node : Exist) { if (node.getX() == exist_node.getX() && node.getY() == exist_node.getY()) { return true; } } return false; } //------------------A*启发函数------------------// //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) private int calcNodeCost(NavigateNode node1, NavigateNode node2) { return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); } //去除拐点算法,给直线增加优先级 private int calcNodeExtraCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { // 第一个点或直线点 if (currNode.getFather() == null || nextNode.getX() == currNode.getFather().getX() || nextNode.getY() == currNode.getFather().getY()) { return 0; } // 拐向终点的点 if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { return 1; } // 普通拐点 /* 拐点判断逻辑 拿到父节点和下一节点 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 */ return 2; } //------------------A*启发函数-end------------------// } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/NavigateUtils.java
New file @@ -0,0 +1,278 @@ package com.zy.asrs.wcs.core.utils; import com.zy.asrs.wcs.core.model.MapNode; import com.zy.asrs.wcs.core.model.NavigateNode; import com.zy.asrs.wcs.core.model.enums.NavigationMapType; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; /** * A*算法使用工具 */ public class NavigateUtils { public static List<NavigateNode> calc(String startPoint, String endPoint, Integer mapType, List<int[]> shuttlePoints) { //通过开始编号和结束编号获取对应的xy轴坐标 int[] startArr = NavigatePositionConvert.positionToXY(startPoint);//开始节点 int[] endArr = NavigatePositionConvert.positionToXY(endPoint);//结束节点 ArrayList<int[]> whiteList = new ArrayList<>();//设置计算节点的白名单 whiteList.add(startArr);//将开始节点设置为白名单,以防被过滤 //获取当前节点计算的层高,并赋值到每一个节点中 int lev = Utils.getLev(startPoint); //初始化开始节点 NavigateNode start = new NavigateNode(startArr[0], startArr[1]); //开始节点无父节点 start.setFather(null); NavigateNode end = new NavigateNode(endArr[0], endArr[1]); NavigateSolution solution = new NavigateSolution(mapType, lev, whiteList, shuttlePoints); //开始节点,不纳入禁用节点内计算 NavigateNode res_node = solution.astarSearch(start, end); if (res_node == null) { System.err.println("未找到路径"); return null; } ArrayList<NavigateNode> list = new ArrayList<>(); //渲染 NavigateNode fatherNode = null;//当前循环上一节点,用于拐点计算 while (res_node != null) { res_node.setDirection(null); res_node.setIsInflectionPoint(false); res_node.setZ(lev);//设置层高 //寻找拐点 HashMap<String, Object> result = searchInflectionPoint(res_node, fatherNode, res_node.getFather());//分别传入当前节点、父节点、下一节点 //判断当前节点是否为拐点 if (Boolean.parseBoolean(result.get("result").toString())) { //当前为拐点 res_node.setIsInflectionPoint(true); //拐点方向 res_node.setDirection(result.get("direction").toString()); } list.add(res_node); fatherNode = res_node;//把当前节点保存成一个父节点 res_node = res_node.getFather();//迭代操作 } Collections.reverse(list); //将每个节点里面的fatherNode至为null(方便后续计算时父节点过多导致显示的节点太多) for (NavigateNode navigateNode : list) { //父节点设置为null,不影响计算结果,不影响后续操作。 //此操作仅为后续排查处理提供视觉方便。 navigateNode.setFather(null); } //起始节点计算方向 String direction = calcDirection(list.get(0), list.get(1)); NavigateNode startNode = list.get(0); startNode.setDirection(direction); //更新节点列表 list.set(0, startNode); return list; } //判断当前节点到下一个节点是否为拐点 public static HashMap<String,Object> searchInflectionPoint(NavigateNode currentNode, NavigateNode fatherNode, NavigateNode nextNode) { HashMap<String, Object> map = new HashMap<>(); map.put("result", false);//是否为拐点,true:拐点,false:直线 // 第一个点或直线点 if (fatherNode == null || nextNode == null || nextNode.getX() == fatherNode.getX() || nextNode.getY() == fatherNode.getY()) { return map;//不是拐点直接返回 } //拐点方向 String direction = calcDirection(currentNode, fatherNode); map.put("result", true);//拐点 map.put("direction", direction);//拐点方向(从当前节点视角看的方向) return map; } /** * 计算方向 */ public static String calcDirection(NavigateNode currentNode, NavigateNode fatherNode) { //拐点方向 String direction = ""; // 普通拐点 //计算拐点方向 if (fatherNode.getX() != currentNode.getX()) { //x轴数据有差异,判断x轴方向 //当前节点X - 父节点X if (currentNode.getX() - fatherNode.getX() > 0) { //大于0,方向top direction = "top"; }else { //小于0,方向bottom direction = "bottom"; } } if (fatherNode.getY() != currentNode.getY()) { //y轴数据有差异,判断y轴方向 //当前节点Y - 父节点Y if (currentNode.getY() - fatherNode.getY() > 0) { //大于0,方向left direction = "left"; }else { //小于0,方向right direction = "right"; } } return direction; } /** * 加转弯节点 * 获取分段路径,每当有一个拐点则进行一次分段,最终返回总分段数据 */ public static ArrayList<ArrayList<NavigateNode>> getSectionPath(List<NavigateNode> mapList) { ArrayList<ArrayList<NavigateNode>> list = new ArrayList<>(); ArrayList<NavigateNode> data = new ArrayList<>(); String direction = mapList.get(0).getDirection();//行走方向 for (NavigateNode navigateNode : mapList) { data.add(navigateNode); //拐点 if (navigateNode.getIsInflectionPoint()) { //分割数据 list.add(data);//添加某一段数据 direction = navigateNode.getDirection();//更新行走方向 data = new ArrayList<>(); data.add(navigateNode);//将拐点的终点,更新成下一段命令的起点坐标 } else { //直行线路 navigateNode.setDirection(direction);//设置行走方向 } Integer distance = getXToNextDistance(navigateNode);//获取当前点到下一点的行走距离 navigateNode.setMoveDistance(distance); } //将最后一段数据添加进入 list.add(data); return list; } //获取从x点到下一点的行走距离 public static Integer getXToNextDistance(NavigateNode xNode) { NavigateMapData mapData = new NavigateMapData(); List<List<MapNode>> lists = mapData.getJsonData(NavigationMapType.NONE.id, null, null); if (lists != null) { MapNode mapNode = lists.get(xNode.getX()).get(xNode.getY()); if (mapNode != null) { switch (xNode.getDirection()) { case "top": return mapNode.getTop(); case "bottom": return mapNode.getBottom(); case "left": return mapNode.getLeft(); case "right": return mapNode.getRight(); } } return 0; } return 0; } /** * 根据原始节点结果,计算总行走距离 */ public static Integer getOriginPathAllDistance(List<NavigateNode> path) { ArrayList<ArrayList<NavigateNode>> sectionPath = NavigateUtils.getSectionPath(path); Integer allDistance = 0; for (ArrayList<NavigateNode> navigateNodes : sectionPath) { Integer distance = NavigateUtils.getCurrentPathAllDistance(navigateNodes); allDistance += distance; } return allDistance; } /** * 获取当前路径总行走距离 */ public static Integer getCurrentPathAllDistance(List<NavigateNode> path) { if (path.size() == 1) { //路径只有一条数据,则直接返回行走距离 return path.get(0).getMoveDistance(); } //总距离 int allDistance = 0; for (int i = 0; i < path.size() - 1; i++) {//路径中最后一个节点不统计到总距离,最后一个节点并不会再行走 allDistance += path.get(i).getMoveDistance(); } return allDistance; } /** * 获取中间点到目标点行走距离 */ public static Integer getMiddleToDistDistance(List<NavigateNode> path, NavigateNode middlePath) { //最后一条节点不计算进行走距离 NavigateNode lastPath = path.get(path.size() - 1); //总距离 int allDistance = 0; boolean flag = false; for (NavigateNode navigateNode : path) { if (!flag && navigateNode.equals(middlePath)) { flag = true; } if (navigateNode.equals(lastPath)) { continue;//最后一条节点不计算进行走距离 } if (flag) { allDistance += navigateNode.getMoveDistance(); } } return allDistance; } /** * 检测路径是否可用(可走) */ public static boolean checkPathIsAvailable(List<NavigateNode> path, Integer shuttleNo, Integer lev) { NavigateSolution solution = new NavigateSolution(NavigationMapType.DFX.id, lev, null, Utils.getShuttlePoints(shuttleNo, lev));//获取无白名单地图(该地图包含小车坐标) int[][] map = solution.map; for (NavigateNode node : path) { int value = map[node.getX()][node.getY()]; if (value != 0 && value != 3 && value != 5) {//母轨道3、子轨道0、充电桩5 return false; } } return true; } public static void main(String[] args) { //计算路径 List<NavigateNode> calc = calc("1000901", "1800201", NavigationMapType.NONE.id, null); System.out.println(calc); System.out.println("------------------------"); // List<NavigateNode> calc = calc("0501401", "0201801", "out"); //将路径分割成多段 ArrayList<ArrayList<NavigateNode>> data = getSectionPath(calc); for (ArrayList<NavigateNode> list : data) { Integer currentPathAllDistance = getCurrentPathAllDistance(list);//计算当前路径总距离 System.out.println(currentPathAllDistance); System.out.println(list); } } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/utils/Utils.java
@@ -1,10 +1,60 @@ package com.zy.asrs.wcs.core.utils; import com.zy.asrs.framework.common.Cools; import java.util.ArrayList; import java.util.List; public class Utils { /** * 通过库位号获取 排 */ public static int getRow(String locNo) { if (!Cools.isEmpty(locNo)) { return Integer.parseInt(locNo.substring(0, 2)); } throw new RuntimeException("库位解析异常"); } /** * 通过库位号获取 列 */ public static int getBay(String locNo) { if (!Cools.isEmpty(locNo)) { return Integer.parseInt(locNo.substring(2, 5)); } throw new RuntimeException("库位解析异常"); } /** * 通过库位号获取 层 */ public static int getLev(String locNo) { if (!Cools.isEmpty(locNo)) { return Integer.parseInt(locNo.substring(5, 7)); } throw new RuntimeException("库位解析异常"); } public static String getLocNo(Number row, Number bay, Number lev) { return zerofill(String.valueOf(row), 2) + zerofill(String.valueOf(bay), 3) + zerofill(String.valueOf(lev), 2); } public static String zerofill(String msg, Integer count){ if (msg.length() == count){ return msg; } else if (msg.length() > count){ return msg.substring(0, 16); } else { StringBuilder msgBuilder = new StringBuilder(msg); for (int i = 0; i<count-msg.length(); i++){ msgBuilder.insert(0,"0"); } return msgBuilder.toString(); } } //获取除白名单外的指定楼层全部穿梭车xy坐标点 public static List<int[]> getShuttlePoints(Integer whiteShuttle, Integer lev) { // SlaveProperties slaveProperties = SpringUtils.getBean(SlaveProperties.class); zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/entity/Motion.java
@@ -438,5 +438,14 @@ return null; } public String getMotionCtgEl(){ MotionCtgService service = SpringUtils.getBean(MotionCtgService.class); MotionCtg entity = service.getById(this.motionCtg); if (!Cools.isEmpty(entity)){ return String.valueOf(entity.getFlag()); } return null; } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/model/protocol/ShuttleProtocol.java
@@ -3,12 +3,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.service.LocService; import com.zy.asrs.wcs.core.utils.RedisUtil; import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant; import com.zy.asrs.wcs.rcs.model.enums.ShuttleDeviceStatusType; import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.entity.ShuttleDeviceStatus; import com.zy.asrs.wcs.rcs.model.enums.SlaveType; import com.zy.asrs.wcs.rcs.service.ShuttleDeviceStatusService; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -225,4 +228,25 @@ return this.taskNo == null ? 0 : this.taskNo; } //通过当前二维码获取当前库位号 public String getCurrentLocNo() { LocService locService = SpringUtils.getBean(LocService.class); if (locService == null) { return null; } if (this.currentCode == null) { return null; } //源库位(小车当前位置) Loc currentLoc = locService.getOne(new LambdaQueryWrapper<Loc>() .eq(Loc::getCode, this.currentCode) .eq(Loc::getHostId, this.device.getHostId())); if (currentLoc == null) { return null; } return currentLoc.getLocNo(); } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/service/MotionCtgService.java
@@ -5,4 +5,6 @@ public interface MotionCtgService extends IService<MotionCtg> { MotionCtg selectByFlag(String flag); } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/service/impl/MotionCtgServiceImpl.java
@@ -1,5 +1,6 @@ package com.zy.asrs.wcs.rcs.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.wcs.rcs.mapper.MotionCtgMapper; import com.zy.asrs.wcs.rcs.entity.MotionCtg; import com.zy.asrs.wcs.rcs.service.MotionCtgService; @@ -9,4 +10,9 @@ @Service("motionCtgService") public class MotionCtgServiceImpl extends ServiceImpl<MotionCtgMapper, MotionCtg> implements MotionCtgService { @Override public MotionCtg selectByFlag(String flag) { return this.getOne(new LambdaQueryWrapper<MotionCtg>().eq(MotionCtg::getFlag, flag)); } } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/ShuttleThread.java
@@ -1,15 +1,23 @@ package com.zy.asrs.wcs.rcs.thread; import com.zy.asrs.wcs.core.model.command.ShuttleCommand; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; public interface ShuttleThread extends ThreadHandler{ ShuttleProtocol getStatus();//获取四向穿梭车状态 Device getDevice();//获取设备信息 boolean movePath();//路径下发 boolean move();//移动 boolean lift();//顶升 //***************获取命令***************** ShuttleCommand getMoveCommand(Integer taskNo, String startCodeNum, String distCodeNum, Integer allDistance, Integer runDirection, Integer runSpeed); } zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/rcs/thread/impl/SurayShuttleThread.java
@@ -2,9 +2,14 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.common.utils.HttpHandler; import com.zy.asrs.framework.common.DateUtils; import com.zy.asrs.framework.common.SpringUtils; import com.zy.asrs.framework.exception.CoolException; import com.zy.asrs.wcs.core.entity.Loc; import com.zy.asrs.wcs.core.model.command.ShuttleCommand; import com.zy.asrs.wcs.core.service.LocService; import com.zy.asrs.wcs.rcs.News; import com.zy.asrs.wcs.rcs.cache.OutputQueue; import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType; @@ -148,6 +153,11 @@ } @Override public Device getDevice() { return this.device; } @Override public synchronized boolean movePath() { return false; } @@ -162,6 +172,32 @@ return false; } @Override public ShuttleCommand getMoveCommand(Integer taskNo, String startCodeNum, String distCodeNum, Integer allDistance, Integer runDirection, Integer runSpeed) { HashMap<String, Object> body = new HashMap<>(); body.put("messageName", "runOrder"); body.put("msgTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); body.put("deviceNo", Integer.parseInt(this.device.getDeviceNo())); body.put("taskId", taskNo); LocService locService = SpringUtils.getBean(LocService.class); Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>() .eq(Loc::getCode, distCodeNum) .eq(Loc::getHostId, this.device.getHostId())); if (loc == null) { throw new CoolException("库位信息不存在"); } body.put("nodeX", loc.getRow()); body.put("nodeY", loc.getBay()); body.put("nodeZ", loc.getLev()); ShuttleCommand command = new ShuttleCommand(); command.setShuttleNo(Integer.parseInt(this.device.getDeviceNo())); command.setBody(JSON.toJSONString(body)); return command; } //***************设备层通讯-不同厂商设备通讯方案不一致*************** //请求登录