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

微空 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 → 选择 MoreDeepSeek
  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 truesudo 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 healthopenclaw 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 官方文档 获取最新的支持列表。

参考资源