#
luxiaotao1123
2024-11-04 7f70cb15d035f0c233b9e62b9e43aa985317c908
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/AllocateService.java
@@ -2,23 +2,21 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zy.acs.framework.common.Cools;
import com.zy.acs.manager.common.utils.CommonUtil;
import com.zy.acs.manager.common.utils.LocUtils;
import com.zy.acs.manager.manager.entity.Agv;
import com.zy.acs.manager.manager.entity.AgvModel;
import com.zy.acs.manager.manager.entity.Task;
import com.zy.acs.manager.core.domain.Lane;
import com.zy.acs.manager.manager.entity.*;
import com.zy.acs.manager.manager.enums.StatusType;
import com.zy.acs.manager.manager.enums.TaskStsType;
import com.zy.acs.manager.manager.service.AgvModelService;
import com.zy.acs.manager.manager.service.AgvService;
import com.zy.acs.manager.manager.service.TaskService;
import com.zy.acs.manager.manager.enums.TaskTypeType;
import com.zy.acs.manager.manager.service.*;
import com.zy.acs.manager.system.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created by vincent on 8/12/2024
@@ -30,11 +28,19 @@
    @Autowired
    private AgvService agvService;
    @Autowired
    private AgvDetailService agvDetailService;
    @Autowired
    private AgvModelService agvModelService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private CodeService codeService;
    @Autowired
    private StaService staService;
    @Autowired
    private LocService locService;
    @Autowired
    private LaneService laneService;
@@ -43,7 +49,7 @@
     */
    private List<Agv> getAvailableAgv() {
        List<Agv> result = new ArrayList<>();
        List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1));
        List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, StatusType.ENABLE.val));
        Collections.shuffle(agvList);
        for (Agv agv : agvList) {
@@ -69,14 +75,160 @@
        return result;
    }
    /**
     * 1.   判断task的起始点和目的点所在的巷道承载任务数量,
     *      如果数量已经达到负载,则判断负载任务的AGV是否还有空背篓,如果有则优先派发给它,
     *      如果没有了,那么则阻塞任务,直到该巷道释放
     * 2.   轮询空闲小车,目标是让每台小车都动起来
     *      判断逻辑:背篓数量最少的小车轮询的时候,优先级最高
     *
     *      it can break the limit of the number of agv backpack
     */
    public synchronized Agv execute(Task task) {
        List<Agv> availableAgvList = getAvailableAgv();
        if (Cools.isEmpty(availableAgvList)) {
            log.warn("No available agv to assign the task[{}]", task.getSeqNum());
            return null;
        }
        List<String> availableAgvNos = availableAgvList.stream().map(Agv::getUuid).distinct().collect(Collectors.toList());
        Integer maxAgvCountInLane = configService.getVal("maxAgvCountInLane", Integer.class);
        // checkout lane
        Lane originLane = taskService.checkoutOriginLane(task);
        Lane destinationLane = taskService.checkoutDestinationLane(task);
        // allocate about origin
        List<String> availableAgvNosByOriLane = new ArrayList<>(availableAgvNos);
        if (null != originLane) {
            List<String> agvNosByOriLane = findAgvNosByLane(originLane);    // the agv list that had tasks in this lane
            if (!Cools.isEmpty(agvNosByOriLane) && agvNosByOriLane.size() >= maxAgvCountInLane) {
                availableAgvNosByOriLane = Cools.getIntersection(agvNosByOriLane, availableAgvNos);
            }
        }
        // valid backpack limit
        availableAgvNosByOriLane = this.validBackpackLimit(availableAgvNosByOriLane);
        // allocate about destination
        List<String> availableAgvNosByDestLane = new ArrayList<>(availableAgvNos);
        if (null != destinationLane) {
            List<String> agvNosByDestLane = findAgvNosByLane(destinationLane);
            if (!Cools.isEmpty(agvNosByDestLane) && agvNosByDestLane.size() >= maxAgvCountInLane) {
                availableAgvNosByDestLane = Cools.getIntersection(agvNosByDestLane, availableAgvNos);
            }
        }
        availableAgvNosByDestLane = this.validBackpackLimit(availableAgvNosByDestLane);
        // valid
        if (Cools.isEmpty(availableAgvNosByOriLane)) {
            log.warn("No available agv to assign the task origin[{}]", task.getSeqNum());
            return null;
        }
        if (Cools.isEmpty(availableAgvNosByDestLane)) {
            log.warn("No available agv to assign the task destination[{}]", task.getSeqNum());
            return null;
        }
        List<String> actualAvailableAgvNos = Cools.getIntersection(availableAgvNosByOriLane, availableAgvNosByDestLane);
        if (Cools.isEmpty(actualAvailableAgvNos)) {
            log.warn("No available agv to assign the task[{}]", task.getSeqNum());
            return null;
        }
        return null;
        // choose min number of running task
        actualAvailableAgvNos.sort(new Comparator<String>() {
            @Override
            public int compare(String agvNo1, String agvNo2) {
                return calcAllocateWeight(agvNo1, task) - calcAllocateWeight(agvNo2, task);
            }
        });
        if (null != originLane) {
            task.setOriLaneHash(originLane.getHashCode());
        }
        if (null != destinationLane) {
            task.setDestLaneHash(destinationLane.getHashCode());
        }
        return agvService.selectByUuid(actualAvailableAgvNos.stream().findFirst().orElse(null));
    }
    private List<String> findAgvNosByLane(Lane lane) {
        if (null == lane) {
            return null;
        }
        List<Task> taskList = taskService.findRunningTasksByLaneHash(lane.getHashCode());
        if (Cools.isEmpty(taskList)) {
            return null;
        }
        return taskList.stream().map(task -> {
            return agvService.getById(task.getAgvId()).getUuid();
        }).distinct().collect(Collectors.toList());
    }
    private List<String> validBackpackLimit(List<String> agvNoList) {
        if (Cools.isEmpty(agvNoList)) {
            return new ArrayList<>();
        }
        return agvNoList.stream().filter(agvNo -> {
            Agv agv = agvService.selectByUuid(agvNo);
            AgvModel agvModel = agvModelService.getById(agv.getAgvModel());
            List<Task> runningTasks = taskService.findRunningTasksByAgv(agv.getId());
            return runningTasks.size() < agvModel.getBackpack();
        }).collect(Collectors.toList());
    }
    // calculate wight = backpack + distance
    private int calcAllocateWeight(String agvNo, Task task) {
        int weight = 0;
        Agv agv = agvService.selectByUuid(agvNo);
        // backpack
        List<Task> runningTasks = taskService.findRunningTasksByAgv(agv.getId());
        if (!Cools.isEmpty(runningTasks)) {
            weight = weight + runningTasks.size() * 100000;
        }
        // distance
        // from
        AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId());
        Code agvCurrCode = codeService.getById(agvDetail.getRecentCode());
        Double[] fromPosition = new Double[]{agvCurrCode.getX(), agvCurrCode.getY()};
        // to
        Code firstCode = null;
        TaskTypeType typeType = TaskTypeType.get(task.getTaskTypeEl());
        switch (Objects.requireNonNull(typeType)) {
            case LOC_TO_LOC:
            case LOC_TO_STA:
                Loc oriLoc = locService.getById(task.getOriLoc());
                firstCode = codeService.getById(oriLoc.getCode());
                break;
            case STA_TO_LOC:
            case STA_TO_STA:
                Sta oriSta = staService.getById(task.getOriSta());
                firstCode = codeService.getById(oriSta.getCode());
                break;
            case TO_CHARGE:
            case TO_STANDBY:
            case MOVE:
                firstCode = codeService.getById(task.getDestCode());
                break;
            default:
                firstCode = codeService.getById(task.getDestCode());
                break;
        }
        assert null != firstCode;
        Double[] toPosition = new Double[]{firstCode.getX(), firstCode.getY()};
        // calculate distance
        weight = weight + CommonUtil.calcDistance(fromPosition, toPosition);
        // return opposite
        return -weight;
    }
    public synchronized Agv execute(Task task, Map<String, List<Long>> taskAllot, List<Long> taskIds) {
@@ -87,7 +239,7 @@
        Agv hit = null;
        List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1));
        List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, StatusType.ENABLE.val));
        Collections.shuffle(agvList);
        for (Agv agv : agvList) {
            AgvModel agvModel = agvModelService.getById(agv.getAgvModel());