Smart Buoy [ GPS, Radio (NRF24) and a SD Card Module ]

1,051

9

5

About: Somebody once thought they could fix a plug socket using chopsticks. They caused a meltdown and burnt down a town. If only they'd watched T3ch Flicks!

In this tutorial, we’ll be showing you how to get GPS data, store it on an SD card and send it somewhere using radio.

We did this so we could keep track of the location of our seaborne buoy. The radio means that we can watch it remotely and the SD card means that on the off chance something breaks and our buoy goes for a wander, we can download the data it collected during its unplanned excursion - if we're ever able to retrieve it!

Supplies:

GPS module - Amazon

SD card module - Amazon

SD card - Amazon

2 X Radio modules (NRF24L01+) - Amazon

2 X Arduino - Amazon

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Getting GPS Data

The smart buoy makes sensor measurements as it sits in the sea, including GPS location and datetime. Take a look at the schematic which shows how we set up the circuit. The GPS module communicates via serial connection, so we’re using the Arduino software serial library as well as the tiny GPS library to communicate with it. These libraries make everything super simple. Let’s take you through the code…

#include <TinyGPS++.h>
#include <SoftwareSerial.h>

// The TinyGPS++ object
TinyGPSPlus gps;

// The serial connection to the GPS device
SoftwareSerial ss(4, 3);

struct dataStruct{
  double latitude;
  double longitude;
  unsigned long date;
  unsigned long time;
}gpsData;

void setup(){
  Serial.begin(115200);
  ss.begin(9600);
}

void loop(){
  while (ss.available() > 0){
    if (gps.encode(ss.read())){
      getInfo();
      printResults();
    }
  }
}

void getInfo(){
  if (gps.location.isValid()){
    gpsData.latitude = gps.location.lat();
    gpsData.longitude = gps.location.lng();
  }
  else{
    Serial.println("Invalid location");
  }
  if (gps.date.isValid()){
    gpsData.date = gps.date.value();
  }
  else{
    Serial.println("Invalid date");
  }
  if (gps.time.isValid()){
    gpsData.time = gps.time.value();
  }
  else{
    Serial.println("Invalid time");
  }
}

void printResults(){
  Serial.print("Location: ");
  Serial.print(gpsData.latitude, 6); Serial.print(", "); Serial.print(gpsData.longitude, 6);
  Serial.print("  Date: ");
  Serial.print(gpsData.date);
  Serial.print("  Time: ");
  Serial.print(gpsData.time);
  Serial.println();
}

(Check out the video for this code at https://youtu.be/xz1ix76U28E)

Step 2: Sending GPS Data Via Radio

Suppose the buoy is in sea taking measurements, but we want to see the data without getting our feet wet or bringing the buoy ashore. To get the measurements remotely, we’re using a radio module connected to an Arduino on both sides of the communication. In future, we will replace the receiver-side Arduino with a raspberry pi. The radio works similarly with both these interfaces so swapping them over is pretty straightforward.

The radio module communicates using SPI, which requires a few more connections than I2C but is still really easy to use because of the NRF24 library. Using the GPS module for the sensor measurements, we transmit its data from one Arduino to the other. We’re going to connect up the GPS and radio module to the Arduino and on the other side an Arduino with the radio module - have a look at the schematic.

Transmitter

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>


TinyGPSPlus gps;
SoftwareSerial ss(4, 3);
RF24 radio(8, 7); // CE, CSN


struct dataStruct{
  double latitude;
  double longitude;
  unsigned long date;
  unsigned long time;
}gpsData;


void setup() {
  Serial.begin(115200);
  ss.begin(9600);
  
  Serial.println("Setting up radio");
  //  Setup transmitter radio
  radio.begin();
  radio.openWritingPipe(0xF0F0F0F0E1LL);
  radio.setChannel(0x76);
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_250KBPS);
  radio.stopListening();
  radio.enableDynamicPayloads();
  radio.powerUp();
  Serial.println("Starting to send");
}


void loop() {
  while (ss.available() > 0){
    if (gps.encode(ss.read())){
      getInfo();
     radio.write(&gpsData, sizeof(gpsData));
    }
  }
} 


void getInfo(){
  if (gps.location.isValid()){
    gpsData.longitude = gps.location.lng();
    gpsData.latitude = gps.location.lat();
  }
  else{
    gpsData.longitude = 0.0;
    gpsData.latitude = 0.0;
  }
  if (gps.date.isValid()){
    gpsData.date = gps.date.value();
  }
  else{
    gpsData.date = 0;
  }
  if (gps.time.isValid()){
    gpsData.time = gps.time.value();
  }
  else{
    gpsData.time = 0;
  }
}

RECEIVER

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>


RF24 radio(8, 7); // CE, CSN

struct dataStruct{
  double latitude;
  double longitude;
  unsigned long date;
  unsigned long time;
}gpsData;

void setup() {
  Serial.begin(115200);
  //  Setup receiver radio
  radio.begin();
  radio.openReadingPipe(1, 0xF0F0F0F0E1LL);
  radio.setChannel(0x76);
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_250KBPS);
  radio.startListening();
  radio.enableDynamicPayloads();
  radio.powerUp();
}

void loop() {
  if (radio.available()) {
    radio.read(&gpsData, sizeof(gpsData));
    Serial.print("Location: ");
    Serial.print(gpsData.latitude, 6);
    Serial.print(", ");
    Serial.print(gpsData.longitude, 6);
    Serial.print("  Date: ");
    Serial.print(gpsData.date);
    Serial.print("  Time: ");
    Serial.print(gpsData.time);
    Serial.println();}
}

(Check out the video for this code at https://youtu.be/xz1ix76U28E)

Step 3: Storing Data Using an SD Card Module

The radio module is quite reliable, but sometimes you need a contingency plan in case there is a power cut on the receiver side or if the radio moves out of range. Our contingency plan is a SD card module which allows us to store the data we collect. The quantity of data being collected isn’t that large, so even a small SD card will easily be able to store a day’s worth of data.

#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>

TinyGPSPlus gps;

SoftwareSerial ss(4, 3);

struct dataStruct{
  double latitude;
  double longitude;
  unsigned long date;
  unsigned long time;
}gpsData;

void setup() {
  Serial.begin(115200);
  ss.begin(9600);
  
  if (!SD.begin(5)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");

File dataFile = SD.open("gps_data.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.println("Latitude, Longitude, Date, Time");
    dataFile.close();
  }
  else{
    Serial.println("nope can't open file");
  }
}

void loop() {
  while (ss.available() > 0){
    if (gps.encode(ss.read())){
      getInfo();
      printResults(); 
      saveInfo();
    }
  }
}

void getInfo(){
  if (gps.location.isValid()){
    gpsData.latitude = gps.location.lat();
    gpsData.longitude = gps.location.lng();
  }
  else{
    Serial.println("Invalid location");
  }
  if (gps.date.isValid()){
    gpsData.date = gps.date.value();
  }
  else{
    Serial.println("Invalid date");
  }
  if (gps.time.isValid()){
    gpsData.time = gps.time.value();
  }
  else{
    Serial.println("Invalid time");
  }
}

void printResults(){
  Serial.print("Location: ");
  Serial.print(gpsData.latitude, 6); Serial.print(", "); Serial.print(gpsData.longitude, 6);
  Serial.print("  Date: ");
  Serial.print(gpsData.date);
  Serial.print("  Time: ");
  Serial.print(gpsData.time);
  Serial.println();
}

void saveInfo(){
 File dataFile = SD.open("gps_data.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.print(gpsData.latitude);
    dataFile.print(", ");
    dataFile.print(gpsData.longitude);
    dataFile.print(", ");
    dataFile.print(gpsData.date);
    dataFile.print(", ");
    dataFile.println(gpsData.time); 
    dataFile.close();
  }
  else{
    Serial.println("nope no datafile");
  }
}

(We talk through this code in the video https://youtu.be/xz1ix76U28E)

Step 4: Sending and Storing GPS Data

{"context":{"location":{"href":"https://www.instructables.com/editInstructable/publish/E7XTBFBJYG8237E","protocol":"https:","host":"www.instructables.com","hostname":"www.instructables.com","port":"","pathname":"/editInstructable/publish/E7XTBFBJYG8237E","search":"","hash":"","origin":"https://www.instructables.com","ancestorOrigins":{}},"jQuery1124022615254677818364":1},"selector":"#editor-Object-40"}

Step 5: Thanks!

Thanks for watching this episode and following us in our journey to building our smart buoy. The next tutorial will show you how we powered the system.

If you enjoyed this check out the full build summary at https://www.instructables.com/id/Smart-Buoy/ and vote for us in the Sensor Contest! <3

Be the First to Share

    Recommendations

    • CNC Contest

      CNC Contest
    • Make it Move

      Make it Move
    • Teacher Contest

      Teacher Contest

    5 Discussions

    0
    None
    IgorF2

    6 weeks ago

    Hi there! Great job! Congrats! :D
    Do you know what's the range of the NRF module? Have you already considered using a Lora module instead? I think it has a longer range...

    2 replies
    1
    None
    t3chflicksIgorF2

    Reply 5 weeks ago

    Thanks a lot!
    We've seen some get kilometres, but we only tested up to ~60m. Yes we'll use LoRa in v2 :)

    0
    None
    IgorF2t3chflicks

    Reply 5 weeks ago

    Great! I live in a costal region and I’m planing to use Lora for remote sensing as well.
    I’ll be happy to see the next version of your project!

    0
    None
    tytower

    6 weeks ago

    I would be interested to see how you keep this going without corrosion from sea water ingress. The SD cards don't last with sea water around

    1 reply
    0
    None
    t3chflickstytower

    Reply 6 weeks ago

    It’s in a water right buoy so hopefully none but we’ll see when we leave it out in the ocean for a bit