Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Gabriel Alejandro Giraldo Santiago
Published © GPL3+

Underwater Monitoring and Sampling Robot

I have designed and built a prototype of an underwater robot with ARM technology AI. For the monitoring, cartography and data collection.

AdvancedWork in progress10 hours2,686
Underwater Monitoring and Sampling Robot

Things used in this project

Hardware components

SeeedStudio BeagleBone Green
BeagleBoard.org SeeedStudio BeagleBone Green
×1
Arduino UNO
Arduino UNO
×1
Helium Starter Kit (LEGACY)
Helium Starter Kit (LEGACY)
×1
Motor Bridge Cape
Seeed Studio Motor Bridge Cape
×1
Seeed Studio 12V electric motor
×3
Grove - 6-Axis Accelerometer&Gyroscope
Seeed Studio Grove - 6-Axis Accelerometer&Gyroscope
×1
Grove - Sunlight Sensor
Seeed Studio Grove - Sunlight Sensor
×1
Grove - Air quality sensor v1.3
Seeed Studio Grove - Air quality sensor v1.3
×1
Grove - Multichannel Gas Sensor
Seeed Studio Grove - Multichannel Gas Sensor
×1
Grove - High Temperature Sensor
Seeed Studio Grove - High Temperature Sensor
×1
Seeed Studio Water sensor grove
×1
Battery 12V 1400 MaP
×1
Seeed Studio wire grove x5 30cm
×1
Male/Male Jumper Wires
×1

Software apps and online services

Arduino IDE
Arduino IDE
Helium Dashboard

Hand tools and fabrication machines

Tube cutter
Tweezers and Pliers
Hot glue gun (generic)
Hot glue gun (generic)
PVC pipe glue
Pipes and PVC connections
black tape insulating

Story

Read more

Schematics

Connect Arduino to BeagleBone

Code

Code to BeagleBone

Assembly x86
// 1 channel RCInput with 5ns accuracy
// 12 channel RCOutput with 1us accuracy 

// Timer
#define TICK_PER_US 200
#define TICK_PER_MS 200000

// PWM

// 920 us
#define PWM_PULSE_DEFAULT (920 * TICK_PER_US)

// 50 Hz
#define PWM_FREQ_DEFAULT (20 * TICK_PER_MS)

// Ringbuffer size
#define RCIN_RINGBUFFERSIZE 300

// PRU Constants Table
#define ECAP C3
#define RAM C24
#define IEP C26

// IEP
#define IEP_TMR_GLB_CFG 0x0
#define IEP_TMR_GLB_STS 0x4
#define IEP_TMR_CNT 0xc

#define IEP_CNT_ENABLE 0x0
#define IEP_DEFAULT_INC 0x4

// ECAP
#define ECAP_TSCTR 0x0
#define ECAP_CTRPHS 0x4
#define ECAP_CAP1 0x8
#define ECAP_CAP2 0xc
#define ECAP_CAP3 0x10
#define ECAP_CAP4 0x14
#define ECAP_ECCTL1 0x28
#define ECAP_ECCTL2 0x2a
#define ECAP_ECEINT 0x2c
#define ECAP_ECFLG 0x2e
#define ECAP_ECCLR 0x30
#define ECAP_ECFRC 0x32
#define ECAP_REVID 0x5c

// ECCTL1
#define ECAP_CAP1POL 0
#define ECAP_CTRRST1 1
#define ECAP_CAP2POL 2
#define ECAP_CTRRST2 3
#define ECAP_CAP3POL 4
#define ECAP_CTRRST3 5
#define ECAP_CAP4POL 6
#define ECAP_CTRRST4 7
#define ECAP_CAPLDEN 8
#define ECAP_PRESCALE 9
#define ECAP_FREE_SOFT 14

// ECCTL2
#define ECAP_CONT_ONESHT 0
#define ECAP_STOP_WRAP 1
#define ECAP_RE_ARM 3
#define ECAP_TSCTRSTOP 4
#define ECAP_SYNCI_EN 5
#define ECAP_SYNCO_SEL 6
#define ECAP_SWSYNC 8
#define ECAP_CAP_APWM 9
#define ECAP_APWMPOL 10

// ECEINT, ECFLG
#define ECAP_INT 0
#define ECAP_CEVT1 1
#define ECAP_CEVT2 2
#define ECAP_CEVT3 3
#define ECAP_CEVT4 4
#define ECAP_CNTOVF 5
#define ECAP_PRDEQ 6
#define ECAP_CMPEQ 7

// RAM
#define CH_ENABLE_RAM_OFFSET (0 * 4)
#define CH_1_PULSE_TIME_RAM_OFFSET (1 * 4)
#define CH_1_T_TIME_RAM_OFFSET  (2 * 4)
#define CH_2_PULSE_TIME_RAM_OFFSET (3 * 4)
#define CH_2_T_TIME_RAM_OFFSET  (4 * 4)
#define CH_3_PULSE_TIME_RAM_OFFSET (5 * 4)
#define CH_3_T_TIME_RAM_OFFSET  (6 * 4)
#define CH_4_PULSE_TIME_RAM_OFFSET (7 * 4)
#define CH_4_T_TIME_RAM_OFFSET  (8 * 4)
#define CH_5_PULSE_TIME_RAM_OFFSET (9 * 4)
#define CH_5_T_TIME_RAM_OFFSET  (10 * 4)
#define CH_6_PULSE_TIME_RAM_OFFSET (11 * 4)
#define CH_6_T_TIME_RAM_OFFSET  (12 * 4)
#define CH_7_PULSE_TIME_RAM_OFFSET (13 * 4)
#define CH_7_T_TIME_RAM_OFFSET  (14 * 4)
#define CH_8_PULSE_TIME_RAM_OFFSET (15 * 4)
#define CH_8_T_TIME_RAM_OFFSET  (16 * 4)
#define CH_9_PULSE_TIME_RAM_OFFSET (17 * 4)
#define CH_9_T_TIME_RAM_OFFSET  (18 * 4)
#define CH_10_PULSE_TIME_RAM_OFFSET (19 * 4)
#define CH_10_T_TIME_RAM_OFFSET  (20 * 4)
#define CH_11_PULSE_TIME_RAM_OFFSET (21 * 4)
#define CH_11_T_TIME_RAM_OFFSET  (22 * 4)
#define CH_12_PULSE_TIME_RAM_OFFSET (23 * 4)
#define CH_12_T_TIME_RAM_OFFSET  (24 * 4)

#define MAX_CYCLE_TIME_OFFSET (25 * 4)

#define RCIN_RING_HEAD_OFFSET 0x1000
#define RCIN_RING_TAIL_OFFSET 0x1002
#define RCIN_RINGBUFFER_RAM_OFFSET 0x1004

// RCOut pins
#define RC_CH_1_PIN r30.t10
#define RC_CH_2_PIN r30.t8
#define RC_CH_3_PIN r30.t11
#define RC_CH_4_PIN r30.t9
#define RC_CH_5_PIN r30.t7
#define RC_CH_6_PIN r30.t6
#define RC_CH_7_PIN r30.t5
#define RC_CH_8_PIN r30.t4
#define RC_CH_9_PIN r30.t3
#define RC_CH_10_PIN r30.t2
#define RC_CH_11_PIN r30.t1
#define RC_CH_12_PIN r30.t0

// RCOut enable bits
#define RC_CH_1_ENABLE register.ch_enable.t0
#define RC_CH_2_ENABLE register.ch_enable.t1
#define RC_CH_3_ENABLE register.ch_enable.t2
#define RC_CH_4_ENABLE register.ch_enable.t3
#define RC_CH_5_ENABLE register.ch_enable.t4
#define RC_CH_6_ENABLE register.ch_enable.t5
#define RC_CH_7_ENABLE register.ch_enable.t6
#define RC_CH_8_ENABLE register.ch_enable.t7
#define RC_CH_9_ENABLE register.ch_enable.t8
#define RC_CH_10_ENABLE register.ch_enable.t9
#define RC_CH_11_ENABLE register.ch_enable.t10
#define RC_CH_12_ENABLE register.ch_enable.t11

// Register struct
.struct RegisterStruct
   .u32 ch_enable
   .u32 ch_1_next_time
   .u32 ch_2_next_time
   .u32 ch_3_next_time
   .u32 ch_4_next_time
   .u32 ch_5_next_time
   .u32 ch_6_next_time
   .u32 ch_7_next_time
   .u32 ch_8_next_time
   .u32 ch_9_next_time
   .u32 ch_10_next_time
   .u32 ch_11_next_time
   .u32 ch_12_next_time
   .u32 time
   .u32 time_max 
   .u32 time_cycle
   .u32 rcin_ram_pointer
   .u32 rcin_ram_pointer_index
   .u32 rcin_ram_pointer_index_max
   .u32 rcin_ram_pointer_head
   .u32 rcin_ram_pointer_tail
   .u32 temp
   .u32 temp1
   .u32 test
 .ends
 .assign RegisterStruct, R4, *, register

.macro RCOUT_PWM
.mparam RC_CH_X_PIN, CH_X_NEXT_TIME, CH_X_ENABLE, CH_X_PULSE_TIME_RAM_OFFSET, CH_X_T_TIME_RAM_OFFSET
pwm:
   // Handle arithmetic and counter overflow, check if there is something to do
   sub register.temp, CH_X_NEXT_TIME, register.time
   mov register.temp1, 0xF0000000
   qbgt pwmend, register.temp, register.temp1

      mov CH_X_NEXT_TIME, register.time

      // Set pin or clear pin?
      qbbs pwmclear, RC_CH_X_PIN

         // Load pulse duration
         lbco register.temp, RAM, CH_X_PULSE_TIME_RAM_OFFSET, 4

         // Calculate time to next event
         add CH_X_NEXT_TIME, CH_X_NEXT_TIME, register.temp

         // Check if channel is enabled 
         qbbc pwmend, CH_X_ENABLE
            
            // Set pin
            set RC_CH_X_PIN
         jmp pwmend

      pwmclear:
         // Load pulse time
         lbco register.temp1, RAM, CH_X_PULSE_TIME_RAM_OFFSET, 4

         // Load T time
         lbco register.temp, RAM, CH_X_T_TIME_RAM_OFFSET, 4

         // Calculate time to next event (T - pulse duration)
         sub register.temp, register.temp, register.temp1
         add CH_X_NEXT_TIME, CH_X_NEXT_TIME, register.temp
         
         // Clear pin
         clr RC_CH_X_PIN
pwmend:
.endm

.macro RCIN_ECAP_INIT
   // Initialize ECAP
   mov register.temp, (1 << ECAP_CTRRST1) | (1 << ECAP_CAP1POL) | (1 << ECAP_CTRRST2) | (1 << ECAP_CAPLDEN)
   sbco register.temp, ECAP, ECAP_ECCTL1, 4
   mov register.temp, (1 << ECAP_STOP_WRAP) | (1 << ECAP_TSCTRSTOP) | (2 << ECAP_SYNCO_SEL)
   sbco register.temp, ECAP, ECAP_ECCTL2, 4
.endm

.macro RCIN_ECAP
   // New value?
   lbco register.temp, ECAP, ECAP_ECFLG, 4
   qbbc rcin_ecap_end, register.temp.t2

      // Copy S0 and S1 duration to temp and temp1
      lbco register.temp, ECAP, ECAP_CAP1, 8

      // Copy S0 and S1 duration to RAM
      sbbo register.temp, register.rcin_ram_pointer, 0, 8

      // Clear event flags
      mov register.temp, (1 << ECAP_CEVT1) | (1 << ECAP_CEVT2)
      sbco register.temp, ECAP, ECAP_ECCLR, 4

      // Set new tail value
      RCIN_WRITE_TAIL register.rcin_ram_pointer_index

      // Update pointer
      add register.rcin_ram_pointer_index, register.rcin_ram_pointer_index, 1
      add register.rcin_ram_pointer, register.rcin_ram_pointer, 8

      // Check end of ringbuffer
      qblt rcin_ecap_end, register.rcin_ram_pointer_index_max, register.rcin_ram_pointer_index
         mov register.rcin_ram_pointer, RCIN_RINGBUFFER_RAM_OFFSET 
         mov register.rcin_ram_pointer_index, 0
rcin_ecap_end:
.endm

.macro RCIN_WRITE_HEAD
.mparam RCIN_HEAD
   sbbo RCIN_HEAD, register.rcin_ram_pointer_head, 0, 2
.endm

.macro RCIN_WRITE_TAIL
.mparam RCIN_TAIL
   sbbo RCIN_TAIL, register.rcin_ram_pointer_tail, 0, 2
.endm

.macro MAX_CYCLE_TIME
   lbco register.temp1, IEP, IEP_TMR_CNT, 4
   sub register.temp, register.temp1, register.time_cycle
   mov register.time_cycle, register.temp1
   max register.time_max, register.time_max, register.temp
   sbco register.time_max, RAM, MAX_CYCLE_TIME_OFFSET, 4
.endm

.macro INIT
   // Reset PWM pins
   mov r30, 0x0

   // Clear register
   zero &register, SIZE(register)

   // Initialize max cycle time
   mov register.temp, 0
   sbco register.temp, RAM, MAX_CYCLE_TIME_OFFSET, 4

   // Initialize ringbuffer
   mov register.rcin_ram_pointer, RCIN_RINGBUFFER_RAM_OFFSET
   mov register.rcin_ram_pointer_index_max, RCIN_RINGBUFFERSIZE 
   mov register.rcin_ram_pointer_head, RCIN_RING_HEAD_OFFSET
   mov register.rcin_ram_pointer_tail, RCIN_RING_TAIL_OFFSET
   mov register.temp, 0
   RCIN_WRITE_HEAD register.temp
   RCIN_WRITE_TAIL register.temp

   // Load balancing
   mov register.ch_1_next_time, 1000
   mov register.ch_2_next_time, 2000
   mov register.ch_3_next_time, 3000
   mov register.ch_4_next_time, 4000
   mov register.ch_5_next_time, 5000
   mov register.ch_6_next_time, 6000
   mov register.ch_7_next_time, 7000
   mov register.ch_8_next_time, 8000
   mov register.ch_9_next_time, 9000
   mov register.ch_10_next_time, 10000
   mov register.ch_11_next_time, 11000
   mov register.ch_12_next_time, 12000

   // Disable all PWMs
   mov register.ch_enable, 0x0
   sbco register.ch_enable, RAM, CH_ENABLE_RAM_OFFSET, 4

   // Initialize PWM pulse (920us)
   mov register.temp, PWM_PULSE_DEFAULT
   sbco register.temp, RAM, CH_1_PULSE_TIME_RAM_OFFSET, 4 
   sbco register.temp, RAM, CH_2_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_3_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_4_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_5_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_6_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_7_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_8_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_9_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_10_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_11_PULSE_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_12_PULSE_TIME_RAM_OFFSET, 4

   // Initialize PWM frequency (50Hz)
   mov register.temp, PWM_FREQ_DEFAULT
   sbco register.temp, RAM, CH_1_T_TIME_RAM_OFFSET, 4 
   sbco register.temp, RAM, CH_2_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_3_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_4_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_5_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_6_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_7_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_8_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_9_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_10_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_11_T_TIME_RAM_OFFSET, 4
   sbco register.temp, RAM, CH_12_T_TIME_RAM_OFFSET, 4

   // Initialize counter (1 step = 5ns) 
   mov register.temp, 1 << IEP_DEFAULT_INC
   sbco register.temp, IEP, IEP_TMR_GLB_CFG, 4

   // Reset counter
   mov register.temp, 0xffffffff
   sbco register.temp, IEP, IEP_TMR_CNT, 4

   // Start counter 
   lbco register.temp, IEP, IEP_TMR_GLB_CFG, 4
   or register.temp, register.temp, 1 << IEP_CNT_ENABLE
   sbco register.temp, IEP, IEP_TMR_GLB_CFG, 4
.endm

.origin 0
init:
   INIT
   RCIN_ECAP_INIT
mainloop:
   lbco register.ch_enable, RAM, CH_ENABLE_RAM_OFFSET, 4
   lbco register.time, IEP, IEP_TMR_CNT, 4
   RCOUT_PWM RC_CH_1_PIN, register.ch_1_next_time, RC_CH_1_ENABLE, CH_1_PULSE_TIME_RAM_OFFSET, CH_1_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_2_PIN, register.ch_2_next_time, RC_CH_2_ENABLE, CH_2_PULSE_TIME_RAM_OFFSET, CH_2_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_3_PIN, register.ch_3_next_time, RC_CH_3_ENABLE, CH_3_PULSE_TIME_RAM_OFFSET, CH_3_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_4_PIN, register.ch_4_next_time, RC_CH_4_ENABLE, CH_4_PULSE_TIME_RAM_OFFSET, CH_4_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_5_PIN, register.ch_5_next_time, RC_CH_5_ENABLE, CH_5_PULSE_TIME_RAM_OFFSET, CH_5_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_6_PIN, register.ch_6_next_time, RC_CH_6_ENABLE, CH_6_PULSE_TIME_RAM_OFFSET, CH_6_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_7_PIN, register.ch_7_next_time, RC_CH_7_ENABLE, CH_7_PULSE_TIME_RAM_OFFSET, CH_7_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_8_PIN, register.ch_8_next_time, RC_CH_8_ENABLE, CH_8_PULSE_TIME_RAM_OFFSET, CH_8_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_9_PIN, register.ch_9_next_time, RC_CH_9_ENABLE, CH_9_PULSE_TIME_RAM_OFFSET, CH_9_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_10_PIN, register.ch_10_next_time, RC_CH_10_ENABLE, CH_10_PULSE_TIME_RAM_OFFSET, CH_10_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_11_PIN, register.ch_11_next_time, RC_CH_11_ENABLE, CH_11_PULSE_TIME_RAM_OFFSET, CH_11_T_TIME_RAM_OFFSET
   RCOUT_PWM RC_CH_12_PIN, register.ch_12_next_time, RC_CH_12_ENABLE, CH_12_PULSE_TIME_RAM_OFFSET, CH_12_T_TIME_RAM_OFFSET
   RCIN_ECAP
//   MAX_CYCLE_TIME
jmp mainloop

Code to Arduino

C/C++
#include "AirQuality.h"
#include "Arduino.h"
#include "Board.h"
#include "Helium.h"
#include "HeliumUtil.h"
#include <TH02_dev.h>
#include "Arduino.h"
#include "Wire.h" 


AirQuality airqualitysensor;

#define CHANNEL_NAME "SPAQM"

Helium  helium(&atom_serial);
Channel channel(&helium);

void setDisplayToOriginalState()
{
    
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(150);
  /* Reset HP20x_dev */
  TH02.begin();
  delay(100);
  Serial.println("TH02_dev is available.\n");    
  DBG_PRINTLN(F("Starting"));

  // Begin communication with the Helium Atom
  // The baud rate differs per supported board
  // and is configured in Board.h
  helium.begin(HELIUM_BAUD_RATE);

  // Connect the Atom to the Helium Network
  helium_connect(&helium);

  // Begin communicating with the channel. This should only need to
  // be done once. The HeliumUtil functions add simple retry logic
  // to re-create a channel if it disconnects.
  channel_create(&channel, CHANNEL_NAME);
  Wire.begin();
  airqualitysensor.init(14);
}

void loop() {
  //Set quality from 0 to 255, with one to 100 being normal
  //Air Quality Pollution
//  int sensorValue = analogRead(A0);
//  int airquality = map(sensorValue, 0, 1023, 0, 255);
    int airquality = airqualitysensor.slope();
  
    //Sound Pollution
    long sound = 0;
    for(int i=0; i<32; i++)
    {
        
    }
  
    float temper = TH02.ReadTemperature(); 
    float humidity = TH02.ReadHumidity();
  
    
    String dataString = "air=" + String(airquality) + "&noise=" + String(sound) + "&temperature=" + String(temper) + "&humidity=" + String(humidity);
    char data[dataString.length()];
    dataString.toCharArray(data, dataString.length());
    channel_send(&channel, CHANNEL_NAME, data, strlen(data));
    Serial.println(data);
  
   
    String temperaturestring = String(temper) + " C";
    char tempbuffer[temperaturestring.length()];
    temperaturestring.toCharArray(tempbuffer, temperaturestring.length());
    
   
    String humidstring = "Humid: " + String(humidity);
    char humidbuffer[temperaturestring.length()];
    humidstring.toCharArray(humidbuffer, humidstring.length());
    

    
ISR(TIMER1_OVF_vect)
{
  if(airqualitysensor.counter==61)//set 2 seconds as a detected duty
  {

      airqualitysensor.last_vol=airqualitysensor.first_vol;
      airqualitysensor.first_vol=analogRead(A0);
      airqualitysensor.counter=0;
      airqualitysensor.timer_index=1;
      PORTB=PORTB^0x20;
  }
  else
  {
    airqualitysensor.counter++;
  }
}

Credits

Gabriel Alejandro Giraldo Santiago
13 projects • 86 followers
Seeed Ranger, AI and Computer Vision expert for key industries. Mentor and speaker on AI, startups, and no-code. Maker enthusiast.
Thanks to Seeed Studio.

Comments