
鸭式布局制导探空火箭
简介
基于STM32的塔式火箭飞控,搭载ICM42688六轴传感器,SPL06气压计,通过控制鸭翼舵面偏转,进而实现火箭制导,支持GPS定位,数据回传,定高开伞回收等功能.
简介:基于STM32的塔式火箭飞控,搭载ICM42688六轴传感器,SPL06气压计,通过控制鸭翼舵面偏转,进而实现火箭制导,支持GPS定位,数据回传,定高开伞回收等功能.开源协议
:CC BY-NC-ND 3.0
(未经作者授权,禁止转载)描述
视频链接:
[B站视频--功能演示及介绍] (https://b23.tv/oJUeSUk)
[抖音视频--火箭发射测试] (https://v.douyin.com/mNeh_hm-i_Y/b@n.dN)
[抖音视频--火箭项目视频介绍] (https://v.douyin.com/crXb9vUJCHw/Q@X.MJ)
欢迎关注我的B站UID:2028030889 抖音号:43167085679。
项目简介
一枚鸭式布局制导火箭,基于STM32的自研塔式火箭飞控,搭载ICM42688六轴传感器,SPL06气压计,通过控制鸭翼舵面偏转,进而实现火箭制导,支持GPS定位,数据回传,定高开伞回收等功能。本项目软件,硬件,机械设计资料在CC-BY-NC-ND 3.0协议下发布,仅供爱好者DIY学习交流使用,未经本人许可严禁任何形式的商业使用及贩卖。火箭研发具有危险性,禁止在无安全防护的情况下进行试验。本设计不提供任何形式的工作保障/售后保修,不对任何因产品设计、操作不当以及违反当地法律法规所造成的制作人、第三方人身财产资源损坏/损害的后果及连带责任负责。
火箭在2025年7月7日进行了首次发射测试

项目功能
火箭由分布于箭体的四路鸭翼舵面控制姿态。飞控实时感知火箭当前飞行姿态,飞行高度,垂直速度,经纬度等,进而控制鸭翼舵面偏转,实现基本的火箭制导功能。飞控通过卡尔曼滤波融合六轴传感器与气压计高度数据,估测垂直速度,当火箭到达最高点时,垂直速度为0,此时火箭开伞。搭配VOFA+地面站,火箭使用Lora实时回传飞行数据,位置信息,用于火箭回收与后期分析研究。

项目参数
火箭飞控由功能明确的三块PCB堆叠而成:
电源层:由12V锂电池或Type-C接口供电,经DCDC芯片和LDO芯片转换为5V与3.3V后,分别给舵机与主控层,信号层供电。电源板有四路舵机接口,通过XH2.54-4P的排线连接主控板,接收PWM信号后用来控制舵机。

主控层:使用STM32F103C8T6作为主控芯片,板上集成ICM42688-P六轴传感器,SPL06-001气压计,通过姿态解算与卡尔曼滤波估测垂直速度后,用于控制火箭姿态与定高开伞功能。同时支持GNSS定位报文解析,获得经纬度与对地速度等位置信息,并一同发送至信号层。

信号层:集成大夏龙雀DX-GP10 GNSS定位芯片,使用泽耀A39C系列(可选)Lora模块,通过串口接收来自主控层的数据并转发至地面站。

连接VOFA+上位机
火箭飞控可通过Lora或数传连接上位机,波特率默认115200,使用FireWater数据协议。
代码内默认传输欧拉角,经纬度,垂直速度,对地速度,高度,加速度等信息。
VOFA+上位机下载地址 https://www.vofa.plus/

3D打印与组装
- 火箭的每个功能舱段使用M36mm + M312mm 十字螺丝固定,鸭翼舵面使用银燕舵机摇臂+1mm螺丝+502胶水固定,火箭摔过几次,依旧能用,当然有更好的方式欢迎讨论。

2. 塔式飞控使用四根M2.5螺纹棒+六角螺母固定,外壳使用长100mm,外径63内径57的亚克力管,需要对其进行钻孔,以便使用螺丝固定亚克力管。舵机依次排列在舵机舱内。舵机型号:银燕ES08MA金属模拟12g

3. 组装舵机舱时,将四组舵机依次放置在舵机舱内,再盖好舵机舱顶盖,舱内上下均有卡扣固定,安装时需要对准卡扣,注意调整。

4. 使用火箭连接件(图中黑色部分)连接各舱段,这样的连接件你一共需要打印四个,整理好舵机的线缆。

5. 组装好降落伞舱还有整流罩,降落伞舱预留了一个M2.5的小孔,用于固定整流罩或者安装挂件,降落伞舱内也预留了小孔,可以安装电子点火头,触发开伞。


6. 火箭底座可以用来安装20mm外径的火箭发动机,例如四凯模型火箭发动机或者自制发动机。你可以使用Soildworks对其尺寸进行修改,以适配其他型号的火箭发动机,将发动机塞进底座圆孔之后,使用螺丝和强力胶水固定即可。火箭发射需在有安全保护的条件下进行。

7. 靠近发动机舱的舱段(图中白色部分是电池舱,可以存放一个三角形的12V锂电池组,购买时注意尺寸),安装螺丝时将电池垫高一点,注意螺丝不要贯穿电池,以免发生危险。我的发动机舱是红色的,3D打印的时候适当提高热床温度,以免发动机舱脱离热床。

8. 打螺丝(hh),建议使用电动螺丝刀。如果把握不了螺丝长度,建议都使用 M3*6mm 的十字螺丝
实物展示
使用加热台焊接飞控各元器件,注意焊接温度不要长时间超过180度,以免损坏气压计和惯性传感器。主控层有两个按键,分别是复位和屏幕信息切换,GPS经纬度,气压高度,欧拉角等重要信息,可以通过此按键切换。飞控组装完成后,建议在飞控与电池之间再外接一个开关,给火箭底部的舱段开一个口 , 就可以在不拆解火箭的情况下开启/关闭电源.

火箭飞控启动后,在火箭朝相应方向倾倒时,鸭翼应保持竖直,以提供相反方向的力矩,从而修正火箭姿态.

使用一个频率在1575.42/1561mhz的GPS有源陶瓷天线,通过SMA接口连接到信号板,在窗台或者室外可以搜索到GPS信号。通过主控板上的按键切换到GPS数据显示模式,可以观察此时的经纬度,对地速度等数据。搜索到GPS卫星并且定位有效时,信号板上会有LED闪烁。

ICM42688P与SPL06驱动(完整代码请参考附件)
ICM42688P
typedef struct{
int16_t AccX;
int16_t AccY;
int16_t AccZ;
}ICM42688AccData;
typedef struct{
float gx;
float gy;
float gz;
}AccG;
typedef struct{
int16_t GyroX;
int16_t GyroY;
int16_t GyroZ;
}ICM42688GyroData;
ICM42688AccData *DataAcc;ICM42688GyroData *DataGyro;
void ICM42688_Read_Reg(uint8_t reg,uint8_t *Data)
{
*Data = 0;
MySPI_ICM42688_Start();
reg |= 0x80;//高1位是读写位
MySPI_ICM42688_SwapByte(reg);
*Data = MySPI_ICM42688_SwapByte(0xFF);//将需要的数据交换过来,0xFF没有意义
MySPI_ICM42688_Stop();
}
void ICM42688_Write_Reg(uint8_t reg,uint8_t Data)
{
MySPI_ICM42688_Start();
MySPI_ICM42688_SwapByte(reg);
MySPI_ICM42688_SwapByte(Data);
MySPI_ICM42688_Stop();
}
void ICM42688_Init(uint8_t *State)
{
MySPI_ICM42688_Init();
uint8_t Time=100,ID = 0;
ICM42688_Read_Reg(ICM42688_WHO_AM_I,&ID);
if(ID != 0x47&&Time>0){
ICM42688_Read_Reg(ICM42688_WHO_AM_I,&ID);
Time--; *State = 0;
}
else {*State = 1;} /*判断ICM42688P是否正确连接*/
if(*State == 1)
{
ICM42688_Write_Reg(0x11,0x01);//设备配置.SPI0,软复位
Delay_ms(100);//软复位后等待响应
ICM42688_Write_Reg(ICM42688_PWR_MGMT0,0x0F); //电源配置
// ICM42688_Write_Reg(ICM42688_ACCEL_CONFIG0,0x46); //1KHz,4G
ICM42688_Write_Reg(ICM42688_ACCEL_CONFIG0,0x01); //32KHz,16G
ICM42688_Write_Reg(ICM42688_ACCEL_CONFIG1,0x14); //3级滤波
//ICM42688_Write_Reg(ICM42688_GYRO_CONFIG0,0x66); //1KHz,250度/s
ICM42688_Write_Reg(ICM42688_GYRO_CONFIG0,0x01); //32KHz,2000度/s
ICM42688_Write_Reg(ICM42688_GYRO_CONFIG1,0x0A); //3级滤波
}
}
void ICM42688_Data(ICM42688AccData *DataAcc,ICM42688GyroData *DataGyro)
{
uint8_t buffer[12];
// 读取加速度+陀螺仪数据(共12字节)
MySPI_ICM42688_Start();
MySPI_ICM42688_SwapByte(ICM42688_ACCEL_DATA_X1 | 0x80); // 设置读标志位[4](@ref)
for(int i=0; i<12; i++) {
buffer[i] = MySPI_ICM42688_SwapByte(0xFF); // 连续读取12字节[4](@ref)
}
MySPI_ICM42688_Stop();
// 解析加速度数据(前6字节)
DataAcc->AccX = (buffer[0] << 8) | buffer[1];
DataAcc->AccY = (buffer[2] << 8) | buffer[3];
DataAcc->AccZ = (buffer[4] << 8) | buffer[5];
// 解析陀螺仪数据(后6字节)
DataGyro->GyroX = (buffer[6] << 8) | buffer[7];
DataGyro->GyroY = (buffer[8] << 8) | buffer[9];
DataGyro->GyroZ = (buffer[10] << 8) | buffer[11];
}
SPl06_001
typedef struct{
float Pressure;
float Tempreture;
float Height;
}SPL06_Data;
void SPL06_Read_Reg(uint8_t reg, uint8_t *Data) {
*Data = 0;
MySPI_SPL06_Start();
reg |= 0x80; // 设置读标志位
MySPI_SPL06_SwapByte(reg);
*Data = MySPI_SPL06_SwapByte(0xFF);
MySPI_SPL06_Stop();
}
void SPL06_Write_Reg(uint8_t reg, uint8_t Data) {
MySPI_SPL06_Start();
MySPI_SPL06_SwapByte(reg); // 写标志位
MySPI_SPL06_SwapByte(Data);
MySPI_SPL06_Stop();
}
uint8_t SPL06_Init(uint8_t *State) {
uint8_t ID;
MySPI_SPL06_Init();
SPL06_Write_Reg(0x0C, 0x09);
Delay_ms(200);
SPL06_Read_Reg(0x0D, &ID);
if (ID != 0x10) {
*State = 0;
}
else
*State = 1;
// 配置传感器
SPL06_Write_Reg(0x08, 0x07); // 连续测量模式
SPL06_Write_Reg(0x06, 0x76); // 压力配置
SPL06_Write_Reg(0x07, 0xF6); // 温度配置,改完还要改下面的系数
SPL06_Write_Reg(0x09, 0x0C); // FIFO禁用,压力移位
return ID;
}
void SPL06_GetData(SPL06_Data *Data) {
uint8_t buffer[6];
int32_t Ori_Pressure,Ori_Tempreture;
MySPI_SPL06_Start();
MySPI_SPL06_SwapByte(0x00 | 0x80); // 读数据寄存器,地址自增
//依次读取数据寄存器
for (int i = 0; i < 6; i++) {
buffer[i] = MySPI_SPL06_SwapByte(0xFF);
}
MySPI_SPL06_Stop();
//组合原始数据
Ori_Pressure = (int32_t)((buffer[0] << 16) | (buffer[1] << 8) | buffer[2]);
Ori_Tempreture = (int32_t)((buffer[3] << 16) | (buffer[4] << 8) | buffer[5]);
Ori_Pressure = (Ori_Pressure << 8) >> 8; // 保留符
Ori_Tempreture = (Ori_Tempreture << 8) >> 8;
//读取校准系数
int16_t Temp_Config0,Temp_Config1;
int32_t Pressure_Config00,Pressure_Config10;int16_t Pressure_Config20,
Pressure_Config30,Pressure_Config01,Pressure_Config11,Pressure_Config21;
uint8_t data[18];
MySPI_SPL06_Start();
MySPI_SPL06_SwapByte(0x10 | 0x80);
for(int j = 0;j < 18;j++)
{
data[j]= MySPI_SPL06_SwapByte(0xFF);
}
MySPI_SPL06_Stop();
//温度校准
Temp_Config0 = (int16_t)((data[0] << 4) | ((data[1] & 0xF0) >> 4));
Temp_Config0 = (Temp_Config0&0x0800)?(0xF000|Temp_Config0):Temp_Config0; //补码转换
Temp_Config1 = (int16_t)((data[2]) | ((data[1] & 0x0F) << 8));
Temp_Config1 = (Temp_Config1&0x0800)?(0xF000|Temp_Config1):Temp_Config1;
float Traw_sc = Ori_Tempreture / 1040384.0f;
Data->Tempreture = Temp_Config0 * 0.5 + Temp_Config1 * Traw_sc;
//压力校准
Pressure_Config00 = (int32_t)((data[3] << 12) | ((data[4] << 4) | ((data[5] & 0xF0) >> 4 )));
Pressure_Config00 = (Pressure_Config00&0x080000)?(0xFFF00000|Pressure_Config00):Pressure_Config00; //补码转换(C00,C10是16位,在16-20位判断负数)
Pressure_Config10 = (int32_t)((data[7] ) | ((data[6] << 8) | ((data[5] & 0x0F) << 16)));
Pressure_Config10 = (Pressure_Config10&0x080000)?(0xFFF00000|Pressure_Config10):Pressure_Config10; //补码转换
Pressure_Config01 = (int16_t)((data[8] << 8 ) | ((data[9])));
Pressure_Config01 = (Pressure_Config01&0x08000)?(0xFFF00000|Pressure_Config01):Pressure_Config01; //补码转换
Pressure_Config11 = (int16_t)((data[10] << 8 ) | ((data[11])));
Pressure_Config11 = (Pressure_Config11&0x08000)?(0xFFF00000|Pressure_Config11):Pressure_Config11; //补码转换
Pressure_Config20 = (int16_t)((data[12] << 8 ) | ((data[13])));
Pressure_Config20 = (Pressure_Config20&0x08000)?(0xFFF00000|Pressure_Config20):Pressure_Config20; //补码转换
Pressure_Config21 = (int16_t)((data[14] << 8 ) | ((data[15])));
Pressure_Config21 = (Pressure_Config21&0x08000)?(0xFFF00000|Pressure_Config21):Pressure_Config21; //补码转换
Pressure_Config30 = (int16_t)((data[16] << 8 ) | ((data[17])));
Pressure_Config30 = (Pressure_Config30&0x08000)?(0xFFF00000|Pressure_Config30):Pressure_Config30; //补码转换
float Praw_sc = Ori_Pressure / 1040384.0f;//改这里的系数
Data->Pressure = Pressure_Config00 + Praw_sc*(Pressure_Config10 + Praw_sc*(Pressure_Config20 + Praw_sc * Pressure_Config30))+ Traw_sc * Pressure_Config01 + Traw_sc *Praw_sc*(Pressure_Config11+Praw_sc*Pressure_Config21);
Data->Height = 43300*(1-pow((Data->Pressure/101325),1/5.255));
}
设计图
未生成预览图,请在编辑器重新保存一次BOM
暂无BOM
克隆工程知识产权声明&复刻说明
本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。
请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。










