Connecting dGPS sensor to arduino


#1

I have been trying to connect the dGPS board that I purchased a couple of yours ago from Dexter Indust to my redboard and communicating with it using I2C.

The connection was made using a brickbox assembly that provides a direct cable connection between the dGPS and breadboard (see attached pix). Analog pins A4 (SDA) and A5 (SCL) were used. Pin outs of the brickbox are:

1 - analog/9v
2 - gnd
3 - gnd
4 - vin
5 - scl
6 - sda

I have tried with and without the 4.7k pull-up resistors but results seem to be the same.

The I2C communications were set up with 7 bytes of data being sent between the NXT and dGPS. The data requested, sending size, receiving size were as per the Table 1 provided by Dexter Indust.

The arduino code I put together is shown below:

#include <Wire.h>

#define I2C_ADDR 0x03

boolean result = false;

void setup()
{
Serial.begin(9600); // start serial for output
Wire.begin();
delay(15);
Serial.println(“Ready!”);
result = dgpsInit();
if (result = true) {
Serial.println(“Got valid signal”);
}
else(Serial.println(“No valid signal”));
Serial.print("dGPS Time: ");
getgpsTime();
Serial.println();
}

void loop()
{
Serial.print("Lat: “);
getLat();
Serial.print(” ");

Serial.print("Long: ");
getLong();
Serial.println();

delay(5000);
}

boolean dgpsInit()
{

Wire.beginTransmission(I2C_ADDR);
delay(5);
Wire.write(0x02);
Wire.write(I2C_ADDR);
Wire.write(0x01);
Wire.endTransmission();
delay(15);
Wire.requestFrom(I2C_ADDR, 0x01);
while(!Wire.available()) {
}
byte b = Wire.read();
if (b == 1) {
return true;
}
else return false;
}

void getLat() {

byte b[4];

Wire.beginTransmission(I2C_ADDR);
delay(5);
Wire.write(0x02);
Wire.write(I2C_ADDR);
Wire.write(0x02);
Wire.endTransmission();
delay(15);
Wire.requestFrom(I2C_ADDR, 0x04);
while(!Wire.available()) {
}

for (byte n = 0; n < 4; n++) {
b[n] = Wire.read();
Serial.print(b[n]);
}

}

void getLong() {

byte b[4];

Wire.beginTransmission(I2C_ADDR);
delay(5);
Wire.write(0x02);
Wire.write(I2C_ADDR);
Wire.write(0x04);
Wire.endTransmission();
delay(15);
Wire.requestFrom(I2C_ADDR, 0x04);
while(!Wire.available()) {
}

for (byte n = 0; n < 4; n++) {
b[n] = Wire.read();
Serial.print(b[n]);
}

}

void getgpsTime() {

byte b[4];

Wire.beginTransmission(I2C_ADDR);
delay(5);
Wire.write(0x00);
Wire.write(I2C_ADDR);
Wire.write(0x04);
Wire.endTransmission();
delay(15);
Wire.requestFrom(I2C_ADDR, 0x04);
while(!Wire.available()) {
}

for (byte n = 0; n < 4; n++) {
b[n] = Wire.read();
Serial.print(b[n]);
}
}

The serial output indicates a valid gps signal but the latitude and longitude and time data do not appear correct.

I have assumed that the data sent from the arduino to the dGPS ATMega328 consists of three bytes (message size (sending), I2C address and data requested). Message size was taken as 3 bytes, scanning indicated I2C address of 0x03, and data requested was as per Table 1.

I was hoping someone may have tried to do this type of connection and may be able to help with either the hardwired connections or program.

Any help would be appreciated. Thanks.


#2

Sounds like a cool project! Mashing the Arduino with stuff is always a lot of fun.

First thing: check that the cr2032 battery is working. The light will come on with the dGPS if it is, so it’s not a good indication of whether that battery is depleted or not. Check it with a multimeter.

You should not need pullups because there are already strong pullups on the dGPS.

These may not be an issue though, because you say you’re getting some data. Can you share a sample of data?

The serial output indicates a valid gps signal but the latitude and longitude and time data do not appear correct.
Lat, lon, and time from the serial or from the I2C data? BTW, are you getting the serial data with a logic analyzer directly on the dGPS sensor?

Thanks! I’m sure we can solve this, I’m just confused a little bit by question, that’s all!


#3

Thanks for your comments and sorry for the confusing nature of my question.

I have been running the code in the ardunio software and using the serial monitor to observe the output. A sample of the output is attached showing the gps time, lat/long as well as the local time here in Toronto. The communications are between the redboard and the dGPS via I2C. I am not using a logic analyzer directly on the sensor.

The 2032 battery was checked and was at 2.963V.

I agree, I don’t think the pull up resistors are needed as there is output, and there is no difference in output running with or without the resistors on SDA/SCL.

The output is a little nonsensical in that the lat/long are the same although the data requested inputs to the dGPS are different. Again, thanks for the comments and and added thoughts would be helpful.


#4

I would say your dGPS sensor is running ok then. If you have enough voltage on the battery, it’s probably working.

I would even guess that you’re getting some data. My best guess at this point is that it’s not being assembled from the array into the long correctly.

Let’s take a look at the time. If you poll the device for UTC every 5 seconds, does it increment? Or does it change? Can you show a printout of that?


#5

The arduino sketch program was revised to iterate the gettime function and the output is attached.

The time increments by 5 in blocks of 12. To get this output I varied the message size (byte 0) in the call from the arduino to the dGPS. Other variations of this variable (ie., tried keeping all at 2, 3, or setting equal to receiving size) resulted in the time/lat/long all being the same.

Anyway, thanks for your help. I will continue looking at different input variations to see if that makes any further difference.

Still not sure how to convert the output in bytes to the utc time (hhmmss) and the integer lat/long from the 4 bytes but will continue working on this.


#6

Good. If the numbers are changing, your sensor is alive and kicking.

As for decoding the incoming data, I think the attached files might help. They are credit to Botbench, who developed the drivers for RobotC for the dGPS.

YOu’ll have to modify the I2C machinery in “DGPSreadRegister” but I think you should be able to more or less copy and paste the functions for converting arrays of data into values since it’s all pure C more or less.


#7

Thank you! Xander’s code converted to an arduino sketch did the trick (see attached screen capture). I extended a couple more of the functions but all seems ok now. The updated code is attached.

I did replace the battery but this was not the problem. Also, the pull-up resistors not required. A couple of the tweaks to get correct data involved changing the message size from the standard 2 given in the I2C discussion for the DGPS in the Dexterind’s docs and in the botbench code to the values shown in the attached table.

Thanks again for all your help.

Arduino code:


/*
dgps_logging_v1 provides implementation of I2C communications between Arduino and Dexter Industries dGPS sensor. It includes only the status, UTC time, latitude, londitude, velocity and heading functions. Others can readily be added but caution the message sizes yet to be confirmed.

Changelog:
0.1: Initial release

Credits:
Developed based on information and comments from Dexter Industries and from C code provided by Xander Soldaat (xander_at_botbench.com) in files dexterind-gps.h and example dexterind-test1.c

License:
This code can be used freely, provided credit is given where due

author: waverider735@gmail.com
date: August 10 2014
version: 0.1
*/

#include <Wire.h>

#define DGPS_I2C_ADDR 0x03 /* dGPS sensor device address /
#define DGPS_CMD_UTC 0x00 /
Fetch UTC /
#define DGPS_CMD_STATUS 0x01 /
Status of satellite link: 0 no link, 1 link /
#define DGPS_CMD_LAT 0x02 /
Fetch Latitude /
#define DGPS_CMD_LONG 0x04 /
Fetch Longitude /
#define DGPS_CMD_VELO 0x06 /
Fetch velocity in cm/s /
#define DGPS_CMD_HEAD 0x07 /
Fetch heading in degrees /
#define DGPS_CMD_DIST 0x08 /
Fetch distance to destination /
#define DGPS_CMD_ANGD 0x09 /
Fetch angle to destination /
#define DGPS_CMD_ANGR 0x0A /
Fetch angle travelled since last request /
#define DGPS_CMD_SLAT 0x0B /
Set latitude of destination /
#define DGPS_CMD_SLONG 0x0C /
Set longitude of destination */

boolean result = false;
byte DGPS_I2CRequest[3];
//byte DGPS_I2CReply[7];
long UTCtime;
long DGPSLat;
long DGPSLong;
long DGPSVelo;
long DGPSHead;

void setup()
{
Serial.begin(9600); // start serial for output
Wire.begin();
delay(15);
Serial.println(“Ready!”);
result = DGPSreadStatus();
if (result = true) {
Serial.println(“Got valid signal”);
}
else(Serial.println(“No valid signal”));
}

void loop()
{

UTCtime = DGPSreadUTC();
Serial.print("dGPS Time: “);
Serial.print(UTCtime);
Serial.print(” ");

DGPSLat = DGPSreadLatitude();
Serial.print("Lat: “);
Serial.print(DGPSLat);
Serial.print(” ");

DGPSLong = DGPSreadLongitude();
Serial.print("Long: “);
Serial.print(DGPSLong);
Serial.print(” ");

DGPSVelo = DGPSreadVelocity();
Serial.print("Vel: “);
Serial.print(DGPSVelo);
Serial.print(” ");

DGPSHead = DGPSreadHeading();
Serial.print("Head: ");
Serial.print(DGPSHead);
Serial.println();

delay(5000);
}

long DGPSreadRegister(byte msgsize, byte command, int replysize)
{
DGPS_I2CRequest[0] = msgsize; //message size
DGPS_I2CRequest[1] = DGPS_I2C_ADDR; //I2C address
DGPS_I2CRequest[2] = command;
byte DGPS_I2CReply[replysize];

Wire.beginTransmission(DGPS_I2C_ADDR);
delay(5);
Wire.write(msgsize);
Wire.write(DGPS_I2C_ADDR);
Wire.write(command);
Wire.endTransmission();
delay(15);
Wire.requestFrom(DGPS_I2C_ADDR, replysize);
while(!Wire.available()) {
}
for (int n = 0; n < replysize; n++) {
DGPS_I2CReply[n] = Wire.read();
}

if (replysize == 4) {
return ((long)DGPS_I2CReply[3] + ((long)DGPS_I2CReply[2] << 8) + ((long)DGPS_I2CReply[1] << 16) + ((long)DGPS_I2CReply[0] << 24));
}

else if (replysize == 3)
return (long)DGPS_I2CReply[2] + ((long)DGPS_I2CReply[1] << 8) + ((long)DGPS_I2CReply[0] << 16);

else if (replysize == 2)
return (long)DGPS_I2CReply[1] + ((long)DGPS_I2CReply[0] << 8);

else if (replysize == 1)
return (long)DGPS_I2CReply[0];

return 0;
}

/**

  • Read the status returned by the GPS.
  • @param message size is 2 and reply size is 1
  • @return ture if valid signal else return false for no valid signal
    */
    boolean DGPSreadStatus()
    {
    return (DGPSreadRegister(0x02, DGPS_CMD_STATUS, 1) == 1) ? true : false;

}

/**

  • Read the time returned by the GPS in UTC.
  • @param message size is 0x00 and reply size is 4
  • @return the time in UTC as long (hhmmss)
    */
    long DGPSreadUTC() {
    return DGPSreadRegister(0x00, DGPS_CMD_UTC, 4);
    }

/**

  • Read the current location’s latitude in decimal degree format
  • @param message size is 0x02 and reply size is 4
  • @return current latitude as long Positive = North, negative = South
    */
    long DGPSreadLatitude() {
    return DGPSreadRegister(0x02, DGPS_CMD_LAT, 4);
    }

/**

  • Read the current location’s longitude in decimal degree format
  • @param message size is 0x04 and reply size is 4
  • @return current longitude as long Positive = East, negative = West
    */
    long DGPSreadLongitude() {
    return DGPSreadRegister(0x04, DGPS_CMD_LONG, 4);
    }

/**

  • Read the current velocity in cm/s
  • @param message size is 0x03 and reply size is 3
  • @return current velocity
    */
    long DGPSreadVelocity() {
    return DGPSreadRegister(0x03, DGPS_CMD_VELO, 3);
    }

/**

  • Read the current velocity in cm/s
  • @param message size is 0x02 and reply size is 2
  • @return current velocity
    */
    long DGPSreadHeading() {
    return DGPSreadRegister(0x02, DGPS_CMD_HEAD, 2);
    }

#8

So glad it worked out! This is awesome! Thanks for sharing the final code, and thanks for working through it.