Ultra sonic sensor seems not to work

hello i am trying to get an ultra sonic sensor to work with an arduino nano every. But i get no signal out of it. may be the sensor is broken or i am doing something wrong.

here is the sensor i bought: https://www.amazon.de/dp/B0BYKJ2NCX?psc=1&ref=ppx_yo2ov_dt_b_product_details

and i followed this tutorial: Waterproof Ultrasonic Distance Sensors with Arduino

may be this sensor does not work as i excpect since it is not the same as in the tutorial? Also i could not find any technical documentation on this exact model. Does anybody have any experience with this sensor?

what code did you use ?

/*
  JSN-SR04T-V3.0 Ultrasonic Sensor - Mode 1 Demo
  srt04-mode1.ino
  Uses JSN-SR04T-V3.0 Ultrasonic Sensor
  Displays on Serial Monitor

  Mode 1 is set by bridging "M1" pads on board

  Also works with A02YYUW Ultrasonic Sensor

  DroneBot Workshop 2021
  https://dronebotworkshop.com
*/

// Include the Software Serial library
#include <SoftwareSerial.h>

// Define connections to sensor
int pinRX = 10;
int pinTX = 11;

// Array to store incoming serial data
unsigned char data_buffer[4] = {0};

// Integer to store distance
int distance = 0;

// Variable to hold checksum
unsigned char CS;

// Object to represent software serial port
SoftwareSerial mySerial(pinRX, pinTX);

void setup() {
  // Set up serial monitor
  Serial.begin(115200);
  // Set up software serial port
  mySerial.begin(9600);
}

void loop() {

  // Run if data available
  if (mySerial.available() > 0) {

    delay(4);

    // Check for packet header character 0xff
    if (mySerial.read() == 0xff) {
      // Insert header into array
      data_buffer[0] = 0xff;
      // Read remaining 3 characters of data and insert into array
      for (int i = 1; i < 4; i++) {
        data_buffer[i] = mySerial.read();
      }

      //Compute checksum
      CS = data_buffer[0] + data_buffer[1] + data_buffer[2];
      // If checksum is valid compose distance from data
      if (data_buffer[3] == CS) {
        distance = (data_buffer[1] << 8) + data_buffer[2];
        // Print to serial monitor
        Serial.print("distance: ");
        Serial.print(distance);
        Serial.println(" mm");
      }
    }
  }
}

can you try this

  • make sure pin 10 is connected to the Tx pin of your sensor (pin 4 on the sensor wire) and pin 11 is connected to the Rx of the sensor (pin 3 on the sensor wire). 5V and GND connected to the red and black wires

  • upload this code

#include <SoftwareSerial.h>
int pinRX = 10; // connected to Tx pin of Sensor
int pinTX = 11; // connected to Rx pin of Sensor
SoftwareSerial mySerial(pinRX, pinTX);

void setup() {
  Serial.begin(115200);
  mySerial.begin(9600);
}

void loop() {
  if (mySerial.available() > 0) {
    byte r = mySerial.read();
    if (r == 0xFF) Serial.println("\nHeader - ");
    else {
      if (r < 0x10) Serial.write('0');
      Serial.print(r, HEX);
      Serial.write(' ');
    }
  }
}
  • open the serial monitor at 115200 bauds

do you see anything?

How did you know which pin is which. There is nothing on the website that explains.

You are right. Actually I do not know. I guessed that red goes to 5V and black to ground. Then a tried around with Tx and Rx but I did not get any signal.

Thank you! I will try that later.

image

I have this sensor, I bought a Grove screw terminal module to connect the wire

you need to be careful as the marking on the Grove kit does not match Vcc and GND

yes, i get:

09:40:40.191 -> 
09:40:40.191 -> Header - 
09:40:40.191 -> 05 9D A1 

And that’s all. Looks like I am getting one reading, right?

Ah, and I just tried it with the script I used before. It also gives me one reading. And the distance output seems to be correct.

But why only once?

Seems wrong on a Nano Every...

that's good

the A02YYUW distance sensor's output frame has 4 bytes
image

so we got the header (0xFF) that's when I print Header - (I should have been print and not println)
and then you got the 2 bytes for the disance High byte first and then low byte, so 0x059D is your distance and to know if it's correct the last byte is the check sum and should match

so if we calculate the CheckSum8 (Sum of Bytes modulo 256) 0xFF + 0x05 + 0x9D = 0x1A1 modulo 256 (ie take the low byte) = 0xA1 ➜ success, this matches the last byte you got, so the distance 0x059D is correct which is 1437mm so when you took the measurement the first obstacle was 1 m 43cm and 7mm away (I would not trust the mm)

so now you can write a small piece of code getting the payload and extracting the data, something like this will probably work

#include <SoftwareSerial.h>
int pinRX = 10; // connected to Tx pin of Sensor
int pinTX = 11; // connected to Rx pin of Sensor
SoftwareSerial sensorSerial(pinRX, pinTX);

uint16_t distance;

bool readDistance(uint16_t & newDistance) {
  const uint8_t headMarker = 0xFF;
  static bool waitingForMarker = true;
  static uint8_t data[3];
  static uint8_t dataIndex = 0;

  if (sensorSerial.available() != 0) {
    uint8_t r = sensorSerial.read();

    if (waitingForMarker) {
      if (r == headMarker) {
        dataIndex = 0;
        waitingForMarker = false;
      }
    } else {
      data[dataIndex++] = r;
      if (dataIndex >= sizeof data) { // we have received the full payload => check content
        waitingForMarker = true; // get ready for next frame
        newDistance = (((uint16_t)data[0]) << 8) + data[1]; // concatenate MSB and LSB into distance in mm
        uint8_t ck = (((uint16_t)data[0]) + ((uint16_t)data[1]) - 1u) & 0x00FFu; // calculate checksum
        return (data[2] == ck); // returns true if the check sum was OK
      }
    }
  }
  return false;
}

void setup() {
  Serial.begin(115200);
  sensorSerial.begin(9600);
}

void loop() {
  if (readDistance(distance)) Serial.println(distance);
}

(typed here, so not tested)

The readDistance function is a small state machine waiting for the 0xFF start marker and then accumulating the 3 next bytes. taking the first two for the distance and verifying that the last byte matches the checksum as I manually did above. if the checksum is correct the call returns true otherwise false. when you get true, you know the value in the parameter has been correctly updated and so you can use it for the distance.

Here I just print the new distance.

Might this be the reason why i get only one measurement? I also tried using the pins labelled with with TX1 and RX0. and instead of software serial is used Serial1. But that does not work at all. Here is the code which does not work.

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
}

void loop() {
  if (Serial1.available() > 0) {
    byte r = Serial1.read();
    if (r == 0xFF) Serial.println("\nHeader - ");
    else {
      if (r < 0x10) Serial.write('0');
      Serial.print(r, HEX);
      Serial.write(' ');
    }
  }
}

then i connected TX1 and RX0 directly and tried this script from the examples, which work fine:

/*
  SerialPassthrough sketch

  Some boards, like the Arduino 101, the MKR1000, Zero, or the Micro, have one
  hardware serial port attached to Digital pins 0-1, and a separate USB serial
  port attached to the IDE Serial Monitor. This means that the "serial
  passthrough" which is possible with the Arduino UNO (commonly used to interact
  with devices/shields that require configuration via serial AT commands) will
  not work by default.

  This sketch allows you to emulate the serial passthrough behaviour. Any text
  you type in the IDE Serial monitor will be written out to the serial port on
  Digital pins 0 and 1, and vice-versa.

  On the 101, MKR1000, Zero, and Micro, "Serial" refers to the USB Serial port
  attached to the Serial Monitor, and "Serial1" refers to the hardware serial
  port attached to pins 0 and 1. This sketch will emulate Serial passthrough
  using those two Serial ports on the boards mentioned above, but you can change
  these names to connect any two serial ports on a board that has multiple ports.

  created 23 May 2016
  by Erik Nyquist

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialPassthrough
*/

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  if (Serial.available()) {        // If anything comes in Serial (USB),
    Serial1.write(Serial.read());  // read it and send it out Serial1 (pins 0 & 1)
  }

  if (Serial1.available()) {       // If anything comes in Serial1 (pins 0 & 1)
    Serial.write(Serial1.read());  // read it and send it out Serial (USB)
  }
}

sure, Serial 1 (hardware UART on D0/D1) is a better choice, but one thing at at time...

the doc states

When "RX" floats or input High level, the module outputs processed value, the data is more steady, response time: 100-300ms; when input Low level, the module outputs real-time value, response time: 100ms.
May be that's an issue for Software Serial and it can't keep up...

In many UART implementations, when there is no incoming data, the Rx pin is typically in a "mark" state, the voltage level on the Rx pin is at a logical HIGH (idle state). this can vary but if it's the case with your Arduino then you should see data coming every 100-300ms

may be you can try connecting only the module's Tx to the arduino D0 and connect the Rx of the module to 5V or GND to ensure the mode is set. don't connect the Arduino D1 to anything and try

// Serial -> USB interface
// Serial1 -> D0 (RX) / D1 (TX)


uint16_t distance;

bool readDistance(uint16_t & newDistance) {
  const uint8_t headMarker = 0xFF;
  static bool waitingForMarker = true;
  static uint8_t data[3];
  static uint8_t dataIndex = 0;

  if (Serial1.available() != 0) {
    uint8_t r = Serial1.read();

    if (waitingForMarker) {
      if (r == headMarker) {
        dataIndex = 0;
        waitingForMarker = false;
      }
    } else {
      data[dataIndex++] = r;
      if (dataIndex >= sizeof data) { // we have received the full payload => check content
        waitingForMarker = true; // get ready for next frame
        newDistance = (((uint16_t)data[0]) << 8) + data[1]; // concatenate MSB and LSB into distance in mm
        uint8_t ck = (((uint16_t)data[0]) + ((uint16_t)data[1]) - 1u) & 0x00FFu; // calculate checksum
        return (data[2] == ck); // returns true if the check sum was OK
      }
    }
  }
  return false;
}

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600);
}

void loop() {
  if (readDistance(distance)) Serial.println(distance);
}

Ok, so when i do this i get again one reading only /Rx to ground). but whenever i disconnect the Rx from Ground while the program ist running i get another reading and then when i reconnect too.

May be you don’t have a real module… you could connect the Rx of the module then to an ouput pin which you would pulse when you want to trigger a reading?

Ok, for my case that’s good. thank you for your patients and fast and competent help.

So your suggested somehow works for some seconds but somehow weirdly. And then stops. I think I would like another sensor. Can you recommend one? It must be waterproof, because I want to use it outside.

I have that one and at the top of a rain collecting water tank to measure how much water is left and it’s working fine for me. May be you got a bad one or a knock off.

Could you try it with another arduino, just to remove doubts about the Nano every

I tested with another arduino nano every and i get the same results. Then i contacted the company that sold me the sensor and they will send me a replacement :slight_smile: