loading
Picture of Darkness Map Data Collection Device
The Darkness Map encompasses both data collection and visualization of nighttime light levels. You can add to the map by downloading the app for iPhone or Android, but you can also contribute data by creating your own data collection device. This tutorial will cover how to build an Arduino powered data logger with a light intensity sensor. Since the sensor modules are attached to the Arduino on a breadboard, it's fairly simple to swap out the light sensor for a different sensor of your choosing. You can use the device to log data about temperature, air quality, noise, and many other environmental factors, and because everything is attached by breadboard, you can easily adapt it to use in other projects.
 
Remove these adsRemove these ads by Signing Up

Step 1: Parts You Need

Picture of Parts You Need
Arduino Uno - available from a variety of online resellers, and even your local Radioshack.
Adafruit Proto Shield for Arduino Kit
Adafruit Ultimate GPS Breakout Kit
Adafruit MicroSD card Breakout Board
TSL2561 Digital Luminosity/Lux/Light Sensor
Half-size breadboard
CR1220 Coin Cell Battery - also available at drug stores, other online resellers
MicroSD Card - you can also repurpose one from an old mobile phone
9V Battery clip
9V Battery

The parts for each device cost about $90, not including the Arduino Uno.

Step 2: Solder Your Breakout Boards and Kits

Picture of Solder Your Breakout Boards and Kits
First things first, you'll want to put together the Proto Shield kit. Adafruit has a great step by step tutorial on how to attach and solder all the necessary parts. When it comes time to attach the last parts, don't, as we'll be putting the half-sized breadboard on top of the protoshield.

Next, attach and solder the header pins to the GPS module, MicroSD breakout board, and the TSL2561 light sensor. You may want to tape them if they aren't staying put as you solder. To attach the coin cell battery holder to the back of the Ultimate GPS module, heat the pads on either side of the battery holder with the tip of your soldering iron. Once they're hot enough, let solder flow on top and hold the battery holder in place until the solder hardens.

After you have soldered all your header pins, you are ready to start connecting the modules together. Follow the steps in the Proto Shield tutorial, and break off the sides of the half-sized breadboard. Then peel the adhesive backing off the back of the breadboard and attach it to the top of the Proto Shield.

Once you have all the modules put together, it's time to connect the wiring.

Step 3: Set up the GPS Module

Picture of Set up the GPS Module
GPS_window.jpg
First, you'll want to set up your Ultimate GPS Module and make sure it's working properly. In order for the GPS to get a signal, you'll want to work near a window (possibly even outside), so that you can stick your Arduino and GPS module on a window ledge for it to get a reading. As per the Adafruit tutorial, you can initially wire it so that it bypasses the Arduino's ATMega chip, and communicates directly with your computer's USB serial port. In order to do this, just wire the GPS module's +5V pin to the Arduino's +5V pin, Ground to the Arduino's Ground pin, RX to pin0 and TX to pin1. Next upload a blank sketch, where both the void setup() and void loop() functions are empty. Open the serial monitor in Arduino and you should start seeing a bunch of characters start to spit out. Make sure the serial baud rate is set to 9600. This is raw GPS NMEA code, which you can read more about here.

Find the line that starts with $GPRMC. The first section is GMT (Greenwich Mean Time), next is the letter A which means the GPS module is Active (as opposed to V which would be void). Then next four values are the Geolocation data. In Brooklyn, NY my location data reads: 4041.3198,N,07357.5915,W. This translates to (Latitude 40 degrees, 41.3198 decimal minutes North and Longitude 73 degrees, 57.5915 decimal minutes West). To check this against google maps, you'd covert it into degrees of latitude and longitude that google understands. I typed in +40 41.3198 ,- 73 57.5915, and it was able to find the correct location. If you're getting readings with lots of zeros, try placing the GPS further on the window ledge.

Next, you'll want to wire the GPS to your Arduino. Change the wiring so that the GPS Module's RX pin is connected to Arduino pin2, and it's TX pin is connected to pin3. Adafruit has a GPS library, but we'll be using the TinyGPS library by Mikal Hart. Download the latest version of the library and put the folder inside Documents --> Arduino --> libraries. Make sure it's called TinyGPS. Open the simple test example sketch. Notice how the serial monitor is set to a baud rate of 115200. Also, where it says
ss.begin(4800); change that to be ss.begin(9600); since the Ultimate GPS Module samples at a 9600 rate. Save your changes and upload it to the Arduino.

Once the sketch is uploaded, open your serial monitor. If you see a bunch of weird characters, change the baud rate to 115200. Then you should be able to see the data being printed to the serial monitor. If you're not seeing any GPS data, you may have to put your module on the window ledge again since it's most likely not receiving any new GPS signals.

If your GPS module is working correctly and you've been able to run the TinyGPS library code, the next step is adding the MicroSD breakout board to the Arduino, and seeing if we can save our GPS data to a text file on the MicroSD card.

Step 4: Set up the MicroSD Breakout Board

Picture of Set up the MicroSD Breakout Board
GPS_SD.jpg
In order to see if the SD card is formatted correctly, and if the MicroSD card breakout board is setup properly, you'll want to take the GPS module off your breadboard for now and work with the MicroSD card breakout board on its own. Feel free to leave your wires in the breadboard so you can remember to leave space for the different modules. For our purposes, wire the MicroSD card like this:

--5V pin to Arduino 5V pin
--Ground to Arduino Ground pin
--Clock pin to Arduino's pin13
--DO pin to Arduino pin12
--DI pin to Arduino pin11
--CS pin to Arduino pin10

Now you'll want to open an example from the SD card library, which comes with Arduino. We'll be checking whether our MicroSD breakout board is wired up properly, and if the SD card is formatted correctly using the CardInfo sketch. Before you upload the code to the Arduino, make sure you change one line of code. The chipSelect pin should be set to 10, not 4.

const int chipSelect = 10;

Upload the code to the Arduino and turn on the serial monitor. If your serial monitor gives you a message that it can't initialize the card, try reformatting it to FAT32 or FAT16 using your Disk Utility application. If you have further problems, follow the steps in the Adafruit tutorial.

Next let's see if we can write files to our SD card. Open the Files example from the SD library. Make sure to change chipSelect to equal 10, not 4. Upload the code and turn on the serial monitor. If it successfully creates and removes the example.txt file then congratulations, you're able to write to an SD card.

Next we want to see if we can get the Arduino to save our GPS readings to the SD card. Disconnect your Arduino from the computer. Put the GPS module back in place. In order to connect both the GPS and MicroSD card breakout board to 5V and Ground on the Arduino, we'll want to bring the power and ground to the breadboard, and then connect it to each module.

Now, upload the following code to your Arduino. It's best if the Arduino is back out on your window ledge so you can get a GPS reading. You can check to see what's happening by opening the serial monitor, but make sure to change the baud rate to 115200 or else the characters won't make much sense. You should be seeing rows of three values. First the longitude coordinate, next the latitude coordinate, and finally the unix timestamp.


#include "Wire.h"
#include "SD.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"
#include "RTClib.h"

const int chipSelect = 10;
RTC_Millis RTC;
File dataFile;

TinyGPS gps;
SoftwareSerial ss(3, 4);

void setup() 
{
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
  ss.begin(9600);
  pinMode(chipSelect, OUTPUT);
  RTC.adjust(DateTime(__DATE__, __TIME__));
 
  // 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:
    while (1) ;
  }
  Serial.println("card initialized.");
 
  // Open up the file we're going to log to!
  dataFile = SD.open("GPStest.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening GPStest.txt");
    // Wait forever since we cant write data
    while (1) ;
  } 
}

void loop()                  
{
  DateTime now = RTC.now();
  bool newData = false;

for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

    if (newData)
  {
    float flat, flon;
    unsigned long age;
    int year;
    byte month, day, hour, minute, second, hundredths;
    gps.f_get_position(&flat, &flon, &age);
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
        char sz[32];
    sprintf(sz, "%02d/%02d/%02d, %02d:%02d:%02d,  ",
     month, day, year, hour, minute, second);
   
    Serial.print("");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(", ");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(", ");
    Serial.println(now.unixtime());

    dataFile.print("");
    dataFile.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    dataFile.print(", ");
    dataFile.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    dataFile.print(", ");
    dataFile.println(now.unixtime());
  }

  dataFile.flush();
  delay(500);
}

Now unplug your Arduino and eject the MicroSD card from the breakout board. Find the SD card adapter and insert it into your computer, either with a card reader or directly if you have an SD card slot. See if there is a text file called GPSTEST.TXT. If there is, yay! If not, then I'd try reformatting your card and trying to write to it again. Open the text file and make sure the data has been written. Sometimes the file gets created but no data gets saved, and if this is your case, check your wiring, and try following LadyAda's SD card tutorials.

Step 5: Adding the Light Sensor

Picture of Adding the Light Sensor
DataLogger.jpg
If you've been able to save GPS data to your SD card, the last step is adding our light sensor to the mix. Add the TSL2561 sensor to the breadboard. Wire it in the following way:

--Connect Ground to the Ground rail on the breadboard
--Connect the VCC pin to the 3V pin on the Arduino
--Connect the SCL pin to Arduino pin A5
--Connect the SDA pin to Arduino pin A4

We'll be using the TSL2561 Arduino libray from Adafruit. You can download it here, unzip it, and put in the Arduino libraries folder. If Arduino is open restart it for the library to appear in the Examples dropdown choices. Open the example sketch and upload it to the Arduino. Press the serial monitor to make sure it's reading data. Wave your hand over the sensor to see if that changes the light values. Once you're satisfied that your sensor is working, upload the following code to the Arduino:


// Darkness Map Data Collection Device
// Genevieve Hoffman, 2012
// TinyGPS Library, by Mikal Hart, download here: http://arduiniana.org/libraries/tinygps/
// TSL2561 Library, by Ladyada (Limor Fried), download here: https://github.com/adafruit/TSL2561-Arduino-Library
// RTClib, by Ladyada (Limor Fried), download here: https://github.com/adafruit/RTClib
// RTClib originally developed by Jeelabs: https://github.com/jcw/rtclib

#include "Wire.h"
#include "TSL2561.h"
#include "SD.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"
#include "RTClib.h"

const int chipSelect = 10;
RTC_Millis RTC;
File dataFile;

int sensorPin = A0;  // input pin from sensor
int lux = 0; // variable to store the value coming from sensor
TSL2561 lightSensor(TSL2561_ADDR_FLOAT);

TinyGPS gps;
SoftwareSerial ss(3, 4);


void setup() 
{
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
  ss.begin(9600);
  pinMode(chipSelect, OUTPUT);
  RTC.adjust(DateTime(__DATE__, __TIME__));

 
  // 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:
    while (1) ;
  }
  Serial.println("card initialized.");
 
  // Open up the file we're going to log to!
  dataFile = SD.open("Data5.txt", FILE_WRITE);
  if (! dataFile) {
    Serial.println("error opening datalog.txt");
    // Wait forever since we cant write data
    while (1) ;
  } 
    lightSensor.begin();
    if (lightSensor.begin()) {
    Serial.println("Found sensor");
  } else {
    Serial.println("No sensor?");
    while (1);
  }
 
  //lightSensor.setGain(TSL2561_GAIN_0X);         // set no gain (for bright situtations)
  lightSensor.setGain(TSL2561_GAIN_16X);      // set 16x gain (for dim situations)
  //lightSensor.setTiming(TSL2561_INTEGRATIONTIME_13MS);  // shortest integration time (bright light)
//lightSensor.setTiming(TSL2561_INTEGRATIONTIME_101MS);  // medium integration time (medium light)
lightSensor.setTiming(TSL2561_INTEGRATIONTIME_402MS);  // longest integration time (dim light)
}

void loop()                     // run over and over again
{
  DateTime now = RTC.now();
  bool newData = false;

for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
     // Read Light Sensor
     uint32_t lum = lightSensor.getFullLuminosity();
     uint16_t ir, full;
     ir = lum >> 16;
     full = lum & 0xFFFF;
     lux = lightSensor.calculateLux(full, ir);    
  }

    if (newData)
  {
    float flat, flon;
    unsigned long age;
    int year;
    byte month, day, hour, minute, second, hundredths;
    gps.f_get_position(&flat, &flon, &age);
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
        char sz[32];
    sprintf(sz, "%02d/%02d/%02d, %02d:%02d:%02d,  ",
     month, day, year, hour, minute, second);
  
    Serial.print("");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(", ");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(", ");
    Serial.print(sz); //prints out GMT time
    Serial.print("unixtime: ");
    Serial.print(now.unixtime());
    Serial.print(", Lux: "); Serial.println(lux);
   
    dataFile.print("");
    dataFile.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    dataFile.print(", ");
    dataFile.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    dataFile.print(", ");
    dataFile.print(lux);
    dataFile.print(", ");
    dataFile.println(now.unixtime());
  }

  dataFile.flush();
  delay(500);
}

Since the Darkness Map project is about collecting light values at night, you'll want to configure your TSL2561 sensor for dim lighting situations. So, you'll want to turn on the line of code that says:

lightSensor.setGain(TSL2561_GAIN_16X);      // set 16x gain (for dim situations)

and

lightSensor.setTiming(TSL2561_INTEGRATIONTIME_402MS);  // longest integration time (dim light)

Comment out the other lines that set the gain and the timing. And feel free to change these settings if you decide to use the TSL2561 sensor for other purposes.

After the code is uploaded, start the serial monitor, making sure it's set to 115200 baud rate. If the monitor stops printing out any information after "Found sensor," then your Arduino probably isn't picking up any GPS signal, and you'll want to stick it back out on your window ledge. You should start seeing values for the longitude, latitude, and lux and timestamp coming into the serial monitor. Congratulations! You've made yourself a datalogger.

Since everything is breadboarded, feel free to swap out the TSL2561 for another sensor of your choice in order to make another GPS enabled datalogger. The possibilities are endless!

Step 6: Troubleshooting

If you have trouble getting a GPS signal, or writing to the SD card, I'd recommend going through the Adafruit tutorials for the TSL2561 light sensor, the Ultimate GPS Module, and the MicroSD Breakout Board separately.

MicroSD breakout board tutorial

Ultimate GPS Module tutorial

TSL2561 Light Sensor tutorial
jwdesign3 months ago

Hi, I have a pinhole spy camera which I would lik to add a microsd breakout board inorder to store the video footage. can I do this with just the microsd breakout board and if yes how? and if not so what can I do? thank you in advance!!

hheidmann made it!3 months ago

Great tutorial! Really helpful to get everything working as desired. Now I just need to wire up my HM-10 BLE chip so I can send data to the app we made via Bluetooth.

Prototype-soldered-topview.jpeg
rmas2 years ago
When I try to upload the code that is on page 2-3 of the instructions I get the following error messages.
TINYgps does not name a type.
RTC_millis does not name a type.
Date was not declared in this scope.
Tinygps.h; no such file or directory.
RTClib.h; no such file or directory.
in function void setup()';
I need some help with this guys.
My email is rmasnj44@optonline.net
gennaveeva (author)  rmas2 years ago
It seems like you don't have the libraries installed in a place where Arduino can find them. I have a folder called "Arduino" inside my Documents directory. Inside that, there is a folder called "libraries" , inside that are various libraries, including a folder called "TinyGPS" and "RTClib"

You may have to restart your Arduino IDE after placing the libraries inside that folder. If that still doesn't work let me know.
rmas gennaveeva2 years ago
Hi: Thanks for your response.
The problem is that I can't compile the code to save it. I get these error messages
that I stated. I have a folder called Arduino and in that a libraries folder and various libraries. I cant save the code because of all these errors that I stated. My question is this. Could you possible have errors in the program when you published it.
Ron
gennaveeva (author)  rmas2 years ago
The code compiles fine for me. Just so we're clear, are you talking about the code on step 4? I'm not sure what specific code you're referring to on pages 2 or 3. To test the GPS module directly over serial (step 3), you hook the RX and TX pins to 0 and 1 on your Arduino, and then upload a blank sketch.

Here's that code from the Adafruit tutorial:
// this sketch will allow you to bypass the Atmega chip
// and connect the fingerprint sensor directly to the USB/Serial
// chip converter.

// Connect VIN to +5V
// Connect GND to Ground
// Connect GPS RX (data into GPS) to Digital 0
// Connect GPS TX (data out from GPS) to Digital 1

void setup() {}
void loop() {}

If you're able to see NMEA data coming in through the Serial Monitor, then I'd proceed to test whether the code examples that come with the TinyGPS library are compiling for you. In the Arduino IDE, go to File --> Examples --> TinyGPS --> Examples --> simple_test. Change your RX and TX wiring to match the example code (pins 3 and 4).

Next I'd proceed with the RTClib examples. Note: If you don't have a coin cell battery then you won't be able to access the Real Time Clock on the GPS module.

Sorry you're having a difficult time of it. I've tested that it compiles without errors, but I'll test the uploading later tonight when I have access to the module.
rmas gennaveeva2 years ago
I'm sorry: The code I am talking about starts With Step 4 Set up the MicroSD breakout Board. It starts with Now,upload the following code to your Arduino.

#include "Wire.h"
#include "SD.h"
#include "SoftwareSerial.h"
#include "TinyGPS.h"
#include "RTClib.h"
rmas rmas2 years ago
Hi:Gennaveeva:
Sorry to be such a pest but were you ever able to check the code that I am talking
about. I'm still getting errors and I cant compile it. I can't go forward with my project until I get this right. If I new how to email you all of my code for you to check I would. Thanks for all your help so fare.
Ron

.
gennaveeva (author)  rmas2 years ago
I'm emailing you now. Hopefully we can troubleshoot better that way.
technitute2 years ago
Nice Sir,,, I love technology and the stuffs going on electronics............

http://www.technitute.com/blog
Reminds me of a nowhere-near-as-sophisticated art project I did on the impact of illumination on the perceived importance of objects in a landscape. This is way cooler.
gennaveeva (author)  The Green Gentleman2 years ago
Thanks. I'd love to read more about your project if it's online anywhere.
Fortunately, the World Wide Web was just a twinkle in Al Gore's eye when I did my project, so I am spared the embarrassment of sharing it!
LOL
What exactly does this do? Does it create a map or what?
gennaveeva (author)  szulli-randall2 years ago
I plan to update the tutorial with instructions for how to add the CSV files to the web-based map visualization. The hardware device was an initial prototype, and we're now developing a way to add to the map with a mobile app. I've made maps from the CSV data in Processing, but wanted to focus on the hardware aspect for this tutorial. Sorry if I wasn't entirely clear.
james.m.k2 years ago
I don't get it. You're mapping light intensity? Why?
gennaveeva (author)  james.m.k2 years ago
I think light, and especially the amount and quality of light at night make up a large part of a city's phenomenological qualities, and how they affect your perceptual experience of the city. It's also part of an experiment in building a crowd-sourced dataset, which might have useful applications to reference against public safety data, like crime or traffic incidents.
irishjim682 years ago
It would be a nice touch to give some background info about the "Darkness Map" project considering how the web site has four links that go nowhere, and therefore really contains NO useful information.
gennaveeva (author)  irishjim682 years ago
Sorry about the issues with the website, they should be fixed now. The Darkness Map is currently being developed, but I wanted to put this tutorial up as a basic overview of how to build a gps enabled data logger, in the hope that it might benefit people in their own projects. Ultimately, the easiest way to contribute to the Darkness Map project will be using the mobile app for data collection, but I thought a tutorial for this initial prototype might be useful outside of my project.