Vimarsh
Published © CC BY-NC-SA

Superintend Oceans

The project measures the speed and acceleration of tsunamis and also keeps an eye on other movements in the ocean.

AdvancedFull instructions provided3 hours749
Superintend Oceans

Things used in this project

Hardware components

Spresense boards (main & extension)
Sony Spresense boards (main & extension)
The brains of the project. Has GPS, audio/DAC and many cores to use.
×1
Wio Tracker - GPS, BT3.0, GSM, Arduino Compatible
Seeed Studio Wio Tracker - GPS, BT3.0, GSM, Arduino Compatible
The module for Communication to a server if a cellular network is available in that region which is not true. The best option will only be satellite communication.
×1
NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
No GSM available so nodemcu does the job by taking the data from spresense and sending it over to GFireBase.
×1

Software apps and online services

Sony Spresense SDK
Based on NuttX For coding the Spresense board.
Arduino IDE
Arduino IDE
For coding the NodeMCU.
Firebase
Google Firebase
Act as Data Storage
A custom algorithm
To Find the distance between consecutive GNSS readings and then make your own one to find the acceleration and velocity of the wave. See below to find the basic distance.

Story

Read more

Schematics

Schematics

Connection Diagram

Spresense Pinout

Pinout for Spresense main board

Spresense Pinout 2

Pinout for Spresense Extention board

NodeMCU Pinout

Pinout for NodeMCU

Code

Main Processor Code

C/C++
The main code to be excecuted.
It is combined form of Spresense ASMP and GNSS code and also communicates with other core.
/****************************************************************************
 * asmp/asmp_main.c
 *
 *   Copyright 2018 Sony Semiconductor Solutions Corporation
 *
 * Modified By: Vimarsh
				vimarshshah.blogspot.in
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <sdk/config.h>
#include <nuttx/compiler.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <unistd.h>

#include <nuttx/drivers/ramdisk.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <debug.h>
#include <errno.h>

#include <asmp/asmp.h>
#include <asmp/mptask.h>
#include <asmp/mpshm.h>
#include <asmp/mpmq.h>
#include <asmp/mpmutex.h>

//GPS Libraries
#include <sdk/config.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <arch/chip/gnss.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#ifdef CONFIG_FS_ROMFS
#  include "worker/romfs.h"

#  define SECTORSIZE   512
#  define NSECTORS(b)  (((b)+SECTORSIZE-1)/SECTORSIZE)
#  define MOUNTPT "/romfs"
#endif

#ifndef MOUNTPT
#  define MOUNTPT "/mnt/vfat/BIN"
#endif

/* MP object keys. Must be synchronized with worker. */

#define KEY_SHM   1
#define KEY_MQ    2
#define KEY_MUTEX 3

#define MSG_ID 4

/* Check configuration.  This is not all of the configuration settings that
 * are required -- only the more obvious.
 */

#if CONFIG_NFILE_DESCRIPTORS < 1
#  error "You must provide file descriptors via CONFIG_NFILE_DESCRIPTORS in your configuration file"
#endif

#define message(format, ...)    printf(format, ##__VA_ARGS__)
#define err(format, ...)        fprintf(stderr, format, ##__VA_ARGS__)


//GPS Definations
#define GNSS_POLL_FD_NUM          1
#define GNSS_POLL_TIMEOUT_FOREVER -1
#define MY_GNSS_SIG               18

/********************************
	Global Variables
*********************************/
int hr,min,sec=0;
double lat,lon=0;
char* send_data="";

/****************************************************************************
 * Private Types
 ****************************************************************************/
struct cxd56_gnss_dms_s
{
  int8_t   sign;
  uint8_t  degree;
  uint8_t  minute;
  uint32_t frac;
};
/****************************************************************************
 * Private Data
 ****************************************************************************/
static uint32_t                         posfixflag;
static struct cxd56_gnss_positiondata_s posdat;

static char fullpath[128];

/****************************************************************************
 * Symbols from Auto-Generated Code
 ****************************************************************************/

/****************************************************************************
 * Private Functions
 ****************************************************************************/

/****************************************************************************
 * Name: double_to_dmf()
 *
 * Description:
 *   Convert from double format to degree-minute-frac format.
 *
 * Input Parameters:
 *   x   - double value.
 *   dmf - Address to store the conversion result.
 *
 * Returned Value:
 *   none.
 *
 * Assumptions/Limitations:
 *   none.
 *
 ****************************************************************************/

static void double_to_dmf(double x, struct cxd56_gnss_dms_s * dmf)
{
  int    b;
  int    d;
  int    m;
  double f;
  double t;

  if (x < 0)
    {
      b = 1;
      x = -x;
    }
  else
    {
      b = 0;
    }
  d = (int)x; /* = floor(x), x is always positive */
  t = (x - d) * 60;
  m = (int)t; /* = floor(t), t is always positive */
  f = (t - m) * 10000;

  dmf->sign   = b;
  dmf->degree = d;
  dmf->minute = m;
  dmf->frac   = f;
}
/****************************************************************************
 * Name: read_and_print()
 *
 * Description:
 *   Read and print POS data.
 *
 * Input Parameters:
 *   fd - File descriptor.
 *
 * Returned Value:
 *   Zero (OK) on success; Negative value on error.
 *
 * Assumptions/Limitations:
 *   none.
 *
 ****************************************************************************/

static int read_and_print(int fd)
{
  int ret;
  struct cxd56_gnss_dms_s dmf;

  /* Read POS data. */

  ret = read(fd, &posdat, sizeof(posdat));
  if (ret < 0)
    {
      printf("read error\n");
      goto _err;
    }
  else if (ret != sizeof(posdat))
    {
      ret = ERROR;
      printf("read size error\n");
      goto _err;
    }
  else
    {
      ret = OK;
    }

  /* Print POS data. */

  /* Print time. */

  printf(">Hour:%d, minute:%d, sec:%d, usec:%d\n",
         posdat.receiver.time.hour, posdat.receiver.time.minute,
         posdat.receiver.time.sec, posdat.receiver.time.usec);
		 
  hr=posdat.receiver.time.hour;
  min= posdat.receiver.time.minute;
  sec=posdat.receiver.time.sec
  if (posdat.receiver.pos_fixmode != CXD56_GNSS_PVT_POSFIX_INVALID)
    {
      /* 2D fix or 3D fix.
       * Convert latitude and longitude into dmf format and print it. */

      posfixflag = 1;

      double_to_dmf(posdat.receiver.latitude, &dmf);
      printf(">LAT %d.%d.%04d\n", dmf.degree, dmf.minute, dmf.frac);
	  lat=posdat.receiver.latitude;
	  
      double_to_dmf(posdat.receiver.longitude, &dmf);
      printf(">LNG %d.%d.%04d\n", dmf.degree, dmf.minute, dmf.frac);
	  lon=posdat.receiver.longitude;
	  
    }
  else
    {
      /* No measurement. */

      printf(">No Positioning Data\n");
    }

_err:
  return ret;
}

/****************************************************************************
 * Name: gnss_setparams()
 *
 * Description:
 *   Set gnss parameters use ioctl.
 *
 * Input Parameters:
 *   fd - File descriptor.
 *
 * Returned Value:
 *   Zero (OK) on success; Negative value on error.
 *
 * Assumptions/Limitations:
 *   none.
 *
 ****************************************************************************/

static int gnss_setparams(int fd)
{
  int      ret = 0;
  uint32_t set_satellite;
  struct cxd56_gnss_ope_mode_param_s set_opemode;

  /* Set the GNSS operation interval. */

  set_opemode.mode     = 1;     /* Operation mode:Normal(default). */
  set_opemode.cycle    = 1000;  /* Position notify cycle(msec step). */

  ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_OPE_MODE, (uint32_t)&set_opemode);
  if (ret < 0)
    {
      printf("ioctl(CXD56_GNSS_IOCTL_SET_OPE_MODE) NG!!\n");
      goto _err;
    }

  /* Set the type of satellite system used by GNSS. */

  set_satellite = CXD56_GNSS_SAT_GPS | CXD56_GNSS_SAT_GLONASS;

  ret = ioctl(fd, CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM, set_satellite);
  if (ret < 0)
    {
      printf("ioctl(CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM) NG!!\n");
      goto _err;
    }

_err:
  return ret;
}

static int run_worker(const char *filename)
{
  mptask_t mptask;
  mpmutex_t mutex;
  mpshm_t shm;
  mpmq_t mq;
  uint32_t msgdata;
  int ret, wret;
  char *buf;
  send_data=hr+";"+min+";"+sec+";"+lat+";"+lon;	
  /* Initialize MP task */

  ret = mptask_init(&mptask, filename);
  if (ret != 0)
    {
      err("mptask_init() failure. %d\n", ret);
      return ret;
    }

  ret = mptask_assign(&mptask);
  if (ret != 0)
    {
      err("mptask_asign() failure. %d\n", ret);
      return ret;
    }

  /* Initialize MP mutex and bind it to MP task */

  ret = mpmutex_init(&mutex, KEY_MUTEX);
  if (ret < 0)
    {
      err("mpmutex_init() failure. %d\n", ret);
      return ret;
    }
  ret = mptask_bindobj(&mptask, &mutex);
  if (ret < 0)
    {
      err("mptask_bindobj(mutex) failure. %d\n", ret);
      return ret;
    }

  /* Initialize MP message queue with asigned CPU ID, and bind it to MP task */

  ret = mpmq_init(&mq, KEY_MQ, mptask_getcpuid(&mptask));
  if (ret < 0)
    {
      err("mpmq_init() failure. %d\n", ret);
      return ret;
    }
  ret = mptask_bindobj(&mptask, &mq);
  if (ret < 0)
    {
      err("mptask_bindobj(mq) failure. %d\n", ret);
      return ret;
    }

  /* Initialize MP shared memory and bind it to MP task */

  ret = mpshm_init(&shm, KEY_SHM, 1024);
  if (ret < 0)
    {
      err("mpshm_init() failure. %d\n", ret);
      return ret;
    }
  ret = mptask_bindobj(&mptask, &shm);
  if (ret < 0)
    {
      err("mptask_binobj(shm) failure. %d\n", ret);
      return ret;
    }

  /* Map shared memory to virtual space */

  buf = mpshm_attach(&shm, 0);
  if (!buf)
    {
      err("mpshm_attach() failure.\n");
      return ret;
    }
  message("attached at %08x\n", (uintptr_t)buf);
  memset(buf, 0, 1024);

  /* Run worker */

  ret = mptask_exec(&mptask);
  if (ret < 0)
    {
      err("mptask_exec() failure. %d\n", ret);
      return ret;
    }

  /* Send command to worker */

  ret = mpmq_send(&mq, MSG_ID, send_data);
  if (ret < 0)
    {
      err("mpmq_send() failure. %d\n", ret);
      return ret;
    }

  /* Wait for worker message */

  ret = mpmq_receive(&mq, &msgdata);
  if (ret < 0)
    {
      err("mpmq_recieve() failure. %d\n", ret);
      return ret;
    }
  message("Worker response: ID = %d, data = %08x\n",
          ret, msgdata);

  /* Show worker copied data */

  /* Lock mutex for synchronize with worker after it's started */

  mpmutex_lock(&mutex);

  message("Worker said: %s\n", buf);

  mpmutex_unlock(&mutex);

  /* Destroy worker */

  wret = -1;
  ret = mptask_destroy(&mptask, false, &wret);
  if (ret < 0)
    {
      err("mptask_destroy() failure. %d\n", ret);
      return ret;
    }

  message("Worker exit status = %d\n", wret);

  /* Finalize all of MP objects */

  mpshm_detach(&shm);
  mpshm_destroy(&shm);
  mpmutex_destroy(&mutex);
  mpmq_destroy(&mq);

  return 0;
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

/****************************************************************************
 * Name: asmp_main
 ****************************************************************************/

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int asmp_main(int argc, char *argv[])
#endif
{
#ifdef CONFIG_FS_ROMFS
  int ret;
  struct stat buf;

  ret = stat(MOUNTPT, &buf);
  if (ret < 0)
    {
      message("Registering romdisk at /dev/ram0\n");
      ret = romdisk_register(0, (FAR uint8_t *)romfs_img,
                             NSECTORS(romfs_img_len), SECTORSIZE);
      if (ret < 0)
        {
          err("ERROR: romdisk_register failed: %d\n", ret);
          exit(1);
        }

      message("Mounting ROMFS filesystem at target=%s with source=%s\n",
              MOUNTPT, "/dev/ram0");

      ret = mount("/dev/ram0", MOUNTPT, "romfs", MS_RDONLY, NULL);
      if (ret < 0)
        {
          err("ERROR: mount(%s,%s,romfs) failed: %s\n",
              "/dev/ram0", MOUNTPT, errno);
        }
    }
#endif

  if (argc > 1)
    {
      snprintf(fullpath, 128, "%s/%s", MOUNTPT, argv[1]);
    }
  else
    {
#ifdef CONFIG_FS_ROMFS
      snprintf(fullpath, 128, "%s/%s", MOUNTPT, "hello");
#else
      snprintf(fullpath, 128, "%s/%s", MOUNTPT, "HELLO");
#endif
    }

  (void) run_worker(fullpath);

  return 0;
}

/****************************************************************************
 * Name: gnss_main()
 *
 * Description:
 *   Set parameters and run positioning.
 *
 * Input Parameters:
 *   argc - Does not use.
 *   argv - Does not use.
 *
 * Returned Value:
 *   Zero (OK) on success; Negative value on error.
 *
 * Assumptions/Limitations:
 *   none.
 *
 ****************************************************************************/

#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int gnss_main(int argc, char *argv[])
#endif
{
  int      fd;
  int      ret;
  int      posperiod;
  sigset_t mask;
  struct cxd56_gnss_signal_setting_s setting;

  /* Program start. */

  printf("Hello, GNSS(USE_SIGNAL) SAMPLE!!\n");

  /* Get file descriptor to control GNSS. */

  fd = open("/dev/gps", O_RDONLY);
  if (fd < 0)
    {
      printf("open error:%d,%d\n", fd, errno);
      return -ENODEV;
    }

  /* Configure mask to notify GNSS signal. */

  sigemptyset(&mask);
  sigaddset(&mask, MY_GNSS_SIG);
  ret = sigprocmask(SIG_BLOCK, &mask, NULL);
  if (ret != OK)
    {
      printf("sigprocmask failed. %d\n", ret);
      goto _err;
    }

  /* Set the signal to notify GNSS events. */

  setting.fd      = fd;
  setting.enable  = 1;
  setting.gnsssig = CXD56_GNSS_SIG_GNSS;
  setting.signo   = MY_GNSS_SIG;
  setting.data    = NULL;

  ret = ioctl(fd, CXD56_GNSS_IOCTL_SIGNAL_SET, (unsigned long)&setting);
  if (ret < 0)
    {
      printf("signal error\n");
      goto _err;
    }

  /* Set GNSS parameters. */

  ret = gnss_setparams(fd);
  if (ret != OK)
    {
      printf("gnss_setparams failed. %d\n", ret);
      goto _err;
    }

  /* Initial positioning measurement becomes cold start if specified hot
   * start, so working period should be long term to receive ephemeris. */

  posperiod  = 200;
  posfixflag = 0;

  /* Start GNSS. */

  ret = ioctl(fd, CXD56_GNSS_IOCTL_START, CXD56_GNSS_STMOD_HOT);
  if (ret < 0)
    {
      printf("start GNSS ERROR %d\n", errno);
      goto _err;
    }
  else
    {
      printf("start GNSS OK\n");
    }

  do
    {
      /* Wait for positioning to be fixed. After fixed,
       * idle for the specified seconds. */

      ret = sigwaitinfo(&mask, NULL);
      if (ret != MY_GNSS_SIG)
        {
          printf("sigwaitinfo error %d\n", ret);
          break;
        }

      /* Read and print POS data. */

      ret = read_and_print(fd);
      if (ret < 0)
        {
          break;
        }

      if (posfixflag)
        {
          /* Count down started after POS fixed. */

          posperiod--;
        }
    }
  while (posperiod > 0);

  /* Stop GNSS. */

  ret = ioctl(fd, CXD56_GNSS_IOCTL_STOP, 0);
  if (ret < 0)
    {
      printf("stop GNSS ERROR\n");
    }
  else
    {
      printf("stop GNSS OK\n");
    }

_err:

  /* GNSS firmware needs to disable the signal after positioning. */

  setting.enable = 0;
  ret = ioctl(fd, CXD56_GNSS_IOCTL_SIGNAL_SET, (unsigned long)&setting);
  if (ret < 0)
    {
      printf("signal error\n");
    }

  sigprocmask(SIG_UNBLOCK, &mask, NULL);

  /* Release GNSS file descriptor. */

  ret = close(fd);
  if (ret < 0)
    {
      printf("close error %d\n", errno);
    }

  printf("End of GNSS Sample:%d\n", ret);

  return ret;
}

CoProcessor Code

C/C++
The code that will run in another core of spresense board.
Dedicated to communicate with the GSM shield or the nodemcu (here) or any other device!
/****************************************************************************
 * asmp/worker/send_gps.c
 *
 *   Copyright 2018 Sony Semiconductor Solutions Corporation
 * Modified By: Vimarsh Shah
					vimarshshah.blogspot.in
*/					
 
/****************************************************************************
 * Included Files
 ****************************************************************************/
#include <errno.h>

#include <asmp/types.h>
#include <asmp/mpshm.h>
#include <asmp/mpmutex.h>
#include <asmp/mpmq.h>

#include "asmp.h"

/* MP object keys. Must be synchronized with supervisor. */

#define KEY_SHM   1
#define KEY_MQ    2
#define KEY_MUTEX 3

#define MSG_ID 4

#define ASSERT(cond) if (!(cond)) wk_abort()

char* data_send="";

static char *strcopy(char *dest, const char *src)
{
  char *d = dest;
  while (*src) *d++ = *src++;
  *d = '\0';

  return dest;
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

int main(void)
{
  mpmutex_t mutex;
  mpshm_t shm;
  mpmq_t mq;
  uint32_t msgdata;
  char *buf;
  int ret;

  /* Initialize MP Mutex */

  ret = mpmutex_init(&mutex, KEY_MUTEX);
  ASSERT(ret == 0);

  /* Initialize MP message queue,
   * On the worker side, 3rd argument is ignored.
   */

  ret = mpmq_init(&mq, KEY_MQ, 0);
  ASSERT(ret == 0);

  /* Initialize MP shared memory */

  ret = mpshm_init(&shm, KEY_SHM, 1024);
  ASSERT(ret == 0);

  /* Map shared memory to virtual space */

  buf = (char *)mpshm_attach(&shm, 0);
  ASSERT(buf);

  /* Receive message from supervisor */

  ret = mpmq_receive(&mq, &msgdata);
  ASSERT(ret == MSG_ID);

  /* Copy hello message to shared memory */

  mpmutex_lock(&mutex);
  strcopy(buf, data_send);
  mpmutex_unlock(&mutex);

  /* Free virtual space */

  mpshm_detach(&shm);

  /* Send done message to supervisor */

  msgdata ^= "Success";
  ret = mpmq_send(&mq, MSG_ID, msgdata);
  ASSERT(ret == 0);
  
  printf("%s",data_send); //sending all the data to serial
  
  return 0;
}

Code for NodeMCU

Arduino
This code reads data from serial and then parses it and sends to google firebase.
The firebase used here is full access but for security other option may be used.
The FirebaseArduino and ArduinoJSON library is required for code to compile.
//
// Code by : Vimarsh Shah
//                  vimarshshah.blogspot.in

#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>

// Set these to run example.
#define FIREBASE_HOST "<project-name>.firebaseio.com"
#define FIREBASE_AUTH " A****your auth token from firebase******A "
#define WIFI_SSID "*Wifi*"
#define WIFI_PASSWORD "*PSK*"

char* data_receive = "";

#include <math.h>

#define R 6371
#define TO_RAD (3.1415926536 / 180)

void setup() {
  Serial.begin(115200);

  // connect to wifi.
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
}

int n = 0;
doublw hour, minute, second, latitude, longitude, prev_lat, prev_lon = 0;

void loop() {

  data_receive = Serial.read();

  n = sscanf(data_receive, "%d;%d;%d;%d;%d", &hour, &minute, &second, &latitude, &longitude);

  String time_data = hour + ":" + minute + ":" + second;
  String position_data = latitude + ";" + longitude;

  // set value
  Firebase.setFloat(time_data, position_data);
  // handle error
  if (Firebase.failed()) {
    Serial.print("setting <> failed:");
    Serial.println(Firebase.error());
    return;
  }
  delay(1000);


  // get value
  String time_prev = hour + ":" + minute + ":" + (second - 1);//calculating the label for previus data
  Serial.print("Previous data: ");
  String data_prev_coordinates = Firebase.getFloat(time_prev);//getting the last data
  Serial.println(data_prev_coordinates);
  n = sscanf(data_prev_coordinates, "%d;%d", &prev_lat, &prev_lon);
//pasring it
  Serial.println("Distance covered: " + find_d(latitude, longitude, prev_lat, prev_lon));//calling the method


}
void find_d(double th1, double ph1, double th2, double ph2) {
  double dx, dy, dz;
  ph1 -= ph2;
  ph1 *= TO_RAD, th1 *= TO_RAD, th2 *= TO_RAD;

  dz = sin (th1) - sin (th2);
  dx = cos (ph1) * cos (th1) - cos (th2);
  dy = sin (ph1) * cos (th1);
  return asin (sqrt (dx * dx + dy * dy + dz * dz) / 2) * 2 * R;
}//the method to find the distance

Finding the distance

C/C++
The code can find the distance between two GPS coordinates!
Add all latidtudes and longitudes to see the direct distance or use the logic in your own algorithm!
This is called the Haversine fomula > Considering earth as perfect spheare, we can use it to find distance (actual - the circular one) between two coordinal points.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define R 6371
#define TO_RAD (3.1415926536 / 180)
double
dist (double th1, double ph1, double th2, double ph2)
{
  double dx, dy, dz;
  ph1 -= ph2;
  ph1 *= TO_RAD, th1 *= TO_RAD, th2 *= TO_RAD;

  dz = sin (th1) - sin (th2);
  dx = cos (ph1) * cos (th1) - cos (th2);
  dy = sin (ph1) * cos (th1);
  return asin (sqrt (dx * dx + dy * dy + dz * dz) / 2) * 2 * R;
}

int
main ()
{
  double d = dist (<lat1>, <long1>, <lat2>, <long2>);
  /* Americans don't know kilometers */
  printf ("dist: %.1f km (%.1f mi.)\n", d, d / 1.609344);

  return 0;
}


//Code fron: https://rosettacode.org/wiki/Haversine_formula

Credits

Vimarsh

Vimarsh

5 projects • 38 followers
Currently, a student studying Physics @ BITS Pilani. A maker and a learner :D

Comments