Nav2 导航集成:新增 nav2_navigator.py,mission_executor 改用 Nav2 action 导航

- 新增 agv_app/utils/nav2_navigator.py:Nav2Navigator 类,通过 ros2 action
  /navigate_to_pose 和 /navigate_through_poses 与 Nav2 通信,支持路径点导航
- app.py:navigate/to, navigate/path, navigate/status 三个 API 改用 Nav2Navigator
- mission_executor.py:_execute_point 中调用 _nav2_go_to_point() 替代原来的
  time.sleep 模拟移动,Nav2 负责从当前点到目标点的自主导航
- 原有的 map_navigator.py(A* + Pure Pursuit 自实现)保留不动,供无 Nav2 时降级用
This commit is contained in:
ywb
2026-05-16 10:23:17 +08:00
parent 924f9f3be6
commit 2bb8dff4e2
5 changed files with 710 additions and 18 deletions
+18 -13
View File
@@ -17,7 +17,7 @@ from utils.agv_controller_ros2 import AGVController
from utils.qr_scanner import QRScanner
from utils.image_uploader import ImageUploader
from utils.mission_executor import MissionExecutor, TaskStatus
from utils.map_navigator import MapNavigator, NavStatus
from utils.nav2_navigator import Nav2Navigator, Nav2Status
# 配置日志
logging.basicConfig(
@@ -51,7 +51,7 @@ class GlobalState:
"positions": [] # 独立点位配置 [{row, col, side, coords, poses}]
}
self.machines_config = [] # 机器配置(每台机器的正面/背面点位+姿态)
self.navigator = None # MapNavigator 实例
self.navigator = None # Nav2Navigator 实例
self.lock = threading.Lock()
def reset(self):
@@ -412,12 +412,13 @@ def api_navigate_to():
try:
if gs.navigator is None:
gs.navigator = MapNavigator(gs.map_config["map_yaml"])
ok = gs.navigator.navigate_to(float(goal_x), float(goal_y))
gs.navigator = Nav2Navigator()
# navigate_to_pose(x, y, yaw=None, timeout_sec=120, blocking=False)
ok = gs.navigator.navigate_to_pose(float(goal_x), float(goal_y), blocking=False)
if ok:
return jsonify({"ok": True, "message": "导航已启动"})
else:
return jsonify({"ok": False, "error": "路径规划失败或导航正在进行中"}), 400
return jsonify({"ok": False, "error": "导航启动失败,可能是Nav2未运行或AGV未连接"}), 400
except Exception as e:
logger.error(f"导航失败: {e}")
return jsonify({"ok": False, "error": str(e)}), 500
@@ -437,12 +438,12 @@ def api_navigate_status():
"""获取导航状态"""
if gs.navigator:
return jsonify(gs.navigator.get_status())
return jsonify({"status": "idle", "current_position": [0, 0, 0], "path_length": 0, "path": []})
return jsonify({"status": "idle", "current_position": [0, 0, 0], "nav2_available": False})
@app.route("/api/navigate/path", methods=["POST"])
def api_navigate_path():
"""预览路径(仅规划不执行)"""
"""预览路径(仅规划不执行)- Nav2版本不支持预计算路径,返回当前导航状态"""
if not gs.map_config or "map_yaml" not in gs.map_config:
return jsonify({"ok": False, "error": "地图未加载"}), 400
@@ -454,12 +455,16 @@ def api_navigate_path():
try:
if gs.navigator is None:
gs.navigator = MapNavigator(gs.map_config["map_yaml"])
path = gs.navigator.get_path_preview(float(goal_x), float(goal_y))
if path is not None:
return jsonify({"ok": True, "path": path, "length": len(path)})
else:
return jsonify({"ok": False, "error": "路径规划失败,目标点不可达"}), 400
gs.navigator = Nav2Navigator()
# Nav2 不提供路径预览,直接返回可用状态
current = gs.navigator.get_current_position()
status = gs.navigator.get_status()
return jsonify({
"ok": True,
"message": "Nav2 路径预览不可用,请在 RViz 中查看规划路径",
"current_position": current,
"nav2_available": status.get("nav2_available", False)
})
except Exception as e:
logger.error(f"路径预览失败: {e}")
return jsonify({"ok": False, "error": str(e)}), 500