少侠好手艺
概述,飞控传感器包括陀螺仪、GPS、气压高度计等,主要使用串口或I2C传输测量的飞行器姿态、位置数据。输出则主要采用PWM控制舵机或电机电调,也会使用数字接口做简单的通断控制。RP2040的接口可灵活设置为硬串口、软串口或I2C接口,也可以设置为PWM输出口,用作飞控主板是很适合的。本实例中,占用2个硬串口、1个软串口、1个I2C口,接人GPS、LoRa、陀螺仪、气压高度计,以50或100Hz的频率实时采集飞行器姿态数据,以18Hz速率采集GPS位置、速度及气压高度数据,并实时控制数字口或PWM输出,LoRa模块能传输飞行数据至地面站,以及远程定位和搜索飞行器。
1,主板硬件:
使用一块成本7块多的RP2040单片机
2,实例用外设模块:
GPS模块 深圳飞空M10 RC12-BO:18Hz高刷新率,支持UBX格式输出,有直接测速输出
陀螺仪GY95T:响应快,串口输出
气压高度计BMP390:高精度
远程通信LoRa 泽耀科技A39C-T900A30S1a:高传输率
舵机 NEEBRC 3.7G:数字舵机,响应速度较快,能低压3.7V工作
3,连线:
3.1 电源,所有模块及RP2040的Vcc并联接在一起,GND也连在一起,调试时由RP2040的Type-C插电脑供电,脱机使用时Vcc并联点与GND并联点分别接单节锂电池正负极,可串电源开关。如使用舵机,因其电流较大,其正负极应单独接线连锂电池正负极;
3.2 GPS模块,左数(按上图放置的情况下)第一根线红色为数据输出线,接RP2040第5脚(GP05),左数第2根黑线为数据输入线,接RP2040 GP05,左数第3黄线、4号绿线分别为Vcc和GND。对应由硬串口2代码Serial2控制。模块还剩2根线为磁罗盘数据线,悬空不用。程序都使用查询方式,因此接好这4根线后,即使还没有接好别的模块,也可以试着运行程序,应该可以在串口监视器里看到GPS数据,在室内无卫星信号的情况下,卫星数为0,其他数值也是0,程序能正常运行。放到窗户外或室外,等上二十几秒就能看见卫星数增加,获得当地经纬度等数据。
3.3 陀螺仪,TD、RC脚分别接RP2040 GP02、03脚,由程序setup中的软串口GYSerial控制。同样,接人陀螺仪模块后,重新插电就能看到测量的姿态数据。
3.4 LoRa,RXD、TXD分别接RP2040 GP0、1脚,由程序setup中的硬串口Serial1控制。
3.5 气压高度计,SDA及SCL分别接RP2040 GP08、09脚,对应setup的I2C接口。
3.6 舵机,黄色控制线接RP2040 GP14-17任意一脚,由代码analogWrite输出PWM信号控制。
3.7 数字输出,可接其余任意引脚,控制三极管、MOS开关模块等执行通断动作。
4,通信基础,串口通信使用Serial1、Serial2、XSerial这一类函数。RP2040有两个硬串口UART1和URAT2,由Serial1和Serial2函数控制,每个硬串口可以在给定的两组引脚中选定两个引脚,如串口1可以选0、1或12、13,如图
设置串口包括指定串口引脚(RX、TX),设置通信速率(115200)等。使用时,在主循环loop中查询是否该串口有数据,如果有数据则依次每次读取一个8位二进制数据。不同设备或模块的串口数据有特定的数据头,比如陀螺仪GY95T的数据头是0xA4、0x03,而GPS的数据则总是以0xB5、0x62开头。对读取的前两个数据进行判断,符合该设备的数据头再依次读取后边的传感器值,通常每个测量值由读取的3个或4个8位二进制数据组成,经过简单8位移(或x256)加和得到测量值。
除这两个硬串口外,还可以使用软串口SoftwareSerial,可以选定任意两个引脚做软串口的数据收发脚RX和TX使用,具体使用方面与硬串口没什么差别,见附件代码。
串口输出应该是最简单的数据通信模式了,有的模块没有串口输出,只有I2C和SPI,I2C也是只占用2个管脚,与串口的区别在于使用的函数不一样,要使用到打包的库函数wire.h,每个模块有一个特定地址,所以可以多个模块并接到RP2040同样两个管脚上,单次只对某个地址的模块读数。本实例中气压高度计就没有串口输出,使用别人编好的开源代码(DFRobot_BMP3XX.h),经过简单设置后,可以用函数如sensor.readAltitudeM()读取数据,看起来比串口还简单,对初学者还是比较友好的。
5,代码解析
5.1,首先#include各种库*.h,主要是RP2040兼容Arduino的库,也有气压高度计的库。别的模块也是可以用库的,也就是别人编好的代码函数,不过在本实例看来必要性不大,串口模式的话直接读就很简单了,如果使用多个串口模块,其代码都是一样的。
5.2,设置,包括气压高度计函数定义,地址设定。还有测量数据名、类型定义,SoftwareSerial GYSerial(2,3)定义了一个软串口的名称及管脚,用于陀螺仪数据连接。进入setup设置函数,设置12-17为数字输出口,定义PWM频率和分辨率。然后设置了两个硬串口管脚,注意GPS的硬串口还要设置一个较大的FIFO,否则数据偶尔会出错,然后启动几个串口。setup中还设置了I2C引脚(8,9),并设置初始海拔高度。
5.3,主循环,陀螺仪软串口GYSerial和GPS硬串口Serial1都采用查询方式,如果数据没准备好就跳过,因此陀螺仪将会以50Hz速率读GY串口,因为它的初始设置是50Hz发一次数据,这个速率也是可以根据说明书来设置的。而GPS速率只有18Hz,气压高度计在高精度读取时差不多也是20几Hz,本实例中把气压高度计的读取放到了GPS串口读取中,因此GPS和气压高度计会以18Hz速率读出。串口打印Serial输出数据到电脑,会看到每2-3次GY数据后会跳出一个GPS和高度数据,因为50Hz差不多就是18Hz的2-3倍。注意每个读数都要加一个100us左右延迟,以匹配串口速率,不然数据会出错。
5.4,串口读数,如上述第4节所述,串口读数首先查询是否有数据,然后读取两个数据看看是不是正确的数据头,然后再用一个for循环批量读取数据到buf数组。
5.5,测量数据生成,根据GY95T模块说明书及GPS的UBX数据协议,不同测量数据在串口数据不同位,找到这些位对应的数组索引,就可以通过位移将高8位、低8位,甚至4个8位二进制数合成一个测量数据。
5.6,PWM控制输出,对于姿态控制,可以设置简单的PD反馈,也就是将姿态陀螺仪的角度和角速度各自乘反馈系数,转换成整型数后放到analogWrite值,不同飞行器用途需要线性组合姿态角进行控制,都是需要自己根据用途设置及调参的。对于开伞这一类简单控制,只需要设置开伞条件,如下降速度大于5m/s,启动给定管脚数字输出即可。
5.7,LoRa远程数据传输,基本原理见之前的帖子,在本实例中不是直接传送GPS所有原始数据,而是选取几个关键数据传输,这样可以减少数据量。在飞行器落地后,还可以在主循环中加delay,设置成每1秒甚至10秒采集和传输一次数据,以达到节能的目的。
本实例是打算应用在火箭上,对体积重量均有限制要求,因此采用了立体布线,将陀螺仪和气压高度计用2.54插针焊在了RP2040上。最上图左边为飞控系统,右边为地面接收站,屏幕显示实时传回的数据。调试时天线打了两个圈,不然无线电发射功率有点大,数据传输会受到干扰出错。
最终火箭应用实例的成品如下图,从上至下依次为GPS(要放在最上面接收卫星信号),陀螺仪、气压高度计、RP2040飞控主板、LoRa、锂电池。含电池重量29.5g,可以装入内径40mm长度40mm的箭体电子仓内。
使用树莓派的目的是降低制作门槛,但纯手工焊接又抵消了这一点,还是建议打一块pcb板把成品电路焊上去。
其他东西问题不大,但天线不是找根线焊上去就“能用”的东西。
这个还是起于Arduino生态,只是RP2040确实性能碾压同价位arduino单片机,arduino编程环境对初学者是比较友好的。
做PCB的话可能直接上芯片布线,如果已经全是现在这种模块,画PCB板还是有点尴尬,就是几个插座插针。具体到我目前需求,还考虑过焊插座
都焊好了,可以插线连接,后来还是觉得直接焊线简洁。我焊工好觉得就几根线还挺简单的,做PCB就有点啰嗦,也许有其他爱好者可以贡献PCB版的。
天线也是比较局限,需要窝在伞仓和头锥里的,可以实测优化一下。
没地方放火箭,今天测试了土办法抛射,用橡皮筋能将模块抛至45米高下落(气压计实测),陀螺仪加速度计实测最大加速度20g(时间0.1s)。GPS没有锁死,不过上升段GPS速度数据延迟了0.5s以上,下降段速度数据延迟小一些。高度数据更是延迟得厉害,也不准确,几乎没法看。推测大机动下这种民用GPS信号需要较长时间重新锁定,另外测试时两面都靠着墙,只有5颗星,也是个不利因素。至少短时大过载下GPS没有锁死,长时间加速的情况只能等有机会上箭测试了。
在我看来,arduino开发环境连嵌入式的门槛也没有够到
你这属于是显摆心态了吧,网上有不少讨论arduino、树莓派、stm32各自适用场合的,即使不考虑学习成本,也要根据技术需求理性选择。另外,RP2040在性能有很大提升,兼容arduino,可以覆盖更多的应用,像这种飞控用传统arduino跑起来是很吃力,RP2040就很轻松。
再说个例子,呐我30年前就会8051、8098,就会画PCB,但是后边20年虽然经常做电路却再没画过PCB,高温导线直接在实验板上搭,调试灵活、效率高。因为我现在的工作是搞研究啊,又不是搞研发的,更不是搞产品开发的,关键都挺忙的,怎么顺手怎么来呗。
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
那条白色的线线是信号线吗?
仅仅是拿“学习成本”来支持用arduino来开发,不觉得显著拉低论坛的嵌入式技术等级吗,我看这科创也是世风日下,连这种毫无技术等级的东西都能够被纳入精选文章列表
精选是因为该方案能解决实际问题,有较为彻底的开源,并且文章写得足够细,有可操作性。
这并不是一个探讨嵌入式开发的文章,因此不适用于从嵌入式开发技术方面去评判。同时,作者选取专业分类时是有错误的,将电子学专业作为主分类,被鄙视也十分正常,现已调整到火箭相关专业。
arduino长期以来总是被“正统的”嵌入式群体所鄙视,但不妨碍它在商业和普及上的成功。实际上高通的收购即便在arduino圈子内部也引起了不小的争议。
KC曾为爱好者开发过正经的遥控点火器,投入研发成本十几万,截至停产下架,产品总营业额一万多点,这就是正经的代价。
如果您有什么解决办法,不妨做出自己的贡献。
GPS串口通讯代码有更新,使用标准GPIO串口通讯函数uart及中断。单片机主频降至66.5MHz,在集成度高的情况下减少对GPS干扰。下面是读取日期时间及卫星数的例程:
#include <hardware/clocks.h>
#include "hardware/uart.h"
#include "hardware/irq.h"
uint16_t Yr;
uint8_t SA,Mt,Dy,Hr,Mn,Sd;
unsigned char GPS_buf[75];
void setup() {
set_sys_clock_khz(66500,true);
//使用Uart0串口及中断读GPS
uart_init(uart0, 115200); // 初始化 UART
gpio_set_function(12, GPIO_FUNC_UART); // 设置 GPIO 引脚为 UART 功能(例如 GP12 作为 TX,GP13作为 RX)
gpio_set_function(13, GPIO_FUNC_UART);
gpio_pull_up(13); // 确保 RX 引脚上拉,避免悬空输入
uart_set_irqs_enabled(uart0, true, false); // 启用 UART 中断,读数中断,写数不中断
irq_set_exclusive_handler(UART0_IRQ, GPS_Read); // 设置GPS读数中断处理函数
irq_set_enabled(UART0_IRQ, true); // 启用串口中断
delay(1000);
}
// GPS读数中断函数
void GPS_Read() {
while (uart_is_readable(uart0)) {
uint8_t ch = uart_getc(uart0); // 读取一个字
if (ch==0xB5){
ch = uart_getc(uart0); // 读取一个字
if (ch==0x62){
uint8_t msgClass = uart_getc(uart0);
uint8_t msgId = uart_getc(uart0);
uint8_t length = (uart_getc(uart0));
if (msgClass 0x01 && msgId 0x07) { // NAV-POSLLH消息
for(uint8_t i=0;i<73;i++){
GPS_buf[i] = uart_getc(uart0);
}
Yr = (GPS_buf[6]<<8)|GPS_buf[5];
Mt = GPS_buf[7];
Dy = GPS_buf[8];
Hr = GPS_buf[9]+8;
Mn = GPS_buf[10];
Sd = GPS_buf[11];
SA = GPS_buf[24];
}
}
}
}
}
论坛里的飞控还停留在大锅熬大药阶段,,,居然那么多人还在用arduino,令人咋舌
最新的公版betaflight加入了对RP2350的支持,老的RP2040也有个madflight的项目支持
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
rp2350a才6块钱一片,成本优势很大,不过不清楚这6块钱一片的是博通原厂原版的还是晶圆厂偷偷封装出来卖的
别小看arduino,俄乌战场上那些花天价按照正规军标MIL-STD流程开发的武器被开源项目+华强北物料+3D打印机+嘉立创的制造的东西吊着打,科技已经换代了