|
|
@ -8,7 +8,7 @@ import java.util.*; |
|
|
import static com.galaxis.rcs.plan.path2.PathUtils.*; |
|
|
import static com.galaxis.rcs.plan.path2.PathUtils.*; |
|
|
|
|
|
|
|
|
public class AStarPathPlanner { |
|
|
public class AStarPathPlanner { |
|
|
private static final float ROTATION_COST_PER_DEGREE = 0.1f; |
|
|
private static final float ROTATION_COST_PER_DEGREE = 0.01f; |
|
|
private static final float BLOCKED_COST = 10000f; // 阻塞系数成本
|
|
|
private static final float BLOCKED_COST = 10000f; // 阻塞系数成本
|
|
|
private static final float WEIGHT_FACTOR = 1.5f; // 权重因子
|
|
|
private static final float WEIGHT_FACTOR = 1.5f; // 权重因子
|
|
|
|
|
|
|
|
|
@ -44,8 +44,7 @@ public class AStarPathPlanner { |
|
|
State current = open.poll(); |
|
|
State current = open.poll(); |
|
|
|
|
|
|
|
|
// 到达目标节点且方向匹配
|
|
|
// 到达目标节点且方向匹配
|
|
|
if (current.node().id().equals(endId) && |
|
|
if (current.node().id().equals(endId) && current.direction() == endDirection) { |
|
|
current.direction() == endDirection) { |
|
|
|
|
|
return buildPath(current); |
|
|
return buildPath(current); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -54,56 +53,86 @@ public class AStarPathPlanner { |
|
|
// 检查节点是否被阻塞
|
|
|
// 检查节点是否被阻塞
|
|
|
if (isBlocked(neighbor.id())) continue; |
|
|
if (isBlocked(neighbor.id())) continue; |
|
|
|
|
|
|
|
|
|
|
|
// 计算移动方向
|
|
|
LCCDirection moveDirection = calculateMoveDirection(current.node(), neighbor); |
|
|
LCCDirection moveDirection = calculateMoveDirection(current.node(), neighbor); |
|
|
|
|
|
|
|
|
// 前进所需方向
|
|
|
// 前进所需方向
|
|
|
LCCDirection forwardHeading = moveDirection; |
|
|
LCCDirection forwardHeading = moveDirection; |
|
|
// 后退所需方向
|
|
|
// 后退所需方向
|
|
|
LCCDirection backwardHeading = getOppositeDirection(moveDirection); |
|
|
LCCDirection backwardHeading = getOppositeDirection(moveDirection); |
|
|
|
|
|
|
|
|
// 尝试前进
|
|
|
// 尝试前进
|
|
|
if (current.direction() == forwardHeading) { |
|
|
if (canMoveForward(current.direction(), moveDirection)) { |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor); |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor, false); |
|
|
considerState(current, neighbor, forwardHeading, |
|
|
considerState(current, neighbor, current.direction(), |
|
|
moveCost, open, visited, end); |
|
|
moveCost, open, visited, end); |
|
|
} else if (current.node().rotatable()) { |
|
|
|
|
|
float rotationCost = calculateRotationCost( |
|
|
|
|
|
current.direction(), forwardHeading, ROTATION_COST_PER_DEGREE |
|
|
|
|
|
); |
|
|
|
|
|
float moveCost = calculateMoveCost(current.node(), neighbor); |
|
|
|
|
|
float totalCost = rotationCost + moveCost; |
|
|
|
|
|
considerState(current, neighbor, forwardHeading, |
|
|
|
|
|
totalCost, open, visited, end); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 尝试后退
|
|
|
// 尝试后退
|
|
|
if (current.direction() == backwardHeading) { |
|
|
else if (canMoveBackward(current.direction(), moveDirection)) { |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor); |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor, true); |
|
|
considerState(current, neighbor, backwardHeading, |
|
|
considerState(current, neighbor, current.direction(), |
|
|
moveCost, open, visited, end); |
|
|
moveCost, open, visited, end); |
|
|
} else if (current.node().rotatable()) { |
|
|
} |
|
|
|
|
|
// 需要旋转
|
|
|
|
|
|
else if (current.node().rotatable()) { |
|
|
|
|
|
// 计算需要旋转到的方向
|
|
|
|
|
|
LCCDirection requiredDirection = calculateRequiredDirection(moveDirection); |
|
|
|
|
|
|
|
|
|
|
|
// 考虑旋转后移动
|
|
|
float rotationCost = calculateRotationCost( |
|
|
float rotationCost = calculateRotationCost( |
|
|
current.direction(), backwardHeading, ROTATION_COST_PER_DEGREE |
|
|
current.direction(), requiredDirection, ROTATION_COST_PER_DEGREE |
|
|
); |
|
|
); |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor); |
|
|
float moveCost = calculateMoveCost(current.node(), neighbor, false); |
|
|
float totalCost = rotationCost + moveCost; |
|
|
float totalCost = rotationCost + moveCost; |
|
|
considerState(current, neighbor, backwardHeading, |
|
|
|
|
|
totalCost, open, visited, end); |
|
|
// 创建旋转状态
|
|
|
|
|
|
State rotatedState = new State( |
|
|
|
|
|
current.node(), requiredDirection, |
|
|
|
|
|
current.g() + rotationCost, |
|
|
|
|
|
heuristic(current.node(), end), |
|
|
|
|
|
current |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 考虑旋转后的移动
|
|
|
|
|
|
considerState(rotatedState, neighbor, requiredDirection, |
|
|
|
|
|
moveCost, open, visited, end); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 处理原地旋转
|
|
|
// 处理原地旋转 - 只考虑目标方向
|
|
|
if (current.node().rotatable()) { |
|
|
if (current.node().rotatable()) { |
|
|
for (LCCDirection rotation : LCCDirection.values()) { |
|
|
// 只考虑旋转到目标方向(如果可能)
|
|
|
if (rotation == current.direction()) continue; |
|
|
if (current.direction() != endDirection) { |
|
|
|
|
|
float rotationCost = calculateRotationCost( |
|
|
|
|
|
current.direction(), endDirection, ROTATION_COST_PER_DEGREE |
|
|
|
|
|
); |
|
|
|
|
|
considerState(current, current.node(), endDirection, |
|
|
|
|
|
rotationCost, open, visited, end); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 另外考虑旋转到移动所需的方向
|
|
|
|
|
|
for (Node neighbor : graph.getNeighbors(current.node())) { |
|
|
|
|
|
LCCDirection moveDirection = calculateMoveDirection(current.node(), neighbor); |
|
|
|
|
|
LCCDirection requiredDirection = calculateRequiredDirection(moveDirection); |
|
|
|
|
|
|
|
|
|
|
|
if (requiredDirection != current.direction()) { |
|
|
float rotationCost = calculateRotationCost( |
|
|
float rotationCost = calculateRotationCost( |
|
|
current.direction(), rotation, ROTATION_COST_PER_DEGREE |
|
|
current.direction(), requiredDirection, ROTATION_COST_PER_DEGREE |
|
|
); |
|
|
); |
|
|
considerState(current, current.node(), rotation, |
|
|
considerState(current, current.node(), requiredDirection, |
|
|
rotationCost, open, visited, end); |
|
|
rotationCost, open, visited, end); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// for (LCCDirection rotation : LCCDirection.values()) {
|
|
|
|
|
|
// if (rotation == current.direction()) continue;
|
|
|
|
|
|
//
|
|
|
|
|
|
// float rotationCost = calculateRotationCost(
|
|
|
|
|
|
// current.direction(), rotation, ROTATION_COST_PER_DEGREE
|
|
|
|
|
|
// );
|
|
|
|
|
|
// considerState(current, current.node(), rotation,
|
|
|
|
|
|
// rotationCost, open, visited, end);
|
|
|
|
|
|
// }
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
return Collections.emptyList(); |
|
|
return Collections.emptyList(); |
|
|
} |
|
|
} |
|
|
@ -166,15 +195,30 @@ public class AStarPathPlanner { |
|
|
blockedNodes.put(nodeId, blockedFactor); |
|
|
blockedNodes.put(nodeId, blockedFactor); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private float calculateMoveCost(Node from, Node to) { |
|
|
private float calculateMoveCost(Node from, Node to, boolean isBackward) { |
|
|
float baseCost = graph.distance(from, to); |
|
|
float baseCost = graph.distance(from, to); |
|
|
float weight = nodeWeights.getOrDefault(to.id(), 1.0f); |
|
|
float weight = nodeWeights.getOrDefault(to.id(), 1.0f); |
|
|
float blockedFactor = blockedNodes.getOrDefault(to.id(), 0f); |
|
|
float blockedFactor = blockedNodes.getOrDefault(to.id(), 0f); |
|
|
|
|
|
|
|
|
|
|
|
// 后退移动增加额外成本??
|
|
|
|
|
|
// return baseCost * weight * (1 + blockedFactor) * (isBackward ? 1.2f : 1.0f);
|
|
|
return baseCost * weight * (1 + blockedFactor); |
|
|
return baseCost * weight * (1 + blockedFactor); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private boolean isBlocked(String nodeId) { |
|
|
private boolean isBlocked(String nodeId) { |
|
|
return blockedNodes.containsKey(nodeId) && blockedNodes.get(nodeId) > 0.8f; |
|
|
return blockedNodes.containsKey(nodeId) && blockedNodes.get(nodeId) > 0.8f; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean canMoveForward(LCCDirection currentDir, LCCDirection moveDir) { |
|
|
|
|
|
return currentDir == moveDir; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean canMoveBackward(LCCDirection currentDir, LCCDirection moveDir) { |
|
|
|
|
|
return currentDir == getOppositeDirection(moveDir); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private LCCDirection calculateRequiredDirection(LCCDirection moveDirection) { |
|
|
|
|
|
// 侧插式AGV只能前进或后退,不能横移
|
|
|
|
|
|
return moveDirection; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|