Project tutorial
Smart Buoy - [Making Wave and Temperature Measurements]

Smart Buoy - [Making Wave and Temperature Measurements] © CC BY-SA

How to use a GY86 (wave measurements) and water temperature sensor.

  • 19 views
  • 0 comments
  • 1 respect

Components and supplies

About this project

In this tutorial, we show you how we took wave and temperature measurements on our smart buoy. Be warned, this tutorial is pretty code-heavy, so if you’re here for a good time not for a long time, check out our summary video first to get a nice brief overview before enjoying this in-depth look.

Supplies:

  • Arduino Nano - Amazon
  • GY-86 (accelerometer, gyroscope, barometer, compass) - Amazon
  • Water temperature sensor - Amazon

Step 1: GY-86: Accelerometer & Gyroscope

The main sensor on the buoy is a GY-86, which contains the MPU6050 accelerometer gyroscope, the HMC5883L Magnetometer and the MS5611 barometer. These sensors enable us to measure air temperature, wave height, wave period and wave energy (and wave direction if someone out there is smart enough to do the maths).

The GY-86 communicates via i2C - see the schematic. This is the code we used to access the accelerometer and gyroscope readings. (We talk through this in the video so check that out)

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h" 
MPU6050 mpu;
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing MP6050...");
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");}
void loop() {
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  printResults();
  delay(10);
}
void printResults(){
  Serial.print("Acc (x,y,z) m/s/s: "); 
  Serial.print(ax); Serial.print(" "); 
  Serial.print(ay); Serial.print(" "); 
  Serial.print(az);
  Serial.print(" Gyro(x,y,z) °/s: "); 
  Serial.print(gx); Serial.print(" "); 
  Serial.print(gy); Serial.print(" "); 
  Serial.println(gz);
}

Step 2: GY-86: Magnetometer (Compass)

The GY-86 contains a magnetometer which we use as a compass. You don’t need to change any connections - woo! Here’s the code to get the compass value

Remember to use the value of declination specific for your location otherwise your results may be inaccurate.

(We talk through this in the video so check that out )

#include "Wire.h"
#include "I2Cdev.h" 
#include "MPU6050.h"
#include "HMC5883L.h" 
MPU6050 mpu;
HMC5883L mag;
int16_t mx, my, mz;
// Find the declination where you are from http://www.magnetic-declination.com
//                  -14°     59'            
float declination = (-14.0 - (59.0 / 60.0)) * (PI/180);
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  mag.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  Serial.println(mag.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");
}
void loop() {
  mag.getHeading(&mx, &my, &mz);
  printResults();
  delay(200);
}
void printResults(){
  float heading = atan2(my, mx);
  heading += declination;
  if (heading < 0) heading += 2 * PI;
  if (heading > 2 * PI) heading -= 2 * PI;
  heading *= 180/M_PI;
  
  Serial.print("Heading °:"); 
  Serial.println(heading);
}

Step 3: GY-86: Barometer and Temperature

Here’s how we got the values from the MS5611 barometer.

(We talk through this in the video so check that out )

#include "Wire.h"
#include "I2Cdev.h" 
#include "MPU6050.h" 
#include <ms5611.h> 
MPU6050 mpu;
MS5611 baro;
double temp;
long pressure;
double altitude;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}
void loop() {
  temp = baro.readTemperature(true);
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  printResults();
  delay(200);
}
void printResults(){
  Serial.print("Pressure hPa: "); Serial.print(pressure);
  Serial.print("  Altitude m: "); Serial.print(altitude);
  float tempC = temp / 340.00 + 36.53;
  Serial.print("  Temp °C: "); Serial.println(tempC);
}

Step 4: Crude Wave Height

Once all those sensors are set up, you can use them to start measuring wave properties.

Starting with wave height...the altitude of the buoy can be calculated using the air pressure value. We can use the relative altitude of the buoy over a time period to work out the wave height like this:

(We talk through this in the video so check that out )

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h" //  ^
#include <ms5611.h> // 
MPU6050 mpu;
MS5611 baro;
long pressure;
double altitude, min_height, max_height, wave_height;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}
void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude;
  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  wave_height = (max_height - min_height)/2.0;
  Serial.print("Wave Height m: "); 
  Serial.println(wave_height);
}

Step 5: Crude Wave Period

The next thing is wave period. We used airy wave theory - a lovely basic wave theory which says that water surface waves can be described as sine waves. It’s great to use because it makes the maths easier, but it is of course a simplification and does have certain caveats, including that it is inaccurate in shallower water where waves transform and break. Using this theory, we should be able to get a value of wave period using the midpoint between our maximum and minimum relative altitudes and finding how frequently the buoy crosses this point.

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h" 
#include <ms5611.h> 
MPU6050 mpu;
MS5611 baro;
long pressure;
double altitude, min_height, max_height, mid_point, smudge_factor;
byte escaped, started;
unsigned long period_start, period_end;
float avg_period = -1;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}
void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude; 
  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  mid_point = (max_height + min_height)/2.0;
  smudge_factor = (max_height - mid_point)*0.15;
  Serial.print("Mid Point m: "); Serial.print(mid_point);
  
  start_time = millis();
  //  for 15 seconds 
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    //    if within a range of 30% of wave height from the mid point
    //    start the timer else stop it
    if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor){
      if ( !started){
        period_start = millis();
        started = true;
      }
      else{
        if ( escaped ){
          // if it has started and escaped and is now returning
          period_end = millis();
          started = false;
          escaped = false;
          // if the variable has already been assigned
          // use its previous value and new value to work out avg
          if(avg_period != -1){
            avg_period = (avg_period + (period_end-period_start)*2)  / 2.0;
          }
          // assign it
          else{
            avg_period =  (period_end-period_start)*2; 
          }
        }
      }
    }
    else{
      escaped = true;
    } 
  }
  Serial.print("  Period s: "); Serial.println(avg_period/1000);
}

(We talk through this in the video so check that out )

Step 6: Wave Direction (HELP US)

We never actually managed to measure wave direction.

However the sensors aboard the buoy should be able to do it. You are able to measure dynamic accelerations with the GY-86 Accelerometer by subtracting the affects of the gravitational force. You are also able to get the direction of this acceleration. Using the direction of buoy acceleration along with the compass value for a given position should allow you to determine wave direction. We gave it a go in the code below.

---- If someone out there could help us with this it would be amazing <3 ----

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "HMC5883L.h"
#include "Wire.h"
MPU6050 mpu;
HMC5883L mag;
int16_t mx, my, mz;
#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
float declination = -14.0 - (59.0 / 60.0);
// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}
void setup() {
    Serial.begin(115200);
    Wire.begin();
    Wire.setClock(400000); 
    
    mpu.setI2CMasterModeEnabled(false);
    mpu.setI2CBypassEnabled(true) ;
    mpu.setSleepEnabled(false);
    mpu.initialize();
    mag.initialize();
   // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
devStatus = mpu.dmpInitialize();
  // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(112);
    mpu.setYGyroOffset(5);
    mpu.setZGyroOffset(-15);
    mpu.setZAccelOffset(1487); 
    if (devStatus == 0) {
        mpu.setDMPEnabled(true);
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        dmpReady = true;
        packetSize = mpu.dmpGetFIFOPacketSize();
    }
}
void loop() {
    if (!dmpReady) return;
    while (!mpuInterrupt && fifoCount < packetSize) {
        if (mpuInterrupt && fifoCount < packetSize) {
          fifoCount = mpu.getFIFOCount();
        }        
    }       
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
        mpu.resetFIFO();
        fifoCount = mpu.getFIFOCount();
    } 
    else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
      // OUTPUT_READABLE_WORLDACCEL
      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetAccel(&aa, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
      mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
      Serial.print("Acceleration (x,y) m/s/s: ");
      Serial.print(aaWorld.x);
      Serial.print("  ");
      Serial.println(aaWorld.y);
     // Find the angle of acceleration
      //  double angle_of_acc = atan2(aaWorld.y, aaWorld.x);
      //  angle_of_acc *= 180/M_PI;
      // Get compass heading
      // mag.getHeading(&mx, &my, &mz);
      // float heading = atan2(my, mx);
      // if (heading < 0) heading += 2 * PI;
      // if (heading > 2 * PI) heading -= 2 * PI;
      // heading *= 180/M_PI;
      // heading += declination;
      // Offset angle of acceleration by the heading angle
      // wave_direction = angle_off_acc + heading
      
    }
} 

Step 7: Crude Wave Energy

One definition of Wave energy is defined by:

P = 0.5 height ** 2 * period [ https://en.wikipedia.org/wiki/Wave_power].

Using our values for wave period and height, we are able to calculate wave energy like this:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include <ms5611.h> 
MPU6050 mpu;
MS5611 baro;
long pressure;
double altitude, min_height, max_height, wave_height, mid_point, smudge_factor, wave_power;
byte escaped, started;
unsigned long period_start, period_end;
float avg_period = -1;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}
void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude;
  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  mid_point = (max_height + min_height)/2.0;
  wave_height = (max_height - mid_point) / 2.0;
  smudge_factor = wave_height * 0.15;
  Serial.print("Wave Height m: "); Serial.print(wave_height);
  
  start_time = millis();
  //  for 15 seconds 
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    //    if within a range of 30% of wave height from the mid point
    //    start the timer else stop it
    if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor){
      if ( !started){
        period_start = millis();
        started = true;
      }
      else{
        if ( escaped ){
          // if it has started and escaped and is now returning
          period_end = millis();
          started = false;
          escaped = false;
          // if the variable has already been assigned
          // use its previous value and new value to work out avg
          if(avg_period != -1){
            avg_period = (avg_period + (period_end-period_start)*2)  / 2.0;
          }
          // assign it
          else{
            avg_period =  (period_end-period_start)*2; 
          }
       }
      }
    }
    else{
      escaped = true;
    } 
  }
  Serial.print("  Period s: "); Serial.print(avg_period/1000);
  wave_power = (0.5 * wave_height * wave_height * avg_period / 1000);
  Serial.print("  Wave Power kW/m: "); Serial.println(wave_power); 
}

(We talk through this in the video so check that out )

Step 8: Water Temperature

Finally, we want to be able to measure water temperature. The DS18B20 water temperature sensor will protrude from the bottom of the buoy into the sea and the Arduino communicates with it using 1-wire.

The only modification you need to make is adding a pull-up resistor on the signal wire and then we can talk to it like this:

#include <onewire.h>
#include <dallastemperature.h>
OneWire oneWire(6);
DallasTemperature sensors(&oneWire);
float water_temperature;
void setup() {
  Serial.begin(115200);
  sensors.begin();
}
void loop() {
  sensors.requestTemperatures();
  water_temperature = sensors.getTempCByIndex(0);  
  Serial.print("Water temperature C "); Serial.println(water_temperature);
  delay(200);
}

(We talk through this in the video so check that out )

Step 9: Thanks

Thanks for reading this tutorial, this has been the first step in building our smart buoy. Check out our next tutorial soon to see how we send and store data and use the GPS.

T3chFlicks

Code

gy_86_accelerometer_gyroscope.inoArduino
No preview (download only).
gy_86_magnetometer.inoArduino
No preview (download only).
gy_86_barrometer.inoArduino
No preview (download only).
wave_height.inoArduino
No preview (download only).
wave_period.inoArduino
No preview (download only).
wave_power.inoArduino
No preview (download only).
Code snippet #1Plain text
#include "Wire.h"

#include "I2Cdev.h"
#include "MPU6050.h" 

MPU6050 mpu;

int16_t ax, ay, az;
int16_t gx, gy, gz;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing MP6050...");
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");}

void loop() {
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  printResults();
  delay(10);
}

void printResults(){
  Serial.print("Acc (x,y,z) m/s/s: "); 
  Serial.print(ax); Serial.print(" "); 
  Serial.print(ay); Serial.print(" "); 
  Serial.print(az);
  Serial.print(" Gyro(x,y,z) °/s: "); 
  Serial.print(gx); Serial.print(" "); 
  Serial.print(gy); Serial.print(" "); 
  Serial.println(gz);
}
Code snippet #2Plain text
#include "Wire.h"

#include "I2Cdev.h" 
#include "MPU6050.h"
#include "HMC5883L.h" 
 
MPU6050 mpu;
HMC5883L mag;

int16_t mx, my, mz;

// Find the declination where you are from http://www.magnetic-declination.com

//                  -14°     59'            
float declination = (-14.0 - (59.0 / 60.0)) * (PI/180);

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  mag.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  Serial.println(mag.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");

}

void loop() {
  mag.getHeading(&mx, &my, &mz);
  printResults();
  delay(200);
}

void printResults(){
  float heading = atan2(my, mx);
  heading += declination;
  if (heading < 0) heading += 2 * PI;
  if (heading > 2 * PI) heading -= 2 * PI;
  heading *= 180/M_PI;
  
  Serial.print("Heading °:"); 
  Serial.println(heading);
}
Code snippet #3Plain text
#include "Wire.h"

#include "I2Cdev.h" 
#include "MPU6050.h" 
#include <ms5611.h> 

MPU6050 mpu;
MS5611 baro;

double temp;
long pressure;
double altitude;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}

void loop() {
  temp = baro.readTemperature(true);
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  printResults();
  delay(200);
}

void printResults(){
  Serial.print("Pressure hPa: "); Serial.print(pressure);
  Serial.print("  Altitude m: "); Serial.print(altitude);
  float tempC = temp / 340.00 + 36.53;
  Serial.print("  Temp °C: "); Serial.println(tempC);
}
Code snippet #4Plain text
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h" //  ^
#include <ms5611.h> // 

MPU6050 mpu;
MS5611 baro;

long pressure;
double altitude, min_height, max_height, wave_height;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}

void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude;

  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  wave_height = (max_height - min_height)/2.0;
  Serial.print("Wave Height m: "); 
  Serial.println(wave_height);
}
Code snippet #5Plain text
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h" 
#include <ms5611.h> 


MPU6050 mpu;
MS5611 baro;
long pressure;
double altitude, min_height, max_height, mid_point, smudge_factor;
byte escaped, started;
unsigned long period_start, period_end;
float avg_period = -1;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}

void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude; 

  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  mid_point = (max_height + min_height)/2.0;
  smudge_factor = (max_height - mid_point)*0.15;
  Serial.print("Mid Point m: "); Serial.print(mid_point);
  
  start_time = millis();
  //  for 15 seconds 
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    //    if within a range of 30% of wave height from the mid point
    //    start the timer else stop it
    if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor){
      if ( !started){
        period_start = millis();
        started = true;
      }
      else{
        if ( escaped ){
          // if it has started and escaped and is now returning
          period_end = millis();
          started = false;
          escaped = false;
          // if the variable has already been assigned
          // use its previous value and new value to work out avg
          if(avg_period != -1){
            avg_period = (avg_period + (period_end-period_start)*2)  / 2.0;
          }
          // assign it
          else{
            avg_period =  (period_end-period_start)*2; 
          }
        }
      }
    }
    else{
      escaped = true;
    } 
  }
  Serial.print("  Period s: "); Serial.println(avg_period/1000);
}
Code snippet #6Plain text
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "HMC5883L.h"
#include "Wire.h"
MPU6050 mpu;
HMC5883L mag;

int16_t mx, my, mz;

#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
float declination = -14.0 - (59.0 / 60.0);

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

void setup() {
    Serial.begin(115200);
    Wire.begin();
    Wire.setClock(400000); 
    
    mpu.setI2CMasterModeEnabled(false);
    mpu.setI2CBypassEnabled(true) ;
    mpu.setSleepEnabled(false);
    mpu.initialize();
    mag.initialize();
   // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
devStatus = mpu.dmpInitialize();
  // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(112);
    mpu.setYGyroOffset(5);
    mpu.setZGyroOffset(-15);
    mpu.setZAccelOffset(1487); 
    if (devStatus == 0) {
        mpu.setDMPEnabled(true);
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        dmpReady = true;
        packetSize = mpu.dmpGetFIFOPacketSize();
    }

}

void loop() {
    if (!dmpReady) return;
    while (!mpuInterrupt && fifoCount < packetSize) {
        if (mpuInterrupt && fifoCount < packetSize) {
          fifoCount = mpu.getFIFOCount();
        }        
    }       
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
        mpu.resetFIFO();
        fifoCount = mpu.getFIFOCount();
    } 
    else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;

      // OUTPUT_READABLE_WORLDACCEL
      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetAccel(&aa, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
      mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
      Serial.print("Acceleration (x,y) m/s/s: ");
      Serial.print(aaWorld.x);
      Serial.print("  ");
      Serial.println(aaWorld.y);

     // Find the angle of acceleration
      //  double angle_of_acc = atan2(aaWorld.y, aaWorld.x);
      //  angle_of_acc *= 180/M_PI;

      // Get compass heading
      // mag.getHeading(&mx, &my, &mz);
      // float heading = atan2(my, mx);
      // if (heading < 0) heading += 2 * PI;
      // if (heading > 2 * PI) heading -= 2 * PI;
      // heading *= 180/M_PI;
      // heading += declination;

      // Offset angle of acceleration by the heading angle
      // wave_direction = angle_off_acc + heading
      
    }
}
Code snippet #7Plain text
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include <ms5611.h> 


MPU6050 mpu;
MS5611 baro;
long pressure;
double altitude, min_height, max_height, wave_height, mid_point, smudge_factor, wave_power;
byte escaped, started;
unsigned long period_start, period_end;
float avg_period = -1;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  Serial.println("Initializing I2C devices...");
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true) ;
  mpu.setSleepEnabled(false);
  mpu.initialize();
  Serial.println(mpu.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
  while (!baro.begin(MS5611_ULTRA_HIGH_RES)) {
    Serial.println("MS5611 connection unsuccessful, check wiring!");
    delay(500);
  }
}

void loop() {
  unsigned long start_time = millis();
  pressure = baro.readPressure(true);
  altitude = baro.getAltitude(pressure);
  max_height = altitude;
  min_height = altitude;

  //  for 15 seconds
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    if (altitude < min_height) min_height = altitude;
    if (altitude > max_height) max_height = altitude;
  }
  mid_point = (max_height + min_height)/2.0;
  wave_height = (max_height - mid_point) / 2.0;
  smudge_factor = wave_height * 0.15;
  Serial.print("Wave Height m: "); Serial.print(wave_height);
  
  start_time = millis();
  //  for 15 seconds 
  while(millis() - start_time < 15000){
    pressure = baro.readPressure(true);
    altitude = baro.getAltitude(pressure);
    //    if within a range of 30% of wave height from the mid point
    //    start the timer else stop it
    if (altitude < mid_point + smudge_factor && altitude > mid_point - smudge_factor){
      if ( !started){
        period_start = millis();
        started = true;
      }
      else{
        if ( escaped ){
          // if it has started and escaped and is now returning
          period_end = millis();
          started = false;
          escaped = false;
          // if the variable has already been assigned
          // use its previous value and new value to work out avg
          if(avg_period != -1){
            avg_period = (avg_period + (period_end-period_start)*2)  / 2.0;
          }
          // assign it
          else{
            avg_period =  (period_end-period_start)*2; 
          }

       }
      }
    }
    else{
      escaped = true;
    } 
  }
  Serial.print("  Period s: "); Serial.print(avg_period/1000);
  wave_power = (0.5 * wave_height * wave_height * avg_period / 1000);
  Serial.print("  Wave Power kW/m: "); Serial.println(wave_power); 
}
Code snippet #8Plain text
#include <onewire.h>
#include <dallastemperature.h>

OneWire oneWire(6);
DallasTemperature sensors(&oneWire);
float water_temperature;

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

void loop() {
  sensors.requestTemperatures();
  water_temperature = sensors.getTempCByIndex(0);  
  Serial.print("Water temperature C "); Serial.println(water_temperature);
  delay(200);
}

Comments

Similar projects you might like

Smart Buoy

Project tutorial by T3ch Flicks

  • 3,908 views
  • 12 comments
  • 31 respects

Arduino-Powered Smart Light (Works with Amazon Echo)

Project tutorial by Tinker Project

  • 20,331 views
  • 8 comments
  • 37 respects

Smart Home - Smart Rules using ARTIK Cloud & Photon

Project tutorial by Raghavendra Ponuganti

  • 4,611 views
  • 2 comments
  • 15 respects

Alexa Smart Power Strip with Temperature

Project tutorial by Muhammad Afzal

  • 1,691 views
  • 0 comments
  • 9 respects

Octopod: Smart IoT Home/Industry Automation Project

Project tutorial by Saksham Bhutani

  • 10,201 views
  • 9 comments
  • 37 respects

Smart Thermostat, Airing and Lights Control with Bluetooth

Project tutorial by Gyula Osi

  • 6,950 views
  • 20 comments
  • 53 respects
Add projectSign up / Login