I’ve used a lot of different configurations of Arduino-related gear as datalogging utilities. So here’s a comprehensive guide on what’s possible, how to set up stuff and on what you can expect regarding accuracy, battery life and logging speed.
My Arduino Uno with the datalogger shield both temperature and brightness sensors connected. I used a normal smartphone charger to power it for more than 3 days and placed it in this fireproof baking tray since I felt somewhat unsure about having it running unattended.
Datalogging with an Arduino: An introduction
I actually learned about Arduino when I was looking for an easy option to measure analog signals and ended up buying both an Arduino-compatible starter kit and a cheap clone of the Adafruit data logging shield. There’s the very easy-to-follow tutorial from Adafruit that gives you a great overview on the possibilities.
In summary, it’s amazingly easy to measure analog signals with an Arduino and store them onto an SD card. Since the Arduino Uno (and most other versions like Nano and Mega) runs on 5V and does not include an SD slot, you need some kind of shield that shifts the signals down to 3.3V for the SD card (either a datalogging shield or one of the LCD display shields with an SD card slot attached to the LCD). In the Arduino software, there’s a datalogger sketch as an example for the SD card library that allows logging of up to ~1 kHz (in this article written in german, there are a few nice graphics with a signal-generator input). Depending on your needs, you might also want to directly transfer the data to a computer via serial or wireless connections – see here or here for examples. I usually ended up logging data onto an SD card.
Temperature in my living room tracked for ~ 3 sunny days in February (the datalogger was placed in a corner of the room without direct exposure to sunlight). Note both the temperature gain due to the sun during daytime and the slow decrease during the night.
Connecting SD cards to an Arduino
A communication between the Arduino and an SD card usually happens via SPI – not all SD cards will work, so if you run into trouble, try switching the card. Depending on the Arduino you use, the SPI output is directed to different pins – my datalogging shield only works with my UNO, for the DUE I had to place wires between the SPI pins and the corresponding ports on the TFT shield. See the pinout diagram here for the DUE. The Adafruit M0 datalogger and the Teensy 3.5/3.6 have the SPI output directly wired to the SD card slot.
Options for slow and accurate datalogging
The Arduino Uno-based solution shown above has both a few advantages and limitations. My Arduno-compatible Sainsmart Uno has the option to run on 3.3 V but if your Arduino does not, you need something to shift the voltage for the SD card to 3.3V. Then again, many sensors require 5V, so sticking to an UNO (or Nano if you care about space) is a hazzle-free option. If your sensors support 3.3V supply, there are other options: an Arduino Pro running on 3.3V or especially if you want a small and robust product without much soldering, this Adafruit Feather M0 datalogger has reasonably low power consumption and can easily be powered by a battery pack (I just bought a M0 datalogger and it works as intended).
All these options are limited to logging frequencys of roughly 1 kHz (see the highspeed logging part below for details). My Arduino Uno + datalogging shield combination runs on either 6 AA-batteries or a small powerbank for ~24 hours without using the arduino’s low-power mode – with a smart design and the sleep function, much longer times may be achieved (see also this Adafruit tutorial – this should also work with the M0 datalogger linked above).
Another issue may be the accuracy of the Arduino’s 10bit analog-digital converter (ADC). My temperature sensor has a temperature range of 0.01 V per degree C, so the measurement resolution is at 500 °C / 1024 = ~ 0.5 ° C resolution. Since my measurements are not supposed to surpass 110° celsius I can set the range to 0 .. 1.1 V with the AnalogReference function, getting a theoretical resolution of ~0.1 ° C. At this point, the noise from either my sensor or the arduino itself surpasses the actual signal which leads to noisy readings.
Temperature measurement in my fridge. You can easily see where the door was opened based on the data from the brightness sensor and the compressor’s cycles based on the temperature gains and losses. Note the noise in the temperature signal and the ADC’s resolution.
One might easily shrug at this point and default to “the Arduinos ADC sucks anyway”. But there is an option for improvement: Since the signal’s noise leads to a randomized distribution and we’re not interested in fast readings anyway, we can also take many readings from the sensor, average them directly on the Arduino and only save the averaged value. In my test, this easily allows for much better accuracy in the range of 0.01 °C relative accuracy (the absolute error is probably much larger unless I find a way to calibrate my sensor, but as long as I only care about temperature gain, this should be good):
Temperature measurement in which the fridge’s door is opened for ~20 seconds (probably to store groceries in the fridge). Note how the temperature accuracy improves by averaging 50 ADC measurements instead of just storing one ADC measurement at a time.
Options for high-frequency datalogging
Suppose you want to tune up the datalogging frequency for a vibration measurement (this blog is about multibody dynamics after all). In this case, all the options discussed above have some serious limitations:
- maximum ADC speed on the UNO: ~10 kHz (might be raised to 50kHz)
- operations on strings appear to be very time-intensive (the SDFat library also includes a binary datalogger but this complicates things – I haven’t tried it yet)
- The standard Arduino has only a rather small memory, so there’s little room for buffering
With a few easy modifications, the standard datalogging sketches from the SD library and adafruit can be tuned to data rates of ~ 1-2 kHz:
- If you need a timestamp from a realtime clock, only grab it once at setup. Afterwards, only output the millis() value.
- avoid collecting data in a string variable – instead directly pass integer variables to the dataFile.print function
- Open the output file in the setup function and use the flush() function each ~500 cycles (tune depending on your needs) to write data.
If you want to increase datarates, an easy option is to switch to a newer teensy 3.x model or an Arduino Due. The teensy 3.5 and 3.6 versions come directly with an sd slot on the board and my 3.5 model performs well with logging rates above 10 kHz. Due to the large onboard memory, you might as well read lots of data at very high speeds into the memory (100 MHz should be possible with the standard AnalogRead function but depending on settings and library, you might well boost it towards higher values) and then store on the SD afterwards. My Arduino Due is already wired to the TFT display with an SD slot and has an oscilloscope mode running, but I haven’t had the time to add a datalogging mode to it (this is on my to-do list – I want to have it directly accesible from the touchscreen menu).
Arduino boards and compatibles allow you to build relatively cheap and robust datalogging devices with low power consumption. Depending on your needs, different devices may be helpful, especially the Adafruit feather M0 datalogger for low-power settings with small installation space and the teensy 3.5/3.6 boards for high-frequency logging.
I’ve merged most of the code I’m using for datalogging into one Arduino sketch – which is rather messy, but it can serve as a reference. You can find it here.