Hi guys,
This is a quick how to on my $20 GPS speed logger. If it all goes smoothly you don't need much in the way of soldering and coding skills but if you run into problems it could be an adventure if you lack the knowledge base. You have been warned.
You can make this as pretty as you want, but mine is held together with hot glue and I used cork to make the case, so you can get away with some pretty dirty work-arounds if you're so inclined.
There's a video here.
Update (Nov15):
- I accidentally plugged in the wires with the wrong polarity and it didn't look good for a day or two. The unit still powered up with the Adafruit logo, but that was it. If you want to avoid this potential oopsy:
- use a proper power plug of some sort (proper meaning with polarity)
- Add a diode to the input to protect against wrong polarity
- I finally got around to hooking it up to my computer for diagnosis and SURPRISE, it works perfectly running off USB power. So, doing the worst thing you can do does not result in catastrophic failure, just some damage to the Arduino. I did not dig any further because it really doesn't seem worth the effort despite being a little curious about what got cooked on the Arduino.
- Yes, I know these things wouldn't happen if I just did things the right way from the get go, but I was psychologically prepared for this day AND knowing this kind of thing can and does happen makes me wayyy more cautious with expensive stuff. Five bucks well wasted IMO.
One BIG Caution:
Guys, my little oopsy above did have a very positive pay off. I read that a lot of guys who like to play with Arduinos run a USB isolation gizmo or a powered USB hub to protect the computer's USB ports from accidental short circuit related damage. I use an old laptop for playing around so my heart wouldn't be broken if bad things happened, but I would be pretty annoyed. Why waste a usable computer, right? Keep in mind that damage is unlikely without a serious mistake like shorting power in a vulnerable part of the Arduino's circuitry. If you're on a budget, you can minimize the risk without spending money by paying attention to things that I probably take for granted:
- Power the Arduino from a battery to test the build of your gadgets prior to connecting to the PC.
- Avoiding loose hanging wires or shoddy connections that might pop loose and touch the wrong thing
- Using a breadboard and power supply for everything except loading code
A little bit of damage is a learning experience you'll remember, right? That said, avoiding the big horrible learning experiences isn't bad for you either.
A few cautions:
- If you don't know what you're doing and feeling nervous, get help from someone more experienced in the ways of DIY.
- Take apart your RC vehicle at your own risk.
- Follow these instructions at your own risk.
- Use common sense and review instructions before you follow them.
- Knives can cut you. Use caution.
- Hot glue can burn you. Use caution.
- Brad nails can stab you. Use caution.
- Rubber bands can shoot you in the eye. Use caution. Please tell me if this happens to you, I can always use a laugh. It's funny if you aren't the victim. That goes for just about everything on this list but a rubber band in the eye is the funniest.
- Screw drivers can stab you. Use caution.
- Drills can drill you. Use caution.
- Soldering irons can solder you. Use caution.
- Molten solder is like lava from a volcano. Use caution.
- Fast spinning wheels or drills or rotary tools can tear the skin right off you. Use caution.
- Forcing something that doesn't fit can cause damage to property or personal injury. Use caution.
- Connecting electronics incorrectly can release the smoke. The smoke can't be put back in. Use caution. Take pictures if you don't know by heart how parts are connected.
- Batteries can cause fires when not handled properly. Use caution.
- Some parts are not very durable. Screw holes may not survive taking a screw out and putting it back in. Disassemble your RC car at your own risk.
On with the show...
Parts:- 1x Arduino Nano (or other suitable board)
- 1x Neo-6M GPS with antenna
- 1x 0.96" 128x64 I2C OLED LED Display (or 128x32)
- Jumper wires and/or small gauge wire
- I used Female/Female and Male/Female jumper wires to mock up
- I used ribbon cable for my final assembly wires
- You can use a cheap shield to practice soldering. Be sure to get one that isn't pre-built.
Supplies:- Solder (1mm or smaller flux/rosin core)
- Solder wick (for boo boos)
- Hot glue sticks
- Electrical tape
Tools:- Soldering iron
- Solder sucker (for boo boos)
- Hobby knife
- Side cutters
- Computer (for programming)
- USB cable (for programming)
- Arduino IDE
- The display uses the data and clock pins for whatever board you use. Look up the pin-out to make sure you use the right pins.
- My Nano boards all use the old boot loader so if you have problems uploading a sketch, check the board version.
- The GPS uses two digital data pins. Check the code for pin numbers if you change things.
- The GPS may take quite a while to find satellites the first time. My understanding is the battery has to charge and it has no data stored so it takes wayyyy more time. I would recommend doing the initial run outside or just leaving the board powered up and walking away till the next day. You'll know it has locked in when the green LED is blinking approx 1Hz.
- My understanding is that if GPS has a voltage regulator on the board you can power it with 5V but if not, 3.3V. Logic pins should tolerate 5V either way. Mine works fine with 5V but I did power it off 3.3 just in case because the Nano has the 3.3 pin.
- In my diagrams, orange is 3.3V power and Red is 5V power. Black is ground and the other colors are data.
I suggest building a mock-up to make sure everything works before you solder this because I actually couldn't get the GPS working with an ESP8266 board. No idea why. Everything worked as expected with the Nano board so that's what I used for the final version. If you're like me, the idea of having Wifi connectivity is pretty appealing, but you have been warned.
I'm not showing the final layout of my project because it actually suffers from some interference so I would suggest isolating the GPS a bit more than I did (I went screen on top, GPS in the middle, Arduino underneath). When I was testing I was in my basement and it found satellites fine, but the final version needs to be outside or it struggles. Fine for my purposes, but it's pretty impressive how much better it worked with the GPS off to the side of everything else. Of course, space comes into the equation too...
I'm not including any instructions on how to use the Arduino IDE, so you may need to figure that out... Download the program, install it, add the libraries needed, select your board type and you should be good to go, but all sorts of little do-das can bite you in the butt, so be prepared to do some Googling if all of this is new to you. Libraries come with examples so you can dig into those to figure out how things work.
Steps:- Connect the Arduino to your PC and upload the "Blink" sketch to make sure its working.
- Disconnect the Arduino.
- If you are doing a mock-up first (recommended), solder individual header pins in the holes used (3V3, A4(SDAta), A5(SCLock), 5V, GND, D5, D6). Individual pins so they are easy to remove for final assembly. If you have a dedicated board for mock-ups, you can skip this step.
- Solder individual header pins onto the GPS and Display boards.
- Wire the project as per the diagram. (I have a handy octopus connector for multiple grounds but you can use a breadboard or whatever works for you)
- GPS-TX -> D6
- GPS-RX -> D5
- GPS-GND -> GND
- GPS-VCC -> 3V3
- LED-GND -> GND
- LED-VCC -> 5V
- LED-SCL -> A5
- LED-DCL -> A4
- Check your connections, especially power.
- Paste the code into a new sketch and save it (Code is below).
- Plug in USB cable and upload the sketch.
- If it works, celebration time. Otherwise, woe is you. Debug time.
- Plot and scheme on how you want to assemble the project...
- Cut wires to the right length for your mad, mad design.
- Make your multi-ground wire for the final version.
- I used male jumper ends to create power and ground inputs that can be plugged into the balance plug on a LIPO.
- Remove the header pins and solder the wires permanently according to your layout.
- Check all connections, especially for shorted connections due to bad soldering.
- Plug into USB and test one more time. All good? Celebration time. Otherwise, debug time.
- Plug into a LIPO and test. All good? Celebration time! (For real) Otherwise, woe is you, more debug time.
/********************** Code Start **********************************/#include <TinyGPS++.h>#include <SoftwareSerial.h>#include <SPI.h>#include <Wire.h>#include <Adafruit_GFX.h>#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16#define LOGO_WIDTH 16static const unsigned char PROGMEM logo_bmp[] ={ B00000000, B11000000, B00000001, B11000000, B00000001, B11000000, B00000011, B11100000, B11110011, B11100000, B11111110, B11111000, B01111110, B11111111, B00110011, B10011111, B00011111, B11111100, B00001101, B01110000, B00011011, B10100000, B00111111, B11100000, B00111111, B11110000, B01111100, B11110000, B01110000, B01110000, B00000000, B00110000 };
// Choose two Arduino pins to use for software serialint RXPin = 5;int TXPin = 6;
int GPSBaud = 9600;
float maxSpeed = 1;float maxSpeedKph = 1;
float maxReset = 600000; // reset after this many cyclesfloat timeCount = 0;
// Create a TinyGPS++ objectTinyGPSPlus gps;
// Create a software serial port called "gpsSerial"SoftwareSerial gpsSerial(RXPin, TXPin);
void setup(){ // Start the Arduino hardware serial port at 9600 baud Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever }
// Show initial display buffer contents on the screen -- // the library initializes this with an Adafruit splash screen. display.display(); delay(2000); // Pause for 2 seconds
// Draw a single pixel in white display.drawPixel(10, 10, WHITE); delay(2000); // Pause for 2 seconds
// Clear the buffer display.clearDisplay();
// Start the software serial port at the GPS's default baud gpsSerial.begin(GPSBaud);}
void loop(){ if (timeCount < maxReset) { timeCount = timeCount + 1; } else { timeCount = 0; maxSpeed = 0; maxSpeedKph = 0; Serial.println("Time count reset"); } // This sketch displays information every time a new sentence is correctly encoded. while (gpsSerial.available() > 0) if (gps.encode(gpsSerial.read())) displayInfo();
// If 5000 milliseconds pass and there are no characters coming in // over the software serial port, show a "No GPS detected" error if (millis() > 5000 && gps.charsProcessed() < 10) { Serial.println("No GPS detected"); delay(1000); }}
void displayInfo(){ display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale display.setTextColor(WHITE); // Draw white text display.setCursor(0,0); // Start at top-left corner
if (gps.speed.isUpdated()) { if (gps.speed.mph() > maxSpeed) { maxSpeed = gps.speed.mph(); maxSpeedKph = gps.speed.kmph(); timeCount = 0; } else { if (timeCount > maxReset) { timeCount = 0; maxSpeed = 0; maxSpeedKph = 0; } } Serial.print("MPH= "); display.print("MPH= "); Serial.print(gps.speed.mph()); display.println(gps.speed.mph()); Serial.print("km/h= "); display.print("km/h= "); Serial.println(gps.speed.kmph()); display.println(gps.speed.kmph());
display.print("Max MPH= "); display.println(maxSpeed); display.print("Max KPH= "); display.println(maxSpeedKph); } else { Serial.println("Speed: Not Available"); Serial.print("TimeCount: "); Serial.println(timeCount); display.print("TimeCount: "); display.println(timeCount); display.println(""); display.print("Max MPH= "); display.println(maxSpeed); display.print("Max KPH= "); display.println(maxSpeedKph); } Serial.println(); Serial.println(); display.display(); delay(100);}/********************** Code End **********************************/
Wrench to drive or drive to wrench?
- 1x Arduino Nano (or other suitable board)
- 1x Neo-6M GPS with antenna
- 1x 0.96" 128x64 I2C OLED LED Display (or 128x32)
- Jumper wires and/or small gauge wire
- I used Female/Female and Male/Female jumper wires to mock up
- I used ribbon cable for my final assembly wires
- You can use a cheap shield to practice soldering. Be sure to get one that isn't pre-built.
Supplies:
- Solder (1mm or smaller flux/rosin core)
- Solder wick (for boo boos)
- Hot glue sticks
- Electrical tape
Tools:
- Soldering iron
- Solder sucker (for boo boos)
- Hobby knife
- Side cutters
- Computer (for programming)
- USB cable (for programming)
- Arduino IDE
- The display uses the data and clock pins for whatever board you use. Look up the pin-out to make sure you use the right pins.
- My Nano boards all use the old boot loader so if you have problems uploading a sketch, check the board version.
- The GPS uses two digital data pins. Check the code for pin numbers if you change things.
- The GPS may take quite a while to find satellites the first time. My understanding is the battery has to charge and it has no data stored so it takes wayyyy more time. I would recommend doing the initial run outside or just leaving the board powered up and walking away till the next day. You'll know it has locked in when the green LED is blinking approx 1Hz.
- My understanding is that if GPS has a voltage regulator on the board you can power it with 5V but if not, 3.3V. Logic pins should tolerate 5V either way. Mine works fine with 5V but I did power it off 3.3 just in case because the Nano has the 3.3 pin.
- In my diagrams, orange is 3.3V power and Red is 5V power. Black is ground and the other colors are data.
I suggest building a mock-up to make sure everything works before you solder this because I actually couldn't get the GPS working with an ESP8266 board. No idea why. Everything worked as expected with the Nano board so that's what I used for the final version. If you're like me, the idea of having Wifi connectivity is pretty appealing, but you have been warned.
- Connect the Arduino to your PC and upload the "Blink" sketch to make sure its working.
- Disconnect the Arduino.
- If you are doing a mock-up first (recommended), solder individual header pins in the holes used (3V3, A4(SDAta), A5(SCLock), 5V, GND, D5, D6). Individual pins so they are easy to remove for final assembly. If you have a dedicated board for mock-ups, you can skip this step.
- Solder individual header pins onto the GPS and Display boards.
- Wire the project as per the diagram. (I have a handy octopus connector for multiple grounds but you can use a breadboard or whatever works for you)
- GPS-TX -> D6
- GPS-RX -> D5
- GPS-GND -> GND
- GPS-VCC -> 3V3
- LED-GND -> GND
- LED-VCC -> 5V
- LED-SCL -> A5
- LED-DCL -> A4
- Check your connections, especially power.
- Paste the code into a new sketch and save it (Code is below).
- Plug in USB cable and upload the sketch.
- If it works, celebration time. Otherwise, woe is you. Debug time.
- Plot and scheme on how you want to assemble the project...
- Cut wires to the right length for your mad, mad design.
- Make your multi-ground wire for the final version.
- I used male jumper ends to create power and ground inputs that can be plugged into the balance plug on a LIPO.
- Remove the header pins and solder the wires permanently according to your layout.
- Check all connections, especially for shorted connections due to bad soldering.
- Plug into USB and test one more time. All good? Celebration time. Otherwise, debug time.
- Plug into a LIPO and test. All good? Celebration time! (For real) Otherwise, woe is you, more debug time.
/********************** Code Start **********************************/
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
B00000001, B11000000,
B00000001, B11000000,
B00000011, B11100000,
B11110011, B11100000,
B11111110, B11111000,
B01111110, B11111111,
B00110011, B10011111,
B00011111, B11111100,
B00001101, B01110000,
B00011011, B10100000,
B00111111, B11100000,
B00111111, B11110000,
B01111100, B11110000,
B01110000, B01110000,
B00000000, B00110000 };
// Choose two Arduino pins to use for software serial
int RXPin = 5;
int TXPin = 6;
int GPSBaud = 9600;
float maxSpeed = 1;
float maxSpeedKph = 1;
float maxReset = 600000; // reset after this many cycles
float timeCount = 0;
// Create a TinyGPS++ object
TinyGPSPlus gps;
// Create a software serial port called "gpsSerial"
SoftwareSerial gpsSerial(RXPin, TXPin);
void setup()
{
// Start the Arduino hardware serial port at 9600 baud
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// Draw a single pixel in white
display.drawPixel(10, 10, WHITE);
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
// Start the software serial port at the GPS's default baud
gpsSerial.begin(GPSBaud);
}
void loop()
{
if (timeCount < maxReset) {
timeCount = timeCount + 1;
} else {
timeCount = 0;
maxSpeed = 0;
maxSpeedKph = 0;
Serial.println("Time count reset");
}
// This sketch displays information every time a new sentence is correctly encoded.
while (gpsSerial.available() > 0)
if (gps.encode(gpsSerial.read()))
displayInfo();
// If 5000 milliseconds pass and there are no characters coming in
// over the software serial port, show a "No GPS detected" error
if (millis() > 5000 && gps.charsProcessed() < 10)
{
Serial.println("No GPS detected");
delay(1000);
}
}
void displayInfo()
{
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
if (gps.speed.isUpdated())
{
if (gps.speed.mph() > maxSpeed)
{
maxSpeed = gps.speed.mph();
maxSpeedKph = gps.speed.kmph();
timeCount = 0;
} else {
if (timeCount > maxReset) {
timeCount = 0;
maxSpeed = 0;
maxSpeedKph = 0;
}
}
Serial.print("MPH= ");
display.print("MPH= ");
Serial.print(gps.speed.mph());
display.println(gps.speed.mph());
Serial.print("km/h= ");
display.print("km/h= ");
Serial.println(gps.speed.kmph());
display.println(gps.speed.kmph());
display.print("Max MPH= ");
display.println(maxSpeed);
display.print("Max KPH= ");
display.println(maxSpeedKph);
} else {
Serial.println("Speed: Not Available");
Serial.print("TimeCount: ");
Serial.println(timeCount);
display.print("TimeCount: ");
display.println(timeCount);
display.println("");
display.print("Max MPH= ");
display.println(maxSpeed);
display.print("Max KPH= ");
display.println(maxSpeedKph);
}
Serial.println();
Serial.println();
display.display();
delay(100);
}
/********************** Code End **********************************/
Wrench to drive or drive to wrench?
Nice tutorial! Thanks very much for putting this up for us.
ReplyDeleteHi, thanks for sharing this project. I was looking for information to build a speedometer and found your work, very interesting and well explained, even for someone with no experience like me. I first tried it with a Nano and now I am working with a ATTiny85 which is really a challenge because of the limited memory. I had to use different libraries for the Oled Display and Wire and also had to limit the amount of info displayed but it is working. Now I am working on a 3D printed case to put everything together.
ReplyDeleteBy the way, I used a BN-220 GPS I already had which is smaller.
Deletehi i am beginner on Arduino , i hv problem downloading to Nano board ;
ReplyDeleteexit status 1
Error compiling for board Arduino Nano.