How to do statistics with an Arduino? (Arduino -> SD card -> R)

In this tutorial it is shown how to do statistics with data that comes from sensors which are connected to an Arduino. For this purpose, I use the open source statistic program “R”.  Strictly speaking, R is a programming language targeting at statistical computing and graphics. Moreover, it has a huge community that works on tons of packages providing all kinds of algorithms. In order to get the data from an Arduino into an R I make use of an SD card reader/writer. Sensor data (that is captured by the Arduino) is written to an SD card, then read by a desktop PC and loaded into R.

The tutorial explains three aspects: (A) setting up an Arduino (Nano) with sensors and an SD card reader/writer to collect some data, (B) collecting data and transferring it to R, and (C) doing some statistics with the data.

List of materials:
– Arduino Nano [Search on Aliexpress | Amazon]
– Jumper wires [Search on Aliexpress | Amazon]
– Breadboard [Search on Aliexpress | Amazon]
– Ultrasonic sensors [Search on Aliexpress | Amazon]
– MicroSD Card Adapter [Search on Aliexpress | Amazon]
– MicroSD card [Search on Aliexpress | Amazon]
– Helping hand (very optional) [Search on Aliexpress | Amazon]

A (1/2): Setting up an Arduino, some sensors and an SD card reader

Schematic of the tutorial’s setup.

To be honest, the tutorial’s setup of an Arduino and sensors won’t make any real sense. It fulfills only one purpose: to collect some data that can be used to do statistics. I chose to use two ultrasonic sensors of type HC-SR04. In particular, an Arduino is plugged into the center of a breadboard. One ultrasonic sensor is plugged into the left part of the breadboard and the other sensor is plugged into the right part. As a result, the left sensor measures the distance to the left side and the right sensor measures the distance to the right side. I won’t cover the wiring in detail since I already wrote a tutorial that shows how to connect an HC-SR04 to an Arduino. In addition, I wire an SD card read/writer to the Arduino. Again, I won’t go into details here as I also wrote a tutorial about wiring an SD card reader to the Aruino.

Setup of the tutorial. The ultrasonic sensors measure the distance to the left and right side. The collected data is used to do some statistics.

Setup of the tutorial. The ultrasonic sensors measure the distance to the left and right side. The collected data is used to do some statistics.

In my previous tutorial about the HC-SR04 ultrasonic sensor, I made use of an approach that uses the pulseIn-function. This approach works well if you have only a single ultrasonic sensor in your setup. If you have two ultrasonic sensors that measure the distance at the same time, then this approach does not work anymore. In this tutorial, I make use of interrupts. These interrupts are triggered when the signal on the corresponding pin changes its state. On the Arduino Uno and Arduino Nano only digital pin 2 and 3 can be bound to interrupts. Therefore, the echo pins of the ultrasonic sensors are connected to digital pin 2 and 3.

A (2/2): Programming

As just mentioned, interrupts are used to measure the distances. Besides that, everything else is similar to the code that was presented in my previous tutorials about the HC-SR04 and Micro SD card reader.
On each loop function call, the distances are measured and then written to the file. Moreover, the old file is deleted on each startup of the Arduino.

// (c) Michael Schoeffler 2018,
#include <SD.h> //Load SD library

// Pins of the ultrasonic sensors
const int pin_echo_left = 2;
const int pin_echo_right = 3;
const int pin_trig_left = 6;
const int pin_trig_right = 7;

// variables that to track the duration of the echo
volatile long echo_left_start = 0;
volatile long echo_left_end = 0;
int distance_left = 0;

volatile long echo_right_start = 0;
volatile long echo_right_end = 0;
int distance_right = 0;

// variables to write data to sd card
int chipSelect = 4; //chip select pin for the MicroSD Card Adapter
File file; // file object that is used to write the data

void setup() {
  pinMode(pin_trig_left, OUTPUT);
  pinMode(pin_echo_left, INPUT);

  pinMode(pin_trig_right, OUTPUT);
  pinMode(pin_echo_right, INPUT);

  attachInterrupt(digitalPinToInterrupt(pin_echo_left), echo_interrupt_left, CHANGE); // only pins 2 and 3 are useable for interrupts on Uno, Nano and Mini
  attachInterrupt(digitalPinToInterrupt(pin_echo_right), echo_interrupt_right, CHANGE);

  pinMode(chipSelect, OUTPUT); 
  if (!SD.begin(chipSelect)) { // Initialize SD card
    Serial.println("Could not initialize SD card."); // if return value is false, something went wrong.
  if (SD.exists("stats.csv")) { // if "stats.csv" exists, fill will be deleted in order to gather new data
    Serial.println("File exists.");
    if (SD.remove("stats.csv") == true) {
      Serial.println("Successfully removed file.");
    } else {
      Serial.println("Could not removed file.");

  // write headers
  file ="stats.csv", FILE_WRITE); // open "file.csv" to write data
  if (file) { // Next, the headers (first line) of the CSV file is written
      file.close(); // close file
      Serial.println("Headers were written to file!");
  } else {
    Serial.println("Could not open file (writing).");


// this function is called by an interrupt on each change of the echo pin of the left sensor
void echo_interrupt_left() {
  switch (digitalRead(pin_echo_left))
  case HIGH:
    echo_left_end = 0;
    echo_left_start = micros();
  case LOW:
    if (echo_left_end == 0) {
      echo_left_end = micros();
      long duration = echo_left_end - echo_left_start;
      long durationOneWay = duration / 2; // divided by two, since duration is a roundtrip signal
      // acoustic velocity of air at a temperature of 20°C => ~343.5 m/s
      // => 0.03435 cm/us
      distance_left = durationOneWay * 0.03435; // distance in cm

// this function is called by an interrupt on each change of the echo pin of the right sensor
void echo_interrupt_right() {
  switch (digitalRead(pin_echo_right))
  case HIGH:
    echo_right_end = 0;
    echo_right_start = micros();
  case LOW:
    if (echo_right_end == 0) {
      echo_right_end = micros();
      long duration = echo_right_end - echo_right_start;
      long durationOneWay = duration / 2; // divided by two, since duration is a roundtrip signal
      // acoustic velocity of air at a temperature of 20°C => ~343.5 m/s
      // => 0.03435 cm/us
      distance_right = durationOneWay * 0.03435; // distance in cm

void loop() {
    // both ultrasonic are triggered to send an ultrasonic signal
    digitalWrite(pin_trig_left, LOW); // turn off the trigger
    digitalWrite(pin_trig_right, LOW); // turn off the trigger
    digitalWrite(pin_trig_left, HIGH);// prepare to send "trigger" command to module
    digitalWrite(pin_trig_right, HIGH);// prepare to send "trigger" command to module
    delayMicroseconds(10); // wait for 10us (module sends signal only, if trigger had a HIGH signal for at least 10 us)
    digitalWrite(pin_trig_left, LOW); // module sends signal now
    digitalWrite(pin_trig_right, LOW); // module sends signal now

    delay(1000); // we wait a second... interrupts should be called by now

    // next we append the measurements to the CSV file.
    file ="stats.csv", FILE_WRITE); // open "file to write data
    if (file) {
      file.close(); // close file
      Serial.println("Values were written to file!");
      Serial.print("Left:  ");
      Serial.print("Right: ");
    } else {
      Serial.println("Could not open file (writing).");

B: Collecting data and transferring it to R

Arduino is moved to the left and to the right in order to collect some data.

Arduino is moved to the left and to the right in order to collect some data.

Next, some data is collected by simply switching on the Arduino and then moving it to the left and to the right for a little while. After some time, the stats.csv file on the SD card should have enough distance values. In particular, the Arduino program stores the distances measurements in a so-called Comma Separated Value (CSV) format. The first line of the stats.csv file represents the so-called header. The header contains the labels for the data. The next lines contain the actual measurements. Most statistics programs offer a functionality to import CSV files. Moreover, since CSV file can be found with slightly different formatting, statistic programs usually have some additional convenience functions to import a CSV file. For example, some CSVs have headers and others don’t have them. Furthermore, some CSV files separate the data entries by ‘comma’, others separate by ‘semicolon’.

So the next step is to plug the SD card from the Arduino’s SD card reader to a desktop PC. Then, the data from the SD card can be loaded to R. There exist many different graphical user interfaces for R. Usually, I use RStudio which makes R accessible especially for beginners. I won’t cover how to install RStudio. You can find more information about the installation on the RStudio website. Keep in mind that RStudio is only a user interface for R. Besides RStudio, you have also to install R itself. Moreover, this tutorial does also not cover an introduction to R. If you are not familiar with R, then you might want to take a look at an R tutorial for beginners in order to fully understand this tutorial.

RStudio workspace. In RStudio it is very easy to set the working directory.

If you have installed R (and a graphical user interface), start with loading the file “stats.csv” to your R environment. In R, the environment is a place to store variables. In this tutorial, I set the working directory of R to the folder which contains the “stats.csv”. Typically, user interfaces such as RStudio offer a option for setting the working directory. In order to store the CSV file to the R environment, you have to enter data = read.csv("STATS.CSV"); to the R console. As a result, you should see that a variable “data” has been added to your environment. This variable should contain two variables and some observations for both variables. The number of observation is dependent on how long you took distance measurements with the setup. If you did not set the working directory, then you have to enter the full path to the CSV file into the “read.csv”-function.

Next, we want to calculate the mean values of our distance measurements. This can be done by entering mean(data$DISTANCE_LEFT)and mean(data$DISTANCE_RIGHT)to the R console. For the left distance I get 12.13043 and for the right distance I get 13.34783 [cm].

If you know only my mean values, you don’t know whether I actually moved my Arduino or not. I would be also possible that I just placed my Arduino in between the obstacles having a distance of about 12cm to the left and about 13cm to the right. In statistics, you can make use of the standard deviation which gives you some indication about the amount of variations of the observations. More strictly speaking, the standard deviation is the square root of the variance. Maybe you are asking yourself now “What is the variance?”. The variance is the average of the squared differences between each observation and the mean.  In R, the standard deviations of the left and right measurements are calculated by entering sd(data$DISTANCE_LEFT) and sd(data$DISTANCE_RIGHT). The result values are 3.876554 (left) and 7.036326 (right). Normally, one would expect that the standard deviants are about the same for the left and right distance measurements. The differences are a result of a non-symmetrical physical setup, measurement noise, skewed movements of the Arduino etc. In order to check whether both variables are related to each other, a correlation measure can be utilized. The Pearson product-moment correlation coefficient, denoted as r, is such a measure. This coefficient ranges from -1 to 1. A value of -1 indicates that the two variables perfectly disagree, a value of 0 indicates that the two variables are independent, and a value of 1 indicates that the two variables perfectly agree. In R, the Pearson product-moment correlation coefficient can be calculated by entering cor(data$DISTANCE_LEFT, data$DISTANCE_RIGHT). As you can see, the function has two arguments which correspond to the two variables of interest. Applying the function to my data returns 0.7782926. This indicates that the two variables rather disagree. This sound logical because if we move the Arduino to the left, the left distance measurement decreases. At the same time, the right distance measurement increases. If both distance measurements had increased at the same time, the correlation coefficient would be close to +1.

Coming soon: Video tutorial with even more content!

Leave a Reply

Your email address will not be published. Required fields are marked *