I am attempting to build a GPS collar to track wildlife using the same methods described in the paper "Open-source, low-cost modular GPS collars for monitoring and tracking wildlife" by BANNED J. Foley Claudio Sillero-Zubiri (linked). My goal is to take a GPS fix with lat, long, altitude, speed, and other variables logged to an SD card, as well as XYZ accelerometer data logged to an SD card. I have wired everything as they said and used the code provided in the supplementary files, but nothing was logged to the SD card. I have been using chatGPT to modify the code, which has been working, but will randomly have the accelerometer report the XYZ values as 1.24, 0, 0.04, even when I am moving. It only happens after a half hour or so after uploading the code to the device, but it lasts until I reload the code, and sometimes even then it doesn't switch back. I am not sure what is causing this (error is the code, the device, or something else like the battery voltage getting too low, even after only 30 minutes), and have not found a solution or even a similar issue when looking online.
I am using the Adafruit Feather M0 Adalogger, Adafruit Ultimate GPS FeatherWing, Adafruit LIS3DH Triple-Axis Accelerometer, and a 3000mAh rechargeable Lipo Battery. Any help or input on if the error could be due to the code would be appreciated. Here is the code in Arduino IDE.
#include <SPI.h>
#include <Adafruit_GPS.h>
#include <SD.h>
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
Adafruit_GPS GPS(&Serial1);
Adafruit_LIS3DH lis = Adafruit_LIS3DH();
#define cardSelect 4
class Accelerometer {
public:
unsigned long interval;
float xRead[99]; // Array size for batching data
float yRead[99];
float zRead[99];
File accellog;
char filename1[15];
unsigned long previoustime;
String Date[99];
String Time[99];
String LOG[99];
float x0;
float x99; // Variable for averaging
int i;
sensors_event_t event;
Accelerometer(unsigned long Interval) {
interval = Interval;
previoustime = 0; // Set to 0 to start immediately
i = 0;
x0 = 0;
x99 = 0;
strcpy(filename1, "ACCLOG00.csv");
for (uint8_t i = 0; i < 100; i++) {
filename1[6] = '0' + i / 10;
filename1[7] = '0' + i % 10;
if (!SD.exists(filename1)) {
break;
}
}
accellog = SD.open(filename1, FILE_WRITE);
if (accellog) {
accellog.println("Date,Time,X (m/s^2),Y (m/s^2),Z (m/s^2),X (raw),Y (raw),Z (raw)");
}
accellog.close();
}
void readaccelerometer() {
unsigned long currentMillis = millis();
if (currentMillis - previoustime >= interval) {
lis.read();
lis.getEvent(&event);
xRead[i] = event.acceleration.x * 0.122; // Multiply raw data by 0.122
x0 += xRead[i];
yRead[i] = event.acceleration.y * 0.122; // Multiply raw data by 0.122
zRead[i] = event.acceleration.z * 0.122; // Multiply raw data by 0.122
Date[i] = String(day()) + "/" + String(month()) + "/" + String(year());
Time[i] = String(hour()) + ":" + String(minute()) + "." + String(second()) + "." + String(i);
previoustime = currentMillis;
i++;
}
if (i == 99) { // Batch size for logging
x99 = x0 / 99; // Calculate average
accellog = SD.open(filename1, FILE_WRITE);
for (int j = 0; j < 99; j++) {
LOG[j] = String(Date[j]) + "," + String(Time[j]) + "," + String(xRead[j]) + "," + String(yRead[j]) + "," + String(zRead[j]) + "," + String(xRead[j] / 0.122) + "," + String(yRead[j] / 0.122) + "," + String(zRead[j] / 0.122);
if (accellog) {
accellog.println(LOG[j]);
}
}
accellog.close();
i = 0;
x0 = 0;
}
}
};
Accelerometer Accel(31); // Interval for 32 Hz sampling rate
class GPSchip {
int OffPin;
unsigned long interval;
int OffState;
unsigned long fixinterval;
unsigned long previoustime;
boolean On;
unsigned long Starttime;
String NoFixLOG;
String FixLOG;
File GPSlog;
char filename2[15];
public:
GPSchip(unsigned long Interval, int Enable, unsigned long Checkfix) {
interval = ((Interval * 60) * 1000);
OffPin = Enable;
pinMode(OffPin, OUTPUT);
previoustime = 0 - interval;
Starttime = 0;
fixinterval = ((Checkfix * 60) * 1000);
On = false;
strcpy(filename2, "GPSLOG00.csv");
for (uint8_t i = 0; i < 100; i++) {
filename2[6] = '0' + i / 10;
filename2[7] = '0' + i % 10;
if (!SD.exists(filename2)) {
break;
}
}
GPSlog = SD.open(filename2, FILE_WRITE);
if (GPSlog) {
GPSlog.println("Date,Time,LatitudeDegrees,LongitudeDegrees,Latitude,longitude,Altitude,Speed,Angle,Satellites");
}
GPSlog.close();
}
void GPSread() {
unsigned long currentMillis = millis();
if (currentMillis - previoustime >= interval) {
Starttime = currentMillis;
digitalWrite(OffPin, LOW);
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
GPS.sendCommand(PGCMD_NOANTENNA);
On = true;
previoustime = currentMillis;
Serial.println("GPS turned on.");
}
if (On) {
while (GPS.read()) {
// Keep reading from GPS
}
}
if (GPS.newNMEAreceived() && On) {
char *stringptr = GPS.lastNMEA();
if (!GPS.parse(stringptr))
return;
if ((currentMillis - Starttime >= fixinterval) && (On == true)) {
if (GPS.hour != 23 && GPS.minute != 59) {
int Year;
byte Month, Day, Hour, Minute, Second;
Year = GPS.year;
Month = GPS.month;
Day = GPS.day;
Hour = GPS.hour;
Minute = GPS.minute;
Second = GPS.seconds;
setTime(Hour, Minute, Second, Day, Month, Year);
}
digitalWrite(OffPin, HIGH);
NoFixLOG = String(day()) + "/" + String(month()) + "/" + String(year()) + "," + String(hour()) + ":" + String(minute()) + ":" + String(second()) + ",No Fix,No Fix,No Altitude";
On = false;
GPSlog = SD.open(filename2, FILE_WRITE);
if (GPSlog) {
GPSlog.println(NoFixLOG);
GPSlog.close();
}
previoustime = currentMillis;
}
if (GPS.fix && On == true) { // Added condition to check for GPS fix
if (GPS.hour != 23 && GPS.minute != 59) {
int Year;
byte Month, Day, Hour, Minute, Second;
Year = GPS.year;
Month = GPS.month;
Day = GPS.day;
Hour = GPS.hour;
Minute = GPS.minute;
Second = GPS.seconds;
setTime(Hour, Minute, Second, Day, Month, Year);
}
FixLOG = String(day()) + "/" + String(month()) + "/" + String(year()) + "," + String(hour()) + ":" + String(minute()) + "." + String(second()) + "," + String(GPS.latitudeDegrees, 4) + "," + String(GPS.longitudeDegrees, 4) + "," + String(GPS.latitude) + "," + String(GPS.longitude) + "," + String(GPS.altitude, 4) + "," + String(GPS.speed) + "," + String(GPS.angle) + "," String(GPS.satellites);
GPSlog = SD.open(filename2, FILE_WRITE);
if (GPSlog) {
GPSlog.println(FixLOG);
GPSlog.close();
}
digitalWrite(OffPin, HIGH);
On = false;
previoustime = currentMillis;
}
}
}
};
GPSchip GPS1(1, 6, 1); // Adjusted timing for 30 seconds interval
unsigned long accelerometerInterval = 31000; // Interval for accelerometer sampling in milliseconds
unsigned long accelerometerDuration = 270000; // Duration of accelerometer sampling in milliseconds
unsigned long accelerometerPause = 30000; // Pause duration between accelerometer samplings in milliseconds
unsigned long accelerometerStartTime = 0;
void setup() {
Serial.begin(115200); // Initialize Serial Monitor for debugging
pinMode(6, OUTPUT);
digitalWrite(6, HIGH);
if (!SD.begin(cardSelect)) {
Serial.println("Card failed, or not present");
while (1);
}
if (!lis.begin(0x19)) { // Use the correct I2C address
Serial.println("Could not start LIS3DH");
while (1);
}
Serial.println("LIS3DH initialized.");
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - accelerometerStartTime < accelerometerDuration) {
Accel.readaccelerometer();
} else if (currentMillis - accelerometerStartTime < accelerometerDuration + accelerometerPause) {
// Do nothing during the pause
} else {
accelerometerStartTime = currentMillis;
}
GPS1.GPSread();
}