Depth sounder for shallow water and recording Mobiel schrijvend echolood
Depth Sounder for shallow water
English version of the page below in pdf. Building a mobile sounder that records depths with their position on an SD card. Suitable for use in a dinghy without electrical installation or an SUP board. (9 pages).
Mobiel schrijvend echolood 2023 03 23
Doel
Het vastleggen van waterdieptes met hun positie ten behoeve van een diepte survey. Het apparaat moet geschikt zijn voor mobiel gebruik in een dinghy zonder electrische installatie of op een SUP board.
Databronnen
Een echolood voor de waterdiepte en een GPS ontvanger voor de positie.
Weergave en bewaren
De diepte wordt digitaal op een voltmetertje weergegeven. (beperkt tot 5m)
De diepte en positie worden vastgelegd op een mini SD card in een txt file zodat de data in een later stadium verwerkt kan worden.
Het echolood
Voor dit project wordt het zend- en ontvangst gedeelte van een Seafarer Mk3 of 4 Echolood gebruikt.
De gemeten tijd van de zendpuls bedraagt ongeveer 300 µs. In die tijd legt de puls 44.4 cm af.
(vSound = 1480 m/s) = (148000 cm/s) = (0.148 cm/ µs) = (44.4 cm/ 300 µs)
Er wordt een 150 kHz transducer gebruikt die gedurende deze puls 45 trillingen maakt,
(150 kHz ) = (150000 trillingen/ s) = (0.150 trilling/ µs) = (45 trillingen / 300 µs)
Enigszins op schaal geschetst voor een periode van 1000 µs ziet dit er zo uit:
De kleinste metingen liggen rond de 45 cm.
Oorspronkelijk werd de diepte bij het Seafarer echolood zichtbaar gemaakt met een ledje op een rond draaiend armpje dat oplichtte bij de ontvangst van de echo. Op een cirkelvormige schaal rond de arm was de diepte af te lezen.
Arduino Uno type microprocessor
Omdat de data digitaal verwerkt moet worden, gebruik ik een Arduino Uno microprocessor om de zender te triggeren en om de tijdsduur te meten. Het motortje, armpje en verder overbodige onderdelen zijn van de print gehaald om stroom te besparen en om ruimte te maken voor Arduino en batterijen.
Het punt tussen weerstanden R19 en 20 is het punt waar de Arduino de zender op transistor TR10 triggert. R19 zelf en TR9 zijn verwijderd. (De onderdelen zijn ook op de print benoemd.)
De Arduino wordt voor dit doel geprogrammeerd via haar USB verbinding. Het programma blijft behouden op de Arduino en begint te lopen zodra er spanning op de Arduino komt. Met de functie pulsIn(pulseInPin, LOW) berekent de microprocessor de tijdsduur dat het signaal 0 is. Met andere woorden de tijdsduur tussen zend- en ontvangst- puls
Bij een vSound in m/s en travelTime in µs is de Diepte in cm: travelTime x vSound / 20000.0
De geluidssnelheid in water, vSound = 1480 m/s
Bij een vSound in m/s en travelTime in µs is de Diepte in cm: travelTime x vSound / 20000.0
De geluidssnelheid in water, vSound = 1480 m/s
Een voorbeeld:
Stel de tijdsduur tussen zend- en ontvangst puls is 700 µs, en de pulseduur 300 µs dan is de totale traveltime 1000 µs en de diepte 1000 x 1480 / 20000 = 74 cm
Display
Om de diepte weer te geven gebruik ik een digitaal voltmetertje met een refreshrate van 200 ms. (Een digitaal aangestuurd LCD schermpje was moeilijk afleesbaar en te traag) De berekende waterdiepte wordt omgezet in een voltwaarde d.m.v. PWM op een digitale uitgang.
Het bereik van het metertje is hiermee wel beperkt tot 5 meter. (5V limiet Arduino) Voor de berekende getalswaarde die op het SD kaartje geschreven wordt geldt die restrictie niet.
Het programma
// 230322_Sounder_Timer0_pulses
// Trigger a pulse 2 times a second via pin 5 (orange)
// Messure time between pulse and echo on pin 2 (grey)
// Display depth with PWM voltage via pin 3 (yellow)
// 1500 m/s = 1.5 m/millis or 1.500 mm/micro
#include <SoftwareSerial.h>
#include <SD.h>
SoftwareSerial mySerial(8,7);
#define chipSelect 10
File logfile;
#include <Adafruit_GPS.h>
#include <SPI.h>
Adafruit_GPS GPS(&mySerial);
#define LOG_FIXONLY false
const int pulseOutPin = 5;
const int displayPin = 3;
const int pulseInPin = 2; //
const int vSound = 1480; // m/s
const int pulseOutDuration = 20; //microseconds
const int timeBetweenPulsea = 500; // milliseconds
float volt = 0.0;
unsigned long previousMillis; //violate
void Update(unsigned long currentMillis)
{
if(currentMillis - previousMillis >= timeBetweenPulsea)
{
previousMillis = currentMillis;
// send a pulse to the sounder
digitalWrite(pulseOutPin, HIGH);
delayMicroseconds(pulseOutDuration);
digitalWrite(pulseOutPin,LOW);
// messure depth and display
unsigned long travelTime = pulseIn(pulseInPin, LOW) + 300;
// 300 is pulselenght at mode 6x
unsigned long depth = travelTime * vSound / 20000; //cm
// devide depth in a way volts equals meters approximately
volt = depth/ 1.55;
if (volt >= 255) // max of range 5V
volt = 255;
analogWrite(displayPin,volt);
// get $GPRMC from GPS
if (GPS.newNMEAreceived())
{
char *stringptr = GPS.lastNMEA();
if (!GPS.parse(stringptr))
return;
if (LOG_FIXONLY && !GPS.fix)
return;
//write the string to the SD file
uint8_t stringsize = strlen(stringptr);
if (stringsize != logfile.write((uint8_t *)stringptr, stringsize))
Serial.println("ërror");
if (strstr(stringptr, "RMC"))
{
unsigned long travelTime = pulseIn(2,LOW) + 300;
unsigned long depth = travelTime * vSound / 20000;
logfile.println();
logfile.print("$SDDBT,");
logfile.println(depth);
logfile.println(millis());
logfile.println();
logfile.flush();
}
}
}
}
void setup()
{
pinMode (pulseOutPin, OUTPUT);
pinMode (pulseInPin, INPUT);
pinMode (displayPin, OUTPUT);
pinMode(chipSelect, OUTPUT);
if (!SD.begin(chipSelect)) // see if the card is present and can be initialized:
Serial.println("Card init. failed!");
char filename[15];
strcpy(filename, "RMCDPT00.TXT");
for (uint8_t i = 0; i < 100; i++)
{
filename[6] = '0' + i/10;
filename[7] = '0' + i%10;
// create if does not exist, do not open existing, write, sync after write
if (! SD.exists(filename))
{
break;
}
}
logfile = SD.open(filename, FILE_WRITE);
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ); // 5 times per second
GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);
GPS.sendCommand(PGCMD_NOANTENNA);
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
}
// Interrupt is called once a millisecond
SIGNAL(TIMER0_COMPA_vect)
{
char c = GPS.read();
#ifdef UDR0 //USART I/O Data Register
if (c) UDR0 = c;
#endif
unsigned long currentMillis = millis();
Update(currentMillis);
}
void loop()
{
}
De GPS positie en het SD Card gedeelte
Voor het ontvangen van de GPS positie en het bewaren van de data wordt een tweede Arduino gebruikt met een GPS shield erop. Hier zit een GPS ontvanger op en een SD card houder. Door een tweede microprocessor te gebruiken loopt de timing van het echolood niet in de war.
De eerste Arduino zorgt voor het aansturen van de zender en geeft de berekende diepte op het voltmetertje aan. De tweede Aduino zorgt voor het bewaren van de GPS positie en de berekende diepte op een SD kaartje.
Het programma voor de tweede Arduino
// 230322_shield_sdlog Saving $GPRMC string and depth on SDcard
#include <SPI.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <SD.h>
#include <avr/sleep.h>
SoftwareSerial mySerial(8, 7);
Adafruit_GPS GPS(&mySerial);
#define chipSelect 10
File logfile;
const int vSound = 1480; // m/s
void setup()
{
Serial.begin(115200);
pinMode(chipSelect, OUTPUT);
if (!SD.begin(chipSelect)) // see if the card is present and can be initialized:
Serial.println("Card failure"); // message via USB to serial monitor program
char filename[15];
strcpy(filename, "RMCDPT00.TXT"); // Automatic numbering of TXT files
for (uint8_t i = 0; i < 100; i++)
{
filename[6] = '0' + i/10;
filename[7] = '0' + i%10;
// create if does not exist, do not open existing, write, sync after write
if (! SD.exists(filename))
{
break;
}
}
logfile = SD.open(filename, FILE_WRITE);
GPS.begin(9600); // Baudrate GPS
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ); // 5 times a second
GPS.sendCommand(PMTK_API_SET_FIX_CTL_5HZ);
GPS.sendCommand(PGCMD_NOANTENNA);
OCR0A = 0xAF; // Output Compare Register A
TIMSK0 |= _BV(OCIE0A); // Timer/Counter Interrupt Mask Register
}
SIGNAL(TIMER0_COMPA_vect) // Interrupt is called once a millisecond.
{ // writing direct to UDR0
char c = GPS.read();
#ifdef UDR0 //USART I/O Data Register
if (c) UDR0 = c;
#endif
}
void loop()
{
if (GPS.newNMEAreceived())
{
char *stringptr = GPS.lastNMEA();
if (!GPS.parse(stringptr))
return;
uint8_t stringsize = strlen(stringptr);
if (stringsize != logfile.write((uint8_t *)stringptr, stringsize))
Serial.println("ërror");
if (strstr(stringptr, "RMC"))
{
unsigned long travelTime = pulseIn(2,LOW) + 300.0;
unsigned long depth = travelTime * vSound / 20000.0;
logfile.println();
logfile.print("$SDDBT,");
logfile.println(depth); // (not NMEA standard, just DBT in cm)
logfile.println();
logfile.flush();
}
}
}
//POWERCONSUMPTION 95 - 105 mA
//(Sounder, 2 Arduino's, GPS shield and Voltmeter display)
Voorbeeld van van een bewaard txt bestand
$GPRMC,102659.000,A,5254.2002,N,00537.5766,E,0.43,222.76,030917,,,D*6F
$SDDBT,64 // Dit is niet de NMEA 0183 standaard Depth Below Transducer Sentence Format
// maar cm. (nauwkeuriger dan de standaard in meters met 1 decimaal)
$GPRMC,102700.000,A,5254.2002,N,00537.5765,E,1.07,226.13,030917,,,D*67
$SDDBT,65
$GPRMC,102701.000,A,5254.1998,N,00537.5761,E,1.01,224.19,030917,,,D*65
$SDDBT,67
$GPRMC,102702.000,A,5254.1995,N,00537.5758,E,1.28,218.16,030917,,,D*6A
$SDDBT,63
$GPRMC,102703.000,A,5254.1992,N,00537.5754,E,1.33,217.97,030917,,,D*6C
$SDDBT,49
$GPRMC,102704.000,A,5254.1987,N,00537.5750,E,1.40,213.54,030917,,,D*64
$SDDBT,46
en zo verder....
De 150 kHz transducer voor gebruik in een Europe dinghy. De stok en kabel worden van buiten af in de voorzijde van de zwaardkast naar boven getrokken. Hierdoor komt de transducer met fairing block, vóór het zwaard, tegen de romp te liggen. Bij de geregistreerde diepte moet in deze positie 28 cm opgeteld worden om de waterdiepte DBS (Depth below Surface) te krijgen. Het echolood kan, in een netje gehangen tegen het voorschot., door de zeiler bediend en afgelezen worden. Tijdens de opnames moet uiteraard niet te schuin gezeild worden
Gebruik op een SUP Board
Dezelfde transducer op een nylon blok gemonteerd samen met een vin. Dit geheel schuift in de rail aan de onder/achter zijde van het SUP board. Bij de geregistreerde diepte wordt 5 cm geteld om de waterdiepte vanaf het oppervlak (SDDBS) te krijgen
Waterdiepte 't Hop (Slotermeer Friesland) en omgeving
Voorbeeld: Oude opnames van 2017 geprojecteerd op de betonnings situatie van begin 2023. (De verdwenen gerapporteerde meerboei mb7 is in mei 2023 weer teruggelegd.)
Jeroen Droogh bootprojecten@gmail.com