|  |  |  | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvCompleteType; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvDirectionType; | 
|---|
|  |  |  | import com.zy.acs.common.enums.AgvSpeedType; | 
|---|
|  |  |  | import com.zy.acs.common.utils.RedisSupport; | 
|---|
|  |  |  | import com.zy.acs.common.utils.GsonUtils; | 
|---|
|  |  |  | import com.zy.acs.common.utils.Utils; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.framework.common.SnowflakeIdWorker; | 
|---|
|  |  |  | 
|---|
|  |  |  | import com.zy.acs.manager.common.domain.TaskDto; | 
|---|
|  |  |  | import com.zy.acs.manager.common.domain.param.HandlerPublishParam; | 
|---|
|  |  |  | import com.zy.acs.manager.common.exception.BusinessException; | 
|---|
|  |  |  | import com.zy.acs.manager.common.utils.CommonUtil; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.AgvBackpackDto; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.Lane; | 
|---|
|  |  |  | import com.zy.acs.manager.core.domain.TaskPosDto; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.astart.MapDataDispatcher; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.controller.param.OpenBusSubmitParam; | 
|---|
|  |  |  | 
|---|
|  |  |  | import org.springframework.transaction.interceptor.TransactionAspectSupport; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.util.*; | 
|---|
|  |  |  | import java.util.concurrent.locks.ReentrantLock; | 
|---|
|  |  |  | import java.util.stream.Collectors; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Component("mainService") | 
|---|
|  |  |  | public class MainService { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final RedisSupport redis = RedisSupport.defaultRedisSupport; | 
|---|
|  |  |  | private static final int LOCK_TIMEOUT = 5; | 
|---|
|  |  |  | private final ReentrantLock lock = new ReentrantLock(Boolean.TRUE); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private BusService busService; | 
|---|
|  |  |  | 
|---|
|  |  |  | private TrafficService trafficService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private AgvModelService agvModelService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private LaneService laneService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @SuppressWarnings("all") | 
|---|
|  |  |  | 
|---|
|  |  |  | for (Task task : taskList) { | 
|---|
|  |  |  | Agv agv = allocateService.execute(task); | 
|---|
|  |  |  | if (null == agv) { | 
|---|
|  |  |  | log.warn("Task[{}] has an issue, because it failed to checkout agv which is idle...", task.getSeqNum()); | 
|---|
|  |  |  | //                    log.warn("Task[{}] has an issue, because it failed to checkout agv which is idle...", task.getSeqNum()); | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | task.setAgvId(agv.getId()); | 
|---|
|  |  |  | 
|---|
|  |  |  | throw new BusinessException("seqNum: " + task.getSeqNum() + " failed to update"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // ------------------------------------------ | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //            Map<String, List<Long>> taskAllot = new HashMap<>(); | 
|---|
|  |  |  | //            for (Task task : taskList) { | 
|---|
|  |  |  | //                Agv agv = missionAssignService.execute(task, taskAllot, taskIds); | 
|---|
|  |  |  | //                if (null == agv) { | 
|---|
|  |  |  | //                    log.warn("Task[{}] has an issue, because it failed to checkout agv which is idle...", task.getSeqNum()); | 
|---|
|  |  |  | //                    continue; | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | // | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //                task.setAgvId(agv.getId()); | 
|---|
|  |  |  | //                task.setTaskSts(TaskStsType.WAITING.val()); | 
|---|
|  |  |  | //                task.setIoTime(now); | 
|---|
|  |  |  | //                task.setUpdateTime(now); | 
|---|
|  |  |  | //                if (!taskService.updateById(task)) { | 
|---|
|  |  |  | //                    throw new BusinessException("seqNum: " + task.getSeqNum() + " failed to update"); | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //                if (taskAllot.containsKey(agv.getUuid())) { | 
|---|
|  |  |  | //                    taskAllot.get(agv.getUuid()).add(task.getId()); | 
|---|
|  |  |  | //                } else { | 
|---|
|  |  |  | //                    taskAllot.put(agv.getUuid(), Utils.singletonList(task.getId())); | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("mainService.infuseAgvForTask", e); | 
|---|
|  |  |  | TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); | 
|---|
|  |  |  | 
|---|
|  |  |  | // valid ----------------------------------------------- | 
|---|
|  |  |  | Agv agv = agvService.getById(agvId); | 
|---|
|  |  |  | if (!agvService.judgeEnable(agv.getId(), true)) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]当前不可用..."); | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | //                throw new CoolException("AGV[" + agv.getUuid() + "]当前不可用..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(taskService.selectInSts(agvId, TaskStsType.ASSIGN, TaskStsType.PROGRESS))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "]分配任务失败,已存在执行任务..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString())) | 
|---|
|  |  |  | || !Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the segment in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // execute ---------------------------------------------------- | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 1.Map<String, List<TaskPosDto>> groups | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 1000 + ORI_LOC | 
|---|
|  |  |  | * key: 1000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 3000 + ORI_LOC | 
|---|
|  |  |  | * key: 3000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 2000 + ORI_LOC | 
|---|
|  |  |  | * key: 2000 + ORIGIN | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 1000 + DESTINATION | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * key: 2000 + DESTINATION | 
|---|
|  |  |  | * val: [TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType), TaskPosDto(taskId, new Double[]{code.getX(), code.getY()}, posType),...] | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * ...... | 
|---|
|  |  |  | 
|---|
|  |  |  | * 对所有巷道进行有序排序,先是针对List为一个单位,对他们进行FirstWeight排序,相当于表1的key的数值进行有序排序 | 
|---|
|  |  |  | *  List<TaskPosDto>: task list on the same lane | 
|---|
|  |  |  | *  ArrayList<List<TaskPosDto>>: all the task list by one agv | 
|---|
|  |  |  | * | 
|---|
|  |  |  | *  tip: ORI 和 DEST 永远不会存在同一个 List | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | ArrayList<List<TaskPosDto>> list = new ArrayList<>(groups.values()); | 
|---|
|  |  |  | list.sort((o1, o2) -> { | 
|---|
|  |  |  | 
|---|
|  |  |  | Code currCode = codeService.getById(agvDetail.getRecentCode()); | 
|---|
|  |  |  | Double[] currPosition = new Double[] {currCode.getX(), currCode.getY()}; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<TaskPosDto> theFirstOne = list.get(0); | 
|---|
|  |  |  | List<TaskPosDto> theLastOne = list.get(list.size() - 1); | 
|---|
|  |  |  | List<List<TaskPosDto>> pickGroups = new ArrayList<>(); | 
|---|
|  |  |  | List<List<TaskPosDto>> dropGroups = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (list.size() == 1) { | 
|---|
|  |  |  | TaskPosDto head = theFirstOne.get(0); | 
|---|
|  |  |  | TaskPosDto tail = theFirstOne.get(theFirstOne.size() - 1); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int distanceByHead = CommonUtil.calcDistance(currPosition, head.getXy()); | 
|---|
|  |  |  | int distanceByTail = CommonUtil.calcDistance(currPosition, tail.getXy()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (distanceByTail < distanceByHead) { | 
|---|
|  |  |  | Collections.reverse(theFirstOne); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | TaskPosDto headOfFirst = theFirstOne.get(0); | 
|---|
|  |  |  | TaskPosDto tailOfFirst = theFirstOne.get(theFirstOne.size() - 1); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | TaskPosDto headOfLast = theLastOne.get(0); | 
|---|
|  |  |  | TaskPosDto tailOfLast = theLastOne.get(theLastOne.size() - 1); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int distanceByHeadOfFirst = CommonUtil.calcDistance(currPosition, headOfFirst.getXy()); | 
|---|
|  |  |  | int distanceByTailOfFirst = CommonUtil.calcDistance(currPosition, tailOfFirst.getXy()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int distanceByHeadOfLast = CommonUtil.calcDistance(currPosition, headOfLast.getXy()); | 
|---|
|  |  |  | int distanceByTailOfLast = CommonUtil.calcDistance(currPosition, tailOfLast.getXy()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (Math.min(distanceByHeadOfLast, distanceByTailOfLast) < Math.min(distanceByHeadOfFirst, distanceByTailOfFirst)) { | 
|---|
|  |  |  | Collections.reverse(list); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (distanceByTailOfLast < distanceByHeadOfLast) { | 
|---|
|  |  |  | Collections.reverse(theLastOne); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | for (List<TaskPosDto> group : list) { | 
|---|
|  |  |  | // Assume 一个任务组中所有TaskPosDto的PosType.brief相同 | 
|---|
|  |  |  | TaskPosDto.PosType posType = group.get(0).getPosType(); | 
|---|
|  |  |  | if (posType == TaskPosDto.PosType.ORI_LOC || posType == TaskPosDto.PosType.ORI_STA) { | 
|---|
|  |  |  | pickGroups.add(group); | 
|---|
|  |  |  | } else if (posType == TaskPosDto.PosType.DEST_LOC || posType == TaskPosDto.PosType.DEST_STA) { | 
|---|
|  |  |  | dropGroups.add(group); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | if (distanceByTailOfFirst < distanceByHeadOfFirst) { | 
|---|
|  |  |  | Collections.reverse(theFirstOne); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | // import tip: the list must only contain ORIGIN and DESTINATION | 
|---|
|  |  |  | log.error("the list must only contain ORIGIN and DESTINATION"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | currPosition = allocateService.pac(currPosition, pickGroups); | 
|---|
|  |  |  | currPosition = allocateService.pac(currPosition, dropGroups); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<List<TaskPosDto>> reorderedList = new ArrayList<>(); | 
|---|
|  |  |  | reorderedList.addAll(pickGroups); | 
|---|
|  |  |  | reorderedList.addAll(dropGroups); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | list.clear(); | 
|---|
|  |  |  | list.addAll(reorderedList); | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // generate travel | 
|---|
|  |  |  | Travel travel = new Travel(); | 
|---|
|  |  |  | 
|---|
|  |  |  | * 充电 回待机位任务 | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Transactional(propagation = Propagation.REQUIRES_NEW) // although there is a Transactional here that the lock is isolated, but we can't join the caller's Transactional | 
|---|
|  |  |  | public boolean buildMinorTask(Agv agv, AgvDetail agvDetail, TaskTypeType taskType, String destination) { | 
|---|
|  |  |  | public boolean buildMinorTask(Agv agv, TaskTypeType taskType, String destination, Jam jam) { | 
|---|
|  |  |  | if (Cools.isEmpty(agv, taskType)) { return false; } | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (null == agvDetail) { | 
|---|
|  |  |  | agvDetail = agvDetailService.selectByAgvId(agv.getId()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); | 
|---|
|  |  |  | if (!agvService.judgeEnable(agv.getId())) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(taskService.selectInSts(agv.getId(), TaskStsType.ASSIGN, TaskStsType.PROGRESS))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the task in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.WAITING.toString())) | 
|---|
|  |  |  | || !Cools.isEmpty(segmentService.getByAgvAndState(agv.getId(), SegmentStateType.RUNNING.toString()))) { | 
|---|
|  |  |  | throw new CoolException("AGV[" + agv.getUuid() + "] failed to assign,because already has the segment in running..."); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Date now = new Date(); | 
|---|
|  |  |  | 
|---|
|  |  |  | if (null == endCode) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!allocateService.validCapacityOfLane(agv, endCode)) { | 
|---|
|  |  |  | throw new BusinessException("the lane with code:" + endCode.getData() + " is full of AGV[" + agv.getUuid() + "]!!!"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Task task = new Task(); | 
|---|
|  |  |  | task.setAgvId(agv.getId()); | 
|---|
|  |  |  | 
|---|
|  |  |  | task.setSeqNum(Utils.generateSeqNum(Cools.isEmpty(lastTasks)?null:lastTasks.get(0).getSeqNum())); | 
|---|
|  |  |  | task.setOriCode(agvDetail.getCode()); | 
|---|
|  |  |  | task.setDestCode(endCode.getId()); | 
|---|
|  |  |  | // lane | 
|---|
|  |  |  | Lane destLane = laneService.search(endCode.getData()); | 
|---|
|  |  |  | if (null != destLane) { | 
|---|
|  |  |  | task.setDestLaneHash(destLane.getHashCode()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | task.setPriority(taskType.equals(TaskTypeType.TO_CHARGE)?2:1); | 
|---|
|  |  |  | task.setTaskSts(TaskStsType.ASSIGN.val()); | 
|---|
|  |  |  | task.setTaskType(taskType.val()); | 
|---|
|  |  |  | 
|---|
|  |  |  | travel.setTravelId(String.valueOf(snowflakeIdWorker.nextId()).substring(3)); | 
|---|
|  |  |  | travel.setAgvId(agv.getId()); | 
|---|
|  |  |  | //            travel.setTaskContent(JSON.toJSONString(list)); | 
|---|
|  |  |  | travel.setTaskIds(JSON.toJSONString(Collections.singletonList(task.getId()))); | 
|---|
|  |  |  | travel.setTaskIds(GsonUtils.toJson(Utils.singletonList(task.getId()))); | 
|---|
|  |  |  | travel.setState(TravelStateType.RUNNING.toString()); | 
|---|
|  |  |  | if (!travelService.save(travel)) { | 
|---|
|  |  |  | throw new BusinessException("travel failed to save"); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!segmentService.save(next)) { | 
|---|
|  |  |  | throw new BusinessException("segment failed to save"); | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | if (null != jam && i == 0) { | 
|---|
|  |  |  | jam.setAvoSeg(next.getId()); | 
|---|
|  |  |  | jam.setAvoCode(endCode.getId()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | default: | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //            if (taskType.equals(TaskTypeType.TO_STANDBY)) { | 
|---|
|  |  |  | //                redis.setObject(RedisConstant.AGV_TO_STANDBY_FLAG, agv.getUuid(), false); | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | case TO_CHARGE: | 
|---|
|  |  |  | // 检验方向 | 
|---|
|  |  |  | FuncSta chargeFuncSta = funcStaService.query(agvId, lastCode.getId(), FuncStaType.CHARGE.toString()); | 
|---|
|  |  |  | FuncSta chargeFuncSta = funcStaService.query(lastCode.getId(), FuncStaType.CHARGE.toString()); | 
|---|
|  |  |  | Double chargeDirection = Double.parseDouble(chargeFuncSta.getAngle()); | 
|---|
|  |  |  | if (!lastDirection.equals(chargeDirection)) { | 
|---|
|  |  |  | actionList.add(new Action( | 
|---|