ros2_mcp桥
ROS 2包将机器人主题和服务公开为 MCP(模型上下文协议)工具,允许LLM代理直接感知和控制机器人。
网桥订阅机器人的传感器主题,缓存最新数据,并通过FastMCP HTTP服务器提供服务。任何MCP兼容的代理(如 onit)然后,可以调用这些工具来读取传感器、驱动机器人、导航到目标、运行更高级别的行为,并执行简短的本地DSL程序以完成紧密的反馈循环任务。
LLM Agent (onit)
│ HTTP / streamable-http
▼
ros2_mcp_bridge (port 18210)
│ rclpy subscriptions / publishers
▼
ROS 2 Robot (camera, LiDAR, ultrasonic, odom, detections, cmd_vel, Nav2)典型的部署分为同一ROS 2 DDS域上的两台机器:
| 机器 | 角色 | 典型节点 |
|---|---|---|
| 机器人上的Raspberry Pi | 基座+传感器 | 电机驱动器、激光雷达、超声波传感器、USB摄像头 |
| Jetson Orin Nano | 计算+人工智能 | ros2_mcp_bridge、YOLO/深度服务、SLAM工具箱、Nav2、MCP客户端/代理 |
因为机器人硬件可能会从不同的机器发布,比如 /scan 或 /image_raw 可以与一起出现 _NODE_NAME_UNKNOWN_ 出版商在接受Jetson的检查时。这是此部署中的正常DDS行为。
______________________________________________________________________
特性
- 扩展MCP表面 --传感器、运动、导航、SLAM、内存、VLM/Cosmos和DSL运行时工具
- 本地DSL运行时 --在机器人上运行简短的Python风格程序,以实现严格意义上的决定动作循环,而不是在每一步上支付MCP往返延迟
- 超声波+激光雷达安全 --即使低轮廓的地面障碍物落在激光雷达扫描平面以下,也能被检测到
- 多功能传感器快照 --姿势、激光雷达、超声波、检测和电池在一次通话中
- A2A视觉试剂 --通用VLM查询加上NVIDIA Cosmos实现的运动/安全决策推理
- YAML可配置 --更改主题、端口、超时、速度限制和传感器几何结构,而无需重新构建
- 加入任何ROS 2机器人 --主题名称和消息类型是可配置的,并在运行时解析
- 死人看门狗 --如果控制交通停止,机器人会在最后一个动作命令后自动停止
- 配置文件部署 --将网桥作为完整服务、机器人本地低延迟服务或Jetson侧感知/命令服务运行
______________________________________________________________________
需求
| 要求 | 版本 |
|---|---|
| ROS 2 | 谦逊、铁或爵士 |
| Python | 3.10+ |
| FastMCP | ≥ 2.0.0 |
| PyYAML | 最近有没有 |
| NumPy | 最近的任何 |
可选的:
nav2_msgs--fornavigate_to_pose航路点导航opencv-python/python3-opencv--DSLcv_*助手httpx--forask_vision_agent,ask_cosmos_agent,以及VLM辅助检测
______________________________________________________________________
安装
1.安装Python依赖项
将FastMCP安装到ROS 2节点将运行的任何Python环境中:
pip install "fastmcp>=2.0.0" pyyaml numpy httpx opencv-python如果你的系统Python和ROS 2 Python不同(在Jetson上很常见),请确保你运行pip对于正确的口译员: ``bash python3 -c "import rclpy; print('ok')" # verify rclpy works pip3 install "fastmcp>=2.0.0" pyyaml numpy httpx opencv-python``
2.克隆/放置包裹
该软件包应位于您的工作区下 src/ 目录:
# If you already have a turtlebot3_ws (or any colcon workspace):
cd ~/your_ws/src
git clone ros2_mcp_bridge
# — or copy the folder directly —3.建造
cd ~/your_ws
colcon build --packages-select ros2_mcp_bridge
source install/setup.bash______________________________________________________________________
快速开始
# Terminal 1 — start your robot / sensors as normal
ros2 launch turtlebot3_bringup robot.launch.py
# Terminal 2 — start the bridge
source ~/your_ws/install/setup.bash
ros2 launch ros2_mcp_bridge bridge.launch.py您应该看到:
[ros2_mcp_bridge] Subscribed: /camera/image_raw/compressed
[ros2_mcp_bridge] Subscribed: /scan
[ros2_mcp_bridge] Subscribed: /odom
[ros2_mcp_bridge] Subscribed: /detections
[ros2_mcp_bridge] Subscribed: /ultrasonic/left
[ros2_mcp_bridge] Subscribed: /ultrasonic/right
[ros2_mcp_bridge] Node ready.
Starting MCP server on streamable-http://0.0.0.0:18210/ros2通过以下方式进行验证:
curl http://localhost:18210/ros2服务配置文件
现在可以从同一代码库的三个MCP配置文件中启动网桥:
| 简介 | 预期机器 | 主要工具系列 |
|---|---|---|
full | 单机或遗留部署 | 一切,外加 /ros2-readonly |
robot | 机器人计算机/基础控制器 | 低延迟传感和闭环运动 |
jetson | Jetson/AI计算机 | 相机、深度、VLM/Cosmos、SLAM/Nav2协调、, cmd_execute_task |
这种分割是围绕延迟设计的:需要紧密控制回路或非常新鲜的本体感觉的工具留在机器人上,而较慢的感知/规划助手留在Jetson上。
机器人简介
将其用于激光雷达、里程计、IMU、超声波、电池和闭环运动工具,如 move_distance, rotate_angle, ultrasonic_approach,以及 lidar_assisted_motion.
ros2 run ros2_mcp_bridge bridge_robot
# or
ros2 launch ros2_mcp_bridge bridge.launch.py profile:=robot杰森简介
将其用于相机和深度工具、VLM/Cosmos场景推理、SLAM/Nav2编排、内存助手和本地 cmd_execute_task 运行时。
ros2 run ros2_mcp_bridge bridge_jetson
# or
ros2 launch ros2_mcp_bridge bridge.launch.py profile:=jetson端点配置
默认情况下, robot 和 jetson 配置文件继承相同的顶级 transport, host, port,以及 path 值从 config/bridge.yaml。当每个配置文件在不同的机器上运行时,这是有效的。
如果你想在一台机器上运行两个配置文件进行测试,请在下设置单独的覆盖 service_profiles.robot 和 service_profiles.jetson 在 config/bridge.yaml.
______________________________________________________________________
配置
所有运行时设置都存在 config/bridge.yaml确实如此 不 更改此文件后需要重建——只需重新启动网桥即可。
ros2_mcp_bridge:
# MCP server settings
transport: streamable-http
host: 0.0.0.0 # bind to all interfaces; change to 127.0.0.1 to restrict to localhost
port: 18210
path: /ros2 # agent connects to http://:18210/ros2
# Robot motion limits (m/s and rad/s)
robot:
max_linear_speed: 0.22
max_angular_speed: 2.84
# Topic for velocity commands
cmd_vel_topic: /cmd_vel
# Approximate camera image width in pixels (used by approach_object steering)
image_width: 640
# Local DSL runtime for tight feedback-loop behaviors
dsl_runtime:
enabled: true
default_timeout: 30.0
max_timeout: 300.0
ultrasonic:
height_m: 0.04
fov_deg: 30.0
left_angle_deg: -20.0
right_angle_deg: 20.0
min_range_m: 0.02
max_range_m: 4.0
collision_avoidance:
enabled: true
min_front_distance: 0.30
min_rear_distance: 0.20
ultrasonic_min_distance: 0.15
# Topics to subscribe to — add/rename/remove as needed
topics:
camera:
topic: /camera/image_raw/compressed
type: sensor_msgs/CompressedImage
laser:
topic: /scan
type: sensor_msgs/LaserScan
odom:
topic: /odom
type: nav_msgs/Odometry
detections:
topic: /detections
type: vision_msgs/Detection2DArray
ultrasonic_left:
topic: /ultrasonic/left
type: sensor_msgs/Range
ultrasonic_right:
topic: /ultrasonic/right
type: sensor_msgs/Range
cosmos_agent:
enabled: true
url: http://localhost:9003使用自定义配置文件
使用环境变量将网桥指向不同的YAML文件:
export ROS2_MCP_BRIDGE_CONFIG=/path/to/my_bridge.yaml
ros2 run ros2_mcp_bridge bridge或者将其作为启动参数传递:
ros2 launch ros2_mcp_bridge bridge.launch.py config:=/path/to/my_bridge.yaml适应你的机器人
| 你的机器人 | 桥上的变化。yaml |
|---|---|
| 不同的相机主题 | topics.camera.topic |
| 原始图像而不是压缩图像 | topics.camera.type: sensor_msgs/Image |
| 不同的扫描主题名称 | topics.laser.topic |
| 无物体探测器 | 移除 detections 入口 |
| 更高的速度限制 | robot.max_linear_speed, robot.max_angular_speed |
| 不同的端口 | port |
任何匹配的消息类型 pkg_name/MessageName 将在运行时通过Python的导入系统自动解析,无需更改代码。
______________________________________________________________________
可用的MCP工具
现在,该桥的曝光量远远超过了原始的相机/扫描/运动集。使用 list_tools() 从您的MCP客户那里获取准确的实时库存。以下组涵盖了主要工具和工作流程。
内省
| 工具 | 说明 |
|---|---|
list_ros2_topics | 列出所有活动主题及其消息类型 |
list_ros2_services | 列出所有活动服务 |
传感器
| 工具 | 关键参数 | 说明 |
|---|---|---|
get_camera_image | timeout | 最新相机帧为base64编码的JPEG |
get_sensor_snapshot | timeout | 组合姿态、激光雷达、超声波、检测和电池 |
get_camera_info | timeout | 相机内部函数、视场和校准元数据 |
get_laser_scan | timeout | 前/左/右/后最小值、每波束航向、原始全范围阵列和抑制瞬态移动的稳定扫描 |
get_robot_pose | timeout | x,y,偏航 /odom |
get_ultrasonic_ranges | timeout | 地板水平左/右超声波读数和安装元数据 |
detect_objects_in_image | timeout | 当前帧中的对象检测 |
get_imu / get_battery_state | timeout | IMU和电池状态 |
运动
| 工具 | 关键参数 | 说明 |
|---|---|---|
move_robot | linear_x, angular_z | 发布一条速度指令;0.5秒后自动停止 |
move_distance | distance_m, speed, collision_avoidance | 带安全检查的闭环线性运动 |
rotate_angle | angle_deg, speed | 闭环旋转 |
stop_robot | -- | 立即公布零速度 |
navigate_to_pose | x, y, yaw, timeout | 发送Nav2目标并阻止,直到完成;需要Nav2 |
防撞系统现在可以检查激光雷达和前部超声波传感器。这对于可能位于LiDAR扫描平面下方的低轮廓障碍物(如电缆、鞋子、门槛和碗)很重要。
行为
| 工具 | 关键参数 | 说明 |
|---|---|---|
find_object | label, timeout | 按类标签搜索对象,最多可旋转360° |
approach_object | label, stop_distance, timeout | 朝向检测到的物体行驶;融合摄像头+激光雷达 |
follow_wall | side, target_distance, duration_s | 反应墙跟随段 |
视觉代理
| 工具 | 关键参数 | 说明 |
|---|---|---|
ask_vision_agent | question 或 task, timeout | 将当前相机帧发送到通用VLM |
ask_cosmos_agent | question 或 task, timeout | 将当前帧发送到NVIDIA Cosmos进行具体推理 |
使用 ask_cosmos_agent 当场景混乱、模糊或安全关键时,在有意义的前进或导航之前。
DSL运行时
DSL运行时是任何需要紧密反馈循环的任务的首选路径。代理可以上传一个在机器人上以交互速率本地运行的短程序,而不是在MCP调用传感器读取和移动之间交替。
典型用例:
- 通过反复重新定中心来跟踪检测到的物体
- 巡逻指定的航路点,无需额外的LLM转弯
- 扫描直到出现对象
- 将视觉、安全检查和局部运动结合在一个循环中
推荐工作流程:
- 呼叫
dsl_get_capabilities以检查可用的DSL功能和约束。 - 呼叫
dsl_list_templates并且可选dsl_get_template(name)从内置的脚手架开始。 - 呼叫
dsl_validate(source)在执行之前。验证现在返回语法错误、禁止调用错误、拼写错误建议和循环提示,如缺失sleep()里面while True循环。 - 呼叫
dsl_run_inline(source, dry_run=True)使用实时传感器来执行逻辑,同时停止运动。 - 与真的一起奔跑
dsl_run_inline(...)或将程序存储在dsl_store_program(...)并重复使用dsl_run_program(...).
内置DSL模板目前包括:
track_detectionscan_until_conditionwall_follow_guardedwaypoint_patrol
DSL名称空间包括传感器、运动、导航、内存助手和OpenCV风格 cv_* 用于本地图像处理的助手。
SLAM和地图工具
该桥还公开了SLAM和地图管理工具,如 slam_get_status, get_map_info, slam_save_map, slam_serialize_map, slam_load_map,以及 slam_pause_mapping. get_map_info 现在,使用所需的QoS设置读取地图主题 slam_toolbox,这使得地图元数据查询更加可靠。
跟踪API
MCP服务器公开了web UI使用的轻量级跟踪端点:
GET /mcp_api/log返回已完成和正在进行的工具调用POST /mcp_api/clear清除跟踪缓冲区
______________________________________________________________________
连接到onit
向添加一个条目 onit/configs/default.yaml 在...之下 mcp.servers:
mcp:
servers:
- name: ROS2BridgeMCPServer
description: "ROS 2 robot control — sensors, ultrasonic safety, DSL runtime, VLM/Cosmos, navigation"
url: http://192.168.0.153:18210/ros2 # ← your robot's IP
enabled: true重新启动它--它调用 list_tools() 在启动时自动注册每个工具。
有关完整演练,请参阅 docs/onit_configuration.md.
______________________________________________________________________
连接到其他MCP客户端
这座桥使用 FastMCP可流式传输http 传输,这是HTTP上的标准MCP。任何支持HTTP传输的MCP客户端都可以连接。
使用FastMCP Python客户端的示例:
from fastmcp import Client
async with Client("http://192.168.0.153:18210/ros2") as c:
tools = await c.list_tools()
result = await c.call_tool("get_laser_scan", {})
print(result)如果您的客户端支持单独的只读MCP服务器,则网桥还将公开一个只读端点,其中仅包含感知和DSL自检工具。
______________________________________________________________________
在没有完整机器人的情况下运行(测试)
您可以在发布任何机器人主题之前启动网桥。每个传感器工具都接受 timeout 参数;如果该窗口内没有数据到达,则返回JSON错误,而不是崩溃。
使用模拟主题 ros2 topic pub 测试单个工具:
# Feed a dummy laser scan
ros2 topic pub /scan sensor_msgs/msg/LaserScan "{header: {frame_id: 'laser'}, \
angle_min: -3.14, angle_max: 3.14, angle_increment: 0.01, \
range_min: 0.1, range_max: 10.0, ranges: [1.0]}"______________________________________________________________________
启动文件参数
ros2 launch ros2_mcp_bridge bridge.launch.py \
host:=0.0.0.0 \
port:=18210 \
config:=/path/to/bridge.yaml______________________________________________________________________
作为systemd服务运行
服务单位文件
创建 /etc/systemd/system/ros2-mcp-bridge.service:
[Unit]
Description=ROS 2 MCP Bridge (Jetson-side perception and command service)
Documentation=https://github.com/jedld/ros2_mcp_bridge
After=network.target orin-cam-web.service orin-detector.service
Wants=orin-cam-web.service orin-detector.service
[Service]
User=joseph
Environment="HOME=/home/joseph"
Environment="ROS2_MCP_BRIDGE_PROFILE=jetson"
ExecStart=/bin/bash -c \
"source /opt/ros/humble/setup.bash && \
source /home/joseph/turtlebot3_ws/install/setup.bash && \
ros2 run ros2_mcp_bridge bridge_jetson"
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target调整User,HOME,以及工作区路径(如果设置不同)。该Jetson装置故意只启动Jetson侧MCP剖面。移除Wants/After线路为orin-cam-web和orin-detector如果你没有使用这些服务。 重要提示: 如果您的ROS 2设置使用非默认设置ROS_DOMAIN_ID(例如,设置.bashrc),将其显式添加到下的每个服务单元文件中[Service]: ``ini Environment="ROS_DOMAIN_ID=42"`` 如果没有这个,systemd服务默认为域0,它们的主题对您的终端和彼此都是不可见的。
启用并启动
sudo systemctl daemon-reload
sudo systemctl enable --now ros2-mcp-bridge有用的命令
# Live log stream (all output)
sudo journalctl -fu ros2-mcp-bridge
# Filter to MCP call/return lines only
sudo journalctl -u ros2-mcp-bridge | grep "\[MCP"
# Restart after a config or code change
sudo systemctl restart ros2-mcp-bridge
# Check current status
sudo systemctl status ros2-mcp-bridge全自动启动堆栈
当所有三个服务都启用时,启动顺序为:
orin-cam-web → publishes /camera/image_raw/compressed
orin-detector → subscribes to camera, publishes /detections
ros2-mcp-bridge → subscribes to all sensor topics, serves MCP tools立即检查所有内容:
sudo systemctl status orin-cam-web orin-detector ros2-mcp-bridge --no-pager______________________________________________________________________
建筑
bridge.py ──────────────────────────────────────────────
│ loads bridge.yaml
│ starts rclpy MultiThreadedExecutor in a daemon thread
│ calls mcp_server.run() (blocks — uvicorn event loop)
│
├── ros_node.py (ROS2BridgeNode)
│ subscribes to configured topics
│ caches latest message per topic (thread-safe)
│ exposes get_latest(topic, timeout)
│ publishes Twist to cmd_vel
│ wraps Nav2 NavigateToPose action client
│
├── mcp_server.py (FastMCP)
│ 12 @mcp.tool functions
│ calls ros_node helpers synchronously
│ serves over streamable-http
│
└── behaviors.py
find_object_behavior — rotate + detect
approach_object_behavior — drive + fuse camera/LiDAR
look_around_behavior — full-circle sweep______________________________________________________________________
日志记录和调试
记录的内容
桥接器记录每个MCP工具调用 INFO 级别通过Python标准 logging 模块。每次调用产生两行:
[INFO] ros2_mcp_bridge.mcp_server: [MCP CALL] get_camera_image(timeout=3.0)
[INFO] ros2_mcp_bridge.mcp_server: [MCP RETURN] get_camera_image → OK in 0.182s
[INFO] ros2_mcp_bridge.mcp_server: [MCP CALL] move_robot(linear_x=0.1, angular_z=0.0, duration=2.0)
[INFO] ros2_mcp_bridge.mcp_server: [MCP RETURN] move_robot → OK in 2.011s
[INFO] ros2_mcp_bridge.mcp_server: [MCP CALL] stop_robot()
[INFO] ros2_mcp_bridge.mcp_server: [MCP ERROR] stop_robot raised in 0.002s查看日志--前台进程
当您直接在终端中启动网桥时,日志行将写入stdout:
ros2 run ros2_mcp_bridge bridge
# — or —
ros2 launch ros2_mcp_bridge bridge.launch.py仅筛选MCP呼叫线路:
ros2 run ros2_mcp_bridge bridge 2>&1 | grep "\[MCP"查看日志--systemd服务
# Stream live logs
sudo journalctl -fu ros2-mcp-bridge
# Show only MCP call/return lines
sudo journalctl -u ros2-mcp-bridge | grep "\[MCP"
# Last 100 lines
sudo journalctl -u ros2-mcp-bridge -n 100 --no-pager调试特定调用
- 实时观看通话 --在一个终端中,跟踪日志;在另一种情况下,触发代理或手动调用工具:
# Terminal 1: watch the bridge
sudo journalctl -fu ros2_mcp_bridge | grep "\[MCP"
# Terminal 2: manually call a tool to verify it round-trips correctly
python3.10 - =2.0.0"` |
| `ModuleNotFoundError: rclpy` |获取您的ROS 2工作区: `source /opt/ros//setup.bash` |
|没有来自传感器工具的数据|检查主题是否正在发布: `ros2 topic hz ` |
|代理未显示任何工具|验证URL是否可访问: `curl http://:18210/ros2` |
| `navigate_to_pose` 返回“不可用”|启动Nav2堆栈: `ros2 launch nav2_bringup navigation_launch.py` |
|机器人继续移动|死人在0.5秒后开火——如果命令没有连续发送,这是意料之中的|
|端口已在使用中|更改 `port` 在 `bridge.yaml` 并更新代理的URL|
|手动运行但不从systemd服务运行时可见的主题| `ROS_DOMAIN_ID` 不匹配--添加 `Environment="ROS_DOMAIN_ID="` 到每个服务单位,然后 `sudo systemctl daemon-reload && sudo systemctl restart ` |
| `/detections` 即使检测器服务正在运行,也缺少主题|相同的域ID问题——见上文|
______________________________________________________________________
## 许可证
Apache 2.0