James (Eddie) Elsenburg
Published

Remote Monitoring of Derelict Vessels

Monitoring derelict vessels in order to prioritize resources for remediation based on the continuous monitoring of the vessels stability.

IntermediateWork in progress97
Remote Monitoring of Derelict Vessels

Things used in this project

Hardware components

heltec Capsule Dev Board
×1
Grove - IMU 9DOF (ICM20600+AK09918)
Seeed Studio Grove - IMU 9DOF (ICM20600+AK09918)
×1
Battery Holder, 18650 x 1
Battery Holder, 18650 x 1
×1
SUNYIMA 10Pcs 5V 60mA Mini Polycrystalline Solar Panels Cells 68mmx37mm/2.67"x1.45"
×1

Software apps and online services

tago.io

Story

Read more

Code

X,Y,Z monitor

Arduino
Code for Heltec Capsule with 9 dof sensor
#include "LoRaWan_APP.h"
#include "Arduino.h"
#include <Wire.h>
#include <MPU9250.h>
#include <math.h>

/*
   set LoraWan_RGB to Active,the RGB active in loraWan
   RGB red means sending;
   RGB purple means joined done;
   RGB blue means RxWindow1;
   RGB yellow means RxWindow2;
   RGB green means received done;
*/

/* OTAA para*/
uint8_t devEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

/* ABP para*/
uint8_t nwkSKey[] = { 0 };
uint8_t appSKey[] = { 0 };
uint32_t devAddr =  ( uint32_t )0;

/*LoraWan channelsmask, default channels 0-7*/
uint16_t userChannelsMask[6] = { 0xFF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };

/*LoraWan region, select in arduino IDE tools*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;

/*LoraWan Class, Class A and Class C are supported*/
DeviceClass_t  loraWanClass = LORAWAN_CLASS;

/*the application data transmission duty cycle.  value in [ms].*/
// float dc = 1;
 uint32_t appTxDutyCycle = (60 * 10000);

/*OTAA or ABP*/
bool overTheAirActivation = LORAWAN_NETMODE;

/*ADR enable*/
bool loraWanAdr = LORAWAN_ADR;

/* set LORAWAN_Net_Reserve ON, the node could save the network info to flash, when node reset not need to join again */
bool keepNet = LORAWAN_NET_RESERVE;

/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = LORAWAN_UPLINKMODE;

/* Application port */
uint8_t appPort = 2;
/*!
  Number of trials to transmit the frame, if the LoRaMAC layer did not
  receive an acknowledgment. The MAC performs a datarate adaptation,
  according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
  to the following table:

  Transmission nb | Data Rate
  ----------------|-----------
  1 (first)       | DR
  2               | DR
  3               | max(DR-1,0)
  4               | max(DR-1,0)
  5               | max(DR-2,0)
  6               | max(DR-2,0)
  7               | max(DR-3,0)
  8               | max(DR-3,0)

  Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
  the datarate, in case the LoRaMAC layer did not receive an acknowledgment
*/
uint8_t confirmedNbTrials = 4;

#define buttonPin GPIO6
// variables will change:
int buttonState = 1;         // variable for reading the pushbutton status, can be used for interupts.  

/* Prepares the payload of the frame */
MPU9250 mySensor;

static void prepareTxFrame( uint8_t port )

{
  float eP, eR, eH, Heading, Pitch, Roll, Alert; //e is the converted to euler angles for PRH 
  /* Get a new sensor event */
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
  pinMode(Vext, OUTPUT);
  digitalWrite(Vext, LOW);
  Wire.begin();
  mySensor.setWire(&Wire);

  mySensor.beginAccel();
  mySensor.beginGyro();
  mySensor.beginMag();

  mySensor.accelUpdate();
  mySensor.gyroUpdate();
  mySensor.magUpdate();

  Wire.end();
  mySensor.computeEulerAngles();
  uint16_t batteryVoltage = getBatteryVoltage();
  eP = mySensor.pitch();
  eR = mySensor.roll();
  eH = mySensor.yaw();
  
  Heading = (roundf ( eH * 100.00));
  Pitch = (roundf (eP * 100.00));
  Roll = (roundf (eR * 100.00));

  if (buttonState == HIGH) {
    Alert = 0;
  }
  else {
    Alert = 1;
  }
  Serial.print("Current Pitch:");
  Serial.println(eP);
  Serial.print("Current Roll:");
  Serial.println(eR);
  Serial.print("Current Heading:");
  Serial.println(eH);
  Serial.print("BatteryVoltage:");
  Serial.println(batteryVoltage);
  Serial.print("Float Alert:");
  Serial.println(Alert);

  unsigned char *puc;

  puc = (unsigned char *)(&Heading);
  appDataSize = 20;
  appData[0] = puc[0];
  appData[1] = puc[1];
  appData[2] = puc[2];
  appData[3] = puc[3];

  puc = (unsigned char *)(&Pitch);
  appData[4] = puc[0];
  appData[5] = puc[1];
  appData[6] = puc[2];
  appData[7] = puc[3];

  puc = (unsigned char *)(&Roll);
  appData[8] = puc[0];
  appData[9] = puc[1];
  appData[10] = puc[2];
  appData[11] = puc[3];

  puc = (unsigned char *) (&Alert);
  appData[12] = puc [0];
  appData[13] = puc [1];
  appData[14] = puc [2];
  appData[15] = puc [3];

  appData[16] = (uint8_t)(batteryVoltage >> 8);
  appData[17] = (uint8_t)batteryVoltage;

}

  
void setup() {
  Serial.begin(115200);
#if(AT_SUPPORT)
  enableAt();
#endif
  deviceState = DEVICE_STATE_INIT;
  LoRaWAN.ifskipjoin();
}
void loop()
{ // read the state of the pushbutton value:
  // buttonState = digitalRead(buttonPin);
  switch ( deviceState )
  {
    case DEVICE_STATE_INIT:
      {
#if(AT_SUPPORT)
        getDevParam();
#endif
        printDevParam();
        LoRaWAN.init(loraWanClass, loraWanRegion);
        deviceState = DEVICE_STATE_JOIN;
        break;
      }
    case DEVICE_STATE_JOIN:
      {
        LoRaWAN.join();
        break;
      }
    case DEVICE_STATE_SEND:
      {
        prepareTxFrame( appPort );
        LoRaWAN.send();
        deviceState = DEVICE_STATE_CYCLE;
        break;
      }
    case DEVICE_STATE_CYCLE:
      {
        // Schedule next packet transmission
        txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
        LoRaWAN.cycle(txDutyCycleTime);
        deviceState = DEVICE_STATE_SLEEP;
        break;
      }
    case DEVICE_STATE_SLEEP:
      {
        LoRaWAN.sleep();
        break;
      }
    default:
      {
        deviceState = DEVICE_STATE_INIT;
        break;
      }
  }
}

Decoder

C#
Used to decode the payload
function bytesToFloat(by) {
   var bits = by[3]<<24 | by[2]<<16 | by[1]<<8 | by[0];
   var sign = (bits>>>31 === 0) ? 1.0 : -1.0;
   var e = bits>>>23 & 0xff;
   var m = (e === 0) ? (bits & 0x7fffff)<<1 : (bits & 0x7fffff) | 0x800000;
   var f = sign * m * Math.pow(2, e - 150);
   return f;
} 
 
function Decoder(bytes, port) {
  var decoded = {};
  i = 0;
  
  decoded.Heading= bytesToFloat(bytes.slice(i,i+=4))/100;
  decoded.Pitch= bytesToFloat(bytes.slice(i,i+=4))/100;
  decoded.Roll= bytesToFloat(bytes.slice(i,i+=4))/100;
  decoded.Alert = bytesToFloat(bytes.slice(i,i+=4));
  decoded.battery = ((bytes[i++] << 8) | bytes[i++])/1000;
 

Credits

James (Eddie) Elsenburg

James (Eddie) Elsenburg

2 projects • 0 followers

Comments