微空科技
文档目录
文章目录

微空 AI 智能无人机教程 5 - AI agent 智能体接入

本章目标

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

AI agent 智能体:让无人机听懂任务并执行飞行

完成本章后,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

80

  • 安装完成后,重新加载 shell 配置使 NVM 生效
source ~/.bashrc
  • 验证安装
nvm --version

81

✅ 执行指令后,控制台输出 NVM 版本号,如 0.40.1 表示安装成功

安装 Node.js

  • 使用 NVM 安装 Node.js
nvm install 22

82

  • 验证安装
node -v
npm -v

83

✅ 执行指令后,控制台输出 Node.js 版本号,如 v22.23.1;npm 版本号,如 10.9.8 表示安装成功

安装 OpenClaw

  • 使用官方脚本安装 OpenClaw
curl -fsSL https://openclaw.ai/install.sh | bash

84

  • 安装完成后会自动进入 Setup 流程,输入 exit 退出(稍后进行配置)

85

  • 验证安装
openclaw --version

86

✅ 执行指令后,控制台输出版本信息 OpenClaw x.x.x 表示安装成功

创建飞书应用

飞书机器人是 OpenClaw 接收用户指令的通信通道。用户通过飞书向机器人发送消息,OpenClaw 将自动接收并处理。

创建应用

  1. 下载并安装 飞书 手机或电脑客户端
  2. 注册并登录 飞书开放平台
  3. 进入 开发者后台 → 创建企业自建应用

130

  1. 填写 应用名称 与 应用描述

131

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

132

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

133 134

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

QQ_1785417367020

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

136

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

137

获取 App ID,App Secret 及 tenant domain

查找并记录以下信息,后续配置 OpenClaw 时需要用到:

135

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

144

OpenClaw 初始化配置

启动 OpenClaw 配置

回到树莓派 SSH 终端,运行 onboard 命令启动配置:

openclaw onboard

OpenClaw(2026.7.1-2 及以上版本)采用 对话式配置,通过内置的 Crestodian 配置助手完成初始化。以下是完整的配置流程。

基础配置

运行 openclaw onboard 后,将进入 Crestodian(OpenClaw 内置的交互式配置助手)对话界面。Crestodian 会自动检测当前环境并列出基础配置方案,输入 yes 确认,即可自动完成 Workspace、Gateway 等基础配置。

140

配置 AI 模型

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

141

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

142

连接飞书

  • 在 Crestodian 对话界面中输入:
connect feishu

143

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

147

148

配置完成后,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

151

执行指令后,控制台状态显示 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智能助手 机器人会话框,发送消息:
你好,你能做什么?

155

⚠️ 这是 OpenClaw 的安全机制——首次给机器人发消息的用户需要被批准后才能正常对话。

  • 复制该指令并在树莓派上执行以批准正常对话

156

  • 重新发送消息

157

✅ MVD35智能助手 正常回复,说明 OpenClaw + AI 模型 API + 飞书整条链路已连通。

2. 系统信息访问能力测试

请告诉我这台机器的 hostname 和系统信息(uname -a)
MVD35上连接了什么USB设备

158

✅ MVD35智能助手 应能正常理解自然语言,自动执行指令并回答用户的问题

3. 资源占用检查

  • 在树莓派上查看 OpenClaw 的资源消耗:
htop

159

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

108

109

  • 验证安装
python3 -c "import mcp; print('MCP SDK 安装成功')"
python3 -c "import rclpy; print('rclpy 可用')"

110

✅ 执行指令后,控制台输出 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

160

  • 验证 mcp 加载
openclaw mcp list

161

✅ 执行指令后,在 MCP servers 中能看到刚添加的 drone-control 服务,则成功加载

  • 重启 Gateway 确认配置生效:
openclaw gateway restart
openclaw gateway status

162

创建无人机 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

163

✅ 执行指令后,在 Skills 列表中能看到刚添加的 mvd35-drone skill,则加载成功

联调验证

本节验证整个链路的连通性:飞书 → OpenClaw → MCP Server → MAVROS → 飞控。此步骤 无需起飞,只需要无人机通电并连接飞控即可。

启动完整系统

确保以下组件均已启动:

1. MAVROS

启动 MAVROS 连接飞控:

ros2 launch mavros apm.launch

165

✅ 控制台输出飞控型号、类型等详细信息,确认飞控连接成功。

2. OpenClaw

  • OpenClaw 已作为 systemd 服务在后台运行,确认其状态:
openclaw gateway status
  • 若服务未运行,手动启动:
openclaw gateway start

166

ℹ️ 本步骤验证无需启动 RealSense 相机和 OpenVINS。仅需 MAVROS 与飞控的连接,即可验证状态查询功能。

通过飞书查询无人机状态

  • 打开飞书,找到已创建的机器人,发送消息:

1. 设定身份

你叫mvd35-001,负责本台mvd35智能无人机的管理与控制。

164

2. 基础对话及信息查询

MVD35现在是什么状态?

167

3. 智能体问题分析

没有位置信息可能是什么原因
飞控固件是什么,为什么没有收到电池信息

168

✅ 通过对话测试,验证 AI 智能体通信链路已完全打通,可随时通过飞书与 MVD35 上 AI 智能体对话并控制无人机。智能任务执行可参考后续教程


附录

常见问题排查

现象可能原因解决方案
curl: (60) SSL certificate problem树莓派系统时间不正确sudo timedatectl set-ntp true 并 sudo timedatectl set-timezone Asia/Shanghai
openclaw: command not foundNVM 安装的 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)国内企业常用,需创建企业内部应用
微信(企业微信)通过企业微信开放平台接入

支持的大语言模型提供商:

提供商推荐模型说明
DeepSeekdeepseek-chat本教程示例,国内访问友好,性价比高
Google Geminigemini-2.5-flash多模态能力强,免费额度充足
OpenAIgpt-4o综合能力强,生态完善
Anthropicclaude-sonnet-4长上下文优秀,指令遵循能力强
通义千问(Qwen)qwen-max阿里云旗下,国内访问稳定
智谱 AIglm-4国产大模型,中文表现优秀
Ollama(本地部署)视硬件选择可在本地运行开源模型,无需 API Key

选择大语言模型时需考虑:网络环境(国内优先选择 DeepSeek、通义千问等)、成本(Gemini 免费额度较多)、性能需求(复杂任务推荐 GPT-4o 或 Claude)。对于无人机状态查询等轻量级任务,DeepSeek 或 Gemini Flash 已足够胜任。

以上列表为撰写本教程时 OpenClaw 支持的平台,实际支持情况可能随版本更新而变化。请查阅 OpenClaw 官方文档 获取最新的支持列表。

参考资源