(2025)F450+树莓派5(Ubuntu24.04)+Dronekit+Aruco二维码降落 实验指南

1、本项目基本遵循苍穹四轴DIY给出的教程,但是由于各个库的版本更新,在环境配置过程中遇到了很多问题,原有教程难以解决,所以整理出一份资料。

2、由于环境配置过于复杂且繁琐,我只在Dronekit环境搭建还有SITL仿真环境搭建这两步进行了全过程的记录,只要对ubuntu系统足够熟悉,配置起来很快。不熟悉ubuntu也没关系,ubuntu使用上的关键部分我都贴出了相应教程。

3、dwc老师原本建议用ROS控制无人机,但是我为了光速毕业主打一个方便快捷且省事,最后还是采用了Dronekit的方案。

4、树莓派上的ubuntu系统用户名我设置为HDUASL,密码hduasl(小写)。

5、在这个项目之前我从未接触过无人机,仅为自身经验总结,如有错误,欢迎指正。(邮箱:Vc_Ri@outlook.com)

代码:

https://github.com/VcRi/F450-Dronekit-Aruco.git

演示视频:

(F450+Dronekit)SITL + MavProxy 仿真演示

F450+树莓派Ubuntu24.04+Dronekit 悬停、移动测试

综述:

1、无人机组装

2、无人机调试(需要下载地面站软件MissionPlanner)

3、树莓派5搭载Ubuntu24.04系统,使用GPIO对机械爪的PWM舵机进行控制以实现开合;使用Dronekit库对无人机进行飞行控制

4、仿真使用SITL+MAVProxy(仿真环境在笔记本虚拟机里的Ubuntu18.04系统上)

5、两个Ubuntu系统下载的都是带图形界面的版本,平时使用让树莓派接上显示器及键盘鼠标,用vscode写代码。户外飞行时用笔记本SSH远程连接树莓派(两台都连接手机热点,或者连接同一wifi,总之在同一网络下),通过命令行的方式运行代码。也可以通过VNC连接让笔记本获取到树莓派的桌面。

硬件准备:

1、F450无人机 (2000r左右,我使用的这台是pixhawk2.4.8飞控 + AT9s Pro遥控器)

苍穹四轴DIY 处购买,出厂已经调试好。我们有三台无人机是在这家购买的,提供订单链接可以被拉到售后群

2、树莓派5 (4G) (500r左右)

  • 树莓派5是23年新发售的,教程不多。我买它是因为买的时候什么也不知道,随便选了个最新的,不过使用上大差不差。
  • 买的是带csi摄像头版本的。raspberry pi os自带了对这个csi摄像头支持的库,但是ubuntu系统下我始终没搞定这个库,且这个摄像头似乎不具备完成这个项目的能力
  • 还额外购买了32G的SD存储卡装在树莓派上
  • 这一套使用下来偶有死机或者卡顿现象,不知道是内存小了还是树莓派本身性能的问题。

3、机械爪 (100r左右)

我购买的是下图这一款:
在这里插入图片描述

安装在无人机上的方式也很潦草,直接用轧带绑在无人机下面的。
机械爪资料-百度网盘分享 店家提供的机械爪资料我没细看,实际上就三根线,接到树莓派上就完事了,如何接线及使用详见文章后面。

4、摄像头 (400r左右)

  • 选择全局快门(而非卷帘快门),我描述了一下我要在离地两三米高度对地面上A4大小左右二维码进行识别的需求后,店家推荐我使用50-60度的摄像头:
    在这里插入图片描述

  • 该摄像头是USB口,在win上和ubuntu上即插即用,无需安装驱动。Ubuntu命令行里输入以下两个命令可以调用该摄像头看看效果:

  • #ffmpeg是一个多媒体处理库,也是sudo apt install ffmpeg一行命令就能下载好
              
    #录制一段10s的视频
    ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 1920x1200 -i /dev/video0 -t 10 -c:v copy output.mp4
              
    #拍摄一张照片
    ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1200 -i /dev/video0 -frames:v 1 -q:v 2 image.jpg
    
  • 但是这款摄像头的拍摄素质有点感人,我只能说完成该二维码识别任务还是可以成功的

  • 店家提供的调试软件:摄像头资料-百度网盘分享


F450很耐造,器材坏了都可以买,单价1000以内的发票学校可以直接报销,总之买之前跟dwc老师讲一声。

无人机桨叶等都是耗材(我的遥控技术实在太烂了),桨叶上有标型号,买的时候注意正桨反桨,可以各买一两副备用。

M8n GPS模块的支架容易摔断,如果断的地方靠底部,把螺丝拧开,支架重新插进去再拧上螺丝还可以继续用,只是会短一截。淘宝上也有单支架可以买,型号基本上是通用的。

苍穹四轴DIY教程整理:

点击可直接跳转:

图文并茂详细教程之–用pixhawk飞控组装一台F450四轴无人机(上)

图文并茂详细教程之-- 用pixhawk飞控组装一台F450无人机(中)

图文并茂详细教程之-- 用pixhawk飞控组装一台F450无人机(下)

Pixhawk无人机扩展教程(1)—树莓派与pixhawk连接

Pixhawk无人机扩展教程(2)—树莓派安装ubuntu-mate系统及必要设置

Pixhawk无人机扩展教程(3)—树莓派安装Dronekit及读取飞控数据

Pixhawk无人机扩展教程(4)—使用Dronekit编写一个控制程序

Pixhawk无人机扩展教程(5)—SITL仿真模拟飞行:开发环境搭建

Pixhawk无人机扩展教程(6)—启动SITL+MAVProxy

Pixhawk无人机扩展教程(7)—SITL+MP/QGC运行

Pixhawk无人机扩展教程(8)—使用键盘控制无人机飞行

Pixhawk无人机扩展教程(9)—树莓派安装opencv

本文是对这份教程的补充和扩展,飞行控制部分也主要参考教程里的代码,只是额外加上了机械爪控制和二维码检测部分。

其中扩展教程(7)和扩展教程(9)我完全没有用到。

温馨提示:

和安全性有关的问题,一定注意注意再注意,不要对自己太自信。

这一小段的内容即使暂时不理解也没有关系,放在前面是因为它非常重要。

祝愿大家都不要炸机。


1、每次安装好桨叶后,都仔细核对一遍桨叶安装是否正确

初次接触无人机的我:不是,这么简单谁能装反

某次起飞侧翻了三次才发现是桨叶装错后的我:我是**

2、锂电池是一个比较危险的东西。电池不要过充及过放,充电时保证有人在场。我的是3s锂电池,即有三片电芯,只要其中有一片坏了就不要再用了,电压会有问题;电池鼓包也不要再用了。每次飞行完毕后,无人机的动力锂电池和遥控器里的电池都及时取下,放进电池防爆袋里,废电池更是需要妥善处理

有次遥控器里的电池忘记取下,隔了一晚上发现电池鼓包,没法用了。

3、针对本项目,需要熟悉定高模式、悬停模式和降落模式,三种模式都要手飞过,并且学会判断GPS信号。

上锁、解锁、BB响使用演示:

YH远航科技-F450无人机PIXHAWK飞控起飞教程(定点+自稳操作)

这个视频里的遥控器设置和我们的不一样。关注使用过程就行。


苍穹四轴DIY提供的飞行教程:

定高模式(F450福斯遥控版)

悬停模式(F450机型乐迪遥控版)

降落模式(F450机型乐迪遥控版)

定高模式: 定高模式不需要GPS。飞上去后,高度虽然能固定,但是水平方向上会有较大偏移,要不断调整位置

悬停模式: 悬停模式需要GPS,飞上去后会定点悬停住。如果GPS信号不足,遥控器是解锁不了的。

降落模式: 降落模式下,无人机会自动降落。

在代码里面使用的都是GUIDED模式,降落时才会切换RTL返航或者LAND降落模式实现降落。

RTL模式下,会先回到航点上空固定高度(在missionplanner里可以查到RTL_ALT这个参数),然后再执行降落。这是教程里的代码提供的降落模式。

Land模式下,会让无人机直接降落。这是在我的项目采用的降落模式。


对于GUIDED模式,想让它飞上去定的住不漂移,也是需要足够的GPS信号的。

我的个人使用经验是,即使GPS信号不充足,在GUIDED模式下也会解锁。

那次的使用体验很恐怖, 我没有检查GPS灯,也没有在悬停模式下试验能否用遥控器解锁,结果无人机起飞后直接大漂移,最后撞到东西摔了。

在那次之后,我还遇到过代码运行中、等待无人机起飞时,LED灯忽然从绿变黄绿的情况。如果没及时暂停代码,恐怕就要梅开二度了。

当然如果你的场地足够空旷,就不用像我这么小心翼翼。我设置的飞行高度一般两三米,飞行时间也很短暂。


检查GPS信号我认为有两种方式:

1、直接连MissionPlanner,可以查到GPS信号是否充足。(实际上直接在遥控器里也能查到GPS搜星数量)

2、通过飞控上的LED灯判断GPS信号

我的数传用不了,每次地面站连飞控都要接线,很麻烦,所以我都用第二种方法,扫一眼就知道能不能起飞了。


如何识别LED灯?

LED灯在飞控上,这里仅说明明如何辨别pix的灯

我这里找到的是pix4的官方教程,与我使用的pixhawk2.4.8还是有点区别的
在这里插入图片描述

参考官方教程:LED灯含义 · PX4 User Guide

在这里插入图片描述

解锁: 在手飞情况下,遥控器“油门最低 + 方向舵右”这一步就是解锁操作,解锁完后,电机会转动,此时推油门无人机才会起飞。呈现在代码里,就是vehicle.armed = True这一句。(注意,拨动安全开关那一步只是解锁的前置条件,但还不是解锁)

GPS锁定: 这里锁定的意思是GPS模块会输出有效的全球定位数据,所以GPS锁定才是我们需要的。


综上,

蓝色,意味着GPS未锁定,即GPS信号不足。解锁操作会使灯从蓝色闪烁状态变成蓝色常亮状态。

绿色,意味着GPS锁定,即GPS信号充足。解锁操作会使灯从绿色闪烁状态变成绿色常亮状态。

但是!实际上我最常遇到的是另外一种快速闪烁的黄绿色灯(毕竟这只是Pixhawk4的教程)

这个灯的意思我猜测是介于蓝色和绿色之间,代表有GPS信号,但是仍然不足,譬如悬停模式下是无法解锁的

等待一段时间后,当GPS信号充足时,黄绿色灯才会转变成为绿色。M8N GPS性能不是很好,无人机附近不要有遮挡物,包括人也离得远一点。


黄绿色灯:
在这里插入图片描述
绿色灯:
在这里插入图片描述
代码控制飞行时,请保证LED灯一定是绿色的。


4、据无人机售后描述,用代码控制飞行时,使用遥控器切换飞行模式可以剥夺控制权。例如飞行中使用悬停模式,遥控器来回拨动一下模式开关就可以得到控制权了。但是在切换时油门需要保持中位,低位会掉下来。


5、如果真的炸机,可以看这篇教程查一下飞行日志检查原因:APM/Pixhawk飞行日志分析入门(苍穹四轴)

一、组装


组装见教程:图文并茂详细教程之–用pixhawk飞控组装一台F450四轴无人机(上)


这一步我没有经验可以分享,我拿到的无人机是已经组装好的,但是想熟悉一下所有结构的话可以参考这个视频:

F450装机教程PIX2.4.8版本

二、调试

图文并茂详细教程之-- 用pixhawk飞控组装一台F450无人机(中)

图文并茂详细教程之-- 用pixhawk飞控组装一台F450无人机(下)

调试过程完全遵循教程。 即使是已经安装使用过的无人机,在长期不用后一些仪器也需要校准。

一些注意事项如下:

1、推荐一个视频PIXHAWK2.4.8飞控调试教程,非常直观地展示了调试的步骤和一些细节。视频仅供参考,调试过程中所有的设置仍然以卖家的教程为准。

2、调试使用的软件是Mission Planner地面站,官网下载即可,教程里用的是版本1.3.62(archive文件夹里有历史版本)。注意下载.msi版本,前者安装完后能帮你装上驱动,后续用数据线连接时电脑可以成功识别到飞控

在这里插入图片描述

3、飞控和笔记本之间连接使用的是micro线,如果插上线后识别不到正确的端口,很有可能是线的问题。短的micro线极有可能只提供充电功能,无法进行数据传输;三合一充电线也不够稳定。这两种线我都试过,用不了。

4、第一次安装的无人机跟着教程一步步设置即可。已经安装使用过的无人机,跳过更新固件这一步(除非有特殊需求)

5、指南针校准这一步,只要三百六十度无死角来回晃让进度条走满就可以,不需要有严格的旋转方向

三、电池使用

如果实验室的电池或者充电器换新设备了,使用方式可能会略有不同。仅以我拿到手的为例:
在这里插入图片描述
在这里插入图片描述

共有两块锂电池,小的是控电,装在遥控器里;大的是动力锂电池,给无人机供电


电池接口:

在这里插入图片描述

左边白色的是平衡头,右边黄色的是XT60头

不同充电器需要用到的接口可能不同,使用B3平衡充的话,将平衡头接到充电器上进行充电即可。放一个电池充电的教程:[航模入门]B3、B6充电器使用方法 航模锂电池充电教程(锂电池易燃,不耐摔,使用务必注意安全,充电时需有人在场)


遥控器电池安装方式:

打开遥控器后侧电池槽

将遥控器电池供电头(红色那个头,有红黑两条电线分别对应正极和负极)插在遥控器的电池槽最左侧的二口排插上,保证正极(红色电线)朝上。

在这里插入图片描述
在这里插入图片描述

四、起飞

在温馨提示部分,已经列出了手飞可以参考的教程。顺便再把温馨提示看一遍。

五、树莓派与Pixhawk连接

见教程:Pixhawk无人机扩展教程(1)—树莓派与pixhawk连接

六、树莓派镜像烧录器烧录Ubuntu24.04系统

对应教程:Pixhawk无人机扩展教程(2)—树莓派安装ubuntu-mate系统及必要设置

在系统选择上,我并没有遵循扩展教程(2)的配置。树莓派5是2023年发售的,买的时候没考虑太多,买完后发现关于树莓派5的使用教程比较少。而且用树莓派镜像烧录器烧录系统的时候,发现能选择的ubuntu系统都比较新(没有教程里的那么古老)。中途系统还被我搞坏了一两次,总之最后配置好环境的Ubuntu系统是24.04 LTS (是一个相当新的Ubuntu版本)

因此,针对这一步骤,我简单描述下我是如何进行配置的:

1、使用树莓派镜像烧录器烧录24.04 LTS系统。
参考教程: 【树莓派5】树莓派5安装Ubuntu 23.10桌面系统


2、安装vim编辑器。
忘了24.04有没有自带vim了,虽然平时用vscode写代码,看文件也是直接用图形界面操作多,但是vim偶尔还是会用到的。

 sudo apt-get install vim

vim编辑器的基础用法是需要额外学一下的。


3、对Ubuntu进行换源。
ubuntu下载好时,官方源使用的是国外服务器,下载速度感人,要换成我们国内的源。常见的有清华源、阿里源、淘宝源等等,都可以使用(简单来说换源就是更改Ubuntu系统里某个文件里的某几行)。

换源教程:Ubuntu24.04换源方法(新版源更换方式,包含Arm64) 注意,树莓派是arm架构,要看最后的Arm64-ubuntu配置,即换源时要额外加上ports。


4、我没有用远程桌面的方案。我室内写代码时树莓派外接显示器鼠标键盘,户外测试时直接使用ssh连接树莓派。

  • 扩展教程(2)提到要在笔记本上提前下载好ubuntu系统,让两个ubuntu系统互连。我觉得没有必要。笔记本之后确实需要下载ubuntu系统(下载在虚拟机里),但这个系统我只用来配置仿真环境。现在用ssh连接只是保证在没有显示器和鼠标键盘的户外时,仍然可以运行树莓派里的代码,所以在win上使用MobaXterm这个软件远程ssh连接到树莓派就可以了。
  • 在笔记本windows系统上下载好MobaXterm(亲测很好用,推荐),树莓派上开启ssh远程服务,需要保证笔记本和树莓派在同一网络下(同一手机热点也可以),之后就可以连接到树莓派用命令行的方式对树莓派进行控制了。

对ubuntu24.04使用的提示:

ubuntu24.04下载好是自带python3的,下面两个命令可以查看python版本

python2 --version
python3 --version

本项目的代码都是在python3环境下运行的,在命令行里运行python代码使用的命令也是 python3 test.py(不加3会默认使用Python2环境)

苍穹四轴DIY里给出的教程应该是在python2环境下,Dronekit库也是Python2版本的。因此用教程里的方法去配置Dronekit完全不成功。这点在讲到Dronekit配置时再展开。

在环境配置阶段,除了Dronekit库下载和SITL仿真环境搭建这两步我卡了很久之外,其他所有的下载靠下面的命令基本就可以完成:

sudo apt install xxxx(你需要的包的名称)

sudo pip3 install xxxx(你需要的包的名称) #pip默认为Python 2使用,而pip3则专门为Python 3使用

总之环境配置就是看提示信息,提示缺什么就下载什么,大部分问题一两个命令就可以解决。下载不成就问GPT。

有时候回车了一个命令后会提示权限不足,这种情况一般是命令开头忘记加sudo了。sudo是临时提升权限的方式,不想频繁输入sudo也可以查下永久提升权限的方式。

在ubuntu命令行下输入密码,密码是被隐藏掉的,没有*号占位,光标也不会后移。放心大胆的输完然后敲回车,输错了会提示你重来的。

在室内使用时,树莓派是接树莓派官方电源使用的(比较稳定,卡顿较少)

在户外测试时,树莓派和无人机都使用电池供电,无人机上有一根Type-C接口的线就是给树莓派供电用的

七、机械爪安装

机械爪上的舵机是PWM舵机,总共有三根线,一根接5V电源,一根接地(Ground),还有一根是信号线,不同功能的线可以根据颜色区分。

查阅树莓派引脚图可发现,树莓派上总共40个引脚,每个引脚功能不同。

其中我接的是4号(5V电源)、6号(接地)和32号引脚(PWM信号),在图中已圈出。

在这里插入图片描述

引脚参考文章:树莓派5-GPIO和40针引脚_树莓派5引脚定义-CSDN博客

里面有提到“GPIO12、GPIO13、GPIO18、GPIO19 上提供硬件 PWM。”

总之我选择了GPIO12(即32号引脚),测试下来可以正常使用。

RPI.GPIO这个库是要下载的,网上查一下ubuntu安装树莓派GPIO库的命令是什么,不赘述。

机械爪测试代码:control.py

import RPi.GPIO as GPIO
import time

# 设置GPIO模式为BCM
GPIO.setmode(GPIO.BCM)
# 定义GPIO引脚
PWM_PIN = 12  # GPIO12(对应32号引脚)
# 设置GPIO引脚为输出模式
GPIO.setup(PWM_PIN, GPIO.OUT)
# 创建PWM实例,频率设置为50Hz(适用于大多数舵机)
pwm = GPIO.PWM(PWM_PIN, 50)
# 启动PWM,初始占空比为0(电机停止)
pwm.start(0)

# 定义函数:打开爪子
def open_claw():
    print("打开爪子")
    pwm.ChangeDutyCycle(8)  # 8%占空比(假设对应爪子打开)
    time.sleep(1)  # 等待1秒,确保动作完成

# 定义函数:闭合爪子
def close_claw():
    print("闭合爪子")
    pwm.ChangeDutyCycle(5)  # 5%占空比(假设对应爪子闭合)
    time.sleep(1)  # 等待1秒,确保动作完成
    
try:
    while True:
        open_claw()  # 打开爪子
        time.sleep(5)  # 等待5秒

        close_claw()  # 闭合爪子
        time.sleep(5)  # 等待5秒

except KeyboardInterrupt:
    # 捕获Ctrl+C,停止程序
    print("程序停止")

finally:
    # 停止PWM并清理GPIO设置
    pwm.stop()
    GPIO.cleanup()
    print("GPIO已清理")

八、树莓派安装Dronekit(修改Dronekit源码)

参考教程:Pixhawk无人机扩展教程(3)—树莓派安装Dronekit及读取飞控数据

之前提到过,我们的树莓派上安装的是Ubuntu24.04,自带python2和python3。

从教程里的Dronekit使用流程里看下来,它使用的应该是python2环境

python2实在太古老,我之后还要控制机械爪,还要使用OpenCV,所以Dronekit也必须在python3环境下使用

按照教程里的方式去下载Dronekit时,遇到了相当多的问题,查阅资料,甚至发现Dronekit 不支持Python3.0。不过都是比较古老的教程,2025年Dronekit还是支持python3的。

在树莓派里我也是误打误撞才装下来Dronekit,不可能为了复刻而重装一遍系统,所以决定在我的笔记本虚拟机里装一个Ubuntu24.04 LTS,复刻一下Dronekit安装流程(但树莓派是arm架构毕竟和笔记本还是有区别,不清楚会不会有影响)

1、查看python版本

python3 --version

输出Python 3.12.3,说明ubuntu24.04确实自带python3


2、下载pip3,下载完后查看

sudo apt install python3 python3-pip python3-dev
pip3 --version #查看pip3版本

3、下载dronekit

sudo pip3 install dronekit

报错:
在这里插入图片描述

言下之意就是和环境有冲突,但如果硬要下载,可以在后面加上–break-system-packages

sudo pip3 install dronekit --break-system-packages

在这里插入图片描述

下载成功,下一步测试一下这个库能不能在python代码里正常使用

我已经提前下载安装好vscode,ubuntu自带的火狐浏览器默认搜索引擎是谷歌,没开vpn是用不了的,初次使用记得去设置里改一下。如果不想额外下载代码编辑器,直接在命令行里用命令创建python文件然后写代码进去也行。就是真的难用。

from dronekit import connect, VehicleMode, LocationGlobalRelative #代码里放这一句就够了。

运行一下测试代码,发现出现了报错。看起来Dronekit确实下载并且引入成功了,问题出在Dronekit内部。

大致原因是,python3的高版本中,MutableMapping已经被弃用。解决方法要么给python版本降级,要么修改Dronekit源代码。


在这里插入图片描述


我们使用修改源代码的方式

其实并不复杂,仔细观察报错可以发现,问题出在文件的第2689行,改掉这一行里的一点内容就可以。
我们使用vim编辑器打开这个文件:

#注意,要给sudo权限,不然改不了这个文件
sudo vim /usr/local/lib/python3.12/dist-packages/dronekit/__init__.py

打开之后会发现vim编辑器没显示行号的,先按esc键,然后输入冒号,再输入set number,回车后会显示行号。

:set number

在这里插入图片描述

既然讲到这就多写一句,vim编辑器有保存退出和不保存退出,不小心改掉了不该改的记得不保存退出:

:wq #保存退出
:wq #强制保存退出
:q #不保存退出
:wq! #强制不保存退出

我们直接跳转2689行。同样是先按esc,再输入:

:2689 

键盘上敲一个a,进入插入模式

把2689行的 class Parameters(collections.MutableMapping, HasObservers):这一句替换成:

from collections.abc import MutableMapping
class Parameters(MutableMapping, HasObservers): 

然后:wq保存退出。

此时再运行测试代码,成功
在这里插入图片描述


接下来就是按照教程的步骤赋予端口权限。

需要提到的是,教程里面永久改写USB口读写权限我一直没有成功,因此每次都用下面这个命令临时赋予权限:

sudo chmod 666 /dev/ttyUSB0

如果环境配置都成功了话,给无人机供上电,在树莓派上运行connect.py代码看下是否能正常输出信息。

connect.py代码:

from dronekit import connect

# Connect to the Vehicle (in this case a UDP endpoint)
#vehicle = connect('/dev/ttyUSB0', wait_ready=True, baud=921600)
vehicle = connect('/dev/ttyUSB0', wait_ready=True, baud=57600) #降低波特率后成功

# vehicle is an instance of the Vehicle class
print("Autopilot Firmware version: %s" % vehicle.version)
print("Autopilot capabilities (supports ftp): %s" % vehicle.capabilities.ftp)
print("Global Location: %s" % vehicle.location.global_frame)
print("Global Location (relative altitude): %s" % vehicle.location.global_relative_frame)
print("Local Location: %s" % vehicle.location.local_frame)
print("Attitude: %s" % vehicle.attitude)
print("Velocity: %s" % vehicle.velocity)
print("GPS: %s" % vehicle.gps_0)
print("Groundspeed: %s" % vehicle.groundspeed)
print("Airspeed: %s" % vehicle.airspeed)
print("Gimbal status: %s" % vehicle.gimbal)
print("Battery: %s" % vehicle.battery)
print("EKF OK?: %s" % vehicle.ekf_ok)
print("Last Heartbeat: %s" % vehicle.last_heartbeat)
print("Rangefinder: %s" % vehicle.rangefinder)
print("Rangefinder distance: %s" % vehicle.rangefinder.distance)
print("Rangefinder voltage: %s" % vehicle.rangefinder.voltage)
print("Heading: %s" % vehicle.heading)
print("Is Armable?: %s" % vehicle.is_armable)
print("System status: %s" % vehicle.system_status.state)
print("Mode: %s" % vehicle.mode.name) 
print("Armed: %s" % vehicle.armed)  

对于波特率这一点我很迷惑。常见的波特率有1200、2400、4800、9600、19200、38400、57600和115200,我改了几次最后发现我的无人机波特率设置为57600时可以正常连接。至于为什么改成57600就可以不清楚。

注意,无人机记得接上电源。未接电源,仅连接地面站的情况下运行代码,我这里出现no heartbeat的报错

WARNING:dronekit:Link timeout, no heartbeat in last 5 seconds
ERROR:dronekit.mavlink:Exception in MAVLink input loop

九、使用Dronekit编写代码

参考教程:Pixhawk无人机扩展教程(4)—使用Dronekit编写一个控制程序

到这一步就可以编写自己需要的功能控制无人机移动了。

再放一下我的代码的实地测试视频:F450+树莓派Ubuntu24.04+Dronekit 悬停、移动测试

代码不能直接上无人机运行! 只要是控制飞行的代码都要提前做好仿真,下一部分才会讲解到仿真如何做。

hover.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import time
from dronekit import connect, VehicleMode, LocationGlobalRelative
import RPi.GPIO as GPIO

# 设置GPIO模式为BCM
GPIO.setmode(GPIO.BCM)
# 定义GPIO引脚
PWM_PIN = 12  # GPIO12(32号引脚)
# 设置GPIO引脚为输出模式
GPIO.setup(PWM_PIN, GPIO.OUT)
# 创建PWM实例,频率设置为50Hz(适用于大多数舵机)
pwm = GPIO.PWM(PWM_PIN, 50)
# 启动PWM,初始占空比为0(电机停止)
pwm.start(0)
# 定义函数:打开爪子
def open_claw():
    print("爪子已打开")
    pwm.ChangeDutyCycle(8)  # 8%占空比(打开)
    time.sleep(1)  # 等待1秒s

# 定义函数:闭合爪子
def close_claw():
    print("爪子已闭合")
    pwm.ChangeDutyCycle(5)  # 5%占空比(闭合)
    time.sleep(1)  # 等待1s

# 在起飞之前,打开爪子5秒,然后合上,等待3秒
print("起飞前操作:抓取物品")
open_claw()  # 打开爪子
print("爪子已打开,请在5s内放上物品")
time.sleep(5)  # 等待5秒
close_claw()  # 闭合爪子
print("闭合后等待3秒")
time.sleep(3)  # 等待3s


# 当前连接的 Pixhawk 飞控的端口
connection_string = '/dev/ttyUSB0'  # 现在使用的是 USB 转 TTL 接口,连接 Pixhawk 飞控
print('连接到设备: %s' % connection_string)
vehicle = connect('/dev/ttyUSB0', wait_ready=True, baud=57600) #降低波特率后成功

# 定义 arm_and_takeoff 函数,使无人机解锁并起飞到目标高度
# 参数 aTargetAltitude 即为目标高度,单位为米
def arm_and_takeoff(aTargetAltitude):
    # 起飞前检查
    print("进行起飞前检查")
    # vehicle.is_armable 会检查飞控是否启动完成
    while not vehicle.is_armable:
        print(" 等待设备初始化...")
        time.sleep(1)

    # 解锁无人机(电机将开始旋转)
    print("解锁电机")
    # 将无人机的飞行模式切换成 "GUIDED"(一般在 GUIDED 模式下控制无人机)
    vehicle.mode = VehicleMode("GUIDED")
    # 通过设置 vehicle.armed 状态变量为 True,解锁无人机
    vehicle.armed = True

    # 在无人机起飞之前,确认电机已经解锁
    while not vehicle.armed:
        print(" 等待解锁...")
        time.sleep(1)

    # 发送起飞指令
    print("起飞!")
    # simple_takeoff 将发送指令,使无人机起飞并上升到目标高度
    vehicle.simple_takeoff(aTargetAltitude)

    # 在无人机上升到目标高度之前,阻塞程序
    while True:
        print(" 当前高度: ", vehicle.location.global_relative_frame.alt)
        # 当高度上升到目标高度的 0.95 倍时,即认为达到了目标高度,退出循环
        if vehicle.location.global_relative_frame.alt >= aTargetAltitude * 0.95:
            print("达到目标高度")
            break
        time.sleep(1)

# 调用上面声明的 arm_and_takeoff 函数,目标高度 3 米
arm_and_takeoff(2)

# 悬停 5 秒,并不断输出“正在悬停”和一些信息
# 这里是为了在悬停的时候输出信息才这么写。如果不需要输出信息,直接time.sleep(5)就可以
print("开始悬停")
start_time = time.time()
while time.time() - start_time < 5: 
    # 打印高度和完整GPS信息
    print(" 正在悬停,当前高度: ", vehicle.location.global_relative_frame.alt)
    print("当前模式:",vehicle.mode.name)
    print("当前GPS:", vehicle.location.global_frame)
    time.sleep(1)

# 发送 "降落" 指令
print("降落")
#这里根据需要选择降落的方式
# RTL模式,无人机会自动返回home点的正上方(RTL高度可以在地面站里更改),之后自动降落。但我不需要无人机返回航点,所以改用Land模式降落。
# vehicle.mode = VehicleMode("RTL")
vehicle.mode = VehicleMode("LAND")  # 直接降落

# 在降落过程中,不断输出当前高度
print("开始降落")
while vehicle.armed:  # 当无人机未降落完成时(电机仍在旋转)
    print(" 正在降落,当前高度: ", vehicle.location.global_relative_frame.alt)
    print("当前模式:",vehicle.mode.name)
    print("当前GPS:", vehicle.location.global_frame)
    time.sleep(1)

# 降落完成后,退出之前,打开爪子
print("降落完成,打开爪子")
open_claw()  # 打开爪子
time.sleep(1)  # 等待1秒,确保动作完成

# 退出之前,清除 vehicle 对象
print("关闭设备连接")
vehicle.close()

# 停止PWM并清理GPIO设置
pwm.stop()
GPIO.cleanup()
print("GPIO已清理")

代码中凡是涉及到GPIO、PWM、Claw相关的代码,都是与机械爪有关的,可以直接删掉。不影响无人机控制部分的使用。

move.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import time
from dronekit import connect, VehicleMode, LocationGlobalRelative
import RPi.GPIO as GPIO
from pymavlink import mavutil 

# 设置GPIO模式为BCM
GPIO.setmode(GPIO.BCM)
# 定义GPIO引脚
PWM_PIN = 12  # GPIO12(32号引脚)
# 设置GPIO引脚为输出模式
GPIO.setup(PWM_PIN, GPIO.OUT)
# 创建PWM实例,频率设置为50Hz(适用于大多数舵机)
pwm = GPIO.PWM(PWM_PIN, 50)
# 启动PWM,初始占空比为0(电机停止)
pwm.start(0)

# 定义函数:打开爪子
def open_claw():
    print("爪子已打开,请在5s内放上物品")
    pwm.ChangeDutyCycle(8)  # 8%占空比(打开)
    time.sleep(1)  # 等待1秒,确保动作完成

# 定义函数:闭合爪子
def close_claw():
    print("爪子已闭合")
    pwm.ChangeDutyCycle(5)  # 5%占空比(闭合)
    time.sleep(1)  # 等待1秒,确保动作完成

# 在起飞之前,打开爪子5秒,然后合上爪子,等待3秒
print("起飞前操作:抓取物品")
open_claw()  # 打开爪子
time.sleep(5)  # 等待5秒
close_claw()  # 闭合爪子
print("等待3秒,开始连接设备")
time.sleep(3)  # 等待3秒


# 当前连接的 Pixhawk 飞控的端口
connection_string = '/dev/ttyUSB0'  # 现在使用的是 USB 转 TTL 接口,连接 Pixhawk 飞控
print('连接到设备: %s' % connection_string)
vehicle = connect('/dev/ttyUSB0', wait_ready=True, baud=57600) #降低波特率后成功


# 定义 arm_and_takeoff 函数,使无人机解锁并起飞到目标高度
# 参数 aTargetAltitude 即为目标高度,单位为米
def arm_and_takeoff(aTargetAltitude):
    # 起飞前检查
    print("进行起飞前检查")
    # vehicle.is_armable 会检查飞控是否启动完成
    while not vehicle.is_armable:
        print(" 等待设备初始化...")
        time.sleep(1)

    # 解锁无人机(电机将开始旋转)
    print("解锁电机")
    # 将无人机的飞行模式切换成 "GUIDED"(一般在 GUIDED 模式下控制无人机)
    vehicle.mode = VehicleMode("GUIDED")
    # 通过设置 vehicle.armed 状态变量为 True,解锁无人机
    vehicle.armed = True

    # 在无人机起飞之前,确认电机已经解锁
    while not vehicle.armed:
        print(" 等待解锁...")
        time.sleep(1)

    # 发送起飞指令
    print("起飞!")
    # simple_takeoff 将发送指令,使无人机起飞并上升到目标高度
    vehicle.simple_takeoff(aTargetAltitude)

    # 在无人机上升到目标高度之前,阻塞程序
    while True:
        print(" 当前高度: ", vehicle.location.global_relative_frame.alt)
        # 当高度上升到目标高度的 0.95 倍时,即认为达到了目标高度,退出循环
        if vehicle.location.global_relative_frame.alt >= aTargetAltitude * 0.95:
            print("达到目标高度")
            break
        time.sleep(1)

# 调用上面声明的 arm_and_takeoff 函数,目标高度 3 米
arm_and_takeoff(2)

# 悬停 5 秒,并不断输出“正在悬停”和一些信息
# 这里是为了在悬停的时候输出信息才这么写。如果不需要输出信息,直接time.sleep(5)就可以
print("开始悬停")
start_time = time.time()
while time.time() - start_time < 5: 
    # 打印高度和完整GPS信息
    print(" 正在悬停,当前高度: ", vehicle.location.global_relative_frame.alt)
    print("当前模式:",vehicle.mode.name)
    time.sleep(1)

print("向左缓慢飞行")
left_speed = 0.5  # 设置向左飞行速度为0.5m/s
flight_time = 2    # 飞行时间4秒(0.5m/s × 4s = 2米)

# 获取起始位置
start_position = vehicle.location.global_relative_frame

# 发送向左速度指令
msg = vehicle.message_factory.set_position_target_local_ned_encode(
    0,       # 时间戳
    0, 0,    # 目标系统ID和目标组件ID
    mavutil.mavlink.MAV_FRAME_BODY_NED,  # 坐标系
    0b0000111111000111, # 控制速度的位掩码
    0, 0, 0, # 位置参数(忽略)
    0, -left_speed, 0, # 速度参数(X,Y,Z)- Y为负表示向左
    0, 0, 0, # 加速度参数(忽略)
    0, 0)    # 偏航参数(忽略)

# 发送指令并保持飞行状态
start_time = time.time()
while time.time() - start_time < flight_time:
    vehicle.send_mavlink(msg)
    vehicle.flush()
    print(" 正在向左飞行,当前高度: ", vehicle.location.global_relative_frame.alt)
    print("当前GPS:", vehicle.location.global_frame)
    time.sleep(0.1)

# 停止移动(发送零速度指令)
msg = vehicle.message_factory.set_position_target_local_ned_encode(
    0, 0, 0,
    mavutil.mavlink.MAV_FRAME_BODY_NED,
    0b0000111111000111,
    0, 0, 0,
    0, 0, 0,
    0, 0, 0,
    0, 0)
vehicle.send_mavlink(msg)
vehicle.flush()
print("向左飞行完成,准备降落")


# 发送 "降落" 指令
print("降落")
#这里根据需要选择降落的方式
# RTL模式,无人机会自动返回home点的正上方(RTL高度可以在地面站里更改),之后自动降落。但我不需要无人机返回航点,所以改用Land模式降落。
# vehicle.mode = VehicleMode("RTL")
vehicle.mode = VehicleMode("LAND")  # 直接降落

# 在降落过程中,不断输出当前高度
print("开始降落")
while vehicle.armed:  # 当无人机未降落完成时(电机仍在旋转)
    print(" 正在降落,当前高度: ", vehicle.location.global_relative_frame.alt)
    print("当前模式:",vehicle.mode.name)
    time.sleep(1)

# 降落完成后,退出之前,打开爪子
print("降落完成,打开爪子")
open_claw()  # 打开爪子
time.sleep(1)  # 等待1秒,确保动作完成

# 先停止PWM
pwm.stop()
# 然后清理GPIO设置
GPIO.cleanup()
print("GPIO已清理")

# 最后退出之前,清除 vehicle 对象
print("关闭设备连接")
vehicle.close()

十、SITL仿真

仿真环境的搭建还是耗了我不少时间的,所以扩展教程(5)和(6)两篇教程里配置环境的步骤我会重新在文章里写一遍

之前已经说过了,仿真环境是需要搭建在另一台电脑上的Ubuntu系统上。

教程里用的是16.04系统。

我最后在笔记本Vmware虚拟机里配置了18.04系统(18.04本身就够古老了)

双系统是在一台计算机上装两个操作系统,每次开机时选择一个操作系统,两个系统是平级的。

虚拟机是在一个操作系统上通过虚拟机软件(如Vmware)模拟出1台或N台计算机,每台计算机上都可以装一个系统。

Vmware虚拟机安装ubuntu系统的帖子网上的教程很多,流程并不复杂,没有什么困难点。

唯一要注意的是,安装好系统后,如果虚拟机和主机之前无法复制粘贴,可以参考这篇:

Vmware虚拟机和主机之间复制、粘贴内容、拖拽文件的详细方法_主机如何复制粘贴到vmware虚拟机上-CSDN博客

我一般都是用这篇最后的三条命令解决这个问题:

sudo apt-get autoremove open-vm-tools
sudo apt-get install open-vm-tools
sudo apt-get install open-vm-tools-desktop

以下没有特别说明,默认是在笔记本端的ubuntu系统进行操作。

搭建Ardupilot开发环境

Pixhawk无人机扩展教程(5)—SITL仿真模拟飞行:开发环境搭建

更新系统,安装git:

sudo apt-get update

sudo apt-get install git

sudo apt-get install gitk git-gui

印象中这三个命令都是可以顺利运行的。不顺利的话自己找下原因

git clone这一步:

git clone https://github.com/ArduPilot/ardupilot #github服务器在国外,不会魔法的还是老实使用下面的镜像站吧

git clone https://kkgithub.com/ArduPilot/ardupilot #使用这个命令

这里的github.com换成镜像站kkgithub.com。镜像站的下载会很慢,请耐心等待一下,有能力也可以选择科学上网。

进入ardupilot文件夹:

cd ardupilot

之后,按照教程原本是要用git submodule update --init --recursive这个命令的

git clone那一步只是下载了仓库,还需要通过submodule 把module里的一些模块给下载下来。

但是我下载的时候总是下载不全,有时候提示下载完了,但是点进modules文件夹里,发现里面好多文件夹是空的。

查阅了很多资料,试了很多方法,最后成功的方法依然是换源。

以下是换源步骤:

首先在ardupilot文件夹下,用ls -a 查看所有文件,其中有一个.gitmodules文件

我们用vim编辑器打开这个文件:

vim .gitmodules

把文件里面所有的github.com换成kkgithub.com,然后保存退出。

输入:

git submodule sync

因为少输了这一句我卡了两天…

此时,镜像站已经更换完成。我们可以回到正常方式下载模块了:

git submodule update --init --recursive

完毕后点进modules文件夹,里面文件夹一个一个查看,发现全部下载成功。

接下来就按照教程,依次输入这几句就可以:

chmod +x Tools/environment_install/install-prereqs-ubuntu.sh
    
Tools/environment_install/install-prereqs-ubuntu.sh -y
    
. ~/.profile

到此环境配置成功了。

对于教程里接下来提到的例子,说实话我没明白它的作用,但还是把命令放上来:

cd ardupilot

./waf configure--board Pixhawk1

./waf copter

印象中我一开始以为我的飞控是pixhwak4,所以对pixhwak4也编译过一次,反而没有针对pixhawk2.4.8进行编译。但是可以正常使用。

启动仿真环境

Pixhawk无人机扩展教程(6)—启动SITL+MAVProxy

首先进入ArduCopter目录:

cd ardupilot/ArduCopter

接下来,教程里直接在ArduCopter目录下输入sim_vehicle.py -w(第一次仿真的时候一般先输入这个命令,初始化一些设置)

但是实际上这个文件挪到别的文件夹去了,所以在ArduCopter目录下应当输入的是:

../Tools/autotest/sim_vehicle.py -w

正式仿真的时候,运行的是下面的命令:

../Tools/autotest/sim_vehicle.py --console --map

正常情况下会弹出一个terminal,一个console,和一个map
在这里插入图片描述

console和map没有弹出来?正常。

在一堆输出里面我找到了一些信息:

Failed to load module: No module named 'console'. Use 'set moddebug 3' in the MAVProxy console to enable traceback
Failed to load module: No module named 'map'. Use 'set moddebug 3' in the MAVProxy console to enable traceback

言下之意就是这两个模块加载不出来。

教程里面给出的解决方法是这个:

sudo -H pip2 install --upgrade MAVProxy pymavlink future lxml

但是运行后,问题并没有解决

看下面这个帖子最终解决了

Pixhawk无人机-ArduPilot 软件SITL仿真模拟飞行(SITL+MAVProxy)_sitl仿真找不到’mavproxy.exe-CSDN博客

我是先试了解决方法二,没用,卡了好几天,回过头来又找到这个帖子,试了下解决方法一,最后成功了。

除了上述console和map模块的两个failed信息之外,我记得当时上面一行还有一行warning,言下之意是要卸载一个什么manager。当时网上搜了一下,反正最后sudo uninstall掉了。


### 连接树莓派运行仿真

再放一次自己录的演示视频:(F450+Dronekit)SITL + MavProxy 仿真演示

这里主要做两件事:

1、在笔记本端,启动仿真后,把树莓派的IP接口加进去

教程里的做法是使用output add命令增加树莓派IP接口。提醒一下,添加接口是每一次重启系统后都要重新做的。

但是有时候仿真启动后,需要等半天才能输入output add命令,不想等的话可以使用这个命令,将启动仿真+添加接口一次性完成:

# 记得把命令里的ip改成自己的树莓派的ip
# 冒号是英文冒号,不要打成中文冒号
../Tools/autotest/sim_vehicle.py -v ArduCopter --console --map --out=udp:192.168.2.239:14550

2、在树莓派端,运行仿真代码

其中仿真代码与实际代码相比,仅仅只是三行有改变而已。

在这里插入图片描述

左为hover.py代码示例,右边为配套的hover_sitl.py代码示例

connection_string = '192.168.2.239:14550'  # 这里的ip地址记得改为你的树莓派的地址
print('连接到设备: %s' % connection_string)
vehicle = connect(connection_string, wait_ready=True)

树莓派运行仿真代码后,在笔记本端的仿真界面里就会出现相应的变化了。

十一、(openCV)Aruco二维码降落

Aruco二维码实现无人机降落是一个比较成熟的方案了,需要下载opencv库

扩展教程(9)里提供了下载openCV的方法,但它选择的是从源码编译安装,非常繁琐。

我没记错的话,我直接使用万能的sudo apt install就下载成功了,同时openCV下载好后自带Aruco模块,无需再额外下载Aruco。

下载好后到python代码里用一行import cv2测试一下,没报错就说明安装成功。


我最后的实现方案非常傻瓜,就是让无人机在空中根据二维码调整自身位置,对准后直接降落。实际测试能不能落到二维码上比较看运气。

Aruco二维码生成网站:Online ArUco markers generator

我用的是它默认的配置,可以根据需要自行更改:

在这里插入图片描述

字典选择4*4,ID选择0,size选择100


相机检测二维码camera_test.py:
import cv2
import numpy as np
import time

# 摄像头参数
CAMERA_DEVICE = "/dev/video0"
FRAME_WIDTH = 1920
FRAME_HEIGHT = 1200
FPS = 30

# ArUco参数
DICTIONARY = cv2.aruco.DICT_4X4_50
MARKER_ID = 0

# 初始化摄像头
cap = cv2.VideoCapture(CAMERA_DEVICE)
if not cap.isOpened():
    print(f"无法打开摄像头 {CAMERA_DEVICE}!")
    exit()

cap.set(cv2.CAP_PROP_FRAME_WIDTH, FRAME_WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, FRAME_HEIGHT)
cap.set(cv2.CAP_PROP_FPS, FPS)

# ArUco初始化
aruco_dict = cv2.aruco.Dictionary_get(DICTIONARY)
parameters = cv2.aruco.DetectorParameters_create()

def get_frame_center(frame):
    h, w = frame.shape[:2]
    return (w // 2, h // 2)

# 主程序
try:
    last_detection_time = 0
    detection_interval = 2.5  # 检测间隔(秒)
    
    while True:
        ret, frame = cap.read()
        if not ret:
            print("摄像头读取失败!")
            break

        # 显示画面
        cv2.imshow("Camera View - 按ESC退出", frame)
        
        # 按固定间隔检测
        current_time = time.time()
        if current_time - last_detection_time >= detection_interval:
            last_detection_time = current_time
            
            # 检测ArUco标记
            corners, ids, _ = cv2.aruco.detectMarkers(frame, aruco_dict, parameters=parameters)
            
            if ids is not None and MARKER_ID in ids:
                idx = np.where(ids == MARKER_ID)[0][0]
                frame_center = get_frame_center(frame)
                marker_center = np.mean(corners[idx][0], axis=0).astype(int)
                
                offset_x = marker_center[0] - frame_center[0]
                offset_y = marker_center[1] - frame_center[1]

                # 输出调整指令
                if abs(offset_x) > 100:
                    print(f"[{time.strftime('%H:%M:%S')}] 向右移动" if offset_x > 0 else f"[{time.strftime('%H:%M:%S')}] 向左移动")
                if abs(offset_y) > 100:
                    print(f"[{time.strftime('%H:%M:%S')}] 向上移动" if offset_y < 0 else f"[{time.strftime('%H:%M:%S')}] 向下移动")
                if abs(offset_x) <= 100 and abs(offset_y) <= 100:
                    print(f"[{time.strftime('%H:%M:%S')}] 已居中,准备降落")
            else:
                print(f"[{time.strftime('%H:%M:%S')}] 未检测到标记")

        # 按ESC退出
        if cv2.waitKey(1) == 27:
            break

finally:
    # 确保资源被正确释放
    cap.release()
    cv2.destroyAllWindows()
    print("程序结束")
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值