Skip navigation

Arduino Projects

3 Posts authored by: CharlesGantt

 

It’s no secret that lighting effects have been one of my major focuses in my career as a maker, and I wanted to share a pretty cool concept that I came up with a few years back. In this tutorial I will walk you through the process of creating a pair of accent lights that that utilizes the popular WS2812B LED modules also known as Neopixels, and an open source library called fastLED. Within this tutorial you will learn how to increment a variable with the push of a button, and how to utilize the colorPalette feature within the fastLED library.

 

Hardware

 

To complete this tutorial you will need the following items:

 

Software

 

To complete this tutorial you will need the following software. Click the links to open their download pages in a separate window.

 

Tools

 

You will also need the following tools.

    • Soldering Iron & Solder
    • Hot Glue Gun & Glue Sticks
    • Drill & Drill Bits
    • Scissors or Xacto Knife
    • Needle Nose Pliers

 

The Code

 

If you have used Adafruit’s Neopixels before, you have most likely used the Neopixel library as well. For this tutorial we are going to use a library called FastLED,  the library from which the Neopixel library was born. In reality you could create a very similar lighting effect with the Neopixel library, but the FastLED library comes with a pre-built example that will greatly speed up the code writing portion of this tutorial. Before you get started, make sure you have downloaded and installed the latest version of the Arduino IDE, and the FastLED library. If you are unsure as to how to install a library in Arduino, check out this document on Arduino.org.

 

I am going to explain this code section by section with a comment for each line that is important in hopes that it will make it easier to follow, but if you would like to see the full source code in its entirety, scroll down to the bottom of this section, or visit its repository on my Github. Now let’s get started!

 

Variable Declaration Section

 

In this section we need to include the libraries we will be using, define the variables and integers that our code will need to run properly.  There is also a line of code in this section that will let you reverse the direction in which the strip of NeoPixels will illuminate from. This is handy if your hanging lantern only has room to hide the Arduino in the top of its housing. This will let the LED strips still appear to flicker from the bottom to the top like a real candle would.

 

#include <FastLED.h>

#define LED_PIN     6         // the pin which attaches to the neopixel data pin
#define COLOR_ORDER GRB      // sets the color order in which the LEDs are designed for
#define CHIPSET     WS2812B  // the chipset that the neopixels use
#define NUM_LEDS    8      // how many leds are being adderessed

#define BRIGHTNESS  200         // sets the overall brightness of the leds
#define FRAMES_PER_SECOND 60    // how fast should the led animation render
#define COOLING  55      // defines the level at which the lighting effect fades before a new "flame" generates
#define SPARKING 120    // defines the rate of flicker which we will see from the flame animation

int switchPin = 2;              // switch is connected to pin 2
int val;                        // variable for reading the pin status
int buttonState;                // variable to hold the button state
int buttonPresses = 0;          // how many times the button has been pressed

bool gReverseDirection = false;  // set this to true if you need to invert the animation direction

CRGB leds[NUM_LEDS];     // sets up an array that we can manipulate to set/clear led data.

CRGBPalette16 currentPalette; // sets a variable for CRGBPalette16 which allows us to change this value later

 

Setup Section

 

This section is where we place the code that needs to be ran once before the loop when the arduino first powers up. Here we will initialize the the NeoPixel Strand and inform the library of the variables needed to help the Arduino send commands to the WS2812B chipset on each of the NeoPixel LEDs.

 

void setup() {
  delay(3000); // sets a delay to insure that everything has initialized before proceeding with the setup

  // Informs the library that a strand of NeoPixel's on pin 6 and those leds will use the led array "leds", and there are NUM_PIXELS (aka 8) of them.
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  
  FastLED.setBrightness( BRIGHTNESS );   // sets the brightness to the predetermined levels
  pinMode(switchPin, INPUT);    // Set the switch pin as input
  Serial.begin(9600);           // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state of the button

 

Loop Section

 

This section is where the code that needs to run in a loop is placed. The code you see below is where much of the magic happens. It takes advantage of the If / Else statement structure, and looks for the number of times the button has been pressed. If that number coincides with one of the numbers in the various if statements, then it will set the color palette being used to whichever color palette has been defined in that if statement. After the if/else statments, there is code that tells the Arduino to count and store the number of times the button was pushed, and once that number reaches 10, it will reset to 0 on the eleventh button push.

 

void loop()
{
  random16_add_entropy( random());  // Add entropy to random number generator; we use a lot of it.

   // The following if statements read the number of times the button has been pressed
   // and then sets the currentPalette variable to the defined CRGBPalette16 color palette.
   // for example: if the button has been pressed 1 time, set the palette to HeatColors. If
   // the button has been pressed 4 times, set the palette to a custom defined palette found in
   // that statement. The else statement at the end helps us return to the top of the if statments.

   if (buttonPresses == 0) {
    currentPalette = CRGBPalette16( CRGB::Black);
    }
  if (buttonPresses == 1) {
    currentPalette = HeatColors_p;
  }
  if (buttonPresses == 2) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua,  CRGB::White);
  }
  if (buttonPresses == 3) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Green, CRGB::GreenYellow,  CRGB::Yellow);
  }
  if (buttonPresses == 4) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Green, CRGB::Purple,  CRGB::Orange);
  }
  if (buttonPresses == 5) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Purple,  CRGB::Red);
  }
  if (buttonPresses == 6) {
    currentPalette = CRGBPalette16( CRGB::White);
  }
  if (buttonPresses == 7) {
    currentPalette = CRGBPalette16( CRGB::Yellow);
  }
  if (buttonPresses == 8) {
    currentPalette = CRGBPalette16( CRGB::Maroon);
  }
  if (buttonPresses == 9) {
    currentPalette = CRGBPalette16( CRGB::DarkBlue);
  }
  if (buttonPresses == 10) {
    static uint8_t hue = 0;
    hue++;
    CRGB darkcolor  = CHSV(hue,255,192); // pure hue, three-quarters brightness
    CRGB lightcolor = CHSV(hue,128,255); // half 'whitened', full brightness
    currentPalette = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White);
  }
  else  {
  }


  Fire2012WithPalette(); // calls the function defined below this loop & runs simulation frames, using palette colors

  FastLED.show(); // display this frame
  FastLED.delay(1000 / FRAMES_PER_SECOND); // sets a delay using the number 1000 devided by the predetermined frames per second.

  val = digitalRead(switchPin);      // read input value and store it in val
  if (val != buttonState) {          // the button state has changed!
    if (val == LOW) {                // check if the button is pressed
      buttonPresses++;               // increment the buttonPresses variable
      Serial.print("Button has been pressed ");  // prints the statement between "" in the serial terminal
      Serial.print(buttonPresses);              // reads the value stored in the buttonPresses variable.
      Serial.println(" times");                // prints the statement between "" in the serial terminal
    }
  }
  if (buttonPresses > 10){    // reads the number of button presses, and if that number is greater than 10 then
  buttonPresses = 0;         // reset the number of button presses to 0 
  }
  buttonState = val;                 // save the new state in our variable

}

 

Function Section

 

This section is not officially a real section found in the Arduino IDE's documentation, but I like to give it a name to help organize my code for tutorials. The code in this section defines one or more functions that can be called in the setup or loop sections of the code. Here we are defining a function which is the original fire2012 code which has been modified to take advantage of FastLED’s color palette features.

 

void Fire2012WithPalette()   // defines a new function
{
// Array of temperature readings at each simulation cell
  static byte heat[NUM_LEDS];

  // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }

    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= NUM_LEDS - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }
   
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < NUM_LEDS; j++) {
      // Scale the heat value from 0-255 down to 0-240
      // for best results with color palettes.
      byte colorindex = scale8( heat[j], 248);
      leds[j] = ColorFromPalette( currentPalette, colorindex);
    }
}

 

I have pasted the full code below, but you can also download it from my Github (https://github.com/CharlesJGantt/Neopixel-Realistic-Flickering-Candle-With-Changing-Color-Palette), or even create a fork if you would like to add more functionality on your own.

 

// Fire2012WithPaletteCycle
// Version 0.12 Revision 3


// Portions of this code originated in the FastLED library, and was
// modified & amended by Charles Gantt on 7/1/2017. Visit Charles' website
// at http://www.themakersworkbench.com


// Origial Fire2012 Code by:
// Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY


// This code is the same fire simulation as the original "Fire2012",
// but each heat cell's temperature is translated to color through a FastLED
// programmable color palette, instead of through the "HeatColor(...)" function
// with additional custom defined color palettes.
// The different palettes can be cycled through by a push of a button
// connected to pin 2, and 5V.


#include <FastLED.h>


#define LED_PIN     6          // the pin which attaches to the neopixel data pin
#define COLOR_ORDER GRB       // sets the color order in which the LEDs are designed for
#define CHIPSET     WS2812B  // the chipset that the neopixels use
#define NUM_LEDS    12       // how many leds are being adderessed


#define BRIGHTNESS  200        // sets the overall brightness of the leds
#define FRAMES_PER_SECOND 60   // how fast should the led animation render
#define COOLING  55           // defines the level at which the lighting effect fades before a new "flame" generates
#define SPARKING 120          // defines the rate of flicker which we will see from the flame animation


int switchPin = 2;              // switch is connected to pin 2
int val;                        // variable for reading the pin status
int buttonState;                // variable to hold the button state
int buttonPresses = 0;          // how many times the button has been pressed


bool gReverseDirection = false;  // set this to true if you need to invert the animation direction


CRGB leds[NUM_LEDS];     // sets up an array that we can manipulate to set/clear led data.


CRGBPalette16 currentPalette; // sets a variable for CRGBPalette16 which allows us to change this value later


void setup() {
  delay(3000); // sets a delay to insure that everything has initalized before proceeding with the setup


  // Informs the library that a strand of NEOPIXEL's on pin 6 and those leds will use the led array "leds", and there are NUM_PIXELS (aka 8) of them.
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );


  FastLED.setBrightness( BRIGHTNESS );   // sets the brightness to the predetermined levels
  pinMode(switchPin, INPUT);    // Set the switch pin as input
  Serial.begin(9600);           // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state of the button
}


void loop()
{
  random16_add_entropy( random());  // Add entropy to random number generator; we use a lot of it.


  // The following if statements read the number of times the button has been pressed
  // and then sets the currentPalette variable to the defined CRGBPalette16 color palette.
  // for example: if the button has been pressed 1 time, set the palette to HeatColors. If
  // the button has been pressed 4 times, set the palette to a custom defined palette found in
  // that statement. The else statement at the end helps us return to the top of the if statments.


  if (buttonPresses == 0) {
    currentPalette = CRGBPalette16( CRGB::Black);
  }
  if (buttonPresses == 1) {
    currentPalette = HeatColors_p;
  }
  if (buttonPresses == 2) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua,  CRGB::White);
  }
  if (buttonPresses == 3) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Green, CRGB::GreenYellow,  CRGB::Yellow);
  }
  if (buttonPresses == 4) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Green, CRGB::Purple,  CRGB::Orange);
  }
  if (buttonPresses == 5) {
    currentPalette = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Purple,  CRGB::Red);
  }
  if (buttonPresses == 6) {
    currentPalette = CRGBPalette16( CRGB::White);
  }
  if (buttonPresses == 7) {
    currentPalette = CRGBPalette16( CRGB::Yellow);
  }
  if (buttonPresses == 8) {
    currentPalette = CRGBPalette16( CRGB::Maroon);
  }
  if (buttonPresses == 9) {
    currentPalette = CRGBPalette16( CRGB::DarkBlue);
  }
  if (buttonPresses == 10) {
    static uint8_t hue = 0;
    hue++;
    CRGB darkcolor  = CHSV(hue, 255, 192); // pure hue, three-quarters brightness
    CRGB lightcolor = CHSV(hue, 128, 255); // half 'whitened', full brightness
    currentPalette = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White);
  }
  else  {
  }




  Fire2012WithPalette(); // calls the function defined below this loop & runs simulation frames, using palette colors


  FastLED.show(); // display this frame
  FastLED.delay(1000 / FRAMES_PER_SECOND); // sets a delay using the number 1000 devided by the predetermined frames per second.


  val = digitalRead(switchPin);      // read input value and store it in val
  if (val != buttonState) {          // the button state has changed!
    if (val == LOW) {                // check if the button is pressed
      buttonPresses++;               // increment the buttonPresses variable
      Serial.print("Button has been pressed ");  // prints the statement between "" in the serial terminal
      Serial.print(buttonPresses);              // reads the value stored in the buttonPresses variable.
      Serial.println(" times");                // prints the statement between "" in the serial terminal
    }
  }
  if (buttonPresses > 10) {   // reads the number of button presses, and if that number is greater than 10 then
    buttonPresses = 0;         // reset the number of button presses to 0
  }
  buttonState = val;                 // save the new state in our variable


}


void Fire2012WithPalette()   // defines a new function
{
  // Array of temperature readings at each simulation cell
  static byte heat[NUM_LEDS];


  // Step 1.  Cool down every cell a little
  for ( int i = 0; i < NUM_LEDS; i++) {
    heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
  }


  // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  for ( int k = NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
  }


  // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
  if ( random8() < SPARKING ) {
    int y = random8(7);
    heat[y] = qadd8( heat[y], random8(160, 255) );
  }


  // Step 4.  Map from heat cells to LED colors
  for ( int j = 0; j < NUM_LEDS; j++) {
    // Scale the heat value from 0-255 down to 0-240
    // for best results with color palettes.
    byte colorindex = scale8( heat[j], 248);
    leds[j] = ColorFromPalette( currentPalette, colorindex);
  }
}

 

Assembly

 

The assembly process is not very hard, but it is fairly time consuming. It involves the use of a soldering iron, high speed drill, and a hot glue gun. If you are unsure as to how these tools operate, please read their instruction manuals before continuing along with this tutorial. Additionally, remember to wear safety glasses, and hearing protection when using power tools.

 

IMG_1065.jpg

 

Before we get started let’s take a moment to inventory the parts that we will need to complete this tutorial. You should have the following items:

    • 2X Votive Lantern
    • 2X Arduino Nano
    • 4X Neopixel Sticks
    • 2X Tall Tactile Buttons
    • 2X 10k Resistors
    • 2X USB A - USB Mini Cables
    • Hookup Wire
    • Soldering Iron & Solder
    • Glass Frosting Spray
    • Vellum or Tracing Paper
    • Hot Glue Gun & Glue Sticks
    • Black Craft Foam

 

IMG_1070.jpg

 

For the purposes of this tutorial, I am going to be building one of the lanterns. I will be making a build video with the second lantern. I picked this lantern up at a local home decore store, but I have seen them for sale on Ebay, Amazon, and a lot of other online retailers. You do not have to use this specific lantern, and any votive candle lantern, wall sconce, or even a more traditional hurricane lantern will work.

 

IMG_1073.jpg

 

To get started, we need to remove the glass panes and prep them for the frosting spray. For this particular lantern and most others like it, each glass pane is held on by four small metal tabs, as seen in the image above, that will need to be folded back to allow the pane to be removed. The glass pane’s are usually quite sharp, with their edges chipped from rough handling at the factory, so be careful, and consider wearing gloves when removing and handling these glass panes.

 

IMG_1077.jpg

 

With the glass panes removed, you can see how sharp and jagged their edges are. Now take the panes outside, or somewhere that is very well ventilated as the frosting spray produces noxious fumes when drying.

 

IMG_1078.jpg

 

To ensure that the frosting spray achieves good adhesion the glass needs to be free of any oily residue from handling it. I have found that using 91% isopropyl alcohol is best for cleaning the glass. I just wipe the glass with an alcohol moistened paper towel until the fingerprints disappear, then wait 10 minutes or so to ensure that all of the alcohol has evaporated.

 

IMG_1080.jpg

 

With the glass clean, I held the frosting spray about 10-inches away from the panes and sprayed a nice wet coat onto the glass. The instructions said to wait about 7 minutes and apply another wet coat. Then I waited for about 10 minutes and added another coat, this time about 14-inches from the surface and lighter than the last two. I repeated this step three more times until I was happy with the opacity of the panes.

 

IMG_1146.jpg IMG_1148.jpg

 

With the glass panes dry, I set them aside and started work on the electronics. Here you can see how opaque the frosting spray made the glass. The frosting spray works well, but we will still have to diffuse the light even more and we will discuss that more later. When setting the panes aside, do not stack them, or place anything on top of them as the frosting spray is pretty fragile and will scratch very easily.

 

IMG_1090.jpg

 

For this project I am using some 4-inch strips that I cut from a 5-meter roll of 140 pixel per meter NeoPixels that I had leftover from a previous project. The Neopixel sticks that I link to at the beginning of this tutorial work much better for this type of project, but unfortunately, my order was delayed and I did not receive the sticks in time for this tutorial.

 

IMG_1094.jpg

 

Before we get started wiring things together, the official Arduino Nano V3  comes with its header pins preassembled. I prefer to get the boards unassembled, but that is only possible with the off-brand variants of the nano. Because of this, the SPI header makes the nano a little too tall for our project, so I need to remove the six pin header on top of the board.

 

IMG_1100.jpg

 

To do remove these pins, I clamp the board in my small bench vice, and use my soldering iron to heat each pin’s solder joint while pulling on that pin with a pair of small needle nose pliers. Once the joint reaches molten temperatures, the pins pull right out. When doing this yourself, remember to not clamp the board too tight, as you could cause it to flex and break loose the surface mount connections of the small ICs and passive components.

 

IMG_1101.jpg

 

Here you can see that all of the SPI header pins have been removed, and nothing but small solder balls are left on the pads. I should have done this to the entire board as doing so would have provided me with a cleaner install. When I originally designed this project several years ago, I actually used Arduino Pro Mini boards which come with the header pins unsoldered. Eventually I developed my own purpose built PCB for this project, but that board was proprietary to the company I used to own, so unfortunately, I can not share it here. I could design a new board if there is enough interest though.

 

IMG_1106.jpg IMG_1109.jpg

 

While we are modifying the Arduino Nano to better fit our project, we need to cut some small strips of black craft foam which we will hot glue to the Nano’s surface to insulate it from the metal bottom of the lantern. Since the USB port sits several millimeters proud of the PCB’s surface, I cut a smaller piece of foam to help level things out for the larger piece which will cover the full surface.

 

IMG_1113.jpg IMG_1115.jpg

 

Here you can see how I glue the foam to the Nano to ensure that the final result is nice and flat. It is important to note that you should not cover the Nano’s reset button with hot glue, and make sure to not depress it when pressing the foam into the glue. If you accidentally get glue on the button, just let it dry and remove it with your fingers or the needle nose pliers. Also note that I used two very small drops of glue on each end of the small strip of foam for this very reason. Once the glue has dried, try depressing the button. It should click, which is an indication that it is not stuck with glue.

 

2017-07-12 03_46_23-Start.png

 

Wiring up the hardware is fairly straightforward. Following the Fritzing diagram above make the following connections. It’s important to wire the Neopixel sticks exactly the same so that their animations sync up later on.

 

    1. Arduino Nano Digital Pin 2 to Button Pin  1
    2. Arduino Nano Digital Pin 2 to Resistor Pin 1
    3. Resistor Pin 2 to Arduino Nano GND
    4. Button Pin 3 to Arduino Nano 5V
    5. Neopixel Stick 1 5V to Arduino Nano 5V
    6. Neopixel Stick 1 GND to Arduino Nano GND
    7. Neopixel Stick 1 Data In to Arduino Nano Digital Pin 6
    8. Neopixel Stick 2 5V to Arduino Nano 5V
    9. Neopixel Stick 2 GND to Arduino Nano GND
    10. Neopixel Stick 2 Data In to Arduino Nano Digital Pin 6

 

 

IMG_1122.jpg

 

Let's begin by focusing on the Neopixel sticks / strips. Since I am using flexible strips that have been cut into 4-inch long pieces, I need to add something rigid to them to ensure they stand up nice and proud later in the build. I simply use a popsicle stick that I cut with an x-acto knife to be slightly thinner and shorter than the strips. Typically, the only glue that will bond to the strips is something super tacky like E6000, which just so happens to be my third favorite glue, and something I stock in my workshop by the half dozen. If you are wondering, Cyanoacrylate (CA) and hot glue are my other two favorite types of glue.

 

IMG_1123.jpg IMG_1125.jpg

 

I spread a small thin line of the glue across each strip, and then sandwiched the popsicle stick between the two strips. E6000 is quite the potent glue, and it would be advisable to have a small fan running near your workbench to avoid over inhalation of its fumes.

 

IMG_1127.jpg IMG_1129.jpg

 

To ensure that the strips stayed oriented on the popsicle stick, I used a pair of small zip ties to secure them to the stick. Then I placed the sandwich between two scrap pieces of wood, and used small clamps to apply gentle pressure until the glue cured about an hour later.

 

IMG_1132.jpg

 

Here you can see a closeup of the stick once it had cured and was ready to solder some wires to. I decided to leave the zip ties on for added insurance.

 

IMG_1133.jpg

 

I forgot to mention earlier that you should orient both strips so that their Data In pins are on the same end of the stick. This makes wiring up the Neopixels a little more difficult, but it is necessary to achieve the effect we are going for.

 

IMG_1134.jpg IMG_1135.jpg

IMG_1137.jpg IMG_1142.jpg

 

I pre tinned the hookup wires before soldering them to the Neopixels. In the second photo (click to enlarge) you can see how I hook the strips together. Since the strips are mirrored from each other, I need to cross over the 5V and GND lines, but the Data In pin remains in the middle. This process is much easier with the Neopixel sticks than it is with these high density strips which have very small solder pads.

 

IMG_1143.jpg

 

Before we solder our wires to the Arduino Nano, cut a small passageway into the top of the foam. This will allow us to pass the Neopixel’s wiring under the Arduino when installing the electronics.

 

IMG_1116.jpg

 

In an attempt to make the install even more low profile, I decided to bend over the pins I would be using, which would allow me to lay the wires down instead of having them stick up and possibly create shadows. As I mentioned earlier, this was a mistake, and I should have desoldered all of the pins from the board, and soldered the wiring directly to the pads. This would have resulted in a much cleaner install, but I guess you live and learn, and in reality, no one will see the mess that is to come once the lantern is finished.

 

IMG_1144.jpg

 

With the pins bent over, it's time to solder the Neopixel’s wires to the Arduino Nano. Refer to the diagram above if you forgot which pins each wire connects to. You can see here how messy this looks, but it's functional, and will not be visible in the completed project, so it's not that big of a deal honestly.

 

IMG_1158.jpg

 

Now it’s time to wire up the button. Notice that I hold it in a pair of helping hands. This makes things easier as one alligator clip can hold the button while the other holds the wire in place. If you are worried about mixing up the pinout on the button, as long as you solder one wire to a pin, and then solder the other wire to the opposite corner, the orientation will be correct.

 

IMG_1165.jpg

 

Here you can see the orientation of the wires on the button. I would leave a good three to four inches of wire length to help make installation easier.  You can also see that I added a layer of black foam to the other side of the Arduino Nano as well. I did this to cover up the mess that you will see in the next photo.

 

IMG_1162.jpg

 

With the button soldered in place, I needed to add the resistor Digital Pin 2 and GND on the Arduino. The button press counting code will not function correctly unless  this pull-down resistor is in place. If you wanted a cleaner layout, you could utilize the 5V and GND pins on the SPI header that we removed earlier. With the electronics finished, this is the time to upload the code to the Arduino Nano. I am not covering that part of the project in this tutorial because if you do not know how to do that, you need to head over to the Arduino website, and walk through their getting started guide.

 

  IMG_1145.jpg IMG_1167.jpg

IMG_1168.jpg IMG_1169.jpg

 

Now that the electronics are finished, it's time to reinstall the glass panes in the lantern body. But before we do that, we need to drill a 7/16-inch hole in the top of the lantern as close to its hanger loop as possible. This will allow us to run the USB cable down into the lantern to provide power to the Arduino Nano. You will also need to touch up the paint on the lantern as the drill will cause some minor scratches and the hole’s rim will need paint.

 

IMG_1154.jpg

IMG_1156.jpg IMG_1157.jpg

 

This is also the time to drill the hole in the bottom for the button. In my case a 3/16-inch drill bit was needed. I like to use a small piece of sandpaper to clean the bur from the hole, and to scuff the surface which will make the hot glue we will use to secure the button stick better.

 

IMG_1150.jpg

 

Installing the panes is as simple as reversing the steps you took to remove them. This time you need to be very careful as to not scratch the frosted coating on the lanterns sharp edges. It’s also worth noting that if you have sweaty hands, this would be a good time to wash them and wear gloves, as the oils from your skin will visibly stain the frosted coating.

 

IMG_1152.jpg

 

Here you can see the difference in the frosted glass versus the clear glass. The clear glass is nice when using an actual candle, but since we are using LEDs it must be frosted to hide the electronics. I actually prefer the frosted look myself. This would be a good time to point out that I chose these lanterns because of the one inch tall wall at the bottom. This wall is tall enough to hide the shadow that will be cast by the LEDs when illuminated. Keep this in mind when choosing your lantern. Alternatively you can hide the electronics in the top of the lantern and uncomment the line near the top of the code that will reverse the led animation’s direction of flow, which will allow you to hang the Neopixel sticks from the top, and it still look like the flame is flickering from bottom to top.

 

IMG_1170.jpg IMG_1171.jpg

 

Now let's begin installing the electronics! The first thing we need to attach is the button, and that’s quite simple to do! Place the button in the small hole, and then cover it in a nice thick layer of hot glue, then hold in place using the wiring until the glue solidifies. Try your best to not get any glue between its mandrel and the button body itself as this could prevent it from working.

 

IMG_1173.jpg

 

Now apply a small strip of hot glue to the corner closest to the back of the lantern in relation to the middle of the door. Then press the USB cable into the hot glue making sure to leave just enough room to connect it to the Arduino Nano.

 

IMG_1174.jpg

 

With the USB Cable in place, its time to use two small dabs of hot glue to secure the Arduino nano in place. Plug the USB cable in before doing this. If you are worried about the cable pulling out through the top, you can zip tie a ½-inch steel nut to it in top of the lantern. I have found the hot glue to be sufficient though.

 

IMG_1182.jpg

 

Installing the Neopixel sticks is a little bit tougher than the other components and it requires a steady hand. Once the stick has been placed as close to the center as possible, I use my glue gun to apply hot glue from the first pixel down. I make sure that some of this glue actually coats the first pixel, which gives it a bit more rigidity. Once this first layer of glue is solidified, I add another layer making even more contact with the stick. Note that I did not include a photo of the surface of the lantern under the stick. I scuffed it up with 80-grit sandpaper before applying the glue. After 2 or 3 layers, the stick should be stuck firmly into place, and very rigid. It is important to ensure that no metal from the solder connections are touching the metal surface, and you can add a thin layer of hot glue to the surface before gluing the stick in place if you are worried about this.

 

IMG_1183.jpg

 

Now we need to take the velum paper and create a small cylinder shaped diffuser. This is necessary because the frosting on the glass is not enough to fully diffuse the circular light pattern the LEDs project. Since the stick is about 4-inches tall, I made my diffuser about 5-inches tall, and secured its ends together with a piece of double sided tape. Glue will work fine here as well, but you want the thinnest layer possible to prevent a dark spot in the diffuser.

 

IMG_1186.jpg

 

Since the blob of hot glue holding the Neopixel stick up is so large, I had to cut out some of the diffuser on the bottom to make it fit. I got it as close as possible, and even though a few gaps were showing, I knew that it would be pointed towards the back of the lantern and not visible from the front.

 

IMG_1188.jpg

 

To secure the diffuser in place, I used a few dabs of hot glue. With this in place, we simply need to hook up our USB cable to a power source and things are finished. I did notice that the lantern’s brightness was a bit high, so I plugged the USB cable into my PC and adjusted the brightness to about 125 by changing the code near the beginning of the code.

 

 

Conclusion

 

 

Overall I am quite pleased with the end result, but I am still bothered by how messy the electronics connections to the Arduino were. I decided to desolder all of the pins in the second lantern to make things a bit cleaner. Since I used 10-foot USB cables, I can hang these lanterns almost anywhere and still have enough cable to connect them to a wall outlet, and since they are USB powered, I can use a USB battery pack to power them on excursions like camping trips, over by our fire pit in the backyard, or even in Halloween decorations in our front yard this october.

 

That is going to wrap up this tutorial, and I want to thank you for taking the time to read through it. This project was quite fun, and is something you can accomplish in an afternoon by yourself or with others, and still have a project that is quite impressive when finished and the lights are turned off. I would love to hear everyone’s feedback on this project, so please feel free to leave a comment below.

Every second and fourth Thursday of each month, I teach a class at my local makerspace, theClubhou.se that centers on STEM Education. Youth between the ages of 8 and 17 attend the class and we strive to teach them how to create fun projects that will hopefully inspire them to embark onto larger projects in the future.

 

During our November and December sessions this past year, we decided that we would teach the YoungMakers how to index strands of LED Christmas lights using nothing but an Arduino, a few Relays, and some LEDs as a proof of concept. After some research, we decided that the best route to take would be to use a program called Vixen Lights to simplify the sequencing process as much as possible. This was necessary because we only had a total of about six-hours spread out over 2 months to complete everything.

 

While I have documented the process we took for the curriculum we wrote around this project, I have yet to take the time to document it online. That is the purpose of this posting and by the end of this post I hope you will be able to use Vixen Lights to sequence some LEDs of your own. Below is a list of materials you will need to complete this tutorial, and almost everything can be bought from Newark.com. You can find all of the necessary code, and related files in my GitHub Repository for this project.

 

 

So to kick this off, we need to plug our LEDs into the breadboard. To simplify things, I like to plug the cathode of each LED into the GND rail of the breadboard, and place the anode into the five-position strip that is in line with the GND hole you plugged the cathode into.  This will allow us to use a jumper wire to connect the anode to the PWM pins on the Arduino, and let us only utilize a single GND port on the Arduino as well.

 

IMG_3306.jpg

 

Make sure to space the LEDs far enough apart to ensure that the ping pong balls will have enough room to fit. To get an idea of how much room you will need, six ping pong balls will take up the entire surface area of a standard breadboard. Once you have all of your LEDs in place, push the ping pong balls onto the 5mm LEDs.

 

IMG_3292.jpg

 

With the LEDs now in position, we can move on to wiring everything up. Starting from the left, attach the first LED anode to digital pin 11 on the Arduino. Follow this up by attaching the next LED’s anode to digital pin 10. The third LED attaches to digital pin 9, with the fourth, fifth and sixth attaching to digital pins 6, 5, and 3 respectively.

 

IMG_3294.jpg

 

Once everything is attached, we can move on to importing and adjusting the code for this project to our specific needs. Head over to my Github repository to download all of the files used in this tutorial, or you can copy and paste the code I have listed below.

 

IMG_3295.jpg

 

Base Code (Needs Modifying)

/*
The purpose of this code is to allow the Arduino to use the
Generic serial output of vixen lights to control 5 channels of LEDs.
Author: Matthew Strange
Created: 14 October 2010

*/

// Output
int Chan1 = 5; // green LED, connected to digital pin 5
int Chan2 = 6; // white LED, connected to digital pin 6
int Chan3 = 9; // red LED, connected to digital pin 9
int Chan4 = 10; // green LED, connected to digital pin 10
int Chan5 = 11; // red LED, connected to digital pin 11

int i = 0; // Loop counter
int incomingByte[8]; // array to store the 7 values from the serial port

//setup the pins/ inputs & outputs
void setup()
{
  Serial.begin(9600); // set up Serial at 9600 bps

  pinMode(Chan1, OUTPUT); // sets the pins as output
  pinMode(Chan2, OUTPUT);
  pinMode(Chan3, OUTPUT);
  pinMode(Chan4, OUTPUT);
  pinMode(Chan5, OUTPUT);
}

void loop()
{ // 7 channels are coming in to the Arduino
  if (Serial.available() >= 5) {
  // read the oldest byte in the serial buffer:
  for (int i=0; i<8; i++) {
  // read each byte
  incomingByte[i] = Serial.read();
  }

  analogWrite(Chan1, incomingByte[0]); // Write current values to LED pins
  analogWrite(Chan2, incomingByte[1]); // Write current values to LED pins
  analogWrite(Chan3, incomingByte[2]); // Write current values to LED pins
  analogWrite(Chan4, incomingByte[3]); // Write current values to LED pins
  analogWrite(Chan5, incomingByte[4]); // Write current values to LED pins
  }
}




 

With the code now open in the Arduino IDE, we need to make some adjustments to it to better match our setup.  The first thing we need to do is adjust the output to follow the schematic on how we hooked up our LEDs on the breadboard. Edit the output to match the code below. What we are doing is telling the Arduino that channel 1 on the breadboard equals pin 11 and so on. This is important because Vixen will tell the Arduino later which channel to turn on during the sequence.

 

Adjust Output Pin Definitions

// Output
int Chan1 = 11; // green LED, connected to digital pin 11
int Chan2 = 10; // white LED, connected to digital pin 10
int Chan3 = 9; // red LED, connected to digital pin 9
int Chan4 = 6; // green LED, connected to digital pin 6
int Chan5 = 5; // red LED, connected to digital pin 5
int Chan6 = 3; // red LED, connected to digital pin 3




 

Up next we need to adjust the set up to match the settings of our output. Again make the code in your sketch match the code below. Basically this tells the Arduino that all six channels defined above should be treated as outputs.

 

Adjust Setup Code

void setup()
{
  Serial.begin(9600); // set up Serial at 9600 bps

  pinMode(Chan1, OUTPUT); // sets the pins as output
  pinMode(Chan2, OUTPUT);
  pinMode(Chan3, OUTPUT);
  pinMode(Chan4, OUTPUT);
  pinMode(Chan5, OUTPUT);
  pinMode(Chan6, OUTPUT);
}





Vixen will utilize the serial communication port to tell our Arduino which channels to turn on and which to turn off and as such, we need to adjust the number of channels that are coming into the Arduino from the serial port.  The original code specifies 5 channels, but since we are doing 6 channels, we need to adjust this to match.  As we did before, make your code match the code I have pasted below.

 

Adjust Loop Code Part 1

void loop()
{ // 6 channels are coming in to the Arduino
  if (Serial.available() >= 6) {
  // read the oldest byte in the serial buffer:
  for (int i=0; i<7; i++) {
  // read each byte
  incomingByte[i] = Serial.read();
  }




 

Now we are almost finished. We now need to add once analogWrite line to the last part of our code. Since the original code was written for 5 channels, we just need to add one more channel to the loop. The correct code is pasted below. Match your code to this.

 

Adjust Loop Code Part 2

  analogWrite(Chan1, incomingByte[0]); // Write current values to LED pins
  analogWrite(Chan2, incomingByte[1]); // Write current values to LED pins
  analogWrite(Chan3, incomingByte[2]); // Write current values to LED pins
  analogWrite(Chan4, incomingByte[3]); // Write current values to LED pins
  analogWrite(Chan5, incomingByte[4]); // Write current values to LED pins
  analogWrite(Chan6, incomingByte[5]); // Write current values to LED pins




 

With that complete, your code should now look like this. If you see any mistakes, please go back and correct them before continuing on with this tutorial.

 

Final Code

/*
The purpose of this code is to allow the Arduino to use the
generic serial output of vixen lights to control 5 channels of LEDs.
Author: Matthew Strange
Created: 14 October 2010
Adapted for 6-PWM-Channels by Charles Gantt on November 14th 2013.

*/

// Output
int Chan1 = 11; // green LED, connected to digital pin 11
int Chan2 = 10; // white LED, connected to digital pin 10
int Chan3 = 9; // red LED, connected to digital pin 9
int Chan4 = 6; // green LED, connected to digital pin 6
int Chan5 = 5; // red LED, connected to digital pin 5
int Chan6 = 3; // red LED, connected to digital pin 3

int i = 0; // Loop counter
int incomingByte[8]; // array to store the 7 values from the serial port

//setup the pins/ inputs & outputs
void setup()
{
  Serial.begin(9600); // set up Serial at 9600 bps

  pinMode(Chan1, OUTPUT); // sets the pins as output
  pinMode(Chan2, OUTPUT);
  pinMode(Chan3, OUTPUT);
  pinMode(Chan4, OUTPUT);
  pinMode(Chan5, OUTPUT);
  pinMode(Chan6, OUTPUT);
}

void loop()
{ // 7 channels are coming in to the Arduino
  if (Serial.available() >= 6) {
  // read the oldest byte in the serial buffer:
  for (int i=0; i<7; i++) {
  // read each byte
  incomingByte[i] = Serial.read();
  }

  analogWrite(Chan1, incomingByte[0]); // Write current values to LED pins
  analogWrite(Chan2, incomingByte[1]); // Write current values to LED pins
  analogWrite(Chan3, incomingByte[2]); // Write current values to LED pins
  analogWrite(Chan4, incomingByte[3]); // Write current values to LED pins
  analogWrite(Chan5, incomingByte[4]); // Write current values to LED pins
  analogWrite(Chan6, incomingByte[5]); // Write current values to LED pins
  }
}




 

1.jpg

Once the code is complete, its time to verify and upload the code to your Arduino. You can do this by simply clicking the “Play” button which is second from the left at the top of the Arduino window. If everything uploads correctly and no errors arose, it is time to move onto installing and configuring Vixen. Head over to VixenLights.com and grab the latest version of Vixen Lights 2.

 

2.jpg

 

Installing Vixen is fairly simple as it comes already unpacked into its directory. Make sure to place it somewhere you will remember to find it such as the desktop, or in your documents folder. To begin, launch Vixen and let’s set up a sequence. This is a very important step and very close attention should be paid and every step should be followed exactly for things to work properly. To start, click on the sequence tab and navigate to New Event Sequence > Vixen Standard Sequence.

 

3.jpg

 

Once you click on Vixen Standard Sequence the New Sequence Wizard will pop up and prompt you with a few configurable options. The first major thing you will need to set up is the Event Period. This value determines the period of time that each LED will stay lit. You can adjust this time down to 25-miliseconds and up as high as 1 second. For the purpose of this tutorial, we are going to keep it simple at 100-miliseconds, giving us 10 events per channel, per second.

 

4.jpg

 

Up next is where most of the configuration happens. To make things simple, we are going to create a profile that we can save and re-use in the future.  Click Profile Manager and then click the Add icon that is highlighted in the image above.

 

5.jpg

 

Give the new profile a name and then click OK. At this point the Edit Profile screen will pop up, and you need to add six channels.

 

6.jpg

 

Once the six channels have been added click the Output Plugins button and you will see the Sequence Plugin Mapping configuration window pop up. Under Available Plugins, select Generic Serial, and click the Use button. Set the channels from 1 to 6, and click the Plugin Setup button.

 

7.jpg

 

Set the Com Port to 4 (also make sure your Arduino is set to Com Port 4) and set the Baud Rate to 9600 and then click OK.

 

8.jpg

 

The Profile window will once again pop up, and you will need to select the profile you just created, and then click next. Since we are not adding any audio to this sequence, click next on the Audio and Event Patterns window.

 

9.jpg

 

Finally we are presented with the Sequence Time configuration window. For this tutorial I have set it to 1-minute, but you can set this to any length you desire. Once you have your time set, click the Create It button and you will be prompted to save this sequence. Give it a name, and click Save.

 

16.jpg

 

The PC will take a few moments to process and create your sequence, but when finished, a sequence configuration window will open and the sequence will be represented in a timeline that is sectioned into a grid-like pattern. Each one of these little blocks represents a single event period, and can be used to turn that channel on, off, or set a brightness value.

 

17.jpg

 

To keep things organized and easy to configure we need to assign a color to each channel. To do this we must right click on the channel list, and select Channel Properties.

 

18.jpg19.jpg

 

When you click Channel Properties, a small window will pop up and will have several configurable options. For the purpose of this tutorial, we will just be changing each channels color. Set the first one to red, and then click the channel dropdown and select channel two.

20.jpg


Continue doing this until each channel has a unique color. I color coded the channels in my sequence to reflect the LED colors on my breadboard.

 

21.jpg

 

So let’s begin building the sequence. Click and highlight the event periods you wish to enable, and then click the solid square button in the control bar as seen highlighted in the image above. You can also enable the event periods by pressing the spacebar. Play around with the rest of the buttons on that row for some cool effects. I don’t want to dive too deep into building advanced sequences as that is an entire article on its own, and this tutorial is already long enough.

 

 

Now we can run the sequence. Make sure the Arduino is plugged in and is set to Com Port 4 in the Device Manager. If everything is correct, click the play button located at the top left of the Vixen Sequence. You should see the LEDs begin to light up and follow the sequence you just built. If you get a router / com port error, simply save your sequence, close Vixen and Arduino and reopen Vixen and load your sequence. Things should work now.

 

You can adapt this same setup to trigger relays to control 110v circuits that can activate LED Christmas Lights, Halloween Lighting, or pretty much anything that runs on mains voltage. Below is a video of a 4-christmas tree setup I built with my Makerspace that sequenced 32 channels of LED Christmas Lights.

 

I recently picked up a new hobby that involves custom building muti-rotor helicopters and during this journey I have found a strong desire to map the flights of my quad copter. Unfortunately, a full sized handheld GPS is much too heavy to add to the payload of the quad copter and still retain respectable flight times. So I began searching for a small, lightweight GPS data logging solution that I could build myself with readily available, off the shelf components.

 

After a few days of research I settled on an Arduino and GPS shield combo with a cusom 3D printed case. Around the time I ordered the hardware I would need, a company called TinyCircuits contacted me and asked me if I would be interested in reviewing their products, and writing a few tutorials around their Tinyduino line of micro-development boards. I agreed and a few days later I had the company’s entire Tinyduino line sitting on my workbench.

 

1.jpg

 

Included in this kit was a fully functional micro-GPS shield that was not much larger than a quarter, an SD card shield, and an ArduinoArduino. When stacked together, the entire package is about 1-inch cubed, which makes the stack the perfect size for attaching to RC aircraft.  With everything I needed to develop my GPS logger I sat down at my bench to get the party started. I began researching and looking for sample code to help me speed up the build process, and during that search, I found a GPS data logger project that was built using the same TinyCircuits hardware I had on hand.


2.jpg

 

The GPS data logging project I found on Make.com was designed to track the author’s cat, but the code I needed to get my project off the ground would do the job whether it was tracking a cat or tracking the flight path of my quad copter. I realized that this project would be the perfect opportunity to write an article on how easy it is to build a project using the Arduino development environment and how easy it is to find, adapt and utilize existing code in your projects.

 

The TinyDuino series is pretty cool in the fact that you have a full Arduino Pro / Pro Mini packed onto a board the size of a quarter. I won’t go into great detail about the boards and what makes them so special, but if you would like further information on them, check out the full overview I wrote on TweakTown.com. Below is a list of everything you need to create a simple GPS Data Logger of your own using the Tiny Circuits hardware.

 

TinyCircuits PartsAlternate Arduino Parts From Newark
  • TinyDuino
  • TinyShield microSD
  • TinyShield GPS
  • TinyShield USB & ICP
  • TinyDuino Mounting Kit
  • 3D Printed Case
  • Code
  • Class 4 or higher 4GB microSD Card

Arduino Uno R3Arduino Uno R3

Arduino GPS ShieldArduino GPS Shield

 

 

IMG_3290.jpg

 

There really is not much to building the GPS Data Logger other than stacking the shields in the correct order, uploading the code to the Arduino, and then getting outside and logging some data. The stack should be built in the following order.  The bottom most board should be the TinyDuino, which should then be followed by the TinyShield microSD board. Up next would be the TinyShield GPS which is followed by the TinyShield USB and ICP.

 

IMG_3287.jpg

 

I chose to power my GPS Logger using a 18650 powered USB cellphone charger instead of the CR2023 or JST methods that the TinyDuino also supports. If you chose to go this route, you will need to arrange your stack with the TinyShield USB & ICP board placed between the TinyDuino and TinyShield GPS, I chose this route because I had several spare USB cellphone chargers laying around.

 

IMG_3288.jpg

 

With everything stacked together, let’s prepare the TinyDuino for coding. Plug a microUSB cable into the TinyShield USB & ICP board, then select the appropriate USB port that the TinyDuino is now connected to. Once the correct port has been selected, we need to set the Arduino IDE to recognize the correct Arduino-compatible board. Since we are using a TinyDuino, we need to select Arduino Pro or Pro Mini (3.3V, 8MHz) w/ ATmega328. Once finished we should be ready to import some test code to the TinyDuino to test that everything is working correctly.

 

Before we upload any code we will need to make a minor change to the SoftwareSerial library in the Arduino IDE. You will need to replace the SoftwareSerial.cpp and SoftwareSerial.h Library files with the ones found in the GitHub repo for this tutorial. Replacing the files is quite easy and you simply need to navigate to Arduino>libraries>SoftwareSerial and rename the existing files to SoftwareSerial_cpp.bak and SoftwareSerial_h.bak and then download the new files into this directory.


Now that that is complete, lets upload some test code to make sure that everything was configured correctly and the TinyShield GPS module is sending raw NMEA data to the Tiny Duino. Upload the code that is embedded below (also found in the Git repo titled GPS_Test_Firmware.ino) and then open the serial terminal in Arduino and set the baud rate to 9600. You should see some weird strings that look like the pasted code below the GPS Test Firmware code.

 

GPS_Test_Firmware

/**********************************************************
* TinyCircuits Test Procedure
* Tiny-Circuits.com
*
* This is the test program for the GPS TinyShield (ASD2501)
*
**********************************************************/


#include <SoftwareSerial.h>


static const int GPS_ONOFFPin = A3;
static const int GPS_SYSONPin = A2;
static const int GPS_RXPin = A1;
static const int GPS_TXPin = A0;
static const int GPSBaud = 9600;
static const int chipSelect = 10;


// The GPS connection is attached with a software serial port
SoftwareSerial Gps_serial(GPS_RXPin, GPS_TXPin);


int led = 13;


void setup()
{
  // Init the GPS Module to wake mode
  pinMode(GPS_SYSONPin, INPUT);
  pinMode(GPS_ONOFFPin, OUTPUT);
  digitalWrite( GPS_ONOFFPin, LOW );
  delay(5);
  if( digitalRead( GPS_SYSONPin ) == LOW )
  {
     // Need to wake the module
    digitalWrite( GPS_ONOFFPin, HIGH );
    delay(5);
    digitalWrite( GPS_ONOFFPin, LOW );  
  }

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  Gps_serial.begin(9600);
}


void loop()
{
  if (Gps_serial.available())
     Serial.write(Gps_serial.read());
}



RAW GPS NMEA DATA

$PSRF150,1*3E
$GPGGA,,,,,,0,00,,,M,0.0,M,,0000*48
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,12,01,0error opening gps.txt
0,000,,02,00,000,,03,00,000,,04,00,000,*7C
$GPGSV,3,2,12,05,00,000,,06,00,000,,07,00,000,,08,00,000error opening gps.txt
,*77
$GPGSV,3,3,12,09,00,000,,10,00,000,,11,00,000,,12,00,000,*71
$GPRMC,,V,,,,,,,,,,N*53
$GPGGA,error opening gps.txt
,,,,,0,00,,,M,0.0,M,,0000*48
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,12,01,00,000,,02,00,000,,03,0error opening gps.txt
0,000,,04,00,000,*7C
$GPGSV,3,2,12,05,00,000,,06,00,000,,07,00,000,,08,00,000,*77
$GPGSV,3,3,12,09error opening gps.txt
,00,000,,10,00,000,,11,00,000,,12,00,000,*71
$GPRMC,,V,,,,,,,,,,N*53
$GPGGA,,,,,,0,00,,,M,0.0,M,,0error opening gps.txt
000*48
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,12,01,00,000,,02,00,000,,03,00,000,,04,00,000,*7C
error opening gps.txt
$GPGSV,3,2,12,05,00,000,,06,00,000,,07,00,000,,08,00,000,*77
$GPGSV,3,3,12,09,00,000,,10,00,000,,11error opening gps.txt
,00,000,,12,00,000,*71
$GPRMC,,V,,,,,,,,,,N*53
$GPGGA,,,,,,0,00,,,M,0.0,M,,0000*48
$GPGSA,A,1,,,,error opening gps.txt
,,,,,,,,,,,*1E


If the data that appears in the serial terminal does not look like this, then you will need to re-upload the SoftwareSerial files and upload the test code again.

 

Now that everything is working fine, we need to upload the actual GPS Data Logging code to the TinyDuino. I have pasted the code below, and remember to insert a properly formatted microSD (Read how to do this here ) card into the TinyShield microSD.

 

GPS Data Logger Code

/*
   This Arduino sketch will log GPS NMEA data to a SD card every second
   This code was written by Ken Burns, founder and CEO of TinyCircuits
*/


#include <SoftwareSerial.h>
#include <SD.h>




// The Arduino pins used by the GPS module
static const int GPS_ONOFFPin = A3;
static const int GPS_SYSONPin = A2;
static const int GPS_RXPin = A1;
static const int GPS_TXPin = A0;
static const int GPSBaud = 9600;
static const int chipSelect = 10;


// The GPS connection is attached with a software serial port
SoftwareSerial Gps_serial(GPS_RXPin, GPS_TXPin);




void setup()
{
  // Init the GPS Module to wake mode
  pinMode(GPS_SYSONPin, INPUT);
  pinMode(GPS_ONOFFPin, OUTPUT);
  digitalWrite( GPS_ONOFFPin, LOW );
  delay(5);
  if( digitalRead( GPS_SYSONPin ) == LOW )
  {
     // Need to wake the module
    digitalWrite( GPS_ONOFFPin, HIGH );
    delay(5);
    digitalWrite( GPS_ONOFFPin, LOW );  
  }


  // Open the debug serial port at 9600
  Serial.begin(9600);

  // Open the GPS serial port
  Gps_serial.begin(GPSBaud);

  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}




int inByte = 0;         // incoming serial byte
byte pbyGpsBuffer[100];
int byBufferIndex = 0;


void loop()
{
  byte byDataByte;

  if (Gps_serial.available())
  {
     byDataByte = Gps_serial.read();

     Serial.write(byDataByte);
     pbyGpsBuffer[ byBufferIndex++ ] = byDataByte;

     if( byBufferIndex >= 100 )
     {
       byBufferIndex = 0;   
       File dataFile = SD.open("gps.txt", FILE_WRITE);

       // if the file is available, write to it:
       if (dataFile) {
        dataFile.write(pbyGpsBuffer, 100);
        dataFile.close();
      }
      // if the file isn't open, pop up an error:
      else {
        Serial.println("error opening gps.txt");
      }    
     }  
  }
}


 

Once the code is finished uploading, you should see the LED on the TinyDuino blink once every second. This is an indication that the TinyShield GPS is doing its job and polling its location every second and writing that point to the microSD Card. Now is the time to venture out unto the world and capture some data. Do this by unplugging the GPS Data Logger stack from your PC, and powering up the board by a CR2023, JST connected battery, or via the TinyShield USB & ICP like I have done. If you placed the TinyShield USB & ISP board on top of the stack you will need to remove it now to ensure that the GPS antenna gets a stong signal. If you need this board to power your stack, then move it to a position between the TinyDuino and TinyShield GPS.



Unfortunately I have not hand a chance to take my TinyCircuits GPS Data Logger outside and gather data yet as we have had some fairly bad weather over the last few weeks. Every chance I get to venture outside on a sunny and nice day, I get caught up with another article, breaking news, or some other task that eats up my free time.  But for you, this tutorial will continue on and I will explain how to take the data that has been written to the SD card and show you how to import it into Google Earth for viewing.

 

When you are finished recording data, head to your nearest PC and open the SD card to view the filed stored inside. If you correctly formatted the SD card then you should only see one file that is titled gps.txt. Make sure you have extensions visible if using Windows, and then rename the file to gps.nmea. The current SD library can only write extensions up to three characters in length and is why the file is saved as a .txt instead of nmea.


Once you have the file renamed, open Google Earth and navigate to Tools>GPS and click GPS. There will be an option to upload a gps file. You can simply browse to the gps.nmea file you renamed, upload that file and Google Earth will plot the exact path that your GPS Logger took when it was gathering data. There are several other programs that can be used to visualize this data, but I will not list them here as a simple Google Search will give you pages of information on them.

 

26.jpg

 

Now that we have the GPS Data Logger working, we need to secure the stack together using the TinyDuino Mounting Kit. This will ensure that the stack stays securely connected during any impacts that might occur during flight.


IMG_3291.jpg

 

With everything secure, we also need to enclose the stack inside the case so that it is safe from static discharges, moisture, and debris. You can head over to Thingiverse , or Github to download the custom enclosure I designed to house this project. It is designed to be affixed to a quad copter or any other ½” surface using nothing but Velcro straps that are commonly used to bind computer cables together. It could also be secured using zipties as well.


Video Here


GPS-Logger-Image.jpg

 

I will update this post with video and tracking data from the first flight as soon as I get the final few parts in for the quad-copter I am currently building. They should be here within a week, so please check back for updates! Not much of any part of this project is of my own design except for the 3D printed case, and that is completely OK. I wrote this tutorial to demonstrate how easy it is to build almost any project with just a little knowledge, some pre-existing code, and a little creative design skills. I hope you enjoyed this project as much as I did, and I can not wait to update it with video and GPS data from some of my first flights with my new scratch-built quad-copter.