Send a message in Morse Code and receive and translate the message

Hello, I am coaching a youth STEM club. They are working on a project that uses two arduinos.

The first detects it's own battery level and shares it's findings by sending a morse code message using a buzzer.

The second arduino should detect the message, translate the morse code into text, and display it on an LCD screen.

This set up is only a model of a solution to a problem. The problem is to create a deep sea communication link between under water autonomous robots (AUROV) and their users. Their model includes a daisy chain of hydrophones that would detect the sound waves transmitted from the AUROVs and interpret the signal (coming through as morse code) to pull data from the AUROV while it is submerged. They are beginning with battery level so they know when these AUROVs should surface to charge or be picked up by their pilots.

The problem we are having is that the buzzer sound is not picked up by the hydrophone. I don't know if there are too many outside noises to detect the buzzer sound or if it's just how we've programmed both sides of the project.

The arduino used to receive the message looks for a sound value but I don't know if that sound value is hertz or decible and I don't know how to make the sound from the buzzer programmed from the other arduino, to make a unique sound that we could make sure is all that is detected.

Any suggestions?

Thanks in advance, Coach Liz

Have you verified that the buzzer transmits fine in water?

1 Like

Hi coach Liz,. Welcome to the forum!

AFAIK, the hydrophone is just a microphone that happens to work under water in which case it will be generating a frequency in response to audio vibrations. It will probably require some amplification. Of course with morse, the code may only need to detect the presence or absence of the buzzer frequency and the duration of each burst.

However, its kind of difficult working in the dark so in order for us to be able to help you could you please:

  1. Post the sender and receiver code, making sure to enclose it in CODE tags
  2. Provide a diagram showing how you have things wired up, particularly on the receiving side
  3. Provide some information about the hydrophone device you are using

Thanks.

Can we guess you have tested the hydrophone so you know it works properly?

1 Like

We have tested the hydrophone we are using so we know that works.

For the receiver we are using a ESP32, a small preamp, 4 1.5 V batteries in a battery pack, and a sealed piezo I found on Etsy that was listed as a hydrophone.

I tried to recreate something similar in Tinkercad to try to make it look cleaner, but the components are not part of the options available, so this is close:

This is the code for the receiver:

#include <LiquidCrystal_I2C.h>

// Define LCD pins
const int lcdColumns = 16;
const int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

// Define sound sensor pin
const int soundPin = 36;

// Define Morse code mapping
const char* morseCode[] = {
  ".-",   // A
  "-...", // B
  "-.-.", // C
  "-..",  // D
  ".",    // E
  "..-.", // F
  "--.",  // G
  "....", // H
  "..",   // I
  ".---", // J
  "-.-",  // K
  ".-..", // L
  "--",   // M
  "-.",   // N
  "---",  // O
  ".--.", // P
  "--.-", // Q
  ".-.",  // R
  "...",  // S
  "-",    // T
  "..-",  // U
  "...-", // V
  ".--",  // W
  "-..-", // X
  "-.--", // Y
  "--.."  // Z
};

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  pinMode(soundPin, INPUT);
}

void loop() {
  static unsigned long lastSoundTime = 0;
  static String currentSymbol = "";
  static String currentMorse = "";
 
  int soundValue = analogRead(soundPin);
  unsigned long currentTime = millis();

  if (soundValue > 500) { // Adjust threshold based on testing
    if (currentTime - lastSoundTime > 1000) { // Long pause - end of letter
      processMorse(currentMorse);
      currentMorse = "";
    }

    unsigned long soundDuration = 0;
    lastSoundTime = currentTime;
    while (analogRead(soundPin) > 500) { // Sound is detected
      soundDuration = millis() - currentTime;
    }

    // Determine if dot or dash based on duration
    if (soundDuration < 200) { // Dot threshold (adjust based on testing)
      currentMorse += ".";
    } else { // Dash threshold
      currentMorse += "-";
    }
  }

  if (currentTime - lastSoundTime > 3000 && currentMorse != "") { // End of word
    processMorse(currentMorse);
    currentMorse = "";
    lcd.print(" "); // Space for word separation
  }
}

void processMorse(String morse) {
  for (int i = 0; i < 26; i++) {
    if (morse == morseCode[i]) {
      lcd.print((char)(i + 65)); // Display character on LCD
      break;
    }
  }
}

For the transmitter, currently we have just the buzzer that came with our kit providing the morse code tone to be picked up and translated by the receiver.

Here is the Tinkercad version:
![image|690x254](upload://l22eFYYE57AAQoCoCd3eUAlNCPf.png)

These are harder to understand:
![image|584x500](upload://my5nHTFpZpvp9geTWLjMbosEBft.jpeg)
![image|502x500](upload://z8VZOKC45gkYNg8Ola6ZeJ5QT3Y.jpeg)

And this code would allow us to use buttons to send a message to test:

// Pin definitions
const int buttonPin1 = 1;  // Button for "HIGH"
const int buttonPin2 = 2;  // Button for "MEDIUM"
const int buttonPin3 = 3;  // Button for "LOW"
const int buzzerPin = 12;  // Buzzer pin
const int ledPin = 6;      // LED pin

// Morse code definitions
const String HIGH_MORSE = ".... .. --. ....";     // Morse for HIGH
const String MEDIUM_MORSE = "-- . -.. .. ..- --"; // Morse for MEDIUM
const String LOW_MORSE = ".-.. --- .--";          // Morse for LOW

// Timing constants
const int dotDuration = 200;  // Duration for a dot (milliseconds)
const int dashDuration = 600; // Duration for a dash (milliseconds)
const int letterPause = 600; // Pause between letters (3 dots duration)

void setup() {
  pinMode(buttonPin1, INPUT_PULLUP);  // Buttons are input with pullup
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(buttonPin3, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);         // Set buzzer as output
  pinMode(ledPin, OUTPUT);            // Set LED as output
}

void loop() {
  // Check if button 1 (HIGH) is pressed
  if (digitalRead(buttonPin1) == LOW) {
    playMorseCode(HIGH_MORSE);  // Play Morse code for "HIGH"
  }
  
  // Check if button 2 (MEDIUM) is pressed
  if (digitalRead(buttonPin2) == LOW) {
    playMorseCode(MEDIUM_MORSE);  // Play Morse code for "MEDIUM"
  }

  // Check if button 3 (LOW) is pressed
  if (digitalRead(buttonPin3) == LOW) {
    playMorseCode(LOW_MORSE);  // Play Morse code for "LOW"
  }
}

// Function to play Morse code using the buzzer and LED
void playMorseCode(String message) {
  for (int i = 0; i < message.length(); i++) {
    char currentChar = message[i];
    if (currentChar == '.') {
      // Short beep and blink for dot
      tone(buzzerPin, 1000);  // Short beep for dot
      digitalWrite(ledPin, HIGH);  // LED ON for dot
      delay(dotDuration);              // Dot duration
      noTone(buzzerPin);       // Turn off buzzer
      digitalWrite(ledPin, LOW);   // LED OFF for dot
      delay(200);              // Silence between elements
    }
    else if (currentChar == '-') {
      // Long beep and blink for dash
      tone(buzzerPin, 1000);  // Long beep for dash
      digitalWrite(ledPin, HIGH);  // LED ON for dash
      delay(dashDuration);              // Dash duration
      noTone(buzzerPin);       // Turn off buzzer
      digitalWrite(ledPin, LOW);   // LED OFF for dash
      delay(200);              // Silence between elements
    }
    else if (currentChar == ' ') {
      delay(letterPause);  // Space between letters (3 dots duration)
    }
  }
  delay(1000);  // Space between different Morse code messages
}

The following is for the transmitter:


My Tinkercad version:

And the code:

// Pin definitions
const int buttonPin1 = 1;  // Button for "HIGH"
const int buttonPin2 = 2;  // Button for "MEDIUM"
const int buttonPin3 = 3;  // Button for "LOW"
const int buzzerPin = 12;  // Buzzer pin
const int ledPin = 6;      // LED pin

// Morse code definitions
const String HIGH_MORSE = ".... .. --. ....";     // Morse for HIGH
const String MEDIUM_MORSE = "-- . -.. .. ..- --"; // Morse for MEDIUM
const String LOW_MORSE = ".-.. --- .--";          // Morse for LOW

// Timing constants
const int dotDuration = 200;  // Duration for a dot (milliseconds)
const int dashDuration = 600; // Duration for a dash (milliseconds)
const int letterPause = 600; // Pause between letters (3 dots duration)

void setup() {
  pinMode(buttonPin1, INPUT_PULLUP);  // Buttons are input with pullup
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(buttonPin3, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);         // Set buzzer as output
  pinMode(ledPin, OUTPUT);            // Set LED as output
}

void loop() {
  // Check if button 1 (HIGH) is pressed
  if (digitalRead(buttonPin1) == LOW) {
    playMorseCode(HIGH_MORSE);  // Play Morse code for "HIGH"
  }
  
  // Check if button 2 (MEDIUM) is pressed
  if (digitalRead(buttonPin2) == LOW) {
    playMorseCode(MEDIUM_MORSE);  // Play Morse code for "MEDIUM"
  }

  // Check if button 3 (LOW) is pressed
  if (digitalRead(buttonPin3) == LOW) {
    playMorseCode(LOW_MORSE);  // Play Morse code for "LOW"
  }
}

// Function to play Morse code using the buzzer and LED
void playMorseCode(String message) {
  for (int i = 0; i < message.length(); i++) {
    char currentChar = message[i];
    if (currentChar == '.') {
      // Short beep and blink for dot
      tone(buzzerPin, 1000);  // Short beep for dot
      digitalWrite(ledPin, HIGH);  // LED ON for dot
      delay(dotDuration);              // Dot duration
      noTone(buzzerPin);       // Turn off buzzer
      digitalWrite(ledPin, LOW);   // LED OFF for dot
      delay(200);              // Silence between elements
    }
    else if (currentChar == '-') {
      // Long beep and blink for dash
      tone(buzzerPin, 1000);  // Long beep for dash
      digitalWrite(ledPin, HIGH);  // LED ON for dash
      delay(dashDuration);              // Dash duration
      noTone(buzzerPin);       // Turn off buzzer
      digitalWrite(ledPin, LOW);   // LED OFF for dash
      delay(200);              // Silence between elements
    }
    else if (currentChar == ' ') {
      delay(letterPause);  // Space between letters (3 dots duration)
    }
  }
  delay(1000);  // Space between different Morse code messages
}

I have not. We are looking for alternatives to the buzzer currently. It was recommended that we send a tone of 69 khz because it wouldn't hurt/interfere with ocean wildlife (most of them) and it travels far enough through water to be detected by a nearby receiver. If we can get the right parts and the correct set up, we'd love to start testing underwater.

For the parts I purchased:
Hydrophone:
https://www.etsy.com/listing/1095357705/water-proof-stereo-contact-microphone?ref=yr_purchases

Amplifier board:

ESP32

Generic Version of Arduino Uno:

I have a strong feeling a regular buzzer won't get far in another media as water.

I doubt you will ever compete with the Navys sonar, but lets not take chances and have beached whales :upside_down_face:

You will need a submersible transducer, like those used in ultrasonic sonar depth sounders and fish finders. They are expensive and usually require a high voltage driver (100 to 400VAC).

The waterproof piezo microphone that you purchased appears to be for audible sounds, and probably won't be useful to receive ultrasonic signals. However, the sonar transducers can receive and transmit, albeit at ultrasonic frequencies.

Underwater communications are very challenging and the available devices tend to be quite expensive.

1 Like

Then you need to generate the tone at the frequency your hydrophone is designed for. How did you test it?

We have the hydrophone picking up audio because the LCD is translating the audio into morse code letters and punctuation. We just need to figure out how to get the hydrophone to focus on the sound coming from the buzzer or another audio device if anyone has suggestions.
I would also like to know if the sound in the code is hertz or decibels or some other unit of measurement so I can try to match the output from the transmitter to the input for the receiver to detect and translate.
For our demonstration for the project, we don't have to be able to test it underwater. We'd like to get to that point, but we would feel a bit of success if we could get it to receive and translate the message we send outside of water.

What I don't understand is why you refuse to tell us the frequency range your hydrophone can hear?

I'm sorry, I don't think I noticed the question. I am not sure what frequency range it can detect. Is there a way to check it with a meter?

[quote="ecrawley, post:14, topic:1342736"]

[/quote] A quick check of the specifications should answer the question.

I didn't see any specs on the Etsy account, so I just sent a message to the seller to see if they can provide me with specs. I'll give a day or two for a reply.

If the hydrophone can detect between 20-20khz, would any audio transmitter work? I found a tutorial to use a Panasonic WM-61A and an old/cheap pair of ear buds. I just wish I knew an audio expert who could give some sound advice.

Isn't that fundamental to your project?

Way back in 1976 my first embedded project was a Morse code decoder and display on a TV set.

One of the most difficult things to get right was the conversion of the incoming sound into a signal.

I would suggest that you take the transmitter circuit and code, but not output this to a buzzer but to connect the buzzer signal directly into the receiver / display circuit. Make sure that the voltage out of the transmitter is less than or equal to the working voltage of the receiver.

If that doesn't work then nothing else will. I have reservations about that code on the receiver being correct. Note that any analogue read will take just under 10mS.

Once you have got this working then replace the tone detection circuit with a PLL (Phase Lock Loop) and test again.

Note that when you get to water testing, any signal you send will appear to as a longer wavelength than it does without water.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.