4. 开发环境搭建

MAVSDK 是一组面向 MAVLink 协议的现代开发库,它把底层消息打包、心跳维持、超时重传、任务协议等细节封装成简洁的异步 API,让开发者可以用 Python、C++、C#、Java 等语言直接控制 PX4 或 ArduPilot 飞控。本节的目标是搭建一条“开发机 → MAVSDK → 飞控(仿真或真机)”的完整链路,并跑通第一个可观测的示例程序。理解这条链路的层次关系,比记住零散命令更重要。

MAVSDK 开发环境链路与端口关系 开发机(Ubuntu / Windows) Python 3.10+ / pip mavsdk 包(异步 API) 示例程序 first_flight.py 连接 / 解锁 / 起飞 / 降落 UDP 客户端 udp://:14540 MAVLink 消息编解码 UDP 14540 / 14580 仿真环境(SITL) PX4 SITL / ArduPilot SITL make px4_sitl gazebo Gazebo / jMAVSim 物理引擎与传感器模型 MAVLink 路由 14580 监听端口 模拟飞控状态机 MAVLink 串口 / UDP 飞控(真机) PX4 / ArduPilot 固件运行 TELEM 接口 57600 / 921600 执行机构 电机 / 舵机 真实飞行 开发阶段用 SITL 仿真替代真机;切换真机时只需把连接地址从 udp://:14540 改为串口或网络地址

一、核心原理:MAVSDK 在链路中的位置

飞控与地面端之间使用 MAVLink 协议通信,它是一套二进制消息格式,包含心跳、姿态、位置、任务、参数等数百种消息。直接手写 MAVLink 需要处理序列号、校验、超时和状态机,成本很高。MAVSDK 位于应用层与 MAVLink 之间,向上提供 System、Action、Telemetry、Mission 等对象,向下负责连接管理、心跳检测和消息收发。

因此,一个 MAVSDK 程序的最小闭环是:创建 System 并连接到指定地址,等待飞控心跳,调用 Action 解锁与起飞,通过 Telemetry 订阅姿态和位置,最后降落并释放连接。仿真环境(SITL)本质上是一个运行在开发机上的“虚拟飞控”,它同样输出 MAVLink 消息,因此 MAVSDK 代码在仿真与真机之间几乎不需要修改,只需更换连接地址。

关键点:MAVSDK 不直接操作电机,它只发送 MAVLink 指令;飞控负责解释指令并驱动执行机构。理解这一点,就能明白为什么“连接成功”不等于“可以起飞”——还需要解锁、模式正确、GPS 或仿真定位有效。

二、方法流程:四步搭建可运行环境

  1. 安装 MAVSDK:推荐使用 Python 版本,便于快速验证。使用虚拟环境隔离依赖,避免污染系统 Python。
  2. 配置仿真环境:安装 PX4 或 ArduPilot 的 SITL,并配合 Gazebo 或 jMAVSim 提供物理仿真。
  3. 连接飞控:仿真时连接 udp://:14540;真机时使用串口或网络地址,并确认波特率与端口。
  4. 运行第一个示例:从官方示例 takeoff_and_land.py 入手,观察日志中的连接、解锁、起飞、降落全过程。
# 1. 创建虚拟环境并安装 MAVSDK
python3 -m venv mavsdk-env
source mavsdk-env/bin/activate
pip install mavsdk

# 2. 启动 PX4 SITL(在 PX4-Autopilot 目录下)
make px4_sitl gazebo

# 3. 另开终端,运行第一个示例
python takeoff_and_land.py

三、连接 PX4 与 ArduPilot 的差异

PX4 与 ArduPilot 都支持 MAVLink,但默认端口和部分行为不同。PX4 SITL 默认在 14540 端口提供 MAVSDK 连接,14580 用于地面站;ArduPilot SITL 常用 14550 作为地面站端口,MAVSDK 连接时通常指定 udp://:14550 或使用 --out 参数转发。真机场景下,PX4 常用 TELEM1 对应 /dev/ttyS0,ArduPilot 常用 /dev/ttyACM0 或 /dev/ttyUSB0,波特率常见为 57600 或 921600。

对比项 PX4 ArduPilot
仿真启动命令 make px4_sitl gazebo sim_vehicle.py -v ArduCopter
MAVSDK 默认连接 udp://:14540 udp://:14550
真机串口示例 /dev/ttyS0 /dev/ttyACM0
常用波特率 57600 / 921600 57600 / 115200
解锁方式 支持 arm() 直接解锁 部分机型需先设置模式

四、案例:第一个示例程序的执行过程

下面是一个典型的起飞降落示例,它覆盖了 MAVSDK 最常用的几个对象。运行后,终端会依次输出连接成功、解锁成功、起飞高度、降落完成等日志。

import asyncio
from mavsdk import System

async def run():
    drone = System()
    await drone.connect(system_address="udp://:14540")

    print("等待飞控连接...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print("飞控已连接")
            break

    print("解锁中...")
    await drone.action.arm()

    print("起飞到 5 米...")
    await drone.action.takeoff()
    await asyncio.sleep(8)

    print("降落中...")
    await drone.action.land()

asyncio.run(run())

如果一切正常,日志中会出现 飞控已连接、解锁中...、起飞到 5 米...、降落中...。若卡在“等待飞控连接”,说明 MAVSDK 没有收到心跳,应检查仿真是否启动、端口是否匹配、防火墙是否拦截 UDP。

建议先只运行“连接并打印心跳”的最小程序,确认链路通畅后再加入解锁和起飞逻辑。这样可以把“连接问题”和“控制问题”分开排查,效率更高。

五、常见误区与复盘

  • 误区一:仿真没启动就运行程序。 MAVSDK 会一直等待心跳,表现为程序无输出或超时。应先确认 SITL 已进入 Ready for takeoff 状态。
  • 误区二:端口写错。 PX4 与 ArduPilot 默认端口不同,混用会导致连接失败。建议在代码中把地址提取为变量,便于切换。
  • 误区三:忽略解锁条件。 真机上电池电压低、GPS 未定位、遥控器未校准都会导致解锁失败,日志中通常有明确原因。
  • 误区四:在异步函数中使用阻塞调用。 MAVSDK Python 是异步 API,应使用 await 和 asyncio.sleep,避免使用 time.sleep 阻塞事件循环。
真机测试前务必取下螺旋桨,并在开阔无人的场地进行。首次连接真机时,建议先用地面站确认飞控状态正常,再运行 MAVSDK 程序。

完成本节后,你应当能够独立完成“安装 MAVSDK → 启动 SITL → 连接飞控 → 运行起飞降落示例”的完整流程,并能根据日志判断问题出在连接层、解锁层还是控制层。这套环境是后续任务规划、航点飞行和编队控制的基础,建议把连接地址、端口和启动命令整理成自己的速查清单。