Hello,
I'm building a high altitude balloon project using a MKR Zero as the balloon payload and an Arduino Mega 2560 for the ground station. It sends data over 433MHz LoRa every 15s and records it on an SD card at both ends.
I've been running some overnight max duration tests to check it all out and I'm finding that after a few hours (somewhere between 2 and 6) I come back to the Mega 2560 ground station and its frozen. The LCD freezes on what ever the last packet said, the buttons are no longer responsive, the reset button doesn't work and the SD card is empty all files have been deleted. This is the case when powering it through USB cable and from battery power to Vin.
I had some suspect code relating to Strings that I've (hopefully) cleaned up a bit, but still had the same result. I'll try and run some more tests with it printing data to the computer so hopefully can get an idea of when exactly it is crashing. Just strange that resetting it does nothing.
Main Code
#include <Wire.h>
#include <QMC5883LCompass.h>
#include <NMEAGPS.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <RH_RF95.h>
#include <SD.h>
#include <EEPROM.h>
#define gpsPort Serial2
#define RFM95_CS 53
#define RFM95_RST 2
#define RFM95_INT 3
#define RF95_FREQ 433.050
const int MPU_Address = 0x68; // I2C address of the MPU-6050
const int Mag_Address = 0x0D; // I2C address of the MPU-6050
static NMEAGPS gps;
LiquidCrystal_I2C lcd(0x27,20,4);
RH_RF95 rf95(RFM95_CS, RFM95_INT);
QMC5883LCompass compass; // Compass
const byte interruptPin = 19; int SF = 8;
int32_t Lat_GPS_raw, Long_GPS_raw, Last_packet, Lastbutton1, Lastbutton2, DisplayFinT = 0, last_GPS;
bool first_packet = false, recording = false, SD_display = true, GPS_valid = false, Balloon_GPS_valid = false;
bool change_button = false, SD_present = true; String dataString;
byte screen = 1, reply = 1; char filename[16];
float Lat, Long, Lat2, Long2, Speed_temp, VS, V_batt_temp;
struct payload{
uint32_t Secs_since_launch;
int32_t Lat;
int32_t Long;
uint16_t GPS_Alt;
uint16_t GPS_Speed;
int16_t VS;
int16_t Temp_in;
int16_t Temp_out;
uint16_t V_batt;
uint16_t Max_Alt;
} __attribute__((packed, aligned(1)));
payload Data = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void setup() {
Setup_code();
}
void loop() {
if(change_button){
Lastbutton1 = millis();
change_button = false;
screen++;
lcd.clear();
if(screen >= 4) screen = 1;
}
if((millis() - DisplayFinT) >= 900 && first_packet){
DisplayFinT = millis();
if(SD_display){
lcd.clear();
SD_display = false;
}
if(screen == 1) Display1();
if(screen == 2) Display2();
if(screen == 3) Display3();
//f(screen == 4) Display4(); // Landing prediction
/*Change SF if needed...
if(millis() - Last_packet > 900000 && SF < 10){ // 900,000s = 15 Mins
SF = 11;
rf95.setSpreadingFactor(SF);
}*/
}
if(digitalRead(31) && millis() - Lastbutton2 > 1000){
lcd.clear();
lcd.setCursor(0, 1);
Lastbutton2 = millis();
DisplayFinT = millis();
if(SD_present){
if(!recording){
lcd.print("SD Recording Started");
}
else{
lcd.print("SD Recording Stopped");
}
recording = !recording;
}
else{
lcd.print("No SD card detected!");
}
delay(15);
SD_display = true;
}
LoRa(); //Put Lora before GPS
GPS();
} //End of main loop
void ISRbutton(){
if(millis() - Lastbutton1 > 600){
change_button = true;
}
}
void GPS()
void GPS(){
while (gps.available(gpsPort)) {
gps_fix fix = gps.read();
if (fix.valid.location) {
GPS_valid = true;
last_GPS = millis();
Lat_GPS_raw = fix.latitudeL();
Long_GPS_raw = fix.longitudeL();
Lat = Lat_GPS_raw / 10000000.0;
Long = Long_GPS_raw / 10000000.0;
}
}
}
void LoRa()
void LoRa(){
if (rf95.available())
{
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (rf95.recv((uint8_t*)&Data, &len))
{
first_packet = true;
Last_packet = millis();
Lat2 = Data.Lat / 10000000.0;
Long2 = Data.Long / 10000000.0;
Speed_temp = Data.GPS_Speed / 10;
VS = Data.VS / 10.0;
V_batt_temp = Data.V_batt / 100.0;
if(Lat2 == 0 || Long2 == 0){
Balloon_GPS_valid = false;
}
else{
Balloon_GPS_valid = true;
}
if (recording) {
File dataFile = SD.open(filename, FILE_WRITE);
if(dataFile){
//Write data to SD card
dataString += String(Data.Secs_since_launch);
dataString += ",";
dataString += String(Lat2,5);
dataString += ",";
dataString += String(Long2,5);
dataString += ",";
dataString += String(Data.GPS_Alt);
dataString += ",";
dataString += String(Speed_temp,1);
dataString += ",";
dataString += String(VS,1);
dataString += ",";
dataString += String(Data.Temp_in);
dataString += ",";
dataString += String(Data.Temp_out);
dataString += ",";
dataString += String(V_batt_temp);
dataString += ",";
dataString += String(SF);
dataString += ",";
dataString += String(Lat,5);
dataString += ",";
dataString += String(Long,5);
dataFile.println(dataString);
dataFile.close();
dataString = "";
}
}
// Send a reply
//rf95.waitPacketSent();
//rf95.send((uint8_t *)&reply, sizeof(reply));
}
}
}
void Setup()
void Setup_code(){
pinMode(4, INPUT);
Wire.begin();
Serial.begin(115200);
//while(!Serial){}
delay(500);
Serial.println("Setup Started..");
//==========================MPU6050==========================//
byte GFS_SEL = 8; // creates binary 0b00001000, this makes gyro sensitivity 500 degs/sec. 65.536 LSBs/deg/sec
Wire.beginTransmission(MPU_Address);
if(Wire.endTransmission() != 0){
Serial.println("MPU failed");
}
Wire.beginTransmission(MPU_Address);
Wire.write(0x6B), Wire.write(0x00); // sends 0's to PWR MNGMT register 0x68 resetting it.
Wire.endTransmission();
Wire.beginTransmission(MPU_Address);
Wire.write(0x1B), Wire.write(GFS_SEL); // 0x1B register sets gyro scale,
Wire.endTransmission();
Serial.println("MPU Started");
//===========================Compass==============================//
Serial.println("Compass Started");
compass.init();
//compass.setCalibration(-1690, 1190, -1703, 1191, -1687, 1458);
compass.setCalibrationOffsets(-174.00, -195.00, -147.00);
compass.setCalibrationScales(1.00, 1.04, 0.96);
///// CALIBRATION TEST DATA //////
gpsPort.begin(38400);
//===========================LoRa Init==============================//
pinMode(RFM95_RST, OUTPUT);
digitalWrite(RFM95_RST, HIGH);
// manual reset
digitalWrite(RFM95_RST, LOW);
delay(10);
digitalWrite(RFM95_RST, HIGH);
delay(10);
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
while (1);
}
Serial.println("LoRa radio init OK!");
// Defaults after init are 433.0MHz, modulation GFSK_Rb250Fd250, +13dbM
if (!rf95.setFrequency(RF95_FREQ)) {
while (1);
}
//Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
rf95.setTxPower(12, false);
rf95.setSpreadingFactor(SF);
rf95.setCodingRate4(5);
rf95.setSignalBandwidth(62500);
//============================SD Card===========================//
if (!SD.begin(13)){
SD_present = false;
Serial.println(F("SD card not detected..."));
}
else{
SD_present = true;
SD_Header();
dataString.reserve(100);
Serial.println(F("SD OK"));
}
//============================LCD init==========================//
uint8_t degrees2[8] = {0x1c,0x14,0x1c,0x0,0x0,0x0,0x0,0x0};
uint8_t m_s_1[8] = {0xa,0x15,0x15,0x11,0x0,0x1,0x2,0x4};
uint8_t m_s_2[8] = {0x1,0x2,0x4,0xb,0x14,0x2,0x1,0x6};
lcd.init(); // initialize the lcd
lcd.createChar(0, degrees2);
lcd.createChar(1, m_s_1);
lcd.createChar(2, m_s_2);
lcd.clear();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(" Setup OK ");
lcd.setCursor(0, 2);
lcd.print(" Waiting for Packets");
//============================Interrupt Pin==========================//
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), ISRbutton, RISING);
Serial.println(F("Setup complete"));
}
void SD_Header()
void SD_Header(){
int file_count = EEPROM.read(1); // Read from EEPROM location 1
if (file_count > 99 || file_count == 0){ // If number is 0 or more than 100 make it 1
file_count = 1;
}
sprintf(filename, "File_%02d.csv", file_count);
//if (!myFile.open(filename, O_RDWR | O_CREAT | O_AT_END)) {}
String header = "Time (S), Latitude, Longitude, GPS_Alt (m), GPS_Speed (m/s), VS (m/s), Temp_in (C), Temp_out (C), Vbatt (V), SF, Lat_GS, Long_GS";
File dataFile = SD.open(filename, FILE_WRITE);
if (dataFile) {
dataFile.println(header);
dataFile.close();
}
EEPROM.write(1, file_count + 1); // Increment EEPROM value by 1
}
Has anyone got any general ideas of what would cause this? The deleting files from the SD card is strange, it just wipes the whole lot. The code running on the MKR Zero is broadly similar but runs with no issues.
Thanks
