Project tutorial
Field-Deployable Ultrasonic Data Logger

Field-Deployable Ultrasonic Data Logger © GPL3+

A modular orientation and acceleration data logger using a pair of ultrasonic sensors, RF transceivers, and a 1Sheeld.

  • 3,493 views
  • 2 comments
  • 11 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
A000057 featured
Arduino Leonardo
×1
51gzz5eu9pl. sx425
Ultrasonic Sensor - HC-SR04 (Generic)
×2
nRF24 Module (Generic)
×2
Screen shot 2019 03 20 at 2 38 27 pm fqndazqcx1
1Sheeld
×1
Camera Tripod
×2
Smartphone
×1
Power/Battery Bank
×2
Resistors
×1
Red & Green LEDs
×1

Apps and online services

Ide web
Arduino IDE
Program your Arduinos with this guy
1Sheeld
Download this to your phone to collect data from built-in sensors

About this project

I needed to get reliable acceleration and orientation data from one point to another for a school project. The data is collected outdoors which makes portability a necessity. I really didn't have someone to assist with timing and logging, so I had to cobble things together.

The contraption consists of the following:

  • Start Node
  • Stop Node
  • Smartphone sensors

The way it works is the Start Node activates the smartphone to start the data collection. The data from the phone's sensors are then logged within the phone's memory. The Stop Node then sends a signal back to the Start Node to end the data collection. Finally, the logged data is saved as a CSV file.

Setting Up the Start Node

The Start Node is composed of the following:

  • Arduino Uno
  • Ultrasonic Sensor (HC-SR04)
  • RF Transceiver (NRF24L01)
  • 1Sheeld
  • Resistors and LEDs
  • Semi-enclosure
  • Camera Tripod
  • Battery Bank

So hook up the components together using the schematic above. Set the 1Sheeld physical switch to Programming Mode. Then open up your Arduino IDE and upload the Start Node code. Return the physical switch to Operating Mode after it completes.

When turned on, the Start Node has the red LED on and waits for the object/subject to trigger the ultrasonic sensor. Once it is activated, the node will turn on the green LED to indicate that it is active. 1Sheeld communicates with the smartphone using bluetooth to start data logging. The node then waits for a stop signal from the End Node. If it does, the red LED turns back on and the green LED turns off. The Start Node then tells the smartphone to stop logging.

Setting Up the End Node

The End Node has a similar build minus the 1Sheeld. All it does is send a signal back to the Start Node to indicate that the object/subject has passed through its ultrasonic sensor. I'm using an Arduino Leonardo because that's the only thing I have lying around. Using a different Arduino board requires a little wiring change due to the SPI pinout.

Setting Up the Smartphone

To communicate and log data, the 1Sheeld app is needed. I have the old hardware version so I can only connect to an Android phone (the revision can connect to iPhones). Anyways, download that from the app store and establish a link to the 1Sheeld device. Remember to set the physical switch of the 1Sheeld device to OperatingMode!

Activate the sensors, in my case the Accelerometer and Orientation, and Data Logger as seen below.

Now the app should start logging the data once the Start Node is activated. The collection lasts until the stop signal is received from the End Node. A CSV file is saved in the phone's storage under "OneSheeld" folder. It's pretty cumbersome to find, but it's there. You'll probably need to access the Settings>Storage>Files to find it or just download a file explorer app. Here's a sample CSV output:

Customizing the Code

I'm logging orientation, x & y axis acceleration, and the timestamp for my data.

 /* Add orientation values as a column in the CSV file. */
 Logger.add("Degrees", OrientationSensor.getX());
 /* Add x-acceleration values as a column in the CSV file. */
 Logger.add("X-axis m/s^2", AccelerometerSensor.getX());
 /* Add y-acceleration values as a column in the CSV file. */
 Logger.add("Y-axis m/s^2", AccelerometerSensor.getY());

There are a lot more sensor options that can be added like magnetometer, GPS, gravity, temperature, pressure, light, sound level, etc. Here's an example from 1Sheeld's data logging tutorial:

/* Add noise level values as a column in the CSV file. */    
Logger.add("Decibels",Mic.getValue());       

The availability of the sensor options really depend on the actual sensors integrated on your smartphone.

Code

Start NodeArduino
/*
  This program is for the start node. The algorithm waits for an object within a given distance
  and executes the data collection. The code is based on TMRh20's RF communication using interrupts
  and 1Sheeld's sample template. 

  Augmented by: HyperChiicken
*/

#define CUSTOM_SETTINGS
#define INCLUDE_DATA_LOGGER_SHIELD
#define INCLUDE_ACCELEROMETER_SENSOR_SHIELD
#define INCLUDE_ORIENTATION_SENSOR_SHIELD
#define INCLUDE_TERMINAL_SHIELD

/* Include 1Sheeld library. */
#include <OneSheeld.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);                          // set up nRF24L01 radio on SPI bus plus pins 9 & 10

uint8_t address[] = { "radio" };            // use the same address for both devices

/* Simple messages to represent a 'ping' and 'pong' */
uint8_t ping = 111;
uint8_t pong = 222;
int trigPin = 4;
int echoPin = 5;
int greenLed = 7;
int redLed = 8;
volatile uint32_t round_trip_timer = 0;
bool startFlag = false;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  Serial.begin(115200);

  /* Start communication. */
  OneSheeld.begin();
  /* Save any previous logged values. */
  Logger.stop();

  //printf_begin();
  digitalWrite(greenLed, LOW);
  digitalWrite(redLed, HIGH);
  
  radio.begin();                               // setup and configure rf radio

  // Use dynamic payloads to improve response time
  radio.enableDynamicPayloads();
  radio.openWritingPipe(address);             // communicate with devices with the same address
  radio.openReadingPipe(1, address);
  radio.startListening();

  //radio.printDetails();                             // Dump the configuration of the rf unit for debugging

  attachInterrupt(0, check_radio, LOW);             // Attach interrupt handler to interrupt #0 (using pin 2) on BOTH the sender and receiver
}

void loop() {

  int duration;
  int distance;

  digitalWrite(trigPin, HIGH);
  delay(1);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;                 //in centimeters (search ultrasonic distance calculation for details)

  /* Start data collection when object is detected within 45 cm */
  if (distance <= 45 && distance >= 0) {
    {
      /* First insure to save previous logged values. */
      Logger.stop();
      /* Set a delay. */
      OneSheeld.delay(500);
      /* Start logging in a new CSV file. */
      Logger.start("TEST");
      /* Set startFlag. */
      startFlag = true;
    }

    /* Check logging started. */
    while (startFlag)
    {
      collectStart();
      if (!startFlag) {
        collectStop();
      }
    }
  }
}

/* Set data to be taken from the phone */
void collectStart() {
  digitalWrite(greenLed, HIGH);
  digitalWrite(redLed, LOW);
  /* Add orientation values as a column in the CSV file. */
  Logger.add("Degrees", OrientationSensor.getX());
  /* Add x-acceleration values as a column in the CSV file. */
  Logger.add("X-axis m/s^2", AccelerometerSensor.getX());
  /* Add y-acceleration values as a column in the CSV file. */
  Logger.add("Y-axis m/s^2", AccelerometerSensor.getY());
  /* Log the row in the file. */
  Logger.log();
  /* Delay for 1 second. */
  OneSheeld.delay(200);
}

void collectStop() {
  Logger.stop();
  OneSheeld.delay(500);
  
  /* Start logging in a new CSV file. */
  Logger.stop();
  Logger.start("TEST");
    
  Terminal.println(startFlag);
}

/* Interrupt */
void check_radio(void)                                // Receiver role: Does nothing!  All the work is in IRQ
{
  bool tx, fail, rx;
  radio.whatHappened(tx, fail, rx);                   // What happened?

  /* If data is available, handle it accordingly */
  if ( rx ) {

    if (radio.getDynamicPayloadSize() < 1) {
      /* Corrupt payload has been flushed */
      return;
    }
    /* Read in the data */
    uint8_t received;
    radio.read(&received, sizeof(received));

    /* If this is a ping, send back a pong */
    if (received == ping) {
      radio.stopListening();
      /* Normal delay will not work here, so cycle through some no-operations (16nops @16mhz = 1us delay) */
      for (uint32_t i = 0; i < 130; i++) {
        __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
      }
      radio.startWrite(&pong, sizeof(pong), 0);
      digitalWrite(redLed, HIGH);
      digitalWrite(greenLed, LOW);
      startFlag = false;
    } else
      /* If this is a pong, get the current micros() */
      if (received == pong) {
        round_trip_timer = micros() - round_trip_timer;
      }
  }

  /* Start listening if transmission is complete */
  if ( tx || fail ) {
    radio.startListening();
  }
}
End NodeArduino
/*
  This program is for the stop node. The algorithm sends a stop command 
  to the start node to end data collection. The code is based on TMRh20's 
  RF communication using interrupts. 

  Augmented by: HyperChiicken
*/

#include <SPI.h>
#include "RF24.h"
#include <printf.h>

RF24 radio(9, 10);                  // set up nRF24L01 radio on SPI bus plus pins 9 & 10

uint8_t address[] = { "radio" };    // use the same address for both devices

/* Simple messages to represent a 'ping' and 'pong' */
uint8_t ping = 111;
uint8_t pong = 222;
int trigPin = 3;
int echoPin = 4;
int builtinLed = 13;
volatile uint32_t round_trip_timer = 0;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(builtinLed, OUTPUT);
  Serial.begin(115200);
  Serial.println(F("STOP NODE"));
  //printf_begin();
  
  radio.begin();                  // Setup and configure rf radio

  /* Use dynamic payloads to improve response time */
  radio.enableDynamicPayloads();
  radio.openWritingPipe(address);             // communicates with devices with the same address
  radio.openReadingPipe(1, address);
  radio.startListening();
}

void loop() {
  int duration;
  int distance;

  digitalWrite(builtinLed, LOW);
  
  digitalWrite(trigPin, HIGH);
  delay(1);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) / 29.1;           // in centimeters (search ultrasonic distance calculation for details)

  /* Send stop command if an object is detected within 45 cm. */
  if (distance <= 45 && distance >= 0) {
    digitalWrite(builtinLed, HIGH);
    radio.stopListening();
    round_trip_timer = micros();
    radio.write( &ping, sizeof(uint8_t), 0 );
  }
}

Custom parts and enclosures

Semi-enclosure
A case of sorts for the arduino and its ultrasonic sensor by fb_51 (thingiverse)
sensor holder ( support de capteur US)

Schematics

Start Node
Ultrasonic start bb 8lwpunglvx
Stop Node
Ultrasonic stop bb q0jdazrgpx
Node Extended
Img 20190327 145654 yvzsm0i7il

Comments

Similar projects you might like

Temperature and Humidity Data Logger

Project tutorial by Wimpie van den Berg

  • 27,028 views
  • 2 comments
  • 25 respects

SD Card Temperature Data Logger

Project tutorial by 3 developers

  • 8,978 views
  • 0 comments
  • 9 respects

MKR Zero Weather Data Logger

Project tutorial by Arduino_Genuino

  • 27,017 views
  • 18 comments
  • 55 respects

Export Data from Arduino to Excel Sheet

Project showcase by ahmed ismail

  • 17,276 views
  • 1 comment
  • 9 respects

Temperature and Humidity Data logger - Breadboard

Project tutorial by Jed Hodson

  • 8,330 views
  • 2 comments
  • 10 respects

How to Build an Arduino Energy Monitor and Data Logger

Project tutorial by Sridhar Rajagopal

  • 6,695 views
  • 2 comments
  • 22 respects
Add projectSign up / Login