Arduino Due, GPS Breakout, and 10DOF IMU randomly freezes

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
dbrad5683
 
Posts: 2
Joined: Mon Sep 08, 2014 4:25 pm

Arduino Due, GPS Breakout, and 10DOF IMU randomly freezes

Post by dbrad5683 »

Hi all,

I'm attempting to use the Arduino Due with Adafruit's Ultimate GPS Breakout and 10DOF IMU. Both work perfectly fine individually. When I have them both connected, however, my code will randomly and completely freeze after anywhere from 30 seconds to 2 hours of runtime. I have the IMU hooked up to the Due's I2C pins 20 and 21, 3V, and GND. I have tried both with and without external pull-up resistors. I know that the internal pull-ups are 1.5k. I have even tried it on the Due's second I2C port that has no internal pull-ups with a bunch of external pull-up values. I'm very confident that my wiring is correct. I believe that there is some sort of blocking effect somewhere in the I2C communication.

Basically, I am reading the GPS every second, syncing it's clock to the IMU, and reading the IMU 10 times a second. All this information is run through a checksum and printed to the serial monitor. Like I said before, for no apparent reason it will stop at any random time and begin spitting out the same IMU line about every 1-5 seconds. I have tried everything and have run out of ideas. Any help is appreciated.

P.S. I have added

Code: Select all

#define PMTK_SET_NMEA_OUTPUT_GGAONLY "$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
to Adafruit_GPS.h to output just the GGA NMEA sentence.

Here is my code:

Code: Select all


#include <avr/dtostrf.h>

unsigned long millisRead = 0;
float startTime = 0;

/*--------------------------- GPS ---------------------------*/

#include <Adafruit_GPS.h>

#define mySerial Serial1  // Pins 18 and 19 on Arduino Due

Adafruit_GPS GPS(&mySerial);  // Initialize GPS serial pins

/*--------------------------- IMU ---------------------------*/

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_10DOF.h>

// Assign a unique ID to the sensors
Adafruit_10DOF                 dof   = Adafruit_10DOF();
Adafruit_LSM303_Accel_Unified  accel = Adafruit_LSM303_Accel_Unified(30301);
Adafruit_LSM303_Mag_Unified    mag   = Adafruit_LSM303_Mag_Unified(30302);
Adafruit_L3GD20_Unified        gyro  = Adafruit_L3GD20_Unified(20);
Adafruit_BMP085_Unified        bmp   = Adafruit_BMP085_Unified(10085);

sensors_event_t accel_event;
sensors_event_t mag_event;
sensors_event_t gyro_event;
sensors_event_t bmp_event;

int IMUReportPeriod = 100;  // ms
unsigned long nextIMUReportTime = 0;  // ms

float IMUTime;
float accelX;
float accelY;
float accelZ;
float gyroX;
float gyroY;
float gyroZ;
float magX;
float magY;
float magZ;
int IMUOffset = 50;  // Millisecond offset from when GPS is read to first IMU reading
int prec = 4;  // Set number of decimal places for IMU data

/*-------------------------- Setup --------------------------*/

void setup() {

  Serial.begin(115200);  // Set serial baud rate
  
  GPS.begin(9600);  // Set GPS baud rate (9600)
  mySerial.begin(9600);  // Set hardware serial baud rate (9600)
  
//  Choose which GPS sentences to output
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);  // RMC Only
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_GGAONLY);  // GGA Only
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);   // RMC and GGA
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);  // All Data

//  Set the update rate of the GPS (5 Hz and 10 Hz not recommended)
    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz
//  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);   // 5 Hz
//  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);  // 10 Hz


  // Don't start until we receive a sentence from GPS (can be empty)  
  while (1) {
    
    GPS.read();
  
    if (GPS.newNMEAreceived()) {
      
      if (GPS.parse(GPS.lastNMEA())) {
               
        millisRead = millis();
        startTime = convertTime(GPS.hour, GPS.minute, GPS.seconds, GPS.milliseconds);
        nextIMUReportTime = millisRead + IMUOffset;  // Set first IMU report time

        break;
        
      }
    }  
  }
  
  initSensors();  // Initialize sensors
    
}

void loop() {

  GPSReport();

  if (millis() >= nextIMUReportTime) {
    
    nextIMUReportTime += IMUReportPeriod;
    IMUReport();
     
  }
}

void GPSReport() {
  
  GPS.read();
      
  if (GPS.newNMEAreceived()) {
   
    if (GPS.parse(GPS.lastNMEA())) {  
            
      millisRead = millis();
      startTime = convertTime(GPS.hour, GPS.minute, GPS.seconds, GPS.milliseconds);
      nextIMUReportTime = millisRead + IMUOffset;

      Serial.println(GPS.lastNMEA());
      
    }
  }  
}

void IMUReport() {
  
  IMUTime = startTime + (float)(millis() - millisRead) / 1000;
  
  accel.getEvent(&accel_event);
  gyro.getEvent(&gyro_event);
  mag.getEvent(&mag_event);
  bmp.getEvent(&bmp_event);
    
  accelX = accel_event.acceleration.x;
  accelY = accel_event.acceleration.y;
  accelZ = accel_event.acceleration.z;
      
  gyroX = gyro_event.gyro.x;
  gyroY = gyro_event.gyro.y;
  gyroZ = gyro_event.gyro.z;
      
  magX = mag_event.magnetic.x;
  magY = mag_event.magnetic.y;
  magZ = mag_event.magnetic.z;
  
  char s[1000];
  int c = 0;
  
  IMUTime = returnTime(IMUTime);
      
  Serial.print("$");
  
  c ^= chk("STRIMU,");
  
  //  Pad timestamps with leading zeros
  
  if (IMUTime < 10) {
    c ^= chk("00000");
  }
  else if (IMUTime >= 10 && IMUTime < 100) {
    c ^= chk("0000");
  }
  else if (IMUTime >= 100 && IMUTime < 1000) {
    c ^= chk("000");
  }
  else if (IMUTime >= 1000 && IMUTime < 10000) {
    c ^= chk("00");
  }
  else if (IMUTime >= 10000 && IMUTime < 100000) {
    c ^= chk("0");
  }

  
  c ^= chk(dtostrf(IMUTime, 0, 3, s));
  c ^= chk(",");

  // Display the results (acceleration is measured in m/s^2)
  c ^= chk(dtostrf(accelX, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(accelY, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(accelZ, 0, prec, s));
  c ^= chk(",");

  // Display the results (speed is measured in rad/s)
  c ^= chk(dtostrf(gyroX, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(gyroY, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(gyroZ, 0, prec, s));
  c ^= chk(",");

  // Display the results (magnetic vector values are in micro-Tesla (uT))
  c ^= chk(dtostrf(magX, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(magY, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(magZ, 0, prec, s));
  
  Serial.print("*");
  
  if (c < 16) {
    
    Serial.print("0");
    
  }
  
  Serial.println(c, HEX);
        
}

// Convert time into seconds
float convertTime(uint8_t hour, uint8_t minute, uint8_t seconds, uint16_t milliseconds) {
  
  return ((float)hour * 3600) + ((float)minute * 60) + (float)seconds + ((float)milliseconds / 1000);
  
}

// Convert time from seconds back into standard form
float returnTime(float t) {
 
  float hour = t / 3600;
  float minute = (hour - floor(hour)) * 60;
  hour = floor(hour);
  float seconds = (minute - floor(minute)) * 60;
  minute = floor(minute);
  
  return (hour * 10000) + (minute * 100) + seconds;
  
}

void initSensors() {
  
  analogReadResolution(12);
  
  if (!accel.begin()) {
    
    Serial.println("NO LSM303 DETECTED");
    
  }
  
  if (!mag.begin()) {
    
    Serial.println("NO LSM303 DETECTED");
    
  }
  
  if (!gyro.begin()) {
    
    Serial.println("NO L3GD20 DETECTED");
    
  }
  
  else {
    
    gyro.enableAutoRange(true);  // Enable auto-ranging
    
  }
}


User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Arduino Due, GPS Breakout, and 10DOF IMU randomly freeze

Post by adafruit_support_rick »

Nothing jumps out at me. Your code looks nice and clean.
I'd start by commenting out sections of code until it starts working, then start working backwards to see if you can zero in on something that can explain this behavior.

I2C can block. You might start by commenting out the getEvent calls, and see if that makes a difference.

If you post a picture of your connections, I can have a look.

User avatar
dbrad5683
 
Posts: 2
Joined: Mon Sep 08, 2014 4:25 pm

Re: Arduino Due, GPS Breakout, and 10DOF IMU randomly freeze

Post by dbrad5683 »

Sorry it has taken me so long to get back. The problem is still occurring. Here is the current code I am using:

Code: Select all

#include <avr/dtostrf.h>

unsigned long millisRead = 0;
float startTime = 0;

/*--------------------------- GPS ---------------------------*/

#include <Adafruit_GPS.h>

#define mySerial Serial3  // Pins 14 and 15 on Arduino Due

Adafruit_GPS GPS(&mySerial);  // Initialize GPS serial pins

/*--------------------------- IMU ---------------------------*/

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_10DOF.h>

// Assign a unique ID to the sensors
Adafruit_10DOF                 dof   = Adafruit_10DOF();
Adafruit_LSM303_Accel_Unified  accel = Adafruit_LSM303_Accel_Unified(30301);
Adafruit_LSM303_Mag_Unified    mag   = Adafruit_LSM303_Mag_Unified(30302);
Adafruit_L3GD20_Unified        gyro  = Adafruit_L3GD20_Unified(20);
Adafruit_BMP085_Unified        bmp   = Adafruit_BMP085_Unified(10085);

int prec = 4;
int IMUOffset = 50;  // Millisecond offset from when GPS is read to first IMU reading
int IMUReportPeriod = 100;  // ms
float IMUTime = 0;
unsigned long nextIMUReportTime = 0;  // ms

/*-------------------------- Setup --------------------------*/

void setup() {

  Serial.begin(115200);  // Set serial baud rate

  GPS.begin(9600);  // Set GPS baud rate (9600)
  mySerial.begin(9600);  // Set hardware serial baud rate (9600)

//  Choose which GPS sentences to output
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);  // RMC Only
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_GGAONLY);  // GGA Only
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);   // RMC and GGA
//  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);  // All Data

//  Set the update rate of the GPS (5 Hz and 10 Hz not recommended)
    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz
//  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);   // 5 Hz
//  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_10HZ);  // 10 Hz

  while (1) {  // Don't start until we receive a sentence from GPS (can be empty)
    
    GPS.read();
  
    if (GPS.newNMEAreceived()) {
      
      millisRead = millis();
      nextIMUReportTime = millisRead + IMUOffset;  // Set first IMU report time
      
      if (GPS.parse(GPS.lastNMEA())) {
        
        startTime = convertTime(GPS.hour, GPS.minute, GPS.seconds, GPS.milliseconds);
        break;
        
      }
    }
  }
  
  initSensors();  // Initialize sensors
    
}

void loop() {

  GPSReport();
  
  if (millis() >= nextIMUReportTime) {
  
    nextIMUReportTime += IMUReportPeriod;
    IMUReport();
    
  }
}

void GPSReport() {
  
  GPS.read();
      
  if (GPS.newNMEAreceived()) {
    
    millisRead = millis();
    nextIMUReportTime = millisRead + IMUOffset;
   
    if (GPS.parse(GPS.lastNMEA())) {  
      
      startTime = convertTime(GPS.hour, GPS.minute, GPS.seconds, GPS.milliseconds);
      Serial.println(GPS.lastNMEA());
      
    }
  }  
}

void IMUReport() {
  
  IMUTime = startTime + (float)(millis() - millisRead) / 1000;
  
  char s[1000];
  int c = 0;
      
  Serial.print("$");
  
  c ^= chk("STRIMU,");
  
  IMUTime = returnTime(IMUTime);
  
  //  Pad timestamps with leading zeros
  
  if (IMUTime < 10) {
    c ^= chk("00000");
  }
  else if (IMUTime >= 10 && IMUTime < 100) {
    c ^= chk("0000");
  }
  else if (IMUTime >= 100 && IMUTime < 1000) {
    c ^= chk("000");
  }
  else if (IMUTime >= 1000 && IMUTime < 10000) {
    c ^= chk("00");
  }
  else if (IMUTime >= 10000 && IMUTime < 100000) {
    c ^= chk("0");
  }

  c ^= chk(dtostrf(IMUTime, 0, 3, s));
  c ^= chk(",");
 
  sensors_event_t event; 

  // Display the results (acceleration is measured in m/s^2)  
  accel.getEvent(&event);
  
  c ^= chk(dtostrf(event.acceleration.x, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.acceleration.y, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.acceleration.z, 0, prec, s));
  c ^= chk(",");

  // Display the results (speed is measured in rad/s)  
  gyro.getEvent(&event);
  
  c ^= chk(dtostrf(event.gyro.x, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.gyro.y, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.gyro.z, 0, prec, s));
  c ^= chk(",");

  // Display the results (magnetic vector values are in micro-Tesla (uT))  
  mag.getEvent(&event);
  
  c ^= chk(dtostrf(event.magnetic.x, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.magnetic.y, 0, prec, s));
  c ^= chk(",");
  c ^= chk(dtostrf(event.magnetic.z, 0, prec, s));
  c ^= chk(",");
  
  bmp.getEvent(&event);
  
  if (event.pressure) {
    
    c ^= chk(dtostrf(event.pressure, 0, 2, s));  // hPa
    c ^= chk(",");  
    
    float temperature;
    bmp.getTemperature(&temperature);
    
    c ^= chk(dtostrf(temperature, 0, 2, s));  // Celsius
    c ^= chk(",");
    
    float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
    
    c ^= chk(dtostrf(bmp.pressureToAltitude(seaLevelPressure, event.pressure, temperature), 0, 2, s));
    
  }
  
  Serial.print("*");
  
  if (c < 16) {
    
    Serial.print("0");
    
  }
  
  Serial.println(c, HEX);
        
}

// Checksum
int chk(char* s) {
  
  Serial.print(s);
  int c = 0;
  
  while(*s) {
    
    c ^= *s++;
    
  }
  
  return c;
  
}

// Convert time into seconds
float convertTime(uint8_t hour, uint8_t minute, uint8_t seconds, uint16_t milliseconds) {
  
  return ((float)hour * 3600) + ((float)minute * 60) + (float)seconds + ((float)milliseconds / 1000);
  
}

// Convert time from seconds back into standard form
float returnTime(float t) {
  
  float hour = t / 3600;
  float minute = (hour - floor(hour)) * 60;
  hour = floor(hour);
  float seconds = (minute - floor(minute)) * 60;
  minute = floor(minute);
  
  return (hour * 10000) + (minute * 100) + seconds;
  
}

void initSensors() {
  
  Serial.println("");
  
  if (!accel.begin()) {
    
    Serial.println("NO LSM303 DETECTED");
    
  }
  
  if (!mag.begin()) {
    
    Serial.println("NO LSM303 DETECTED");
    
  }
  
  if (!gyro.begin()) {
    
    Serial.println("NO L3GD20 DETECTED");
    
  }
  
  if (!bmp.begin()) {
    
    Serial.println("NO BMP085 DETECTED");
    
  }
}
I've attached some pictures of my connections. Like I said, I'm pretty confident in them. I've made my own little shield to hold the GPS breakout. I am powering it through the 3V3 pin to bypass any level shifting. I'm using Serial3 on the Due. The IMU is also powered from 3V3 and is connecting via Adafruit's four conductor water-proof connector and then through about 6 feet of ethernet cable. I've read that the I2C bus can be very sensitive to electromagnetic interference. Would it be worth it to try some shielded wires? I was also thinking about separately powering the IMU from a 5V source on the Due, taking advantage of the IMU's internal level shifters, but I'm not positive that would help in any way. Maybe it would cut down some of the noise?

As for commenting the code... I've been through it what feels like a hundred times and haven't been able to confidently narrow it down to anything specific other than the I2C or UART communication.
Attachments
20140929_111101.jpg
20140929_111101.jpg (106.39 KiB) Viewed 483 times
20140929_110616.jpg
20140929_110616.jpg (156.27 KiB) Viewed 483 times
20140929_110329.jpg
20140929_110329.jpg (113.69 KiB) Viewed 483 times

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Arduino Due, GPS Breakout, and 10DOF IMU randomly freeze

Post by adafruit_support_rick »

I don't know. Did you try backing out bits and pieces of it until it starts to work?
Start with the GPS, and add in one other sensor at a time, until it breaks.

You might try powering the GPS with 5V through VIN. There are no level-shifting issues with doing that.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”