rm_mcp
# rm_mcp
`rm_mcp` 是面向 `rm_ws` 的 ROS Noetic MCP Server。它把团队已有的调试 SOP、ROS 状态内省、控制器操作、受控激振和 PID 分析能力提供给 Agent,使调参过程可重复、可审计,并保留实车安全边界。
## 背景
在控制组的任务中,除了控制器开发,还需要在仿真和实车中进行参数调试与标定。其中一部分工作,例如云台 PID 调试、底盘功率限制调试和拨盘 offset 调试,具有固定流程、指令格式以及可以量化的验收指标。
因此可以让 LLM 通过 MCP 与 ROS 系统结合,按照团队 SOP 完成环境检查、参数修改、受控激振、数据采集和分析,形成自动化调参闭环。
## Why rm_mcp?
`rm_mcp` 是针对团队工作空间特化的 MCP Server。它既提供对接 ROS 调试流程的工具,也通过 `docs/sop/` 记录连车、控制器启动和云台调试等操作规程。Agent 因而可以先理解当前系统与调试步骤,再在明确的安全约束下执行调参。
与直接编写 ROS 脚本相比,`rm_mcp` 提供:
- 结构化的 ROS 状态、话题、节点和控制器信息;
- 对实车及敏感动作的 `confirm_token` 两阶段确认;
- 独占发布仲裁、Quiet State 恢复、看门狗和诚实失败结果;
- 可直接用于 PID 分析的零落盘内存采样数据;
- 与团队 SOP 一致的故障诊断和调参建议。
## 工具列表
当前共有 22 个工具,按调试流程分为以下类别。
### 1. 环境检查与 ROS 内省
用于确认 ROS 图、话题、节点和系统前置条件;出现 `success=False` 时应根据 `error` 及返回中存在的 `remediation` 排查。
- `preflight()`:检查 ROS Master、基础设施、车型、TF 支持与控制器依赖。
- `list_topics()`:列出活动话题及消息类型。
- `get_topic_info(topic)`:查询话题类型、发布者和订阅者。
- `list_nodes()`:列出活动节点。
- `get_node_info(node)`:查询节点发布、订阅和服务信息。
- `echo_topic(topic, duration_sec, max_messages)`:限时、限量采样话题消息。
### 2. 目标、进程与控制器生命周期
用于声明操作目标、启动调试环境以及检查或切换控制器状态。
- `configure_target(mode, robot_type, rosbridge_uri, ssh_host, confirm_token)`:设置目标。sim 必须由用户显式指定 `robot_type`;real 从远程车辆 `~/environment.sh` 读取 `ROBOT_TYPE`。
- `launch(package, launch_file, args, confirm_token)`:仿真本地启动或实车 SSH 启动 launch 文件。
- `list_launches()`:列出由 MCP 管理的 launch 进程。
- `kill_launch(handle, confirm_token)`:停止指定 launch 进程组。
- `ensure_infrastructure(target_services, confirm_token)`:检查并拉起 `rosapi`、`rosbridge_websocket` 等基础设施。
- `list_controllers()`:列出 ros_control 控制器及其状态。
- `switch_controller(start_controllers, stop_controllers, strictness, confirm_token)`:启停控制器。
- `reload_controller(name, confirm_token)`:stop → unload → load → start 一步完成,用于应用 init() 时才读取的静态参数(如 feedforward.gravity/mass_origin);单纯 stop/start 不会重读此类参数。
调参 bring-up 参见 [`docs/sop/01-连车与手跑控制器.md`](../../docs/sop/01-连车与手跑控制器.md)。`load_controllers.launch` 只加载控制器,仍需通过 `switch_controller` 启动所需控制器。
### 3. 参数与机械约束
用于读取参数、热更新运行时配置以及检查关节边界。
- `get_param(param_name, name)`:读取 ROS 参数。
- `set_param(param_name, value, confirm_token)`:写入 ROS 参数;运行中控制器参数请改用 `set_dynamic_param`。
- `set_dynamic_param(node, params, confirm_token, dry_run)`:通过 dynamic_reconfigure 热更新参数,或用 `dry_run=True` 查询可用 schema。
- `get_joint_limits(joint_name, robot_type)`:查询 URDF 的物理限位、软限位、effort 与速度约束。
### 4. 激振与零落盘采集
用于在受控条件下发送测试输入并获取反馈数据。
- `inject_signal(topic, field, waveform, amplitude, frequency, duration_sec, publish_rate_hz, extra_fields, dry_run, force, confirm_token)`:发送阶跃、正弦、方波或三角波;包含独占发布仲裁、Quiet State 归零和消息时间戳补全。
- `capture_topic_sync(topic, fields, duration_sec, max_messages, timeout_sec)`:零落盘内存采样,适用于稳态、外部输入或低速手动诊断。
动态激振闭环调参优先使用 rosbag 路径(`record_bag` → `inject_signal` → `stop_record_bag` → `analyze_pid(bag_path=...)`):返回体量可控、可持久化审计。`capture_topic_sync` 仅用于稳态或外部输入下的低速采样。
### 5. 录包与调参分析
用于持久化数据、分析闭环响应和生成诊断建议。
- `record_bag(topics, duration_sec, mode, output_path, background, trigger_on_topic, confirm_token)`:本地或远程录包;动态注入场景使用 `background=True`。
- `stop_record_bag(bag_handle, confirm_token)`:停止后台录包并读取元数据。
- `analyze_pid(topic_data, bag_path, signal_type, settle_threshold, accept_threshold, diagnostics, angle_wrapping, axis, ...)`:统一 PID 分析——阶跃/正弦/跟踪指标、验收判定与 opt-in 诊断(oscillation/windup/saturation)。验收条件:正弦激振时位置环跟踪误差 `error < 0.006 rad`(max\|error\|,`accept_threshold=0.006`)。
云台调参流程参见 [`docs/sop/04-云台调试.md`](../../docs/sop/04-云台调试.md)。位置环跟踪误差的参考验收阈值为 `0.006 rad`。
## 使用约定
1. 开始会话时先调用 `configure_target(mode="sim", robot_type="<type>")`;real 模式调用 `configure_target(mode="real")`,车型由远程车辆发现。
2. 优先使用 MCP 工具;只有工具明确不覆盖所需能力时才退回 `rostopic`、`rosparam`、`rosservice` 或 `rosbag` CLI,并说明工具缺口。
3. 实车写操作、红线关键字以及高幅值激振可能返回 `PENDING_CONFIRMATION`;取得用户确认后使用返回的 `confirm_token` 重试。
4. 对实时控制参数使用 `set_dynamic_param`,不要期望 `set_param` 写入后被运行中控制器自动重读。
5. `record_bag` 是动态调参的默认采集路径;`capture_topic_sync` 仅用于稳态或外部输入场景。
## Tools (English)
The server exposes 22 tools, grouped by their role in the debugging workflow.
### 1. Environment checks and ROS introspection
- `preflight()`: Checks ROS Master reachability, target identity, required TF/feedback publishers, and controller dependencies. In simulation, BLOCKING or UNKNOWN TF/feedback status always makes `ready=False`.
- `list_topics()`: Lists active ROS topics and message types.
- `get_topic_info(topic)`: Reports a topic's type, publishers, and subscribers.
- `list_nodes()`: Lists active ROS nodes.
- `get_node_info(node)`: Reports a node's publications, subscriptions, and services.
- `echo_topic(topic, duration_sec, max_messages)`: Samples a topic with bounded duration and message count.
### 2. Target, process, and controller lifecycle
- `configure_target(mode, robot_type, rosbridge_uri, ssh_host, confirm_token)`: Selects the target. Sim requires a user-supplied `robot_type`; real discovers `ROBOT_TYPE` from the remote vehicle's `~/environment.sh`.
- `launch(package, launch_file, args, confirm_token)`: Starts a local simulation launch or a remote launch over SSH.
- `list_launches()`: Lists launch processes tracked by this MCP server.
- `kill_launch(handle, confirm_token)`: Terminates a tracked launch process group.
- `ensure_infrastructure(target_services, confirm_token)`: Ensures supported `rosapi` and `rosbridge_websocket` infrastructure is available.
- `list_controllers()`: Lists ros_control controllers and their states.
- `switch_controller(start_controllers, stop_controllers, strictness, confirm_token)`: Starts or stops ros_control controllers.
- `reload_controller(name, confirm_token)`: stop -> unload -> load -> start in one call, to apply static parameters read only in init() (e.g. feedforward.gravity/mass_origin); plain stop/start never re-reads them.
### 3. Parameters and mechanical constraints
- `get_param(param_name, name)`: Reads a ROS parameter.
- `set_param(param_name, value, confirm_token)`: Writes a ROS parameter; for runtime parameters of a running controller use set_dynamic_param instead.
- `set_dynamic_param(node, params, confirm_token, dry_run)`: Hot-updates dynamic_reconfigure parameters or returns their schema in dry-run mode.
- `get_joint_limits(joint_name, robot_type)`: Reads physical and soft joint limits, effort/velocity constraints, and the robot identity and source that own those limits.
### 4. Excitation and zero-disk capture
- `inject_signal(topic, field, waveform, amplitude, frequency, duration_sec, publish_rate_hz, extra_fields, dry_run, force, confirm_token)`: Publishes bounded step/sine/square/triangle excitation with exclusive-publisher arbitration, timestamps, and Quiet State restoration.
- `capture_topic_sync(topic, fields, duration_sec, max_messages, timeout_sec)`: Captures topic samples directly in memory for steady-state or externally driven diagnostics.
### 5. Recording and tuning analysis
- `record_bag(topics, duration_sec, mode, output_path, background, trigger_on_topic, confirm_token)`: Records local or remote rosbag data, with background mode for injection workflows.
- `stop_record_bag(bag_handle, confirm_token)`: Stops a background recording and returns bag metadata.
- `analyze_pid(topic_data, bag_path, signal_type, settle_threshold, accept_threshold, diagnostics, angle_wrapping, axis, effort_limit, skip_initial_sec, skip_final_sec, topic_filter)`: Unified PID analysis — step/sine/tracking metrics (python-control step_info conventions, IAE/ITAE), pass/fail acceptance (acceptance condition: position-loop tracking error `error < 0.006 rad` at every sample under sinusoidal excitation; `accept_threshold=0.006`), and opt-in diagnostics (oscillation, windup cross-checked with saturation, saturation). Trailing quiet-window setpoint returns are excluded via `skip_final_sec`; unexcluded trailing edges are reported in `warnings`.
Use the rosbag path for the dynamic tuning loop (record_bag -> inject_signal -> stop_record_bag -> analyze_pid(bag_path)); use `capture_topic_sync` only for steady-state or externally driven sampling.
## 快速开始
### 环境要求
- ROS Noetic
- Python >= 3.10
- [uv](https://docs.astral.sh/uv/)
### 安装与启动
```bash
cd src/rm_mcp
uv sync
uv run python -m rm_mcp.server
```
也可以通过 MCP Inspector 调试:
```bash
cd src/rm_mcp
uv run mcp dev src/rm_mcp/server.py
```
### 测试
```bash
cd src/rm_mcp
uv run pytest
```
Gazebo 硬件在环测试需显式启用:
```bash
cd src/rm_mcp
RUN_HW_TESTS=1 uv run pytest tests/hardware/ -m hardware -v
```
## 相关文档
- [`CONTEXT.md`](./CONTEXT.md):工具行为、传输与安全边界。
- [`DEVELOPMENT.md`](./DEVELOPMENT.md):开发状态、设计决策和测试约定。
- [`docs/sop/01-连车与手跑控制器.md`](../../docs/sop/01-连车与手跑控制器.md):连车与控制器启动。
- [`docs/sop/04-云台调试.md`](../../docs/sop/04-云台调试.md):云台 PID 调参。
TDQS
Scored across 26 tools
Several tool pairs overlap in function: list_topics/get_topic_info, list_nodes/get_node_info, capture_topic_sync/capture_inject_sync, and the three analysis tools (analyze_step_response, analyze_gimbal_pid, diagnose_gimbal_tuning). While descriptions clarify the differences, the boundaries are not always obvious to an agent.
Most tools follow a verb_noun pattern (list_topics, get_param, set_param, etc.). Exceptions like 'preflight' and 'launch' are bare verbs, and 'capture_inject_sync' is a compound. Overall the pattern is consistent enough.
With 26 tools, the surface is heavy, and there is notable redundancy (e.g., three analysis tools, two capture tools). Some tools could be merged, making the count feel inflated for the stated purpose.
The core gimbal tuning workflow is well covered: parameter read/write, injection, capture, recording, and analysis. Minor gaps exist, such as a generic service caller or generic publish tool, but agents can work around these using existing tools.