highlevel_skills 模块

daystar_api.highlevel_skills 是基于 lowlevel 接口封装的高层任务技能集合。 相比 lowlevel 接口直接对应单个 ROS 服务/动作,highlevel skill 通常组合多个 lowlevel 调用、 内置前置状态检查与降级逻辑,对调用方屏蔽底层状态机复杂性。

模块概览

当前已收录的 highlevel skill:

  • 导航类::py:func:`go_to_location`(导航到指定点位 / 位姿 / 经过多点)

快速示例

from daystar_api.highlevel_skills import go_to_location

# 1. 单点(自动路网规划)
result = go_to_location("茶水间")
print(f"导航结果: {result.state.cn}")

# 2. 多点路线(直接执行,跳过路网;最后一个即终点)
result = go_to_location(locations=["大厅", "走廊", "会议室"])

# 3. 带回调
def on_complete(ev): print("到达", ev)
result = go_to_location("充电桩", complete_callback=on_complete)

Note

highlevel skill 是纯 Python 实现(位于 daystar_api/highlevel_skills/ 包下)。 本页采用手写 py:function 指令而非 autodoc,与同类无法 autodoc 的页面 (逻辑流控制)风格对齐——daystar_api 顶层包的导入链涉及 ROS workspace 外部依赖(path_planer_api_lowlevel_skills 的 pybind 绑定等), sphinx 构建环境不保证全部可用。

导航类

go_to_location(location=None, pose=None, locations=None, poses=None, travel_params=None, timeout=600, complete_callback=None, failed_callback=None, progress_callback=None, graph_file=None, start_location=None)

导航到指定命名点位、坐标位姿,或顺序经过多个点位 / 位姿。在执行导航前自动完成定位检查、 姿态调节、控制模式切换等前置步骤;对单点目标支持基于路网文件的最短路径展开。

底层始终走多点导航 API:单点情形本质上等价于”长度为 1 的多点导航”, 因此不再单独调用 _lowlevel_skills.navigation_to_pose()

参数互斥规则location / pose / locations / poses 必须且只能提供其中一个。

Parameters:
  • location (str | None) – 单个目标点位名称,须已在系统中注册(可通过 _lowlevel_skills.get_available_location() 查询)。

  • pose (Pose | None) – 单个目标坐标位姿,通常配合 _lowlevel_skills.get_current_pose() 使用以实现”返回原位”。

  • locations (list[str] | None) – 多个已注册点位的顺序列表,最后一个即终点。 想要”先经过 A、B 再到 C”,直接写 locations=["A", "B", "C"]。 提供时跳过路网规划,graph_file / start_location 被忽略。

  • poses (list[Pose] | None) – 多个位姿的顺序列表,最后一个即终点。 提供时跳过路网规划,graph_file / start_location 被忽略。

  • travel_params (MsgTravelParams | None) – 导航行驶参数。仅作用于序列最后一个点 (即真正的终点);底层 action server 设计如此。为 None 时使用默认值。

  • timeout (int) – 整个导航过程的超时时间(秒),默认 600。上限 30 分钟。

  • complete_callback (callable | None) – 导航成功完成时的回调, 接收 _lowlevel_skills.NavCompleteEvent

  • failed_callback (callable | None) – 导航失败时的回调, 接收 _lowlevel_skills.NavFailedEvent

  • progress_callback (callable | None) – 导航进度回调, 接收 _lowlevel_skills.NavProgressEvent

  • graph_file (str | None) – 路网图文件名或路径。为 None 时自动发现 GRAPH_DIR 中的默认路网(default.yaml 优先)。 仅对 ``location`` / ``pose`` 单点目标生效

  • start_location (str | None) – 起始路网节点名称。为 None 时根据当前位置 自动匹配最近节点。仅对 ``location`` / ``pose`` 单点目标生效

Returns:

底层多点导航结果。state.code == 0 表示成功;state.cn 包含中文描述。

Return type:

_lowlevel_skills.NavigationViaPosesResponse

Raises:
  • GoToLocationError – 前置检查失败或参数不合法时抛出 (如多个目标参数同时提供、目标点位未注册等)。

  • RuntimeError – 在导航回调内部递归调用本函数(或任何 block=True 的底层 nav API)时由 C++ 层立即抛出,防止 ROS 动作客户端死锁。详见下方”回调死锁防御”。

执行路径

入参

行为

locations 显式列表

跳过路网规划,原样作为 navigation_via_locations 入参

poses 显式列表

跳过路网规划,原样包装为 PoseStamped 列表后调 navigation_via_poses

location + 有可用路网 + 目标在路网中

路网最短路径展开为完整节点序列(含起点),一次性调用 navigation_via_locations

location 无路网(或目标不在路网中)

退化为单点列表 [location]navigation_via_locations

pose + 有可用路网

路网节点 yaml 读 Pose 拼成前缀 + 最终 pose,一次性调用 navigation_via_poses

pose 无路网

退化为单点列表 [pose]navigation_via_poses

Note

路网展开后的列表**包含起点节点**(机器人当前位置最近的路网节点),原样下发。 是否 skip 已到达的 waypoint 由底层 navigation 控制器自行判定, Python 高层不做猜测式剔除。这保证了”路网展开”与”显式 locations 列表” 在底层眼中完全等价。

回调安装机制

每次调用通过底层 C++ 绑定的 NavCallbackGuard RAII 临时安装 callback, 调用结束自动还原调用前的全局回调(per-call scoped)。不会污染其它模块注册的全局回调。

回调死锁防御

底层 navigation_client_ 绑定在 send_goal_cb_group_``(``MutuallyExclusive), 同组同时只能执行一个回调。若在 complete_callback / failed_callback / progress_callback 内部又调用 block=True 的 nav API,会等同组下一次回调被派发, 但该组已被当前回调占用——必然死锁。

C++ 层加了 thread_local 标志 + RAII:进入用户 callback 前置位, 阻塞 nav 入口(RequestNavigationAct(block=true) / WaitForNavigation / RequestCancelNav)检测到立刻抛 std::runtime_error,pybind11 自动转 Python RuntimeError

回调中可安全调用block=False 的异步派发,get_current_pose / get_robot_state 等其它回调组的服务,纯 Python 计算 / 置标志位, threading.Thread 起独立线程后在其中调阻塞 nav(独立 OS 线程不触发防御)。

回调中禁止调用go_to_location(block 隐含 True) / navigation_*(block=True) / wait_for_navigation / cancel_navigation

from daystar_api.highlevel_skills import go_to_location
from daystar_api.lowlevel_skills import get_current_pose, Pose

# 1. 单点(自动路网规划,无路网则直接导航)
result = go_to_location("茶水间")
if result.state.code != 0:
    raise RuntimeError(f"导航失败: {result.state.cn}")

# 2. 多点名字路线(直接执行,不规划。"先去 A 再去 B 最后到 C" 就走这里)
result = go_to_location(locations=["大厅", "走廊", "会议室"])

# 3. 多点位姿
result = go_to_location(poses=[pose_a, pose_b, pose_c])

# 4. 返回原位(先记录出发位置,执行任务后回去)
pose_resp = get_current_pose()
origin_pose = pose_resp.response.location_pose
# ... 执行中间任务 ...
result = go_to_location(pose=origin_pose)
print(f"返回原位: {result.state.cn}")

# 5. 带回调(callback 内禁止调阻塞 nav API)
def on_complete(ev):
    print("到达终点", ev)
def on_failed(ev):
    print("失败", ev)
result = go_to_location(
    "充电桩",
    complete_callback=on_complete,
    failed_callback=on_failed,
)

# 6. 回调中发起下一段导航的推荐做法:主线程串行
result = go_to_location("A")
if result.state.code == 0:
    result = go_to_location("B")
exception GoToLocationError

go_to_location 前置检查失败或参数不合法时抛出。继承自 RuntimeError

相关数据类型