4、MAVSDK-Python环境搭建

好,咱们进入第四章。前面几章我们把仿真环境、MAVLink基础都捋了一遍,现在该动真格的了——把MAVSDK-Python装起来,写几行代码跟无人机打个招呼。

MAVSDK是什么?说白了,它就是一套帮你跟无人机对话的SDK。你不用去手撕MAVLink协议里的那些字节流,直接调Python函数就行。我个人习惯用Python做原型验证,因为快,改起来也方便。

本章核心目标:装好MAVSDK-Python,理解它的几个核心概念,然后写一个能发现无人机、读取姿态和位置的脚本。

4.1 安装MAVSDK-Python

安装其实很简单,一行命令的事。但我建议你先确认一下Python版本——我遇到过有人用Python 3.12装不上,后来发现是某些依赖还没跟上。

# 推荐Python 3.8 ~ 3.11
pip install mavsdk

嗯,就这么简单。如果你在Linux上装,可能会遇到grpcio编译报错。别慌,先装个系统依赖:

# Ubuntu/Debian
sudo apt install libssl-dev libffi-dev python3-dev

# 然后再装
pip install mavsdk

小技巧:我习惯在虚拟环境里装,避免污染全局Python。用python -m venv mavsdk_env创建一个干净的隔离环境,再pip install,出了问题直接删掉重来,省心。

装完之后验证一下:

python -c "import mavsdk; print(mavsdk.__version__)"

如果能打印出版本号,恭喜,环境通了。

4.2 MAVSDK核心概念介绍

MAVSDK的设计思路其实很清晰。我刚开始看的时候觉得概念有点多,但用起来发现就那么几个东西。你想想看,无人机系统无非就是:连接、系统、插件。

概念 说明 类比
System 代表一架无人机或地面站 就像你手机通讯录里的一个联系人
Plugin 功能模块,比如Telemetry、Action、Mission 联系人下面的电话号码、地址、备注
Connection 通信方式,串口、UDP、TCP 你用什么方式打电话——座机还是手机
Core 管理连接和系统发现的核心层 电话交换机

核心流程是这样的:你先建立一个连接,然后MAVSDK会自动发现网络里的无人机(也就是System),接着你就可以通过插件去读写数据了。

MAVSDK核心架构图 MAVSDK核心架构 用户代码(你的Python脚本) 调用Plugin API,处理回调/协程 Plugin 层 Telemetry | Action | Mission | Param | ... Core 层 System发现 | 连接管理 | 消息路由 连接层 串口 (Serial) | UDP | TCP 你只需要关心用户代码和Plugin API,Core和连接层MAVSDK帮你搞定

这张图你看明白了吗?从上往下,你写的代码调用Plugin,Plugin通过Core把请求发到连接层,最后送到无人机。反过来,无人机发回来的数据也走这条路。

4.3 连接与系统发现

连接方式有三种,我列个表给你对比一下:

方式 连接地址格式 适用场景
UDP udp://:14540 仿真、局域网内地面站
TCP tcp://192.168.1.10:5760 远程连接、桥接场景
串口 serial:///dev/ttyUSB0:57600 物理数传、Pixhawk直连

咱们做仿真,用UDP最方便。还记得第三章的仿真环境吗?启动之后,PX4会在本机开一个UDP端口,MAVSDK连上去就行。

系统发现这块,我曾经踩过一个坑。一开始我以为连上就能直接用,结果发现system对象是异步发现的。什么意思呢?就是connect之后,MAVSDK需要一点时间去“找到”无人机。如果你立刻去读数据,大概率读到空值。

注意:一定要等system.is_connected变成True,或者用first_system()协程等待发现完成,再往下走。否则你会遇到各种诡异的NoneType错误。

正确的做法是这样:

from mavsdk import System
import asyncio

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(f"发现无人机!系统UUID: {state.uuid}")
            break

asyncio.run(run())

你看,用async for监听connection_state,一旦连上就跳出循环。我个人习惯把这个逻辑封装成一个wait_for_system()函数,后面每个脚本都能复用。

4.4 基础API调用示例

好,现在无人机连上了,我们来读点数据。最常用的就是遥测数据——姿态、位置、电池这些。

先看一个完整的例子:

import asyncio
from mavsdk import System

async def run():
    drone = System()
    await drone.connect(system_address="udp://:14540")
    
    # 等待系统发现
    async for state in drone.core.connection_state():
        if state.is_connected:
            print("系统已连接")
            break
    
    # 等待位置数据就绪
    print("等待位置数据...")
    async for position in drone.telemetry.position():
        print(f"位置: 纬度={position.latitude_deg:.4f}, "
              f"经度={position.longitude_deg:.4f}, "
              f"相对高度={position.relative_altitude_m:.2f}m")
        break  # 只取第一个数据
    
    # 读取姿态
    async for attitude in drone.telemetry.attitude_euler():
        print(f"姿态: 横滚={attitude.roll_deg:.1f}°, "
              f"俯仰={attitude.pitch_deg:.1f}°, "
              f"偏航={attitude.yaw_deg:.1f}°")
        break
    
    # 读取电池
    async for battery in drone.telemetry.battery():
        print(f"电池: {battery.remaining_percent:.0%}")
        break

asyncio.run(run())

跑这个脚本之前,记得先启动仿真环境(第三章的内容)。如果一切正常,你会看到类似这样的输出:

系统已连接
位置: 纬度=47.3977, 经度=8.5456, 相对高度=0.00m
姿态: 横滚=0.0°, 俯仰=0.0°, 偏航=0.0°
电池: 100%

嗯,位置是苏黎世,因为PX4默认的起飞点就在那里。高度0米,说明无人机在地面待命。

经验之谈:MAVSDK的API几乎都是异步的,用async for可以持续接收数据流。如果你只想取一次,记得加break,不然它会一直等新数据。我刚开始写的时候就忘了break,结果脚本卡在那不动,还以为是bug。

除了读数据,你还可以发指令。比如让无人机起飞:

# 先确认无人机状态
async for health in drone.telemetry.health():
    if health.is_global_position_ok and health.is_home_position_ok:
        print("无人机状态正常,准备起飞")
        break

# 起飞
print("起飞!")
await drone.action.arm()
await drone.action.takeoff()

# 等5秒
await asyncio.sleep(5)

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

这里要注意,arm()和takeoff()都是协程,必须用await调用。而且起飞前最好检查一下health,确保GPS和home点都就绪了。我曾经在室内仿真时忘了开GPS模拟,结果arm()一直报错,折腾了半天才发现是这个问题。

4.5 本章小结

到这,你已经把MAVSDK-Python环境搭好了,也学会了怎么连接仿真无人机、读取遥测数据、发送起飞指令。这些东西看着简单,但它们是后面所有高级功能的基础——任务规划、航点飞行、参数调优,全都建立在今天这几行代码之上。