#
vincentlu
2026-04-07 7958b0e136e96d2730c2df17a46046d1bbe74358
#
6个文件已修改
289 ■■■■ 已修改文件
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/hik/HikOrderPublishService.java 166 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/AgvModelController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/result/AgvResult.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/AgvModelService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/AgvModelServiceImpl.java 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/AgvServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-manager/src/main/java/com/zy/acs/manager/core/service/hik/HikOrderPublishService.java
@@ -16,6 +16,7 @@
import com.zy.acs.framework.exception.CoolException;
import com.zy.acs.manager.common.config.HikOrderProperties;
import com.zy.acs.manager.core.constant.HikAngleConstant;
import com.zy.acs.manager.core.service.MapService;
import com.zy.acs.manager.manager.entity.Action;
import com.zy.acs.manager.manager.entity.AgvDetail;
import com.zy.acs.manager.manager.entity.AgvModel;
@@ -23,6 +24,7 @@
import com.zy.acs.manager.manager.enums.ActionTypeType;
import com.zy.acs.manager.manager.service.AgvDetailService;
import com.zy.acs.manager.manager.service.CodeService;
import com.zy.acs.manager.system.service.ConfigService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -47,6 +49,8 @@
    private CodeService codeService;
    @Autowired
    private AgvDetailService agvDetailService;
    @Autowired
    private ConfigService configService;
    private final RedisSupport redis = RedisSupport.defaultRedisSupport;
@@ -106,9 +110,10 @@
        int edgeIndex = 0;
        NodeCursor currentNode = createNode(actionGroupId, firstAction.getCode(), nodeIndex++, sequenceId++);
        Double currentDirection = resolveInitialNodeDirection(firstAction);
        applyNodeTheta(currentNode.node, currentDirection);
        nodes.add(currentNode.node);
        Double currentTheta = currentNode.node.getNodePosition().getTheta();
        for (int i = 0; i < actionList.size(); i++) {
            Action action = actionList.get(i);
            ActionTypeType actionType = resolveActionType(action);
@@ -121,35 +126,31 @@
            switch (actionType) {
                case TurnCorner:
                    if (i == 0) {
                        AgvDetail agvDetail = agvDetailService.selectMajorByAgvId(firstAction.getAgvId());
                        currentTheta = parseThetaRadians(String.valueOf(agvDetail.getAgvAngle()));
                        currentNode.node.getNodePosition().setTheta(currentTheta);
                    } else {
                        currentTheta = parseThetaRadians(action.getParams());
                        currentNode.node.getNodePosition().setTheta(currentTheta);
                    }
                    currentDirection = parseDirectionDegrees(action.getParams());
                    currentNode.node.getActions().add(buildRotateAgvAction(action, currentDirection));
                    break;
                case StraightAheadTurnable:
                case StraightAheadUnturnable:
                case StraightBackTurnable:
                case StraightBackUnturnable:
                    String endCode = findNextMoveEndCode(actionList, i, currentNode.code);
                    Double edgeTheta = currentTheta != null ? currentTheta : calculateTheta(currentNode.code, endCode);
                    HkOrderEdge edge = createEdge(actionGroupId, edgeIndex++, sequenceId++, currentNode, endCode, edgeTheta, action, agvModel);
                    Double travelDirection = calculateTravelDirection(currentNode.code, endCode);
                    Double moveDirection = resolveMoveDirection(currentDirection, travelDirection, actionType, actionGroupId, currentNode.code, endCode);
                    Double edgeOrientation = resolveEdgeOrientation(moveDirection, travelDirection);
                    HkOrderEdge edge = createEdge(actionGroupId, edgeIndex++, sequenceId++, currentNode, endCode, edgeOrientation, action, agvModel);
                    edges.add(edge);
                    NodeCursor nextNode = createNode(actionGroupId, endCode, nodeIndex++, sequenceId++);
                    nextNode.node.getNodePosition().setTheta(edgeTheta);
                    applyNodeTheta(nextNode.node, moveDirection);
                    nodes.add(nextNode.node);
                    currentNode = nextNode;
                    currentTheta = edgeTheta;
                    currentDirection = moveDirection;
                    break;
                case FinishPath:
                    break;
                default:
                    currentNode.node.getActions().add(buildNodeAction(action, actionType, currentTheta));
                    currentNode.node.getActions().add(buildNodeAction(action, actionType, toHikThetaRadians(currentDirection)));
                    break;
            }
        }
@@ -210,7 +211,7 @@
                                   long sequenceId,
                                   NodeCursor startNode,
                                   String endCode,
                                   Double edgeTheta,
                                   Double edgeOrientation,
                                   Action action,
                                   AgvModel agvModel) {
        HkOrderEdge edge = new HkOrderEdge();
@@ -223,11 +224,8 @@
//        edge.setEndNodeId(buildId(actionGroupId, "N", edgeIndex + 1, endCode));
        edge.setEndNodeId(endCode);
        edge.setMaxSpeed(resolveMaxSpeed(action, agvModel));
        // GLOBAL
        // TANGENTIAL
        edge.setOrientationType("TANGENTIAL");
        edge.setOrientation(0.0);
//        edge.setOrientation(edgeTheta);
        edge.setOrientation(edgeOrientation);
        edge.setRotationAllowed(Boolean.FALSE);
        edge.setActions(new ArrayList<>());
        return edge;
@@ -291,6 +289,21 @@
        return hkAction;
    }
    private HkAction buildRotateAgvAction(Action action, Double targetDirection) {
        HkAction hkAction = new HkAction();
        hkAction.setActionId("A" + action.getId());
        hkAction.setActionDescription(ActionTypeType.TurnCorner.desc);
        hkAction.setBlockingType(HkBlockingType.HARD);
        hkAction.setActionType(HkActionType.ROTATE_AGV);
        List<HkActionParameter> parameters = new ArrayList<>();
        addParameter(parameters, "sourceActionType", ActionTypeType.TurnCorner.name());
        addParameter(parameters, "sourceActionId", action.getId());
        addParameter(parameters, "angle", toHikThetaRadians(targetDirection));
        hkAction.setActionParameters(parameters);
        return hkAction;
    }
    private HkActionType resolveHkActionType(ActionTypeType actionType) {
        switch (actionType) {
            case ReadyTakeFromShelvesLoc:
@@ -350,22 +363,127 @@
        return new HeightDepthParam(heightDepthDto.getHeight(), heightDepthDto.getDepth());
    }
    private Double parseThetaRadians(String params) {
        Double thetaDegrees = parseDouble(params);
    private Double resolveInitialNodeDirection(Action firstAction) {
        if (firstAction == null || firstAction.getAgvId() == null) {
            return null;
        }
        AgvDetail agvDetail = agvDetailService.selectMajorByAgvId(firstAction.getAgvId());
        if (agvDetail == null || agvDetail.getAgvAngle() == null) {
            return null;
        }
        return MapService.mapToNearest(agvDetail.getAgvAngle());
    }
    private Double parseDirectionDegrees(String params) {
        return parseDouble(params);
    }
    private Double toHikThetaRadians(Double thetaDegrees) {
        if (thetaDegrees == null) {
            return null;
        }
        return HikAngleConstant.toHikAngleRadians(Math.toRadians(thetaDegrees));
    }
    private Double calculateTheta(String startCode, String endCode) {
    private void applyNodeTheta(HkOrderNode node, Double directionDegrees) {
        if (node == null || node.getNodePosition() == null) {
            return;
        }
        node.getNodePosition().setTheta(toHikThetaRadians(directionDegrees));
    }
    private Double calculateTravelDirection(String startCode, String endCode) {
        Code start = codeService.getCacheByData(startCode);
        Code end = codeService.getCacheByData(endCode);
        if (start == null || end == null) {
            throw new CoolException("hik order adaptation failed: code position missing");
        }
        double rcsTheta = Math.atan2(end.getY() - start.getY(), end.getX() - start.getX());
        return HikAngleConstant.toHikAngleRadians(rcsTheta);
        Integer angleOffsetVal = configService.getVal("mapAngleOffsetVal", Integer.class);
        if (angleOffsetVal == null) {
            angleOffsetVal = 0;
        }
        double deltaX = end.getX() - start.getX();
        double deltaY = end.getY() - start.getY();
        double angle = Math.atan2(deltaX, deltaY);
        angle = Math.toDegrees(angle) + angleOffsetVal;
        return normalizeDegrees(angle);
    }
    private Double resolveMoveDirection(Double currentDirection,
                                        Double travelDirection,
                                        ActionTypeType actionType,
                                        String actionGroupId,
                                        String startCode,
                                        String endCode) {
        Double expectedDirection = inferMoveDirection(travelDirection, actionType);
        if (currentDirection == null) {
            return expectedDirection;
        }
        if (!sameDegrees(currentDirection, expectedDirection)) {
            log.warn("hik order direction adjusted by move semantics, groupId={}, startCode={}, endCode={}, nodeDirection={}, expectedDirection={}, moveType={}",
                    actionGroupId,
                    startCode,
                    endCode,
                    currentDirection,
                    expectedDirection,
                    actionType);
        }
        return expectedDirection;
    }
    private Double inferMoveDirection(Double travelDirection, ActionTypeType actionType) {
        if (travelDirection == null) {
            return null;
        }
        switch (actionType) {
            case StraightAheadTurnable:
            case StraightAheadUnturnable:
                return normalizeDegrees(travelDirection);
            case StraightBackTurnable:
            case StraightBackUnturnable:
                return normalizeDegrees(travelDirection + 180D);
            default:
                throw new CoolException("hik order adaptation failed: unsupported move action type=" + actionType);
        }
    }
    private Double resolveEdgeOrientation(Double moveDirection, Double travelDirection) {
        if (moveDirection == null || travelDirection == null) {
            return null;
        }
        double delta = normalizeDegrees(moveDirection - travelDirection);
        if (almostZeroOrFull(delta)) {
            return 0.0;
        }
        if (almostEqual(delta, 180D)) {
            return Math.PI;
        }
        throw new CoolException("hik order adaptation failed: move direction is not tangential, moveDirection="
                + moveDirection + ", travelDirection=" + travelDirection);
    }
    private Double normalizeDegrees(Double degrees) {
        if (degrees == null) {
            return null;
        }
        double normalized = degrees % 360D;
        return normalized >= 0 ? normalized : normalized + 360D;
    }
    private boolean sameDegrees(Double left, Double right) {
        if (left == null || right == null) {
            return Objects.equals(left, right);
        }
        double delta = normalizeDegrees(left - right);
        return almostZeroOrFull(delta);
    }
    private boolean almostZeroOrFull(double value) {
        return almostEqual(value, 0D) || almostEqual(value, 360D);
    }
    private boolean almostEqual(double left, double right) {
        return Math.abs(left - right) < 1e-6;
    }
    private Double resolveMaxSpeed(Action action, AgvModel agvModel) {
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/AgvModelController.java
@@ -13,7 +13,6 @@
import com.zy.acs.manager.manager.entity.AgvModel;
import com.zy.acs.manager.manager.enums.StatusType;
import com.zy.acs.manager.manager.service.AgvModelService;
import com.zy.acs.manager.manager.service.impl.AgvModelServiceImpl;
import com.zy.acs.manager.system.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -106,19 +105,8 @@
        agvModel.setUpdateTime(new Date());
        if (!agvModelService.updateById(agvModel)) {
            return R.error("Update Fail");
        } else {
            // update cache
            for (Map.Entry<Long, AgvModel> entry : AgvModelServiceImpl.AGV_ID_MODEL_CACHE.entrySet()) {
                if (entry.getValue().getId().equals(agvModel.getId())) {
                    entry.setValue(agvModel);
                }
            }
            for (Map.Entry<String, AgvModel> entry : AgvModelServiceImpl.AGV_NO_MODEL_CACHE.entrySet()) {
                if (entry.getValue().getId().equals(agvModel.getId())) {
                    entry.setValue(agvModel);
                }
            }
        }
        agvModelService.refreshCacheByModelId(agvModel.getId());
        return R.ok("Update Success").add(agvModel);
    }
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/controller/result/AgvResult.java
@@ -3,6 +3,7 @@
import com.zy.acs.framework.common.Cools;
import com.zy.acs.manager.manager.entity.Agv;
import com.zy.acs.manager.manager.entity.AgvDetail;
import com.zy.acs.manager.manager.entity.Code;
import com.zy.acs.manager.manager.entity.Task;
import com.zy.acs.manager.manager.enums.TaskStsType;
import com.zy.acs.manager.manager.service.AgvService;
@@ -52,7 +53,10 @@
                this.setSoc(String.valueOf(agvDetail.getSoc()));
            }
            if (null != agvDetail.getRecentCode()) {
                this.setCode(codeService.getCacheById(agvDetail.getRecentCode()).getData());
                Code code = codeService.getCacheById(agvDetail.getRecentCode());
                if (null != code) {
                    this.setCode(code.getData());
                }
            }
            List<Task> tasks = taskService.selectInSts(agvDetail.getAgvId(), TaskStsType.WAITING, TaskStsType.ASSIGN, TaskStsType.PROGRESS);
            if (!Cools.isEmpty(tasks)) {
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/AgvModelService.java
@@ -11,6 +11,10 @@
    AgvModel getByAgvNo(String agvNo);
    void refreshCacheByModelId(Long modelId);
    void evictCacheByAgv(Long agvId, String agvNo);
    Boolean isSingleBasket(Long agvId);
}
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/AgvModelServiceImpl.java
@@ -8,17 +8,19 @@
import com.zy.acs.manager.manager.service.AgvModelService;
import com.zy.acs.manager.manager.service.AgvService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
@Service("agvModelService")
public class AgvModelServiceImpl extends ServiceImpl<AgvModelMapper, AgvModel> implements AgvModelService {
    public static final Map<Long, AgvModel> AGV_ID_MODEL_CACHE = new HashMap<>();
    public static final Map<String, AgvModel> AGV_NO_MODEL_CACHE = new HashMap<>();
    public static final Map<Long, AgvModel> AGV_ID_MODEL_CACHE = new ConcurrentHashMap<>();
    public static final Map<String, AgvModel> AGV_NO_MODEL_CACHE = new ConcurrentHashMap<>();
    @Autowired
    private AgvService agvService;
@@ -27,8 +29,7 @@
    public void init() {
        for (Agv agv : agvService.list()) {
            AgvModel agvModel = this.getById(agv.getAgvModel());
            AGV_ID_MODEL_CACHE.put(agv.getId(), agvModel);
            AGV_NO_MODEL_CACHE.put(agv.getUuid(), agvModel);
            this.cacheAgvModel(agv, agvModel);
        }
    }
@@ -39,28 +40,75 @@
    @Override
    public AgvModel getByAgvId(Long agvId) {
        if (agvId == null) {
            return null;
        }
        AgvModel agvModel = AGV_ID_MODEL_CACHE.get(agvId);
        if (agvModel == null) {
            Agv agv = agvService.getById(agvId);
            if (agv == null || agv.getAgvModel() == null) {
                return null;
            }
            agvModel = this.getById(agv.getAgvModel());
            if(agvModel != null) {
                AGV_ID_MODEL_CACHE.put(agv.getId(), agvModel);
            if (agvModel != null) {
                this.cacheAgvModel(agv, agvModel);
            }
        }
        return agvModel;
        return this.copyModel(agvModel);
    }
    @Override
    public AgvModel getByAgvNo(String agvNo) {
        if (agvNo == null) {
            return null;
        }
        AgvModel agvModel = AGV_NO_MODEL_CACHE.get(agvNo);
        if (agvModel == null) {
            Agv agv = agvService.selectByUuid(agvNo);
            if (agv == null || agv.getAgvModel() == null) {
                return null;
            }
            agvModel = this.getById(agv.getAgvModel());
            if(agvModel != null) {
                AGV_NO_MODEL_CACHE.put(agvNo, agvModel);
            if (agvModel != null) {
                this.cacheAgvModel(agv, agvModel);
            }
        }
        return agvModel;
        return this.copyModel(agvModel);
    }
    @Override
    public void refreshCacheByModelId(Long modelId) {
        if (modelId == null) {
            return;
        }
        AgvModel latestModel = this.getById(modelId);
        if (latestModel == null) {
            AGV_ID_MODEL_CACHE.entrySet().removeIf(entry -> this.hitModel(entry.getValue(), modelId));
            AGV_NO_MODEL_CACHE.entrySet().removeIf(entry -> this.hitModel(entry.getValue(), modelId));
            return;
        }
        for (Map.Entry<Long, AgvModel> entry : AGV_ID_MODEL_CACHE.entrySet()) {
            AgvModel cachedModel = entry.getValue();
            if (this.hitModel(cachedModel, modelId)) {
                AGV_ID_MODEL_CACHE.put(entry.getKey(), this.copyModel(latestModel));
            }
        }
        for (Map.Entry<String, AgvModel> entry : AGV_NO_MODEL_CACHE.entrySet()) {
            AgvModel cachedModel = entry.getValue();
            if (this.hitModel(cachedModel, modelId)) {
                AGV_NO_MODEL_CACHE.put(entry.getKey(), this.copyModel(latestModel));
            }
        }
    }
    @Override
    public void evictCacheByAgv(Long agvId, String agvNo) {
        if (agvId != null) {
            AGV_ID_MODEL_CACHE.remove(agvId);
        }
        if (agvNo != null) {
            AGV_NO_MODEL_CACHE.remove(agvNo);
        }
    }
    @Override
@@ -69,4 +117,25 @@
        return model.getBackpack() <= 1;
    }
    private void cacheAgvModel(Agv agv, AgvModel agvModel) {
        if (agv == null || agvModel == null) {
            return;
        }
        AGV_ID_MODEL_CACHE.put(agv.getId(), this.copyModel(agvModel));
        AGV_NO_MODEL_CACHE.put(agv.getUuid(), this.copyModel(agvModel));
    }
    private boolean hitModel(AgvModel agvModel, Long modelId) {
        return agvModel != null && Objects.equals(agvModel.getId(), modelId);
    }
    private AgvModel copyModel(AgvModel agvModel) {
        if (agvModel == null) {
            return null;
        }
        AgvModel target = new AgvModel();
        BeanUtils.copyProperties(agvModel, target);
        return target;
    }
}
zy-acs-manager/src/main/java/com/zy/acs/manager/manager/service/impl/AgvServiceImpl.java
@@ -142,8 +142,7 @@
        Agv oldAgv = this.getById(agv.getId());
        String oldAgvNo = oldAgv.getUuid();
        AgvModelServiceImpl.AGV_ID_MODEL_CACHE.remove(agv.getId());
        AgvModelServiceImpl.AGV_NO_MODEL_CACHE.remove(oldAgvNo);
        agvModelService.evictCacheByAgv(agv.getId(), oldAgvNo);
        agv.setUpdateBy(userId);
        agv.setUpdateTime(now);
@@ -163,10 +162,6 @@
            AGV_NO_MAP.put(newAgv.getId(), newAgvNo);
        }
//        AgvModel agvModel = agvModelService.getById(agv.getAgvModel());
//        AgvModelServiceImpl.AGV_ID_MODEL_CACHE.put(agv.getId(), agvModel);
//        AgvModelServiceImpl.AGV_NO_MODEL_CACHE.put(newAgvNo, agvModel);
        return newAgv;
    }
@@ -179,6 +174,7 @@
        Agv agv = this.getById(agvId);
        AGV_NO_MAP.remove(agvId);
        AGV_ID_MAP.remove(agv.getUuid());
        agvModelService.evictCacheByAgv(agvId, agv.getUuid());
        mapDataDispatcher.modifyDynamicMatrix(MapDataDispatcher.MAP_DEFAULT_LEV, null, agv.getUuid(), true);