My asset tracker is sending the coordinates to my arduino mega over serial 5. My mega is reading from serial2. I have a logic level shifter, common ground, and I’m receiving the data(String). Since the asset tracker sends the plain string, I can’t figure out how to have a separate string(lat) to be assigned to the latitude in the serial buffer- and same with the longitude. For some reason, I can see the latitude but not the longitude…After several failed attempts, I’m out of ideas.
My code:
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
// Start each software serial port
Serial2.begin(9600);
}
void loop() {
while (Serial2.available() > 0) {
String lat = Serial2.readStringUntil(',');
Serial.print(lat);
String lon = Serial2.readStringUntil("");
for(int i = 8; i < 18; i++){
lon = lon.substring(i);
Serial.print(lon);
}
}
}
A couple of thoughts. @rickkas7 has a nice Particle I2C tutorial. To add to @kennethlimcp, are you using a level shifter? Are the grounds tied together? This can lead to anomalous comms.
The delay where it is may be questionable. The default queue size is 32 characters for I2C. Actual transmission is delayed until endTransmission takes place. Having a delay after the write might trigger a timeout on the slave?
If you transmit again too quickly you can interrupt the previous inprogress transmission and bind up comms.
I’d try an unusually long delay after endTrasmission as a trial and see if you get the entire transmission.
I don't think this does what you want since readLatLon returns a String and Wire.write is just going to copy all the bytes in the object, not just the string characters. I would try getting the c_str pointer out of the String object and using that instead.
#include <AssetTracker.h>
#include "Serial5/Serial5.h"
// Set whether you want the device to publish data to the internet by default here.
// 1 will Particle.publish AND Serial.print, 0 will just Serial.print
// Extremely useful for saving data while developing close enough to have a cable plugged in.
// You can also change this remotely using the Particle.function "tmode" defined in setup()
int transmittingData = 1;
// Used to keep track of the last time we published data
long lastPublish = 0;
// How many minutes between publishes? 10+ recommended for long-time continuous publishing!
int delayMinutes = 10;
// Creating an AssetTracker named 't' for us to reference
AssetTracker t = AssetTracker();
// A FuelGauge named 'fuel' for checking on the battery state
FuelGauge fuel;
// setup() and loop() are both required. setup() runs once when the device starts
// and is used for registering functions and variables and initializing things
void setup() {
// Sets up all the necessary AssetTracker bits
Wire.begin();
t.begin();
// Enable the GPS module. Defaults to off to save power.
// Takes 1.5s or so because of delays.
t.gpsOn();
Serial.begin(9600);
// Opens up a Serial port so you can listen over USB
Serial5.begin(9600); // via TX/RX pins
// These three functions are useful for remote diagnostics. Read more below.
Particle.function("tmode", transmitMode);
Particle.function("batt", batteryStatus);
Particle.function("gps", gpsPublish);
}
// loop() runs continuously
void loop() {
// You'll need to run this every loop to capture the GPS output
t.updateGPS();
/*
Wire.beginTransmission(8);
//Wire.write("1");
Wire.write(t.readLatLon());
Wire.endTransmission(true);
delay(5000);
*/
// if the current time - the last time we published is greater than your set delay...
// GPS requires a "fix" on the satellites to give good data,
// so we should only publish data if there's a fix
//if(millis()-lastPublish > delayMinutes*60*1000){
// Remember when we published
//lastPublish = millis();
// Wire.beginTransmission(8);
// Wire.write("HELLO");
//delay(500);
// Wire.endTransmission();
//String pubAccel = String::format("%d,%d,%d",t.readX(),t.readY(),t.readZ());
//Serial.println(pubAccel);
//Particle.publish("A", pubAccel, 60, PRIVATE);
// Dumps the full NMEA sentence to serial in case you're curious
//Serial.println(t.preNMEA());
Serial5.println(t.readLatLon());
Serial5.flush();
// Serial.flush();
// GPS requires a "fix" on the satellites to give good data,
// so we should only publish data if there's a fix
if(t.gpsFix()){
// Only publish if we're in transmittingData mode 1;
if(transmittingData){
// Short publish names save data!
Particle.publish("G", t.readLatLon(), 60, PRIVATE);
}
// but always report the data over serial for local development
//Serial.println(t.readLatLon());
}
//}
}
// Allows you to remotely change whether a device is publishing to the cloud
// or is only reporting data over Serial. Saves data when using only Serial!
// Change the default at the top of the code.
int transmitMode(String command) {
transmittingData = atoi(command);
return 1;
}
// Actively ask for a GPS reading if you're impatient. Only publishes if there's
// a GPS fix, otherwise returns '0'
int gpsPublish(String command) {
if (t.gpsFix()) {
Particle.publish("G", t.readLatLon(), 60, PRIVATE);
//W//ire.beginTransmission(8);
// Wire.print(t.readLatLon());
// Wire.endTransmission();
Serial.print(String(t.readLatLon()));
// uncomment next line if you want a manual publish to reset delay counter
// lastPublish = millis();
return 1;
} else {
return 0;
}
}
// Lets you remotely check the battery status by calling the function "batt"
// Triggers a publish with the info (so subscribe or watch the dashboard)
// and also returns a '1' if there's >10% battery left and a '0' if below
int batteryStatus(String command){
// Publish the battery voltage and percentage of battery remaining
// if you want to be really efficient, just report one of these
// the String::format("%f.2") part gives us a string to publish,
// but with only 2 decimal points to save space
Particle.publish("B",
"v:" + String::format("%.2f",fuel.getVCell()) +
",c:" + String::format("%.2f",fuel.getSoC()),
60, PRIVATE
);
// if there's more than 10% of the battery left, then return 1
if (fuel.getSoC()>10){ return 1;}
// if you're running out of battery, return 0
else { return 0;}
println()
Available on Serial, USBSerial1, Serial1, Serial2, Serial4, Serial5.
Prints data to the serial port as human-readable ASCII text followed by a carriage return character (ASCII 13, or ‘\r’) and a newline character (ASCII 10, or ‘\n’).
So, the for loop you might have assumed the lat was still in there as part of the message which is why you were going from 8 to 18. A good guess.
When you start reading lon, you are actually reading the lon at that point. The for loop in combination of setting lon at the end to lon.substring(18) or the 18th character of what you might have read… which is nothing. That is why you ended up with nothing printed. At any rate, those two statements were the main problem.
Ok, new problem. Both latitude and longitude are in lat.
String lat = Serial2.readStringUntil(',');
String lon = Serial2.readStringUntil('\r');
It may not strip the ‘,’ or the ‘\r’ and then the \n’. You may have to consume them.
Thanks, I don’t think I would’ve realized the problem with the lon in the lat. This code is for my robot that is going to drive to my phone’s location. So this aspect of reading the lat, lon was important to me.
Sorry just one last quick question. So your example works great(and I never would’ve been able to come up with that ! Is there any way that you can convert the string(lat & lon) to a float after it’s been read?
In my code I get an error thats says cannot convert 'String' to 'float' in assignment