Arduino GPS and Accelerometer Data Problem

Hello,

I’m new to the forum but am seeking some help with a programming question. I’m currently using an ESP8266 dev kit with a few modules including an MMA845X accelerometer, an HMC5883L magnetometer, a MicroSD adapter, and a Neo-6MV2 GPS unit.

I’ve successfully coded each individual component to execute their intended functions, but I cannot get them to all operate using the same code file. I think this is because my GPS code relies on whenever the speed is updated/fixed, and the other components rely on using the delay() function.

I currently have the accelerometer, magnetometer, and SD card modules all working together (since they all rely on the delay() function to update new values), but I can’t get the GPS to work together with the other code. I’ll post both codes at the bottom of the post.

I need the data values from all components to be printed together per update

Make note: I am using a code that changes the update frequency on the GPS from 1Hz to 5Hz. At a minimum, I’d like all values to be updated at 5Hz (every 0.2 seconds).

Any help I can get would be great!

GPS.ino (2.98 KB)

accel_mag_sd.ino (2.9 KB)

A schematic, not a frizzy thing would be most helpful. Just a SWAG but I believe you have a conflict with the GPS and the serial port. Are all grounds connected? What is your power source?

The devil is in the details.

How have you tried to bring the two sketches together? Could you share the complete (non-working) sketch?

One thought on the GPS.ino. It's currently using SoftwareSerial, which I think is likely to cause issues. Are you using the NeoGPS library? If so there are some good notes on serial interfaces for GPS use in the src/GPSport.h in that codebase. It's worth reading.

Thank you both for your responses.

I have tried bringing both codes together, and I'll provide the code below. I don't have a schematic, but I can also post a picture of the wired device as well.

All connections are grounded. Again, the components work totally fine using their own codes posted previously, but I can't seem to figure out how to put the GPS code into the already existing accel_mag_sd code.

Let me know what you guys think, thanks again!

LJPIS.ino (4.94 KB)

What is the Wire library you're using? The sketch doesn't build here as-is because my Wire library has no begin(int, int) method. I'm just using the default version that comes with the 1.8.13 IDE.

I think the default library Arduino - Wire Wire.begin() should take no argument (join bus as master) or a uint8_t address (join bus as slave device with the specified address).

Other than that, a couple of potential issues:

  1. You are blocking when reading the I2C sensor(s) (calling delay(1) in a while loop). That won't help the GPS side of things, as while you're sat in delay the serial buffer will be filling up, especially at a 5Hz update rate.

  2. The logic in loop() is a bit confused, with sensor reading being wrapped in the if (gps.available()) conditional. What is the goal? When do you want to store data?

Could you share the results you get (i.e. serial monitor output) v.s. what you expect to see?

You need to get rid of the delay()'s.
My tutorial Multi-tasking in Arduino covers handling multiple devices and an example of removing delays from a library and a loopTimer so you can see where the delays are.
My tutorial on Arduino Serial I/O for the Real World covers non-blocking reads and debugging Serial prints and GPS parsing.

Currently, I'm getting no output when the complete code. The GPS code prints out speed data every 200 ms, and the accel/mag/sd code prints out sensor information every ~50 ms (both as expected).

The GPS code updates at a rate of 5Hz exactly (every 200 ms) based on the way I have it configured. The Accelerometer/Mag/SD code updates from the delay() function every ~50 ms (not exact).

I want to get accelerometer/mag data to print out at the exact same rate as the GPS (at 5Hz) since that is the fastest the GPS can update and provide information.

I understand the delay() function isn't supposed to be in the GPS function, and that's why I'm here! :smiley:

Does this make sense? What else can I provide that would better help with this issue?

A couple of points,
First put you accel/mag sampling is a separate method and call it on a repeating timer (see my links above)
Set the timer to repeat every 200mS. (Also a good way to combine the two sketches)
Second your calls to the SD card can block every now and again for a second or so so that will slow things down and you will miss GPS and accel data.
See my project on High Speed SD data logging It has a link to an Uno Mega version. It logs at much higher speed then you need, but includes code to pre-allocate file blocks to minimize long delays when writing to the SD card.

Actually one way to synchronize the measurements is to call the accel/mag sample method each time you get an new GPS line of data. No delays needed.

Could you provide an example code as to how to do this? Or revise mine to reflect this?

I don't fully understand what you mean since I'm not too keen on using Arduino. Majority of this code was provided throughout my classes.

Thank you for the help, I really appreciate it.

Wanted to bump this thread since I haven't heard anything in a few days.

Thanks

agearha2:
Wanted to bump this thread since I haven't heard anything in a few days.

Unless I've misread the thread to date, we've given you some specific suggestions of things to look into to help improve your sketch. Are these suggestions making sense?

So it sounds to me like I have to create individual functions (outside of the void loop function) for the components that are currently collecting data using the delay() function: i.e. the accelerometer and magnetometer.

Then, I need to initialize a repeating timer in the void setup function to refresh every 200 ms, then when the codes print separately, they will be in sync every 200 ms.

Is this correct?

Again, I'm very much a beginner so trying to interpret the code is difficult, hence why I'm asking for an example based on the code I've provided.

Thanks for all the help everyone

This part of the forum is usually for helping people fix problems with code they have written.

If you want someone to write code for you, post on the Gigs and Collaborations forum section. You may be asked to pay for the help.

I have provided the code I have in previous replies, but I can reattach them here. I’ve seen people help with pre-existing code that was posted. I figured this was the same case, but maybe I’m wrong.

accel_mag_sd.ino (3.38 KB)

GPS.ino (2.98 KB)

I think you're (probably) posting in the right place.

But you have to help us to help you. If people are engaging with your topic, asking questions and making suggestions, you have to respond in kind in order for us to have a meaningful dialogue. Simply saying "thanks for the suggestions, can you revise my code" sort of feels like you're asking to have your work done for you, which is perhaps where @jremington is coming from.

In terms of your combined sketch, it looks to me as though it should at least somewhat work. There are still delay() calls used, but assuming the sensors respond fairly quickly they're probably not too bad. You should at least see some output from the GPS. If not, you need to start debugging as to why that is. Is the GPS unit flashing it's LED to show it has a good fix? What happens if you comment out the code doing one sensor reading? What about if you comment both sensors?

I'd be happy to help further, but so far you've not responded to the suggestions I have made or a number of the questions I have asked. So it's hard for me to do much more than talk in general terms.

Here’s my progress:

  • I put the accelerometer/mag code into their own functions (get_accel & get_mag)
  • I commented out the SD card code for now in order to first get data collected from the components and seen through the serial monitor
  • I was able to get SOME code printed (I’ll provide below) but stopped after one single GPS fix. I believe this is due to there being a delay() function in the while loops of both the get_accel and get_mag functions

Both while loops with the delay functions were given to me by a professor. They are supposed to “After the request is made, a while loop waits for 6 bytes to be transferred from the accelerometer. Once 6 bytes are transferred, the code can read in the bytes.” If there’s any way I can get around using a delay() function to perform this process, I think this could solve the issue.

When I remove get_accel and get_mag from the void loop function, the GPS updates properly and provide speed and time information as expected every 200 ms. Clearly the issue is in the get_accel and get_mag functions.

Here is what my attached code printed:

Speed m/s:0.19
CentiSeconds:20

Hopefully this helps!

LJPIS.ino (5.34 KB)

They are supposed to “After the request is made, a while loop waits for 6 bytes to be transferred from the accelerometer. Once 6 bytes are transferred, the code can read in the bytes.”

Not correct. Remove these lines. They are completely unnecessary, as Wire.requestFrom() either works as instructed, or not at all.

 while(Wire.available() < 6) {
    delay(1);
  }

Increase this to a reasonable value, like 115200 Baud. Serial.print() is SLOW, and you do a lot of it.

 Serial.begin(9600);

It is a really bad idea to open a file, write a few bytes, then close it again. Open the SD file ONCE in setup() and then close it again when you are done collecting data. As it is now, the program will be very slow and the SD card error rate will be high.

Move the open and close statements in the code below to another part of the program.

void write_sd() {
  fd = SD.open("data.csv",FILE_WRITE);
  if(fd) {
    fd.print(currentMillis); fd.print(",");
    fd.print(gx,2); fd.print(","); fd.print(gy,2); fd.print(","); fd.print(gz,2); fd.print(",");
    fd.print(grav,2); fd.print(",");
    fd.println(an);
    fd.close(); } else Serial.println("Error opening");
}

Finally, this code in the magnetometer data collection is a really bad idea, too. The magnetometer offsets need to be estimated by a separate program, and used as constants here. Look up “magnetometer calibration”.

In this code, the offsets are being continuously updated, and you can’t believe any of the measurements.

  if (a > maxX) maxX = (int)a;
  if (a < minX) minX = (int)a;
  if (b > maxY) maxY = (int)b;
  if (b < minY) minY = (int)b;
  if (c > maxZ) maxZ = (int)c;
  if (c < minZ) minZ = (int)c;
  offX = (maxX + minX) / 2;
  offY = (maxY + minY) / 2;
  offZ = (maxZ + minZ) / 2;
  int fx = (int)a - offX;
  int fy = (int)b - offY;
  int fz = (int)c - offZ;

You started this project with code that provides several unfortunate but instructive examples of bad programming practice.

UPDATE:

I commented out the while loop of the accel/mag functions and they work properly in their own codes, but not in this code posted. However, I was able to get the GPS to update and print data every 200 ms including the accel/mag data. BUT, the accel/mag data is incorrect and doesn’t update. It stays the same for every printed line. I’ll provide this below:


Speed m/s:0.20
CentiSeconds:0
-0.01 -0.01 -0.01 0.02
10.89

Speed m/s:0.12
CentiSeconds:20
-0.01 -0.01 -0.01 0.02
10.89

Speed m/s:0.09
CentiSeconds:40
-0.01 -0.01 -0.01 0.02
10.89

Speed m/s:0.06
CentiSeconds:60
-0.01 -0.01 -0.01 0.02
10.89

Speed m/s:0.07
CentiSeconds:80
-0.01 -0.01 -0.01 0.02
10.89

Speed m/s:0.09
CentiSeconds:0
-0.01 -0.01 -0.01 0.02
10.89

As you can see, the speed and centiseconds updates, but not the accel/mag data. Again, on their own, the accel and mag data updates in their own codes. But those have a delay function at the end. Somehow, the data isn’t able to update, but printing along with the GPS updates is a step in the right direction.

FYI, the accel data should be around “-0.1 -0.5 -9.8 9.8” as opposed to the “-0.01 -0.01 -0.01 0.02” it is now.

LJPIS.ino (5.33 KB)

Thank you for suggesting the baud rate change, I did that. I also removed the while loops in the accel/mag functions. I’m not going to worry about the SD card function until after I get accel data to update properly.

I tried using millis() to update the accel function, and that works for the accel code itself, but not with the combined code. However, using that method I was able to put the accel function in a different spot in the GPS code, but it still is stuck at -0.01 -0.01 -0.01 0.02 and won’t update. This must be some interface issue between the GPS and accel code. I’m now getting this output:

Speed m/s:0.10
CentiSeconds:0

-0.01 -0.01 -0.01 0.02

Speed m/s:0.06
CentiSeconds:20

-0.01 -0.01 -0.01 0.02

Speed m/s:0.04
CentiSeconds:40

-0.01 -0.01 -0.01 0.02

Speed m/s:0.06
CentiSeconds:60

-0.01 -0.01 -0.01 0.02

Speed m/s:0.05
CentiSeconds:80

-0.01 -0.01 -0.01 0.02

Speed m/s:0.05
CentiSeconds:0

-0.01 -0.01 -0.01 0.02

How can I get the accel to update?

LJPIS.ino (5.33 KB)