文档目录
文章目录
微空 AI 智能无人机教程 5 - AI agent 智能体接入
本章目标
本章在机载电脑(树莓派 5)上部署 OpenClaw 开源 AI 智能体框架,接入云端大语言模型,通过 Telegram 打通自然语言指令到无人机 AI 智能体的完整通信链路。同时编写 MCP 飞控桥接服务,实现通过 Telegram 实时查询无人机状态。
完成本章后,MVD35 应达到以下状态:
- OpenClaw 框架安装完成并以系统服务运行(开机自启)
- 云端大语言模型 API 接入并正常调用
- Telegram Bot 配置完成,可接收自然语言指令
- MCP 飞控桥接服务部署完成,可通过 Telegram 查询无人机实时状态
前期准备
硬件准备
- MVD35 智能版(完成前置教程的软件配置与飞行测试)
- 电脑与良好的网络条件
软件准备
系统架构概览
在序章中我们已经介绍过,AI 智能体运行在机载电脑上,充当一个"聪明的调度员":接收人类的自然语言指令,调用云端大模型进行理解和决策,再将具体动作转化为飞控指令。实现这一架构需要两个核心组件:OpenClaw 框架负责智能体调度与通信,运行在 Node.js 上,支持多种大语言模型,并通过 Telegram Bot 等渠道接收用户指令;MCP Server(Python)作为飞控桥接层,通过 ROS2 和 MAVROS 将飞控数据暴露给 AI 智能体。
自然语言指令(Telegram 消息)
↓
OpenClaw 智能体(Node.js)
├── 云端 Gemini API(理解 + 决策)
├── Skill(SKILL.md,描述可用能力)
└── MCP 协议(stdio / JSON-RPC)
↓
drone_mcp_server.py(Python MCP Server)
└── rclpy → MAVROS → 飞控安装 OpenClaw
OpenClaw 依赖 Node.js 22 或更高版本。树莓派 Ubuntu 24.04 默认源中的 Node.js 版本过旧,需通过 NVM(Node Version Manager)安装。
安装 NVM
- 使用 curl 安装 NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
- 安装完成后,重新加载 shell 配置使 NVM 生效
source ~/.bashrc- 验证安装
nvm --version
✅ 输出 NVM 版本号,如
0.40.1表示安装成功
安装 Node.js
- 使用 NVM 安装 Node.js
nvm install 22
- 验证安装
node -v
npm -v
✅ 输出 Node.js 版本号,如
v22.23.1;npm 版本号,如10.9.8表示安装成功
安装 OpenClaw
- 使用官方一键安装脚本安装 OpenClaw
curl -fsSL https://openclaw.ai/install.sh | bash
- 安装完成后会直接进入 Setup 流程,使用
exit指令退出设置(稍后进行配置)

- 验证安装
openclaw --version
✅ 输出
OpenClaw x.x.x表示安装成功
创建 Telegram Bot
Telegram Bot 是 OpenClaw 接收用户指令的通信通道。用户通过 Telegram 向 Bot 发送消息,OpenClaw 将自动接收并处理。
创建 Bot
- 注册并登录 Telegram
- 搜索 @BotFather 并开始对话
- 发送
/newbot - 按提示输入:
- Bot 名称,如
my mvd35 - Bot 用户名,必须以
bot结尾,如mvd35_bot
- Bot 名称,如
- BotFather 会回复一个 API Token,保存该 Token,在后续配置 OpenClaw 时使用

获取 Telegram 用户 ID
为安全起见,需要设置 OpenClaw 白名单,确保只有授权用户能控制无人机的 AI 智能体。
- 在 Telegram 搜索 @userinfobot 并开始对话
- Bot 会回复你的数字用户 ID,记录该 ID,用于后续配置 allowlist 白名单
- 用户 ID:
8295873839

OpenClaw 初始化配置
启动 OpenClaw 配置
回到树莓派 SSH 终端,运行 onboard 命令启动配置:
openclaw onboardOpenClaw(2026.7.1-2 及以上版本)采用 对话式配置,通过内置的 Crestodian 配置助手完成初始化。以下是完整的配置流程。
基础配置
运行 openclaw onboard 后,将进入 Crestodian(OpenClaw 内置的交互式配置助手)对话界面。Crestodian 会自动检测当前环境并列出基础配置方案,输入 yes 确认,即可自动完成 Workspace、Gateway 等基础配置。

配置 AI 模型
- 基础配置完成后,Crestodian 会询问是否配置模型。输入
yes,依次完成以下配置:
- Model/auth provider → 选择
Google(如使用 DeepSeek、OpenAI 等其他模型,选择对应 Provider) - Google auth method → 选择
Google Gemini API key - Enter Gemini API key → 输入 API Key
- Model configured → 显示默认模型
- Default model → 选择
Browse all models→google/gemini-3-flash-preview(兼顾性能与速度)

- 模型配置完成后,Crestodian 会返回对话界面并显示配置状态:

连接 Telegram
- 在 Crestodian 对话界面中输入:
connect telegram
- Crestodian 会显示通信渠道列表,依次完成以下配置:
- Bot Token 存储方式 → 输入
1,将 Token 直接存储在 OpenClaw 配置中 - Bot Token → 粘贴前面「创建 Bot」步骤中获取的 Token
- allowFrom → 输入前面「获取 Telegram 用户 ID」步骤中记录的数字 ID(用于设置 DM 白名单,仅该用户可与 Bot 交互)

allowFrom白名单是无人机的安全屏障,务必正确配置,防止未授权用户发送控制指令。
配置完成后,Crestodian 会显示:
Done – telegram is configured.
Say restart gateway to apply channel changes, or channels to review.
- 在 Crestodian 中输入
restart gateway应用配置,然后输入yes确认重启。

验证 OpenClaw 服务状态
openclaw gateway status --deep
状态显示
Runtime: running;Connectivity probe: ok,服务即正常运行。
OpenClaw 是用户级 systemd 服务,请使用
openclaw gateway命令管理,勿用sudo systemctl。
常用管理指令:
openclaw gateway start # 启动服务
openclaw gateway stop # 停止服务
openclaw gateway restart # 重启服务
openclaw logs --follow # 查看实时日志验证安装
1. 基本对话测试
- 从 Telegram BotFather 上进入 my mvd35 会话框,发送消息:

你好,你能做什么?
✅ Bot 正常回复,说明 OpenClaw + AI 模型 API + Telegram 整条链路已连通。
2. 系统信息访问能力测试
请告诉我这台机器的 hostname 和系统信息(uname -a)
✅ OpenClaw 应该能执行 shell 命令并返回树莓派的系统信息。
3. 资源占用检查
- 在树莓派上查看 OpenClaw 的资源消耗:
htop
MCP 飞控桥接服务
OpenClaw 本身是一个通用的 AI 智能体框架,并不直接与飞控通信。为了让 AI 智能体能够获取无人机的状态数据并实施控制,需要编写一个 MCP Server 作为桥接层。
MCP(Model Context Protocol)是 AI 智能体调用外部工具的标准协议。通过 MCP,可以将无人机的状态查询和飞行控制封装为一组 Tool(工具),AI 智能体在需要时自动调用。本教程使用 Python 编写 MCP Server(drone_mcp_server.py),通过 stdio 与 OpenClaw 通信,内部通过 rclpy 和 MAVROS 获取飞控数据。
本节先实现只读工具(状态查询),可通过 Telegram 查询电池、位置、飞行模式等信息,无需起飞即可验证链路。飞行控制工具将在教程 6 中实现。
安装 Python MCP SDK
- 创建虚拟环境并安装 mcp
Ubuntu 24.04 禁止直接使用 pip 在系统 Python 中安装第三方包,需要创建虚拟环境。
sudo apt install -y python3-venv
python3 -m venv --system-site-packages ~/openclaw_drone/venv
source ~/openclaw_drone/venv/bin/activate
pip install mcp

- 验证安装
python3 -c "import mcp; print('MCP SDK 安装成功')"
python3 -c "import rclpy; print('rclpy 可用')"
✅ 输出
MCP SDK 安装成功;rclpy 可用表示安装成功
编写 drone_mcp_server.py
- 在树莓派上创建 MCP Server 文件:
sudo vim ~/openclaw_drone/drone_mcp_server.py- 将以下代码写入文件
#!/usr/bin/env python3
"""
MVD35 Drone MCP Server
通过 MCP 协议将无人机状态查询接口暴露给 OpenClaw AI 智能体。
通信方式:stdio (JSON-RPC)
注意:MCP Server 通过 stdio 与 OpenClaw 通信,
绝对不能在代码中使用 print(),否则会破坏 JSON-RPC 数据流。
调试信息请输出到 sys.stderr。
"""
import sys
import threading
import math
import rclpy
from rclpy.node import Node
from mcp.server.fastmcp import FastMCP
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from sensor_msgs.msg import BatteryState
# ============ ROS 2 节点 ============
class DroneROSNode(Node):
"""持久运行的 ROS 2 节点,订阅无人机状态数据"""
def __init__(self):
super().__init__('drone_mcp_bridge')
# 状态数据(持续更新)
self.state = State()
self.pose = PoseStamped()
self.battery = BatteryState()
# 连接状态标记
self.state_received = False
self.pose_received = False
self.battery_received = False
# 订阅 MAVROS 话题
self.state_sub = self.create_subscription(
State, '/mavros/state', self._state_cb, 10)
self.pose_sub = self.create_subscription(
PoseStamped, '/mavros/local_position/pose', self._pose_cb, 10)
self.battery_sub = self.create_subscription(
BatteryState, '/mavros/battery', self._battery_cb, 10)
self.get_logger().info('DroneROSNode 初始化完成,等待 MAVROS 数据...')
def _state_cb(self, msg):
self.state = msg
self.state_received = True
def _pose_cb(self, msg):
self.pose = msg
self.pose_received = True
def _battery_cb(self, msg):
self.battery = msg
self.battery_received = True
def quaternion_to_yaw(self, q):
"""将四元数转换为偏航角(度)"""
siny_cosp = 2.0 * (q.w * q.z + q.x * q.y)
cosy_cosp = 1.0 - 2.0 * (q.y * q.y + q.z * q.z)
yaw_rad = math.atan2(siny_cosp, cosy_cosp)
return math.degrees(yaw_rad)
# ============ MCP Server ============
mcp = FastMCP("MVD35-DroneControl")
drone_node = None # 全局 ROS 节点引用
@mcp.tool()
def get_drone_status() -> str:
"""获取无人机的综合状态信息,包括连接状态、飞行模式、解锁状态、位置和电池。
这是了解无人机当前情况的最常用工具。"""
if drone_node is None:
return "错误:ROS 2 节点尚未初始化"
lines = []
# 飞控连接状态
if drone_node.state_received:
s = drone_node.state
lines.append(f"飞控连接: {'已连接' if s.connected else '未连接'}")
lines.append(f"飞行模式: {s.mode}")
lines.append(f"解锁状态: {'已解锁(电机可运转)' if s.armed else '未解锁(安全状态)'}")
else:
lines.append("飞控连接: 未收到状态数据(MAVROS 可能未启动)")
# 位置
if drone_node.pose_received:
p = drone_node.pose.pose.position
yaw = drone_node.quaternion_to_yaw(drone_node.pose.pose.orientation)
lines.append(f"位置: x={p.x:.2f}m, y={p.y:.2f}m, z={p.z:.2f}m")
lines.append(f"朝向: {yaw:.1f} 度")
else:
lines.append("位置: 暂无数据")
# 电池
if drone_node.battery_received:
b = drone_node.battery
pct = b.percentage * 100 if b.percentage >= 0 else -1
lines.append(f"电池: {pct:.0f}% ({b.voltage:.1f}V)")
else:
lines.append("电池: 暂无数据")
return "\n".join(lines)
@mcp.tool()
def get_position() -> str:
"""获取无人机当前的本地坐标位置(米)。
坐标系:x 为前方,y 为左方,z 为高度。"""
if drone_node is None or not drone_node.pose_received:
return "暂无位置数据"
p = drone_node.pose.pose.position
yaw = drone_node.quaternion_to_yaw(drone_node.pose.pose.orientation)
return f"位置: x={p.x:.3f}m, y={p.y:.3f}m, z={p.z:.3f}m, 朝向={yaw:.1f} 度"
@mcp.tool()
def get_battery() -> str:
"""获取无人机的电池状态,包括电压和剩余电量百分比。"""
if drone_node is None or not drone_node.battery_received:
return "暂无电池数据"
b = drone_node.battery
pct = b.percentage * 100 if b.percentage >= 0 else -1
return f"电压: {b.voltage:.2f}V, 剩余电量: {pct:.0f}%"
@mcp.tool()
def is_armed() -> str:
"""检查无人机电机是否已解锁。返回解锁状态说明。"""
if drone_node is None or not drone_node.state_received:
return "暂无状态数据"
if drone_node.state.armed:
return "已解锁:电机可以运转,无人机可能正在飞行中"
else:
return "未解锁:电机锁定,无人机处于安全状态"
@mcp.tool()
def get_flight_mode() -> str:
"""获取无人机当前的飞行模式。
常见模式:STABILIZE(自稳)、ALT_HOLD(定高)、LOITER(定点)、
GUIDED(引导)、LAND(降落)。"""
if drone_node is None or not drone_node.state_received:
return "暂无状态数据"
return f"当前飞行模式: {drone_node.state.mode}"
@mcp.tool()
def check_connection() -> str:
"""检查各个系统组件的连接状态,包括飞控连接、位置数据和电池数据。"""
if drone_node is None:
return "错误:ROS 2 节点尚未初始化"
lines = []
lines.append(f"MAVROS 状态话题: {'已连接' if drone_node.state_received else '未收到数据'}")
lines.append(f"位置数据: {'正常' if drone_node.pose_received else '未收到数据'}")
lines.append(f"电池数据: {'正常' if drone_node.battery_received else '未收到数据'}")
if drone_node.state_received:
lines.append(f"飞控连接: {'已连接' if drone_node.state.connected else '未连接'}")
return "\n".join(lines)
# ============ 启动逻辑 ============
def run_ros_spin(node):
"""在单独线程中运行 ROS 2 事件循环"""
rclpy.spin(node)
def main():
global drone_node
# 初始化 ROS 2
rclpy.init()
drone_node = DroneROSNode()
# 在后台线程运行 ROS 2 spin(持续接收话题数据)
ros_thread = threading.Thread(
target=run_ros_spin, args=(drone_node,), daemon=True)
ros_thread.start()
# 调试信息输出到 stderr(不能用 print!)
sys.stderr.write("[drone_mcp_server] MCP Server 启动中...\n")
sys.stderr.flush()
# 启动 MCP Server(阻塞主线程,通过 stdio 与 OpenClaw 通信)
mcp.run(transport="stdio")
if __name__ == "__main__":
main()- 保存并退出
创建启动脚本
OpenClaw 以 systemd 服务运行,其子进程不会自动加载 ROS 2 环境变量,需要通过 wrapper 脚本加载 ROS 2 环境:
sudo vim ~/openclaw_drone/start_mcp_server.sh- 写入以下内容:
#!/bin/bash
# MCP Server 启动脚本,加载 ROS 2 环境和虚拟环境后运行 drone_mcp_server.py
source /opt/ros/jazzy/setup.bash
source ~/ros2_ws/install/setup.bash 2>/dev/null
source ~/openclaw_drone/venv/bin/activate
exec python3 ~/openclaw_drone/drone_mcp_server.py- 添加执行权限:
sudo chmod +x ~/openclaw_drone/drone_mcp_server.py
sudo chmod +x ~/openclaw_drone/start_mcp_server.shMCP Server 通过 stdio 与 OpenClaw 通信,代码中 禁止使用
print(),否则会破坏 JSON-RPC 数据流。调试信息请使用sys.stderr.write()输出。
注册 MCP Server
- 使用 OpenClaw CLI 命令将 MCP Server 注册到配置中:
openclaw mcp add drone-control --command bash --arg /home/micoair/openclaw_drone/start_mcp_server.sh
- 验证 mcp 加载
openclaw mcp list
✅ 在 MCP servers 中能看到刚添加的 drone-control 服务,则成功加载
- 重启 Gateway 确认配置生效:
openclaw gateway restart
openclaw gateway status
创建无人机 Skill
OpenClaw 的 Skill 体系中,Skill 是一个 Markdown 文件(
SKILL.md),用自然语言描述 AI 智能体在什么场景下应该使用哪些工具、遵循什么规则。
- 创建 Skill 目录和文件:
mkdir -p ~/.openclaw/skills/mvd35-drone
vim ~/.openclaw/skills/mvd35-drone/SKILL.md- 写入以下内容:
---
name: mvd35-drone
description: 查询和监控 MVD35 智能无人机的飞行状态。当用户询问无人机状态、电池、位置、飞行模式等信息时使用此技能。
---
# MVD35 无人机状态查询
你是一架 MVD35 微型智能无人机上的 AI 助手。你可以通过 MCP 工具 `drone-control` 来查询无人机的实时状态。
## 可用查询工具
- `get_drone_status`:获取无人机综合状态(飞行模式、解锁状态、位置、电池),这是最常用的工具
- `get_position`:获取无人机当前坐标位置
- `get_battery`:获取电池电压和剩余电量
- `is_armed`:检查电机是否已解锁
- `get_flight_mode`:获取当前飞行模式
- `check_connection`:检查各系统组件连接状态
## 使用规则
1. 当用户询问无人机的总体情况时,优先使用 `get_drone_status` 获取综合信息
2. 当用户只关心某个具体指标时,使用对应的专用工具
3. 如果工具返回"暂无数据",告诉用户可能是 MAVROS 尚未启动或飞控未连接
4. 用简洁友好的中文回复用户- 保存退出后,重启 OpenClaw 使 Skill 生效:
openclaw gateway restart- 验证 Skill 是否被识别
openclaw skills list
✅ 在 Skills 列表中能看到刚添加的 mvd35-drone skill,则加载成功
联调验证
本节验证整个链路的连通性:Telegram → OpenClaw → MCP Server → MAVROS → 飞控。此步骤无需起飞,只需要无人机通电并连接飞控即可。
启动完整系统
确保以下组件已经在运行:
1. MAVROS
启动 MAVROS 以连接飞控:
ros2 launch mavros apm.launch
✅ 等待看到飞控型号、类型等详细信息,确认飞控连接成功。
2. OpenClaw
- OpenClaw 已作为 systemd 服务在后台运行,确认其状态:
openclaw gateway status- 若服务未运行,手动启动:
openclaw gateway startℹ️ 本步骤验证无需启动 RealSense 相机和 OpenVINS。仅需 MAVROS 与飞控的连接,即可验证状态查询功能。
通过 Telegram 查询无人机状态
- 打开 Telegram,找到已创建的 Bot,发送消息:
1:设定身份
你叫mvd35-001,负责本台mvd35智能无人机的管理与控制。
2:基础对话
你好,你能做什么?
✅ Bot 应回复其能力介绍,并提到无人机相关信息。
3:无人机状态及设备状态查询
无人机现在是什么状态?检查一下各个系统的连接状态
✅ 以上测试全部通过,说明 AI 智能体通信链路已完全打通,可随时通过 Telegram 查询无人机的实时状态。控制及智能任务执行可参考后续教程 6
附录
常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
curl: (60) SSL certificate problem | 树莓派系统时间不正确 | sudo timedatectl set-ntp true 并 sudo timedatectl set-timezone Asia/Shanghai |
openclaw: command not found | NVM 安装的 Node.js 环境未加载 | 执行 source ~/.bashrc,确认 NVM 配置已写入 .bashrc |
| 安装脚本下载失败 | 网络问题,无法访问 GitHub 或安装源 | 配置代理:export https_proxy=http://代理地址:端口 后重试 |
| Telegram Bot 没有响应 | 服务未启动或网络问题 | 依次检查:openclaw health → openclaw logs --follow → 确认树莓派能访问 Telegram API |
| API 调用超时 | 网络状态不稳定 | 检查网络连接 |
| Bot 回复但不查询无人机状态 | MCP Server 未正确注册 | 执行 openclaw mcp list 确认已注册,路径正确后 openclaw gateway restart |
| Bot 回复"暂无数据" | MAVROS 未启动或飞控未连接 | 确认 MAVROS 已运行并显示 FCU connected,用 ros2 topic list 检查话题是否存在 |
ModuleNotFoundError: No module named 'mcp' | Python MCP SDK 未安装 | 执行 pip install mcp |
| MCP Server 启动后立即退出 | ROS 2 环境未正确加载 | 确认 openclaw.json 的 env 中包含了 ROS 2 所需的环境变量 |
如果进程能正常启动且不报错,说明 ROS 2 和 MCP SDK 的环境配置都是正确的。

