文档目录
文章目录
微空 AI 智能无人机教程 5 - AI agent 智能体接入
本章目标
本章在机载电脑(树莓派 5)上部署 OpenClaw 开源 AI 智能体框架,接入云端大语言模型(DeepSeek),并通过即时通讯软件(飞书)打通自然语言指令到无人机 AI 智能体的完整通信链路。同时编写 MCP 飞控桥接服务,使 AI 智能体能够读取无人机状态并下发飞行控制指令,实现从自然语言对话到无人机操控的端到端闭环。

完成本章后,MVD35 应达到以下状态:
- OpenClaw 框架安装完成并以系统服务后台运行
- 云端大语言模型 API 接入并正常调用
- 即时通讯软件配置完成并可与无人机 AI 智能体对话交流
- MCP 飞控桥接服务部署完成,AI 智能体可查询无人机实时状态
前期准备
硬件准备
- MVD35 智能版(完成前置教程的软件配置与飞行测试)
- 电脑与良好的网络条件
软件准备
ℹ️ 即时通讯软件及大语言模型选用 OpenClaw 支持的通信平台即可,详见 附录 - OpenClaw 大语言模型与通讯软件支持列表,本教程仅以 飞书 和 DeepSeek 为例
系统架构概览
在序章中已经介绍过,AI 智能体运行在机载电脑上,充当「智能调度员」:接收人类的自然语言指令,调用云端大模型进行理解和决策,再将具体动作转化为飞控指令。实现这一架构需要两个核心组件:OpenClaw 框架负责智能体调度与通信,运行在 Node.js 上,支持多种大语言模型,并通过飞书等渠道接收用户指令;MCP Server(Python)作为飞控桥接层,通过 ROS 2 和 MAVROS 将飞控数据暴露给 AI 智能体。
自然语言指令(飞书对话消息)
↓
OpenClaw 智能体(Node.js)
├── 云端 DeepSeek 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表示安装成功
创建飞书应用
飞书机器人是 OpenClaw 接收用户指令的通信通道。用户通过飞书向机器人发送消息,OpenClaw 将自动接收并处理。
创建应用

- 填写 应用名称 与 应用描述

- 在 添加应用能力 中,添加 机器人

- 在 权限管理 中,添加以下权限并申请开通:
im:message(获取与发送消息)

- 在 事件与回调 中:
- 将 订阅方式 设为 使用长连接接收事件
- 添加事件 im.message.receive_v1(接收消息)

- 在 版本管理与发布 中 创建版本 并 申请发布

- 创建完成后,飞书中会收到 开发者小助手 发布成功消息,通过 打开应用 进入机器人聊天窗口

获取 App ID,App Secret 及 tenant domain
查找并记录以下信息,后续配置 OpenClaw 时需要用到:
- 在 飞书开放平台 凭证与基础信息 页面记录:
- App ID
- App Secret

- 在 飞书管理后台 -> 企业管理 -> 企业设置 -> 企业信息 记录:
- 企业域名

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

配置 AI 模型
- 基础配置完成后,Crestodian 会询问是否配置模型。输入
yes,依次完成以下配置:
- Model/auth provider → 选择
More→DeepSeek - Install DeepSeek plugin? → 选择
Download from ClawHub - Enter DeepSeek API key → 输入 API Key (需用户自行订阅 AI 服务获取)
- Default model → 保持默认模型
Keep current (deepseek/deepseek-v4-flash)

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

连接飞书
- 在 Crestodian 对话界面中输入:
connect feishu

- 按照 Crestodian 引导配置所需信息


配置完成后,Crestodian 会显示:
Done – feishu 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. 基本对话测试
- 打开飞书,找到 MVD35智能助手 机器人会话框,发送消息:
你好,你能做什么?

⚠️ 这是 OpenClaw 的安全机制——首次给机器人发消息的用户需要被批准后才能正常对话。
- 复制该指令并在树莓派上执行以批准正常对话

- 重新发送消息

✅ MVD35智能助手 正常回复,说明 OpenClaw + AI 模型 API + 飞书整条链路已连通。
2. 系统信息访问能力测试
请告诉我这台机器的 hostname 和系统信息(uname -a)
MVD35上连接了什么USB设备

✅ MVD35智能助手 应能正常理解自然语言,自动执行指令并回答用户的问题
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 获取飞控数据。
本节先实现 只读工具(状态查询),可通过飞书查询电池、位置、飞行模式等信息,无需起飞即可验证链路。飞行控制工具将在后续教程中实现。
安装 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 脚本手动加载:
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.sh
⚠️ MCP 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,则加载成功
联调验证
本节验证整个链路的连通性:飞书 → 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 与飞控的连接,即可验证状态查询功能。
通过飞书查询无人机状态
- 打开飞书,找到已创建的机器人,发送消息:
1. 设定身份
你叫mvd35-001,负责本台mvd35智能无人机的管理与控制。

2. 基础对话及信息查询
MVD35现在是什么状态?

3. 智能体问题分析
没有位置信息可能是什么原因
飞控固件是什么,为什么没有收到电池信息

✅ 通过对话测试,验证 AI 智能体通信链路已完全打通,可随时通过飞书与 MVD35 上 AI 智能体对话并控制无人机。智能任务执行可参考后续教程
附录
常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
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://代理地址:端口 后重试 |
| 飞书机器人没有响应 | 事件订阅未配置 | 确认飞书应用已配置「使用长连接接收事件」并订阅 im.message.receive_v1 事件 |
| 飞书机器人没有响应 | 服务未启动或网络问题 | 依次检查:openclaw health → openclaw logs --follow → 确认树莓派网络连接正常,飞书应用已发布 |
| 飞书回复 Pairing code | 用户未通过配对批准 | 在树莓派上执行 openclaw pairing approve feishu <CODE> 批准该用户 |
| 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 环境未正确加载 | 确认启动脚本中已正确 source ROS 2 环境 |
OpenClaw 大语言模型与通讯软件支持列表
本教程以 飞书 和 DeepSeek 为例进行演示,但 OpenClaw 支持多种通信渠道和大语言模型。用户可根据自身需求选择,配置方法大同小异,只需在 openclaw onboard 配置流程中选择对应的 Provider / Channel 即可。
支持的即时通讯平台(通信渠道):
| 平台 | 说明 |
|---|---|
| 飞书(Lark) | 本教程示例平台,需创建企业自建应用 |
| Discord | 海外常用,需创建 Bot 应用并获取 Token |
| Telegram | 通过 BotFather 创建机器人并获取 Token |
| Slack | 企业级协作平台,需创建 Slack App |
| 钉钉(DingTalk) | 国内企业常用,需创建企业内部应用 |
| 微信(企业微信) | 通过企业微信开放平台接入 |
支持的大语言模型提供商:
| 提供商 | 推荐模型 | 说明 |
|---|---|---|
| DeepSeek | deepseek-chat | 本教程示例,国内访问友好,性价比高 |
| Google Gemini | gemini-2.5-flash | 多模态能力强,免费额度充足 |
| OpenAI | gpt-4o | 综合能力强,生态完善 |
| Anthropic | claude-sonnet-4 | 长上下文优秀,指令遵循能力强 |
| 通义千问(Qwen) | qwen-max | 阿里云旗下,国内访问稳定 |
| 智谱 AI | glm-4 | 国产大模型,中文表现优秀 |
| Ollama(本地部署) | 视硬件选择 | 可在本地运行开源模型,无需 API Key |
选择大语言模型时需考虑:网络环境(国内优先选择 DeepSeek、通义千问等)、成本(Gemini 免费额度较多)、性能需求(复杂任务推荐 GPT-4o 或 Claude)。对于无人机状态查询等轻量级任务,DeepSeek 或 Gemini Flash 已足够胜任。
以上列表为撰写本教程时 OpenClaw 支持的平台,实际支持情况可能随版本更新而变化。请查阅 OpenClaw 官方文档 获取最新的支持列表。

