亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

高性能 Arduino 气象气球数据记录器

元器件与物料清单

元器件 数量
Maxim Integrated DS18B20 可编程分辨率 1-Wire 数字温度计 2
DHT22 温湿度传感器 1
SparkFun 三轴加速度计模块 - ADXL335 1
公头排针 36 位单排长针 (0.1") 2
Arduino Mega 2560 1
5050 SMD LED 1
电阻 4.75kΩ 2
电阻 100Ω 3
电阻 10kΩ 1
Flash 存储卡, MicroSD 卡 1
Micro SD 卡模块 1

所需工具与设备

应用与在线服务

项目简介

大家好!你可能会想:Arduino 真的能送入太空吗?几乎可以。利用气象气球,你可以将 Arduino、相机、蒜香面包或任何你想要的东西送到距离太空三分之一的高度!尽管只到达了太空边缘,但那里已没有 99% 的大气层,因此我们称之为“近空间”。

本指南内容详尽,除非你只是浏览,否则请务必阅读完“路径 1”部分。现在让我们开始探索如何实现这个项目。

三大实施路径

根据你的需求和技能水平,提供三条路径供选择。所有路径都需要一定的焊接技能,因为平流层中存在强风。每条路径各有优劣,取决于你的兴趣点:

路径选择建议

重要法规与安全提示

在开始前,必须了解相关法规,气象气球发射可能受地区限制。本指南不涵盖气球选择、载荷舱制作、充气等内容,但会提供相关指南链接。以下是关键限制(以美国 FAA 规定为例):

  1. 载荷舱不得包含手机信号设备;如携带手机必须设为飞行模式。
  2. 使用 GPS 追踪需取得 HAM 无线电执照(需考试和费用)。
  3. 载荷重量与尺寸比超过 3.0 盎司/平方英寸时,总重量必须小于 4 磅。
  4. 单个载荷/包裹重量不得超过 6 磅。
  5. 双载荷总重量不得超过 12 磅。

FAA 完整指南链接(美国居民适用)

路径 1 - 万能板方案

设计考量

开始设计前需考虑:所需传感器类型、飞行剖面、供电方案、回收方式等。原理图包含温湿度传感器、气压传感器、IMU 和 SD 卡模块。如需 GPS 定位载荷舱,需额外添加 GPS 模块。

回收方案对比

  1. SPOT GPS 模块: 易用、无限范围(卫星通讯)、电池寿命长,但价格昂贵、倒置时失效、信号易被厚物体阻挡。我们使用 SPOT 3 卫星信使并设计 3D 打印云台保持直立。
  2. APRS 无线电: 最可靠,可传回数据、坐标、高度,但需 HAM 执照,本指南不含接线图。
  3. 手机: 不推荐。需解决飞行后退出飞行模式问题,成本高于 SPOT,仅作备用。

飞行剖面规划

原理图与接线图

高性能 Arduino 气象气球数据记录器
传感器接线原理图

Arduino Mega 对这些传感器属于过配,但使用我们提供的代码必须用 Mega。若改用 Nano,需将 MicroSD 模块引脚改为对应板子的 SPI 引脚。

核心代码

// DHT22 设置
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// SD 卡设置
#include 
#include 
File sdcard_file;
int CS_pin = 10;

// DS18B20 温度传感器
#include 
#include 
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

int scale = 3; // ADXL337 用 3(±3g), ADXL377 用 200(±200g)
boolean micro_is_5V = true; // 5V 单片机设为 true

void setup() {
  Serial.begin(9600);
  sensors.begin();
  dht.begin();
  pinMode(CS_pin, OUTPUT);
  if (SD.begin()) {
    Serial.print("SD Card found!");
  } else {
    Serial.print("Error finding SD Card");
    return;
  }
  sdcard_file = SD.open("data.csv", FILE_WRITE);
  if (sdcard_file) {
    // 写入 CSV 表头
    sdcard_file.print("DS18B20");
    sdcard_file.print(",");
    sdcard_file.print("DHT22 Temp");
    sdcard_file.print(",");
    sdcard_file.print("Hum");
    sdcard_file.print(",");
    sdcard_file.print("H.InX");
    sdcard_file.print(",");
    sdcard_file.print("rawX");
    sdcard_file.print(",");
    sdcard_file.print("rawY");
    sdcard_file.print(",");
    sdcard_file.print("rawZ");
    sdcard_file.print(",");
    sdcard_file.print("scaledX");
    sdcard_file.print(",");
    sdcard_file.print("scaledY");
    sdcard_file.print(",");
    sdcard_file.print("scaledZ");
    sdcard_file.print(",");
    sdcard_file.println(" ");
  }
}

void loop() {
  delay(222);
  
  // 加速度计读取
  int rawX = analogRead(A0);
  int rawY = analogRead(A1);
  int rawZ = analogRead(A2);
  float scaledX, scaledY, scaledZ;
  
  if (micro_is_5V) {
    scaledX = mapf(rawX, 0, 675, -scale, scale);
    scaledY = mapf(rawY, 0, 675, -scale, scale);
    scaledZ = mapf(rawZ, 0, 675, -scale, scale);
  } else {
    scaledX = mapf(rawX, 0, 1023, -scale, scale);
    scaledY = mapf(rawY, 0, 1023, -scale, scale);
    scaledZ = mapf(rawZ, 0, 1023, -scale, scale);
  }
  
  // DS18B20 温度
  sensors.requestTemperatures();
  int etemp = sensors.getTempCByIndex(0);
  
  // DHT22 温湿度
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);
  if (isnan(h) || isnan(t) || isnan(f)) return;
  
  float hif = dht.computeHeatIndex(f, h);
  float hic = dht.computeHeatIndex(t, h, false);
  
  // 写入 SD 卡
  sdcard_file.print(etemp); sdcard_file.print(",");
  sdcard_file.print(t); sdcard_file.print(",");
  sdcard_file.print(h); sdcard_file.print(",");
  sdcard_file.print(hic); sdcard_file.print(",");
  sdcard_file.print(rawX); sdcard_file.print(",");
  sdcard_file.print(rawY); sdcard_file.print(",");
  sdcard_file.print(rawZ); sdcard_file.print(",");
  sdcard_file.print(scaledX); sdcard_file.print(",");
  sdcard_file.print(scaledY); sdcard_file.print(",");
  sdcard_file.print(scaledZ); sdcard_file.print(",");
  sdcard_file.print(" "); sdcard_file.println(" ");
  sdcard_file.close();
  delay(223);
}

float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

关键注意事项

数据记录器可记录温度、湿度、加速度数据。高度测量需用 GPS,90% 气压计在 30,000 英尺以上失效。更多指南请查阅链接,欢迎联系我们提问。

路径 2 - 预设计 PCB 方案

使用预设计的 Eclipse PCB,可获取内部温度、外部温度、湿度、加速度数据。所需元件:

Gerber 文件托管于 GitHub 仓库。我们已在实际飞行中测试并改进。

PCB 订购设置

推荐 JLCPCB 等中国制造商性价比高,美资厂商质量更稳定,但服务商不影响最终质量。

PCB 组装指南

高性能 Arduino 气象气球数据记录器
焊接指南示意图

所有排针焊接在 PCB 两侧,直接插入 Arduino Mega 即可完成所有接线。PCB 内部走线宽 0.35mm,连接各传感器至对应排针,比万能板/面包板更可靠。

代码烧录与测试

将 PCB 插上 Mega,连接电脑,打开 Arduino IDE 烧录 GitHub 仓库中的 1.6 版代码。MicroSD 卡格式化为 FAT16/FAT32,容量 ≤ 16GB(2GB 足够 2 小时飞行)。插入 SD 卡上传代码,串口监视器应显示 SD 卡初始化成功并开始记录。等待 10 秒取出卡读取 CSV 文件验证数据。

完整代码(含 MPL3115A2 气压计与 LED 状态指示)

// DHT22 设置
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// SD 卡设置
#include 
#include 
File sdcard_file;
int CS_pin = 10;

// DS18B20 温度传感器
#include 
#include 
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// MPL3115A2 气压计设置
#include 
#include 
Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();

int scale = 3;
boolean micro_is_5V = true;

// LED 指示灯
int Blue = 7;
int Red = 6;
int Green = 5;

void setup() {
  pinMode(23, INPUT); // 检测开关停止写入保存数据
  sensors.begin();
  pinMode(Blue, OUTPUT);
  pinMode(Red, OUTPUT);
  pinMode(Green, OUTPUT);
  digitalWrite(Green, HIGH);
  dht.begin();
  pinMode(CS_pin, OUTPUT);
  
  if (SD.begin()) {
    // 绿灯闪烁 3 次表示成功
    for(int i=0;i<3;i++) {
      digitalWrite(Green, LOW); digitalWrite(Green, HIGH);
    }
  } else {
    digitalWrite(Green, LOW); digitalWrite(Red, HIGH); delay(5000); return;
  }
  
  sdcard_file = SD.open("data.csv", FILE_WRITE);
  if (sdcard_file) {
    digitalWrite(Red, LOW); digitalWrite(Blue, LOW); digitalWrite(Green, HIGH);
  } else {
    // 红/蓝灯交替闪烁报错
    digitalWrite(Green, LOW); digitalWrite(Red, HIGH); delay(1000);
    digitalWrite(Red, LOW); digitalWrite(Blue, HIGH); delay(1000);
    digitalWrite(Green, LOW); digitalWrite(Red, HIGH); delay(1000);
    digitalWrite(Red, LOW); digitalWrite(Blue, HIGH); delay(1000);
    digitalWrite(Red, HIGH); digitalWrite(Blue, LOW);
  }
  
  // 写入 CSV 表头
  sdcard_file.print(","); sdcard_file.print("DS18B20"); sdcard_file.print(",");
  sdcard_file.print("DHT22 Temp"); sdcard_file.print(","); sdcard_file.print("Hum"); sdcard_file.print(",");
  sdcard_file.print("H.InX"); sdcard_file.print(","); sdcard_file.print("Int. Temp"); sdcard_file.print(",");
  sdcard_file.print("Pres. Pasc."); sdcard_file.print(","); sdcard_file.print("alt."); sdcard_file.print(",");
  sdcard_file.print("rawX"); sdcard_file.print(","); sdcard_file.print("rawY"); sdcard_file.print(","); sdcard_file.print("rawZ"); sdcard_file.print(",");
  sdcard_file.print("scaledX"); sdcard_file.print(","); sdcard_file.print("scaledY"); sdcard_file.print(","); sdcard_file.print("scaledZ");
}

void loop() {
  delay(222);
  digitalWrite(Green, LOW); digitalWrite(Blue, HIGH);
  
  if(!baro.begin()) { }
  float pascals = baro.getPressure();
  float altm = baro.getAltitude();
  float tempC = baro.getTemperature();
  
  // 加速度计
  int rawX = analogRead(A0);
  int rawY = analogRead(A1);
  int rawZ = analogRead(A2);
  float scaledX, scaledY, scaledZ;
  if (micro_is_5V) {
    scaledX = mapf(rawX, 0, 675, -scale, scale);
    scaledY = mapf(rawY, 0, 675, -scale, scale);
    scaledZ = mapf(rawZ, 0, 675, -scale, scale);
  } else {
    scaledX = mapf(rawX, 0, 1023, -scale, scale);
    scaledY = mapf(rawY, 0, 1023, -scale, scale);
    scaledZ = mapf(rawZ, 0, 1023, -scale, scale);
  }
  
  // DS18B20
  sensors.requestTemperatures();
  // DHT22
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);
  if (isnan(h) || isnan(t) || isnan(f)) return;
  float hif = dht.computeHeatIndex(f, h);
  float hic = dht.computeHeatIndex(t, h, false);
  
  // 写入数据
  sdcard_file.println(sensors.getTempCByIndex(0));
  sdcard_file.print(","); sdcard_file.print(t); sdcard_file.print(","); sdcard_file.print(h); sdcard_file.print(",");
  sdcard_file.print(hic); sdcard_file.print(","); sdcard_file.print(tempC); sdcard_file.print(","); 
  sdcard_file.print(pascals); sdcard_file.print(","); sdcard_file.print(altm); sdcard_file.print(",");
  sdcard_file.print(rawX); sdcard_file.print(","); sdcard_file.print(rawY); sdcard_file.print(","); sdcard_file.print(rawZ); sdcard_file.print(",");
  sdcard_file.print(scaledX); sdcard_file.print(","); sdcard_file.print(scaledY); sdcard_file.print(","); sdcard_file.print(scaledZ); sdcard_file.print(",");
  delay(223);
  sdcard_file.close();
}

float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

路径 3 - 自制 PCB 方案

本指南不教授 PCB 设计,请先掌握相关技能。此处仅提供设计指南(基于美国法规):

核心设计考量

PCB 设计建议

可设计为扩展板或完整 PCB。完成后全面测试并确认合规。

结语

气象气球是将设备送入平流层的酷炫方式,可搭载相机(我们用 360 相机)获取精彩画面和数据,法规相对宽松。但必须遵守所有规则:

FAA 限制不多,请遵守规则,别让监管收紧毁了大家的乐趣。希望本指南对你有帮助!欢迎订阅我们的 YouTube 频道支持团队,有任何问题随时留言或联系。

祝 Arduino 之旅愉快!

NM Rocketry Reviews

自定义零件与外壳

用于保持 SPOT 个人追踪器直立的云台 3D 打印模型 (.stl)

原理图

路径 1 参考原理图

高性能 Arduino 气象气球数据记录器
高性能 Arduino 气象气球数据记录器
GitHub 仓库 (PCB 文件与代码)

https://github.com/nmrocketryreviews/HADLdatalogger

制造工艺

  1. Arduino 数字骰子:LCD 显示随机点数的电子骰子
  2. 多位置温度传感器系统,助力智能家居集成
  3. DIY Arduino USB 游戏手柄 — 自制高性能游戏手柄
  4. MotionSense:基于 Arduino 与 ESP8266 的智能入侵检测系统
  5. 3D 打印机防火卫士:智能传感器安全系统
  6. Pixel Chaser:Arduino Nano 单键 NeoPixel 追逐小游戏
  7. 基于 Arduino、Yaler 与 IFTTT 构建 Web 化 IoT 仪表盘
  8. Arduino 简易排斥式磁悬浮:电路与 DIY 指南
  9. Arduino 8×8 LED 矩阵翻页时钟 - DIY 实时时钟项目
  10. 自制 10 美元便携 Arduino 气象站 - Nano + DHT22 + BMP180 + LCD
  11. 进阶微控制器实验平台:ESP32、Arduino、PIC 与多传感器模块集成
  12. CoroFence 热成像检测器:Panasonic GridEye + PIR + IoT 集成