非常精彩,要是能给个试车视频就更好了
感觉作者所采用的推杆开伞有点浪费空间,若使用开伞药能缩减开伞装置的体积。火箭很好看
在二十一天寒假期间,快速制作了我的第一发模型火箭。这个想法我已经构思很久了,终于在这个高二的寒假得以仓促实施。火箭全高0.886m,总共两个舱段——伞舱段、发动机舱/承力舱段,伞舱段直径0.04m,发动机舱/承力舱段直径0.06m,起飞质量1.063kg,起飞推力100N,起飞推重比约为10。
图1
这款小型探空火箭总共分两个舱段——发动机舱/承力舱段、伞包舱段。其中发动机舱/承力舱段承担固定固体火箭发动机、装载箭载电子设备的功能;伞包舱段的功能是搭载降落伞以及作为开伞机械结构的一部分。开伞机构使用了类似枪械闭锁的突榫结构,降落伞推杆通过突榫锁定。箭体呈现预定姿态时,舵机带动推杆旋转,实现解锁,释放降落伞(见图2)。
图2
这款小型探空火箭使用最简单保守的静稳定气动布局,使用四块平行四边形尾翼稳定箭体,尾翼翼型为长方形。同时在头锥内增加配重(见图3),提高火箭的静稳定性。
图3
这款火箭装备一台XTZ-3214固体火箭发动机,使用KNSB燃料,地面测试时总冲48.2Ns,工作时间1.2s,最大推力102N。XTZ-3214固体火箭发动机使用铝合金外壳,纸质隔热层,树脂复材堵头和发动机喷管,使用卡簧进行所有零件的固定(见图4)。
图4
KNSB燃料是一种成本低廉、容易制造的固体火箭燃料。本次使用的KNSB燃料配方为66%硝酸钾+34%山梨糖醇。药柱制作工艺为自研创新的重结晶熔融法。具体流程如下:
1.对硝酸钾盐进行两次重结晶提纯。(见图5)
2.在烧杯中充分混合所有硝酸钾和山梨糖醇。
3.根据硝酸钾的质量配置硝酸钾与山梨糖醇的过饱和溶液。(见图6)
4.将配置好的溶液放置在恒温加热台上进行加热。加热台设置200℃持续加热蒸发水分。
5.随着加热时间增加,硝酸钾和山梨糖醇逐渐溶解,溶液变为硝酸钾和山梨糖醇的饱和溶液。(见图7)
6.而后水分逐渐蒸发,溶液开始变得黏稠,逐渐变为潮湿结块的粉末状。(见图8)
7.继续加热并逐渐降低加热台温度至140℃~160℃,同时不断搅拌燃料。
8.继续搅拌、加热,燃料水分逐渐蒸发,燃料变为白色米糊状。(见图9)
9.将燃料快速倒入模具中并压实密封压紧冷却,期间可在模具两端施加压力,六小时后脱模,然后继续冷却满24小时。
重结晶熔融法有以下优点:
1.重结晶过程使硝酸钾和山梨糖醇充分混合,同时省去了研磨原材料的步骤,避免了因研磨不充分导致硝酸钾和山梨糖醇结合度低不充分混合的问题。
2.加热期间因燃料中水分较多,故燃料比热容较高,燃料不易快速升温引发危险,相比熔融法容易控制燃料温度,更加安全。
图5
图6
图7
图8
图9
为了实现飞行是的姿态记录和火箭飞行至最高点时,飞控系统检测箭体姿态控制开伞的功能,这款火箭的飞控使用Seeed XIAO ESP32C3单片机搭配Seeed的Grove接口扩展板链接Seeed配套舵机,同时外接意法半导体的LSM6DS3六轴陀螺仪加速度计用以检测飞行姿态。卡录用来拍摄飞行时的视频,卡录与飞控电路板并联在5v电源上。箭载电子设备的电源使用一块5v锂电池。(见图10)
图10
软件部分主要实现LSM6DS3六轴陀螺仪加速度计与单片机的通信和数据记录,同时单片机判断火箭姿态,控制开伞时机。LSM6DS3相关程序中,使用互补滤波原理进行滤波。程序在Arduino IDE中进行编写,单片机程序中大部分代码由Deepseek编写后人工修饰。以下是单片机的代码:
#include <Wire.h>
#include <SPI.h>
#include <SdFat.h> // 使用SdFat库支持exFAT
#include <Deneyap_Servo.h>
#include <LSM6DS3.h>
Servo myservo;
LSM6DS3 myIMU(I2C_MODE, 0x6B);
// TF卡模块引脚定义
#define SD_CS D7 // TF卡模块的CS引脚
#define SD_MISO D9
#define SD_MOSI D10
#define SD_SCK D8
int serialstate = 0;
int judge1 = 0;
// SdFat对象
SdFs sd;
FsFile dataFile; // 使用File32支持exFAT
#define SPI_SPEED SD_SCK_MHZ(10) // 通信速率,单位MHz
#define SD_SPI_CFG SdSpiConfig(SD_CS, DEDICATED_SPI, SPI_SPEED, &SPI)
int state = 0;
// 欧拉角变量
float roll = 0.0; // 横滚角
float pitch = 0.0; // 俯仰角
float yaw = 0.0; // 偏航角
// 互补滤波参数
float alpha = 0.98; // 互补滤波系数,陀螺仪权重
float dt = 0.01; // 采样时间间隔,单位秒(100ms)
// 上一次的时间戳
unsigned long lastTime = 0;
// 初始化I2C通信
void setup() {
myservo.attach(D1);
Serial.begin(115200);
// 初始化SD卡
pinMode(D3, OUTPUT);
int retry = 0;
digitalWrite(D3, HIGH);
while (!sd.begin(SD_SPI_CFG)) {
digitalWrite(D3, LOW);
Serial.println("SD card initialization failed!");
if (sd.card()->errorCode()) {
Serial.print("Error code:");
Serial.println(sd.card()->errorCode());
Serial.print("Error data:");
Serial.println(int(sd.card()->errorData()));
}
delay(500);
digitalWrite(D3, HIGH);
Serial.print("Retry: ");
Serial.println(++retry);
}
Serial.println("SD card initialized.");
Wire.begin();
if (myIMU.begin() != 0) {
state = 1;
} else {
pinMode(D3, OUTPUT);
digitalWrite(D3, LOW);
delay(100);
digitalWrite(D3, HIGH);
delay(100);
digitalWrite(D3, LOW);
delay(100);
}
while (state == 1) {
pinMode(D3, OUTPUT);
digitalWrite(D3, HIGH);
delay(1000);
digitalWrite(D3, LOW);
delay(1000);
}
// 创建或打开数据文件
dataFile = sd.open("data.txt", FILE_WRITE);
if (!dataFile) {
Serial.println("Failed to open data file!");
state = 5;
while (state == 5) {
pinMode(D3, OUTPUT);
digitalWrite(D3, HIGH);
delay(100);
digitalWrite(D3, LOW);
delay(100);
}
while (1)
;
}
Serial.println("Data file opened.");
// 写入文件标题
dataFile.println("Time(ms), Accel_X(g), Accel_Y(g), Accel_Z(g), Gyro_X(dps), Gyro_Y(dps), Gyro_Z(dps), Roll(deg), Pitch(deg), Yaw(deg)");
dataFile.flush();
Serial.println(state);
}
// 主循环
void loop() {
digitalWrite(D3, HIGH);
myservo.write(0);
// 读取加速度计数据并转换为实际加速度值(单位:g)
float ax = myIMU.readFloatAccelX();
float ay = myIMU.readFloatAccelY();
float az = myIMU.readFloatAccelZ();
// 读取陀螺仪数据并转换为实际角速度值(单位:dps)
float gx = myIMU.readFloatGyroX();
float gy = myIMU.readFloatGyroY();
float gz = myIMU.readFloatGyroZ();
// 计算时间差
unsigned long currentTime = millis();
float dt = (currentTime - lastTime) / 1000.0; // 转换为秒
lastTime = currentTime;
// 使用加速度计计算俯仰角和横滚角
float accelPitch = atan2(ay, sqrt(ax ax + az az)) * 180 / PI;
float accelRoll = atan2(-ax, sqrt(ay ay + az az)) * 180 / PI;
// 使用互补滤波结合陀螺仪和加速度计数据
pitch = alpha (pitch + gy dt) + (1 - alpha) * accelPitch;
//pitch += gy * dt;
roll = alpha (roll + gx dt) + (1 - alpha) * accelRoll;
yaw += gz * dt; // 偏航角仅使用陀螺仪数据
if (abs(yaw) >= 90) {
myservo.write(45);
while (1) {
delay(1);
}
}
if (abs(pitch) >= 90) {
myservo.write(45);
while (1) {
delay(1);
}
}
// 打印数据到串口
Serial.print("Acceleration (X, Y, Z) [g]: ");
Serial.print(ax);
Serial.print(", ");
Serial.print(ay);
Serial.print(", ");
Serial.println(az);
Serial.print("Gyroscope (X, Y, Z) [dps]: ");
Serial.print(gx);
Serial.print(", ");
Serial.print(gy);
Serial.print(", ");
Serial.println(gz);
Serial.print("Euler Angles (Roll, Pitch, Yaw) [deg]: ");
Serial.print(roll);
Serial.print(", ");
Serial.print(pitch);
Serial.print(", ");
Serial.println(yaw);
// 将数据写入TF卡
if (dataFile) {
dataFile.print(millis()); // 写入时间戳
dataFile.print(", ");
dataFile.print(ax);
dataFile.print(", ");
dataFile.print(ay);
dataFile.print(", ");
dataFile.print(az);
dataFile.print(", ");
dataFile.print(gx);
dataFile.print(", ");
dataFile.print(gy);
dataFile.print(", ");
dataFile.print(gz);
dataFile.print(", ");
dataFile.print(roll);
dataFile.print(", ");
dataFile.print(pitch);
dataFile.print(", ");
dataFile.println(yaw);
dataFile.flush();
} else {
Serial.println("Failed to write to data file!");
}
delay(10); // 延迟100ms
为了满足本项目100N级固体火箭发动机的试车试验,使用Nodemcu esp8266、HX711压力传感器模块和MAX6675 K型热电偶模块实现实时记录发动机推力和外壳温度的功能。在整个火箭项目中,成功完成了多次试车任务,并且安全处理了一次发动机超压爆炸事故。
图11
图12
发射架由2020铝合金型材拼搭而成,十分简陋,但成功完成了发射任务。(见图13)
图13
完成总装后,在2025年2月16日的一片空地上进行了首飞。总装完成状态见图14。
图14
随后进行了首飞。发动机点火成功,上升段一切正常,成功但降落伞未弹出,初步判断开伞失败原因是开伞结构设计缺陷。最终记录飞行姿态的TF卡损坏,卡录拍摄的视频回收成功,火箭箭体损坏,发射任务基本成功。
80019161e80cdb92182e63b27ea61a3f.mp4 点击下载
新人的第一发模型火箭准备十分仓促,但在过程中我也学习到了非常多的知识,并尝试创新。希望各位多多指教。本人目前高三生,可能没有时间回复信息,请谅解。在此感谢我的父母与同学们,他们在项目过程中给予了我诸多支持。