Translate

Showing posts with label GPS. Show all posts
Showing posts with label GPS. Show all posts

Friday 12 August 2016

Arduino Fast GPS datalogger - with switchable units, configuration of U-blox GPS in runtime, and KML. The International Version !!

Well, here it is folks.

Ryan's Dad lives in Australia, and Ryan wanted to make a version of the fast GPS datalogger that his dad could use on is boat.

After sorting out the problems Ryan had with his U-blox GPS module here, we set about a few mods.

Firstly, was to be able to select the units of speed selectable when the unit first starts up. The sketch now looks for a button, connected between A3 and ground. This allows the unit to be set for KPH (Kilometres per hour), KTS (knots) and MPH (Miles per hour). This is selected by the new void configureUnits. It times out after a couple of seconds. The configureUnits void sets a flag, which selects which type of data is written to the Speed variable, and written to both the display and the card.

 Here's Ryan's version, bread-boarded and tested on the bench.










Here's the new schematic, showing the addition of the "Select units" switch, and the extra connection to the GPS module to allow us to set the Ublox receiver's configuration.



And, of course, the new code:


Thursday 4 August 2016

Automatic configuration of ublox M6 GPS receivers for Arduino during runtime.

My good friend Ryan wants to make a GPS tracker with KML, as detailed on this very website.

He wants to make a couple of revisions, which I'll publish here later...

But, he runs into a problem.

It doesn't work....

After some careful examination of the receiver, and checking the configuration with the U-blox U-center application, it becomes apparent that the receiver isn't storing the new configuration (57,600 baud serial, and 200mS update rate) after a power cycle... It defaults to 9,600 baud and a rate of 1s.

... damn it, a faulty receiver. So another is tried. Same results...

So, presumably the receivers aren't faulty....

This is one of the guilty receivers....

.... notice anything??







Here's one of mine....

... and there's the difference. See where the "faulty" receiver has a white circle marked with a 2??  Mine has a battery fitted. After a quick look at the datasheet for the U-blox chip, this is a RAM back-up battery. The configuration settings are stored in RAM. On Ryan's receiver these are lost as soon as the supply is removed.




Ryan looked into getting the correct battery and fitting it, but it's got one helluva specification, and was about £7... which is a touch expensive considering the GPS module was £9!

How about sending the configuration data from the sketch every time it starts up?

Why not....

I did a few experiments with two FTDI boards connected to a receiver...

In this picture you can see I've connected the lower FTDI to the receiver, RX to TX, TX to RX. This FTDI is used to communicate to the U-Center application. The top FTDI is used to "sniff" the serial data on the TX line on the first FTDI. Only it's ground and the RX pin are connected. This is so I can run a terminal program and grab the configuration data when I click "send" on the u-center application.

After a bit of buggering around with Real term (download from here.) I grabbed the data, in hex, being sent to the receiver from u-center.

This is what it looks like:

Set to 200mS rate

B5 62 06 08 06 00 C8 00 01 00 01 00 DE 6A B5 62 06 08 00 00 0E 30
 
set 57,600 baudrate

B5 62 06 00 14 00 01 00 00 00 D0 08 00 00 00 E1 00 00 07 00 02 00 00 00
00 00 DD C3 B5 62 06 00 01 00 01 08 22

So, now we just need to send that each time we power up...

You'll need to add a wire from the Arduino's TX pin to the receiver's RX pin, so the receiver can receive the configuration commands.

Here's the code snippet, you'll just need to add it in the void setup ()




.... and so on. I'll post up the whole thing , and the modifications we made to Ryan's tracker soon!

Friday 22 July 2016

Arduino GPS master clock with 433/315 MHz transmitter

I've got a few clock projects in the back of my mind, and this is a bit of an aside to them all. I also wish to upgrade the Astronomical clock project, as the DS1307 often drifts about, losing and gaining seconds as it feel like it...

The idea is to have a master clock, GPS locked with built in 433 MHz transmitter, which will send an accurate time signal to the other clocks to bring them into sync. The transmitter will be triggered randomly, at least once every 24 hours, or by a push button connected to pin 12.

I'll be re-using the code from the quick and dirty 7-segment GPS clock here, and some of the code for the transmit function from the dehumidifier project.

I've added a 4x20 LCD display, with I2C piggyback interface board, and the u-blox GPS module we've used in the GPS logger.

The GPS module will be configured by the sketch itself, to 200mS refresh rate.

There's two sketches, the GPS clock itself, and a simple test receiver sketch to check everything's working as it should.

The I2C display is a generic display, purchased from eBay, and uses the PCF8574 I2C receiver IC. I tried a couple of different libraries, but eventually settled with the library from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads which works well with my display.
Well also use the virtual wire library to handle our comms, https://www.pjrc.com/teensy/td_libs_VirtualWire.html and the most excellent TinyGPS++ http://arduiniana.org/libraries/tinygpsplus/

There's an LED connected to pin 9, which blinks on and off every time the seconds are updated.

Here's the schematic...




... and the hardware lashed up for testing.

The second arduino is acting as our test receiver. There's no RF module in there as yet.. It's coupled to the clock arduino, GND is coupled, and pin 10 on the clock is connected to pin 9 on the receiver board. It's also supplying 5V to the other board.







Here's the data being displayed. Date (in UK format DD/MM/YYYY) , UTC time, latitude, longitude, no of satellites in use, horizontal dilution of precision and the number of seconds until the next transmission.







Here's the output from our terminal window, connected to the receiver board, showing the time and date are being correctly received when A3 is pulled to ground.




So, the final build looks like this...

You can see the antenna is simply a straight piece of wire, 173mm long (for 433 MHz modules, other frequencies will need a different length)


And assembled. Managed to cut the right sized hole for the display for once!











Here's the GPS receiver, which I'm going to mount remotely on the roof, so it get's good reception. I've stuck it into of a water-proof IP rated box, and fitted a Buccaneer connector.









OK, so to the code....

This is the transmitter code:



and the test receiver code...



Now all that remains is to box it up, and create some clocks!

Wednesday 13 July 2016

Arduino Fast GPS datalogger updated. Now with KML!

Now Updated (again) with selectable speed units, and configuration of U-blox GPS in runtime, avoiding the need to use U-Center to configure the receiver.  Click Here!

The fast GPS datalogger project is the most popular project on here. Link.


It's been working well on the race car since it's inception, and has provided some really useful data to improve the performance of the driver!

What isn't so great is how the data is stored. It stores everything, regardless of fix, number of races etc, so it's a headache to filter out each race, and remove useless invalid data, either without a time stamp or valid position or speed, and then turn it into something that could be used. I have been painstakingly converting the data into KML, which we can directly read with mapping software, such as Google Earth.

I've made some modifications to the software to sort out some of these issues... here's the new features:

Each time the record switch is pressed, valid GPS data is required, and once obtained, a new file name is created from the current time, HHMMSSCC.kml  (in UTC, CC representing centiseconds here), and the KML header file is written.

Now the file is built as in the previous version, except this time in KML format.

Speeds below 5 MPH are not recorded.

When record is switched off, the KML file is completed and closed.

So once the card is removed from the unit, simply read the kml file from the card, and open in google earth.

So I went out for a quick jaunt in England's green and pleasant....










... and loaded the KML file straight into google earth.

No more tedious editing required!

No changes to the hardware are required. Just remember to disconnect the RX line from the GPS module when attempting to load the new sketch.


Here's the code:


Friday 8 May 2015

Arduino GPS clock with MAX7219 driven 7 segment displays.

This is the start of an on-going time standard project.

The idea is to have three clocks, one MSF clock being received from the NPL on 60KHz, one DCF77 clock on 77.5 KHz and one GPS clock.

This is the first part of the clock, the GPS clock.

I'll be using the Ublox NEO receiver I've used before in the fast GPS-logger project here. The receiver is configured in exactly the same manner as described in that article, so pop along there and learn how to use u-center to configure your receiver.

I purchased some great MAX7219 display boards from eBay. There was a bit of a wait, as they came from China, but they were much less expensive than others, and the build quality is OK.

 Note on some board the CS pin is marked up LOAD.






I'm not going to draw a schematic, as it really is simple. (Leave me a comment if you get stuck!)
The wiring is commented in the code below.





The code is also simple, we're not doing anything particularly clever. There's a bit in the code which writes "no GPS" on the display, and this is defined as a bitmap. The bitmap refers to the segments as follows:

Bit 1(LSB) is G
Bit 2 is F
Bit 3 is E
Bit 4 is D
Bit 5 is C
Bit 6 is B
Bit 7 is A
and finally, bit 8 is the decimal point.






Here's a quick video of the clock in action:


... and here's the code:-

/*
 7-segment GPS clock 
 Version 0.9
 Written by Andy Doswell 2015
 License: The MIT License (See full license at the bottom of this file)
   
 Schematic can be found at www.andydoz.blogspot.com/
 
 You will need the LedControl library from http://playground.arduino.cc/Main/LedControl
 and the very excellent TinyGPS++ library from http://playground.arduino.cc/Main/LedControl
 
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to CS
 pin 0 (RX)  is connected to the GPS TX pin

 */
 
#include "LedControl.h"
#include <TinyGPS++.h>

LedControl lc=LedControl(12,11,10,1); //Tells LedControl where our hardware is connected.
TinyGPSPlus gps; //TinyGPS++ class
static const uint32_t GPSBaud = 57600; //Our GPS baudrate. 
int hourTen; //tens of hours
int hourUnit; //units of hours
int minTen; // you get the idea..
int minUnit;
int secTen;
int secUnit;
int centTen; //centiseconds.
int centUnit;
unsigned long timer =0;

void setup() {

  lc.shutdown(0,false); // Wake up the MAX 72xx controller 
  lc.setIntensity(0,8); // Set the display brightness
  lc.clearDisplay(0); //Clear the display
  
  Serial.begin(GPSBaud); // start the comms with the GPS Rx
}

// This contains the bit patterns for the "no GPS" display.

void displayNoGPS() { // displays "noGPS" if the GPS lock isn't valid
  lc.setRow(0,0,B00000000);
  lc.setRow(0,1,B00000000);
  lc.setRow(0,2,B01011011);
  lc.setRow(0,3,B01100111);
  lc.setRow(0,4,B01011110);
  lc.setRow(0,5,B00000000);
  lc.setRow(0,6,B00011101);
  lc.setRow(0,7,B00010101);
}

void displayNoSerial() { // Displays "noSeriAL" in the event of serial comms fail.

  lc.setRow(0,7,B00010101);
  lc.setRow(0,6,B00011101);
  lc.setRow(0,5,B01011011);
  lc.setRow(0,4,B01001111);
  lc.setRow(0,3,B00000101);
  lc.setRow(0,2,B00010000);
  lc.setChar(0,1,'a',false);
  lc.setRow(0,0,B00001110);
}
  
// Displays the time on our LEDs
void displayTime() { 
  if (gps.time.isValid()) {
    timer = millis(); // reset the serial comms timer
    hourUnit = (gps.time.hour()%10);
    hourTen = ((gps.time.hour()/10)%10);
    minUnit = (gps.time.minute()%10);
    minTen = ((gps.time.minute()/10)%10);
    secUnit = (gps.time.second()%10);
    secTen = ((gps.time.second()/10)%10);
    secUnit = (gps.time.second()%10);
    secTen = ((gps.time.second()/10)%10);
    centUnit = (gps.time.centisecond()%10);
    centTen = ((gps.time.centisecond()/10)%10);
    lc.setDigit (0,7,hourTen,false);
    lc.setDigit (0,6,hourUnit,false);
    lc.setDigit (0,5,minTen,false);
    lc.setDigit (0,4,minUnit,false);
    lc.setDigit (0,3,secTen,false);
    lc.setDigit (0,2,secUnit,false);
    lc.setDigit (0,1,centTen,false);
    lc.setDigit (0,0,centUnit,false);
  }
  else
  {
    displayNoGPS();
    delay (2000);
  }
  
}

void loop()
{
  // If the GPS data is OK, then display it. If not display "no GPS"
  while (Serial.available() > 0)
    if (gps.encode(Serial.read())){
      displayTime();
    }
  if (millis() > timer+1000 ) // detects if the serial comms has failed.
  {
    displayNoSerial();
  }
  


  
}

/*
 * Copyright (c) 2015 Andrew Doswell
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


Saturday 14 February 2015

Fast Arduino GPS Datalogger.


STOP PRESS! This project is now revised and updated here, and will now create KML files, to open directly in google earth!

Now, my friend Julian and I have, for the past three years, been building a racing car. I've been lending a hand with the electrics and certain mechanical bits.

It's based on a 1971 Mini Clubman (by the name of Florence)

Here's Julian, fitting the door mirror.








After it's first season competing (with Julian at the wheel) , it's not disgraced itself at a few hillclimbs...








This video isn't mine, but this is Julian at the National Championship at Wiscombe Park late last year.

Anyway. Julian wants a bit more power, this has necessitated a new and bigger engine, and a new and bigger carburetor. In turn, the baulkhead had to be modified to accommodate the changes. Now the lovely dashboard we had created to house the instruments had to face some changes, and the large mechanical speedo had to go (when you're racing, you're not looking at how fast you're going!)

We looked for a small speedo that would suit our requirements, but I mooted the idea of a digital speedo, collecting it's data from a GPS receiver... I have previously used U-blox receivers and chipsets commercially, so I ordered one from the lovely people at Hobby Components here.




Excellent. Provides updates at up to 5 times per second.

Now, this coupled to an Arduino pro-mini, and a nice OLED display would provide a nice speedo...

The display is a 128x64 SDD1306 OLED display, and was purchased from eBay.







Then I got to thinking ... what if I could log some data to an SD card as well... might provide some interesting data for when the car is racing. So I ordered an SD card reader at the same time ...


eBay is once again our friend!









Now first things first, we need to configure our GPS receiver. This is done by hooking up the receiver board to our PC (I used the same FTDI converter I use to program the Pro-mini boards).

Go and get yourself a copy of uCenter from the U Blox website here.

Now when the software opens, you will need to tell it which com port and baud rate the receiver is on. Click on the receiver tab, and select the com port. Try 9600 for the baud rate, if you see no data, try another speed. Soon enough you should see some data from the receiver.



Amazing, isn't it!

Now click View and Messages View. Maximise the messages window.

Now scroll down to UBX and click it to expand the tree. Click on CFG . Now click on RATES and change the Measurement Period to 200mS.

Now expand the PORTS section, and change the baudrate to 57600. Once you do this, uCenter will lose communications with the receiver module. Go to Receiver, and re-set the baudrate to 57600.


Now click on Receiver again, selection Action and click Save Config.


You can now disconnect the receiver from the PC.

Now, a word about power. The uBlox receiver is happy at 3.3 or 5v, The Pro-mini I've got is good at 3.3v or 5v, the display works great on 3.3v or 5v... the SD Card reader, whilst it has a pin marked 5v, is only happy with 3.3v on it's data and clock pins. The 5v is purely to power the on-board 3.3v regulator. Now, we can either run everything from 5v and use a level converter between the arduino and the SD card reader (stupid) , or we can use the 3.3v from the card reader's on board reg to drive everything else (a really good idea!)

So, from the car our 12v is dropped to 5v using an ordinary 7805 voltage regulator, this is then supplied to the SD Card reader. The 3.3V pin on the card reader then supplies power to the arduino, the GPS receiver and the display.

SDA on the display is connected to A4, SDC to A5. The SD card interface is connected to pins 4 (CS), 11 (MOSI), 12 (MISO) & 13 (SCK).

A toggle switch is connected between pin 9 and ground. The toggle switch is used to switch on and off the logging feature.

The GPS receiver's TX pin is simply coupled to the hardware RX pin on the arduino, but not until we've uploaded the software!

Now there is an excellent library to control the display from Adafruit, but it is very memory intensive, and somewhat slow. This caused difficulty in writing to the SD card in time.

After spending a while surfing, I happened upon a lightweight library at http://blog.oscarliang.net/arduino-oled-display-library/ which is perfect, although it's not designed for this display. There's a requirement to enable the on-board inverter in our sketch.

We'll also need the most excellent TinyGPSPlus library from https://github.com/mikalhart/TinyGPSPlus

The SD card will need to be formatted on your Windows PC as FAT32. Open notepad and save a blank file as gps.txt to the card.

Here's the schematic:-

You will notice there's a zener diode before the 7805, this to clamp any nasties that might be present on our 12V supply from the vehicle (usually on cranking). Any value between 18 and 32 volts will do. 

 Lashed up for testing...


 7805 power supply.

Will it all fit in the box?


Of course ;)



Painted black to match the dash.

Not many satellites being received on the bench!

But a few in the window!

The receiver is actually very sensitive, although initial lock may take a few minutes, once recent data is stored in the receiver's non-volatile memory, warm starts are very quick indeed.





Out for a quick test run, and logged some data....

 It's pretty easy to import the txt file into google maps, and get some useful data...


Here, individual data points are shown, each showing the speed at that point.






Anyway, here's the sketch....


/*
Fast GPS data logger.
(c) 14th February 2015 A.G.Doswell

Released to all and sundry under GNU License.

The sketch uses a U-Blox 6M GPS satellite module connected to the hardware serial interface, 
a 128x64 SDD1306 OLED display module connected as an I2C device to pins A4 (SDA)& A5 (SCL) and an SD card interface 
connected to pins 4 (CS), 11 (MOSI), 12 (MISO) & 13 (SCK) The arduino used is a Nano with 3.3v ATMEGA328P.
Warning - Many SD card interfaces are not 5V. 
There's a toggle switch which connects pin 9 to GND for Record.
Data is written to the card an impressive 4 times per second, in real-time. 

The OzOled library is not quite "right" for this application, but works, and is lightweight and fast enough. Thanks Oscar!
It is available here : http://blog.oscarliang.net/arduino-oled-display-library/
TinyGPSPlus is available here :https://github.com/mikalhart/TinyGPSPlus

*/

#include <SPI.h>
#include <Wire.h>
#include <OzOLED.h>
#include <TinyGPS++.h>
#include <SD.h>

static const uint32_t GPSBaud = 57600;
int SatVal;                        // Number of satellites locked
int Speed;                         // Speed in MPH
char SpeedA [4];                   // Speed as char
TinyGPSPlus gps;                   // Feed gps data to TinySGPSPlus
File myFile;                       // Start SD
int speedDigit;                    // Number of digits in Speedo display 
boolean card;                      // Is there a card present?
boolean rec = false;               // Is the record switch low? (false = high)
int recPin = 9;                    // Record pin (Pull low to record data) 

void setup()   {                

  Serial.begin(GPSBaud);           // Start GPS serial comms
  pinMode (recPin, INPUT_PULLUP);  // recPin as input and pulled high
  OzOled.init();                   // initialze SDD1306 OLED display
  OzOled.sendCommand(0x8d);        // Set displays inbuilt inverter on
  OzOled.sendCommand(0x14);          
  OzOled.setBrightness(0xFF);      // ... and brightness to max
  OzOled.clearDisplay();           // Clear the screen
  OzOled.setNormalDisplay();       // Set display to Normal mode
  pinMode(10, OUTPUT);             // CS for SD card, wether it likes it, or not.
  OzOled.clearDisplay();
  
  
  if (!SD.begin(4)) {              //Check SD card is present
      OzOled.printString("SD card fail    ",0,7);
      card = false;  
      }
      else {
      OzOled.printString("SD card OK      ",0,7);
      card = true;
      }
  
  OzOled.printString("Sats:",0,0);  // Set up display
  OzOled.printString("Speed:",0,1);
  OzOled.printString("MPH",7,6);
}

void loop() {
    while (Serial.available() > 0) //While GPS message received
    if (gps.encode(Serial.read()))
      displayInfo();
}

void displayInfo() {               // Display the data
  SatVal = int(gps.satellites.value());
  Speed = int(gps.speed.mph());
  itoa (Speed,SpeedA,10);
  OzOled.printNumber ((long)SatVal,6,0);
  OzOled.printBigNumber (SpeedA, 7,1);
  speedDigit = strlen(SpeedA);    // get length of Speed , and delete left behind zero if req'd
  if (speedDigit == 1) OzOled.printBigNumber(" ",10,1);
  if (digitalRead(recPin) == HIGH && card == true) { //If the record switch is high and the card is OK, write card data
    rec = true;
    OzOled.printString("SD card OK REC",0,7);
  }
  if (digitalRead(recPin) == LOW && card == true) {
    rec = false;
    OzOled.printString("SD card OK    ",0,7);
  }
  
  if (card==true && rec==true) {
    writeInfo(); //write the data to the SD card
  }
  smartDelay(200);

}

// This custom version of delay() ensures that the gps object
// is being "fed".
static void smartDelay(unsigned long ms)
{
  unsigned long start = millis();
  do 
  {
    while (Serial.available())
      gps.encode(Serial.read());
  } while (millis() - start < ms);
}

void writeInfo() { //Write the data to the SD card Date,Time,Lat,Long,Spped (MPH) and number of satellites locked
  
  myFile = SD.open("gps.txt", FILE_WRITE);
  if (myFile) {
    myFile.print(gps.date.month());
    myFile.print(F("/"));
    myFile.print(gps.date.day());
    myFile.print(F("/"));
    myFile.print(gps.date.year());
    myFile.print(F(","));
    if (gps.time.hour() < 10) myFile.print(F("0"));
    myFile.print(gps.time.hour());
    myFile.print(F(":"));
    if (gps.time.minute() < 10) myFile.print(F("0"));
    myFile.print(gps.time.minute());
    myFile.print(F(":"));
    if (gps.time.second() < 10) myFile.print(F("0"));
    myFile.print(gps.time.second());
    myFile.print(F(","));
    myFile.print(gps.location.lat(), 6);
    myFile.print(F(","));
    myFile.print(gps.location.lng(), 6);
    myFile.print(F(","));
    myFile.print(gps.speed.mph(),1);
    myFile.print(F(","));
    myFile.println(gps.satellites.value());
 // close the file:
    myFile.close();
  }
}