| | |
| | | MotionCtgType.SHUTTLE_MOVE |
| | | )); |
| | | |
| | | // 锁定目标楼层穿梭车待机位路径 |
| | | motionList.addAll(kernelService.mapLockPath( |
| | | null, |
| | | MotionDto.build((dto -> { |
| | | dto.setShuttleNo(shuttleDevice.getId().intValue()); |
| | | dto.setLocNo(standbyLocNoFrom); |
| | | })) |
| | | )); |
| | | |
| | | // 提升机空载移动到穿梭车层 |
| | | motionList.addAll(kernelService.liftMove( |
| | | null |
| | |
| | | MotionCtgType.SHUTTLE_MOVE |
| | | )); |
| | | |
| | | // 锁定目标楼层穿梭车待机位路径 |
| | | motionList.addAll(kernelService.mapLockPath( |
| | | null, |
| | | MotionDto.build((dto -> { |
| | | dto.setShuttleNo(shuttleDevice.getId().intValue()); |
| | | dto.setLocNo(standbyLocNoFrom); |
| | | })) |
| | | )); |
| | | |
| | | // 提升机空载移动到穿梭车层 |
| | | motionList.addAll(kernelService.liftMove( |
| | | null |
| | |
| | | return motionList; |
| | | } |
| | | |
| | | // Map ----------------------------------------------------------------------------- |
| | | |
| | | /** |
| | | * 地图路径锁定 |
| | | */ |
| | | public List<Motion> mapLockPath(MotionDto origin, MotionDto target) { |
| | | List<Motion> motionList = new ArrayList<>(); |
| | | |
| | | motionList.add(Motion.build(motion -> { |
| | | motion.setDeviceCtg(DeviceCtgType.MAP.val()); |
| | | motion.setDevice(String.valueOf(target.getShuttleNo())); |
| | | motion.setMotionCtg(MotionCtgType.MAP_LOCK_PATH.val()); |
| | | |
| | | motion.setTarget(target.getLocNo()); |
| | | })); |
| | | |
| | | return motionList; |
| | | } |
| | | |
| | | /** |
| | | * 地图路径解锁 |
| | | */ |
| | | public List<Motion> mapUnlockPath(MotionDto origin, MotionDto target) { |
| | | List<Motion> motionList = new ArrayList<>(); |
| | | |
| | | motionList.add(Motion.build(motion -> { |
| | | motion.setDeviceCtg(DeviceCtgType.MAP.val()); |
| | | motion.setDevice(String.valueOf(target.getShuttleNo())); |
| | | motion.setMotionCtg(MotionCtgType.MAP_UNLOCK_PATH.val()); |
| | | |
| | | motion.setTarget(target.getLocNo()); |
| | | })); |
| | | |
| | | return motionList; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.zy.asrs.wcs.core.kernel.command; |
| | | |
| | | import com.zy.asrs.wcs.core.entity.Motion; |
| | | import com.zy.asrs.wcs.core.model.MapNode; |
| | | import com.zy.asrs.wcs.core.model.NavigateNode; |
| | | import com.zy.asrs.wcs.core.model.enums.MotionCtgType; |
| | | import com.zy.asrs.wcs.core.model.enums.NavigationMapType; |
| | | import com.zy.asrs.wcs.core.utils.*; |
| | | import com.zy.asrs.wcs.rcs.cache.SlaveConnection; |
| | | import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant; |
| | | import com.zy.asrs.wcs.rcs.model.enums.SlaveType; |
| | | import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol; |
| | | 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; |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class MapCommandService { |
| | | |
| | | @Autowired |
| | | private RedisUtil redisUtil; |
| | | @Autowired |
| | | private NavigateMapUtils navigateMapUtils; |
| | | @Autowired |
| | | private NavigateMapData navigateMapData; |
| | | |
| | | public Boolean accept(Motion motion) { |
| | | switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))) { |
| | | case MAP_LOCK_PATH: |
| | | return lockPath(motion, true); |
| | | case MAP_UNLOCK_PATH: |
| | | return lockPath(motion, false); |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | return Boolean.TRUE; |
| | | } |
| | | |
| | | public Boolean finish(Motion motion) { |
| | | switch (Objects.requireNonNull(MotionCtgType.get(motion.getMotionCtgEl()))) { |
| | | case MAP_LOCK_PATH: |
| | | return checkLockPath(motion, true); |
| | | case MAP_UNLOCK_PATH: |
| | | return checkLockPath(motion, false); |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | return Boolean.TRUE; |
| | | } |
| | | |
| | | private boolean lockPath(Motion motion, boolean lock) { |
| | | Integer deviceNo = Integer.parseInt(motion.getDevice()); |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); |
| | | if (shuttleThread == null) { |
| | | return false; |
| | | } |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (null == shuttleProtocol) { |
| | | return false; |
| | | } |
| | | |
| | | NavigateNode navigateNode = NavigatePositionConvert.locNoToNode(motion.getTarget()); |
| | | List<NavigateNode> nodes = new ArrayList<>(); |
| | | nodes.add(navigateNode); |
| | | |
| | | //所使用的路径进行锁定/解锁 |
| | | boolean lockResult = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(motion.getTarget()), shuttleProtocol.getShuttleNo(), nodes, lock);//所使用的路径进行锁定/解锁 |
| | | if (!lockResult) { |
| | | return false;//锁定/解锁失败 |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private boolean checkLockPath(Motion motion, boolean lock) { |
| | | NavigateNode navigateNode = NavigatePositionConvert.locNoToNode(motion.getTarget()); |
| | | List<NavigateNode> nodes = new ArrayList<>(); |
| | | nodes.add(navigateNode); |
| | | |
| | | int lev = Utils.getLev(motion.getTarget()); |
| | | |
| | | Object o = redisUtil.get(DeviceRedisConstant.MAP + lev); |
| | | if (o == null) { |
| | | return false; |
| | | } |
| | | |
| | | Integer deviceNo = Integer.parseInt(motion.getDevice()); |
| | | ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, deviceNo); |
| | | if (shuttleThread == null) { |
| | | return false; |
| | | } |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | if (null == shuttleProtocol) { |
| | | return false; |
| | | } |
| | | |
| | | //获取小车节点 |
| | | List<int[]> shuttlePoints = Utils.getShuttlePoints(shuttleProtocol.getShuttleNo(), lev); |
| | | List<List<MapNode>> map = navigateMapData.getJsonData(NavigationMapType.DFX.id, null, shuttlePoints); |
| | | |
| | | for (NavigateNode node : nodes) { |
| | | List<MapNode> listX = map.get(node.getX()); |
| | | MapNode mapNode = listX.get(node.getY()); |
| | | if (lock) {//检测是否锁定 |
| | | if (mapNode.getValue() != -999) { |
| | | return false;//路径未锁定 |
| | | } |
| | | }else {//检测是否未锁定 |
| | | if(mapNode.getValue() == -999) { |
| | | return false;//路径已锁定 |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.zy.asrs.wcs.core.kernel.command; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.zy.asrs.framework.common.Cools; |
| | | import com.zy.asrs.framework.exception.CoolException; |
| | |
| | | // return false; |
| | | // } |
| | | |
| | | shuttleCommands = this.shuttleAssignCommand(motion.getOrigin(), motion.getTarget(), NavigationMapType.NORMAL.id, assignCommand, shuttleThread); |
| | | shuttleCommands = this.shuttleInOutLiftCommand(motion.getOrigin(), motion.getTarget(), NavigationMapType.NORMAL.id, assignCommand, shuttleThread); |
| | | shuttleTaskModeType = ShuttleTaskModeType.SHUTTLE_MOVE_LOC_NO; |
| | | break; |
| | | case SHUTTLE_MOVE_TO_LIFT://进提升机 |
| | |
| | | return commands; |
| | | } |
| | | |
| | | public synchronized List<ShuttleCommand> shuttleInOutLiftCommand(String startLocNo, String endLocNo, Integer mapType, ShuttleAssignCommand assignCommand, ShuttleThread shuttleThread) { |
| | | NavigateNode startNode = NavigatePositionConvert.locNoToNode(startLocNo); |
| | | NavigateNode endNode = NavigatePositionConvert.locNoToNode(endLocNo); |
| | | List<NavigateNode> unlockPath = new ArrayList<>(); |
| | | unlockPath.add(startNode); |
| | | unlockPath.add(endNode); |
| | | |
| | | ShuttleProtocol shuttleProtocol = shuttleThread.getStatus(); |
| | | |
| | | //所使用的路径进行锁定/解锁 |
| | | boolean lockResult = navigateMapUtils.writeNavigateNodeToRedisMap(Utils.getLev(endLocNo), shuttleProtocol.getShuttleNo(), unlockPath, false);//所使用的路径进行解锁 |
| | | if (!lockResult) { |
| | | News.error("{} dash {} can't find unlock path!", startLocNo, endLocNo); |
| | | return null;//解锁失败 |
| | | } |
| | | |
| | | |
| | | //获取小车移动速度 |
| | | Integer runSpeed = Optional.ofNullable(basShuttleService.getOne(new LambdaQueryWrapper<BasShuttle>().eq(BasShuttle::getDeviceId, assignCommand.getDeviceId())).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<>(); |
| | | for (NavigateNode node : nodeList) { |
| | | allNode.add(node.clone()); |
| | | } |
| | | |
| | | List<ShuttleCommand> commands = new ArrayList<>(); |
| | | //获取分段路径 |
| | | ArrayList<ArrayList<NavigateNode>> data = NavigateUtils.getSectionPath(nodeList); |
| | | //将每一段路径分成command指令 |
| | | for (ArrayList<NavigateNode> nodes : data) { |
| | | //开始路径 |
| | | NavigateNode startPath = nodes.get(0); |
| | | |
| | | //目标路径 |
| | | 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.getDeviceTaskNo(), startCodeNum, distCodeNum, allDistance, ShuttleRunDirection.get(startPath.getDirection()).id.intValue(), runSpeed, nodes); |
| | | command.setNodes(nodes);//将行走节点添加到每一步命令中 |
| | | commands.add(command); |
| | | } |
| | | |
| | | assignCommand.setNodes(allNode);//当前任务所占用的节点list |
| | | |
| | | return commands; |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | SHUTTLE, |
| | | AGV, |
| | | LED, |
| | | MAP, |
| | | ; |
| | | |
| | | DeviceCtgType() { |
| | |
| | | // AGV ---------------------------------------------- |
| | | AGV_TRANSPORT(AGV), |
| | | |
| | | // MAP ---------------------------------------------- |
| | | MAP_LOCK_PATH(MAP),//地图锁定路径 |
| | | MAP_UNLOCK_PATH(MAP),//地图解锁路径 |
| | | |
| | | ; |
| | | |
| | | public DeviceCtgType deviceCtg; |
| | |
| | | private LiftCommandService liftCommandService; |
| | | @Autowired |
| | | private ShuttleCommandService shuttleCommandService; |
| | | @Autowired |
| | | private MapCommandService mapCommandService; |
| | | |
| | | @Scheduled(cron = "0/1 * * * * ? ") |
| | | public synchronized void executeTask() { |
| | |
| | | case AGV: |
| | | executeRes = agvCommandService.accept(motion); |
| | | break; |
| | | case MAP: |
| | | executeRes = mapCommandService.accept(motion); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | |
| | | case CONVEYOR: |
| | | executeRes = conveyorCommandService.finish(motion); |
| | | break; |
| | | case MAP: |
| | | executeRes = mapCommandService.finish(motion); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | |
| | | |
| | | //WCS系统库位号转路径算法节点 |
| | | public static NavigateNode locNoToNode(String locNo) { |
| | | int col = Integer.parseInt(locNo.substring(0, 2)); |
| | | int row = Integer.parseInt(locNo.substring(2, 5)); |
| | | int col = Utils.getRow(locNo); |
| | | int row = Utils.getBay(locNo); |
| | | int[] newPosition = coverPosition(col,row); |
| | | NavigateNode node = new NavigateNode(col, row); |
| | | NavigateNode node = new NavigateNode(newPosition[0], newPosition[1]); |
| | | node.setZ(Utils.getLev(locNo)); |
| | | return node; |
| | | } |
| | |
| | | import com.zy.asrs.wcs.core.entity.*; |
| | | import com.zy.asrs.wcs.core.kernel.AnalyzeService; |
| | | import com.zy.asrs.wcs.core.model.NavigateNode; |
| | | import com.zy.asrs.wcs.core.model.enums.DeviceCtgType; |
| | | import com.zy.asrs.wcs.core.model.enums.NavigationMapType; |
| | | import com.zy.asrs.wcs.core.model.enums.TaskCtgType; |
| | | import com.zy.asrs.wcs.core.model.enums.TaskStsType; |
| | | import com.zy.asrs.wcs.core.model.enums.*; |
| | | import com.zy.asrs.wcs.core.service.*; |
| | | import com.zy.asrs.wcs.rcs.News; |
| | | import com.zy.asrs.wcs.rcs.cache.SlaveConnection; |
| | |
| | | |
| | | } |
| | | |
| | | //搜索是否存在前往目标楼层的小车工作档 |
| | | for (Task task : taskService.list(new LambdaQueryWrapper<Task>() |
| | | .in(Task::getTaskSts, TaskStsType.NEW_INBOUND.sts, TaskStsType.ANALYZE_INBOUND.sts, TaskStsType.EXECUTE_INBOUND.sts, TaskStsType.COMPLETE_INBOUND.sts |
| | | , TaskStsType.NEW_OUTBOUND.sts, TaskStsType.ANALYZE_OUTBOUND.sts, TaskStsType.EXECUTE_OUTBOUND.sts, TaskStsType.COMPLETE_OUTBOUND.sts))) { |
| | | |
| | | List<Motion> motions = motionService.list(new LambdaQueryWrapper<Motion>() |
| | | .eq(Motion::getTaskNo, task.getTaskNo()) |
| | | .in(Motion::getMotionCtg, MotionCtgType.SHUTTLE_MOVE |
| | | , MotionCtgType.SHUTTLE_MOVE_LIFT_PALLET |
| | | , MotionCtgType.SHUTTLE_MOVE_DOWN_PALLET |
| | | , MotionCtgType.SHUTTLE_MOVE_FROM_LIFT |
| | | , MotionCtgType.SHUTTLE_MOVE_TO_LIFT |
| | | , MotionCtgType.SHUTTLE_MOVE_FROM_CONVEYOR |
| | | , MotionCtgType.SHUTTLE_MOVE_TO_CONVEYOR |
| | | , MotionCtgType.SHUTTLE_MOVE_FROM_LIFT_TO_CONVEYOR |
| | | )); |
| | | |
| | | boolean isUpdateLev = false; |
| | | for (Motion motion : motions) { |
| | | if (motion.getOrigin() == null || motion.getTarget() == null) { |
| | | continue; |
| | | } |
| | | |
| | | int sourceLev = Utils.getLev(motion.getOrigin());//动作源楼层 |
| | | int targetLev = Utils.getLev(motion.getTarget());//动作目标楼层 |
| | | if (sourceLev != targetLev) { |
| | | isUpdateLev = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if(isUpdateLev) { |
| | | levCount++;//工作档属于跨层任务,小车归属于目标楼层 |
| | | continue; |
| | | } |
| | | |
| | | } |
| | | |
| | | return levCount < Integer.parseInt(dict.getValue()); |
| | | } |
| | | |