Ultrasonic Sensor USB Serial Python

which mode are you using
3. Automatic Serial Port Mode
4. Low Power Serial Port Mode

I had assumed auto serial

I'm using Mode 5: Computer Printing Mode (ASCII code output) but should be the same thing as Mode 3 if I'm not mistaken

in mode 5 you have to trigger the serial somehow? sent it a character ??
try

# print bytes in hex

import serial
import sys
import msvcrt
import time
from time import sleep

serialPort = serial.Serial(
    port="COM12", baudrate=9600, bytesize=8, timeout=1, stopbits=serial.STOPBITS_ONE
)
serialPort.rtscts = False
serialPort.xonxoff = False
serialPort.dsrdtr = False 
sys.stdout.write("Python jsn_sr04t ultrasonic transducer\n")
i=0
command = b'\xF1' # character in hex
serialPort.write(command)  # read Device information

while i<30:
   while serialPort.in_waiting > 0:
         char = serialPort.read()
         hex_string = char.hex()
         print(hex_string)
         i=i+1

mode 4 transmits continuously

It worked here are the characters

Python jsn_sr04t ultrasonic transducer
47
61
70
3d
37
31
38
6d
6d
0d
0a

looks like you are not in serial mode but in Computer Printing Mode (think you have shorted R19 pads)
the characters are printable ASCII Gap=718mm followed by Carriage Return Line Feed

1 Like

Correct. that's how this sensor came. I'm not sure if it's an issue or if it's even possible to use Python to print distance. In addition, what's the difference between the two?

if you are using Computer Printing Mode try

# print bytes in ASCII

import serial
import sys
import msvcrt
import time
from time import sleep

serialPort = serial.Serial(
    port="COM12", baudrate=9600, bytesize=8, timeout=1, stopbits=serial.STOPBITS_ONE
)
serialPort.rtscts = False
serialPort.xonxoff = False
serialPort.dsrdtr = False 
sys.stdout.write("Python jsn_sr04t ultrasonic transducer\n")
i=0
command = b'\xF1' # character in hex
serialPort.write(command)  # read Device information

while 1:
    while serialPort.in_waiting > 0:
         char = serialPort.read()
         #sys.stdout.write("\nreceived ")
         if ord(char) < 128:
             sys.stdout.write(str(char,'ASCII'))

whichshould print

Gap=468mm
Gap=468mm
Gap=468mm
Gap=468mm
  etc

The code did run however there's two issues with it

  1. The code does not run continuously it only gives 1 distance and that's it
  2. the code gives out wrong distance
Python jsn_sr04t ultrasonic transducer
Gap=3510mm  
Python jsn_sr04t ultrasonic transducer
Gap=668mm
Python jsn_sr04t ultrasonic transducer
Gap=198mm

the problem is the documentation is vague
possibly one has to prompt Computer Printing Mode to make it work???

1 Like

Okay so a weird phenomenon happens it reads the data correctly but if something is super close to it, it won't detect it. The code is correct but does not output continuously

it has a minimum range of 20cm
if you require shorter distances use TOF sensors

1 Like

I see do you recommend I switch to Mode 3 for easier debugging?

@horace could we not send a simple 0x01 command using the serial port for getting the distance? this just came to mind but not sure how we would achieve this

automatic serial mode is probably the simplest approach
you scan received bytes for start byte (0xFF?) read following three bytes, calculate checksum, if OK calculate distance

EDIT: when you have it set up try running the following script to print the values

# print bytes in hex

import serial
import sys
import msvcrt
import time
from time import sleep

serialPort = serial.Serial(
    port="COM12", baudrate=9600, bytesize=8, timeout=1, stopbits=serial.STOPBITS_ONE
)
serialPort.rtscts = False
serialPort.xonxoff = False
serialPort.dsrdtr = False 
#sys.stdout.write("Python jsn_sr04t ultrasonic transducer\n")
i=0
#command = b'\xF1' # character in hex
#serialPort.write(command)  # read Device information

while i<30:
   while serialPort.in_waiting > 0:
         char = serialPort.read()
         hex_string = char.hex()
         print("0x"+hex_string,end=",")
         i=i+1

then upload the output which should look like

0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,

@sdeleon21 I wasn't sure of the protocol as I don't have the sensor but I tried the following sketch on an ESP32 using micropython, whether it's micropython or Python 3 it should work with minor modification in particular with the serial port settings, I used UART 2 at 9600 with my example. Select poll is another way of using in_waiting on Python 3 or uart.any() on micropython and is the recommended method of testing for incoming serial data using micropython.

from machine import UART
import select

uart = UART(2,9600)
sData =  bytearray(3)

poller = select.poll()
poller.register(uart, select.POLLIN)

while True:
    events = poller.poll(10) # takes milliseconds as an argument for delay, no argument = zero delay
    header = 0
    if events:
        header = int.from_bytes(uart.read(1),"big")
        
        if header == 0xff:
            uart.readinto(sData,3)
            hi_byte , lo_byte , chk_sum = (sData)			
            checksum = (header + hi_byte + lo_byte) & 0x0f 
            distance = (hi_byte << 8) + lo_byte
            print("Distance :", distance,'    ',"chk sum :",chk_sum,'    ',"checksum :",checksum)

what does the code of post 35 do? any printout?

if you are using automatic serial mode try this code which

  1. looks for a start byte 0xff
  2. calculate the checksum
  3. if checksum OK calculates distance and deletes the array data
  4. if checksum fails delete the first array byte and try again
# Python read jsn_sr04t ultrasonic transducer

# automatic serial mode - start byte + hi byte + low byte + checksum

import serial
import sys
import msvcrt
import time
from time import sleep

serialPort = serial.Serial(
    port="COM12", baudrate=9600, bytesize=8, timeout=1, stopbits=serial.STOPBITS_ONE
)
serialPort.rtscts = False
serialPort.xonxoff = False
serialPort.dsrdtr = False 
sys.stdout.write("Python read jsn_sr04t ultrasonic transducer data\n")

bytecount = 0           # byte count
array1 = []    # array for received data
while 1:
   # read four bytes from serial
   while bytecount < 4:
      if serialPort.in_waiting > 0:
         array1.append(serialPort.read())
         #hex_string = array1[bytecount].hex()
        # print("0x"+hex_string,end=",")
         bytecount = bytecount + 1
   print(array1)
   # check if first byte is start byte 0xFF
   if array1[0] != b'\xFF':
      # not 0xFF remove first byte and try again
      array1.pop(0)           
      bytecount=bytecount-1
   else:
      # is 0xFF calculate checksum
      checksum = (int.from_bytes(array1[1])+int.from_bytes(array1[2])) & 0xff
      if checksum == int.from_bytes(array1[3]):
         # checksum OK calculate distance
         print(f"0xff found checksum OK {checksum} ", end='')
         distance = int.from_bytes(array1[1]) << 8 | int.from_bytes(array1[2])
         print(f'Distance {distance}')
         array1.pop(0)  # clear array
         array1.pop(0)
         array1.pop(0)
         array1.pop(0)
         bytecount=0
      else:
         print(f"0xff found checksum error {checksum} {int.from_bytes(array1[3])}")
         array1.pop(0)
         bytecount=bytecount-1
   sleep(0.05)

using some sample data

0xff found checksum OK 200 Distance 200
[b'\xff', b'\x00', b'\xc9', b'\xc9']
0xff found checksum OK 201 Distance 201
[b'\xff', b'\x00', b'\xca', b'\xca']
0xff found checksum OK 202 Distance 202
[b'\xff', b'\x00', b'\xcb', b'\xcb']
0xff found checksum OK 203 Distance 203
[b'\xff', b'\x00', b'\xcc', b'\xcc']
0xff found checksum OK 204 Distance 204
[b'\xff', b'\x00', b'\xd0', b'\xd0']
0xff found checksum OK 208 Distance 208
[b'\xff', b'\x00', b'\xdb', b'\xdb']
0xff found checksum OK 219 Distance 219
[b'\xff', b'\x00', b'\xdf', b'\xdf']
0xff found checksum OK 223 Distance 223
[b'\xff', b'\x01', b'\x01', b'\x02']
0xff found checksum OK 2 Distance 257
[b'\xff', b'\x01', b'\x0c', b'\r']
0xff found checksum OK 13 Distance 268
[b'\xff', b'\x01', b'\n', b'\x0b']
0xff found checksum OK 11 Distance 266
[b'\xff', b'\x01', b'\x10', b'\x11']
0xff found checksum OK 17 Distance 272
[b'\xff', b'\x01', b'\x0e', b'\x0f']
0xff found checksum OK 15 Distance 270
[b'\xff', b'\x01', b'\x11', b'\x12']
0xff found checksum OK 18 Distance 273
[b'\xff', b'\x01', b'\x11', b'\x1f']
0xff found checksum error 18 31
[b'\x01', b'\x11', b'\x1f', b'\xff']
[b'\x11', b'\x1f', b'\xff', b'\x01']
[b'\x1f', b'\xff', b'\x01', b'\x11']
[b'\xff', b'\x01', b'\x11', b'\x12']
0xff found checksum OK 18 Distance 273

Hi, a break down of sketch in #35, it assumes, as suggested, automatic serial mode and does a full print out at the end

Keeps looping until it reads the header byte 0xFF

 	if events:
        	header = int.from_bytes(uart.read(1),"big")
        
        	if header == 0xff:

Next it reads the following three bytes into the buffer sData

uart.readinto(sData,3)

The high byte, low byte and check sum are then unpacked from the sData bytearray

hi_byte , lo_byte , chk_sum = (sData)

A calculation of the check sum is performed but only as a visual check in this example

checksum = (header + hi_byte + lo_byte) & 0x0f

Then the data is assembled and printed in the last two lines

	distance = (hi_byte << 8) + lo_byte
    print("Distance :", distance,'    ',"chk sum :",chk_sum,'    ',"checksum :",checksum)

It is the simplest example I could think of and works with micropython and also Python 3

EDIT added the Python 3 version of the above

import serial
import sys
import msvcrt
import time
from time import sleep

ser = serial.Serial()
ser.port = 'COM24'
ser.baudrate = 9600
ser.open()

sData = bytearray(3)

while True:
    header = 0

    if ser.inWaiting():
        header = int.from_bytes(ser.read(1),"big")
       
        if header == 0xff:
            ser.readinto(sData)
            hi_byte , lo_byte , chk_sum = (sData)			
            checksum = (header + hi_byte + lo_byte) & 0x0f 
            distance = (hi_byte << 8) + lo_byte
            print("Distance :", distance,'    ',"chk sum :",chk_sum,'    ',"checksum :",checksum)
1 Like

I don't have a version of the jsn_sr04t with this particular protocol either so I implemented a program to transmit protocol test data over serial (runs on ESP32, Nano, etc)

byte data[]={0xff, 0x00, 0xC8, 0xC8, 0xff, 0x00, 0xC9, 0xC9, 0xff, 0x00, 0xCA, 0xCA, 0xff, 0x00, 0xCB, 0xCB, 0xff, 0x00, 0xCC, 0xCC,  
               0xff, 0x00, 0xD0, 0xD0, 0xff, 0x00, 0xDB, 0xDB, 0xff, 0x00, 0xDF, 0xDF, 0xff, 0x01, 0x01, 0x02, 
                0xff, 0x01, 0x0C, 0x0D, 0xff, 0x01, 0x0A, 0x0B, 0xff, 0x01, 0x10, 0x11,
                0xff, 0x01, 0x0E, 0x0F, 0xff, 0x01, 0x11, 0x12, 0xff, 0x01, 0x11, 0x1F, 0xff, 0x01, 0x11, 0x12 };
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < sizeof(data); i++)
    Serial.write(data[i]);
}

void loop() {}

as well as valid data the test contains 0xff, 0x01, 0x11, 0x1F to force a checksum error

with this data your Python3 code of post 37 gives

Python 3.11.1 (tags/v3.11.1:a7a450f, Dec  6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

= RESTART: F:/Ardunio/Networking/WiFi/ESP32/sensors/Ultrasonic sensor/Python/sumguy_1`.py
Distance : 200      chk sum : 200      checksum : 7
Distance : 201      chk sum : 201      checksum : 8
Distance : 202      chk sum : 202      checksum : 9
Distance : 203      chk sum : 203      checksum : 10
Distance : 204      chk sum : 204      checksum : 11
Distance : 208      chk sum : 208      checksum : 15
Distance : 219      chk sum : 219      checksum : 10
Distance : 223      chk sum : 223      checksum : 14
Distance : 257      chk sum : 2      checksum : 1
Distance : 268      chk sum : 13      checksum : 12
Distance : 266      chk sum : 11      checksum : 10
Distance : 272      chk sum : 17      checksum : 0
Distance : 270      chk sum : 15      checksum : 14
Distance : 273      chk sum : 18      checksum : 1
Distance : 273      chk sum : 31      checksum : 1
Distance : 273      chk sum : 18      checksum : 1

your calculation of checksum was

checksum = (header + hi_byte + lo_byte) & 0x0f 

I just added the hi and low bytes

checksum = (int.from_bytes(array1[1])+int.from_bytes(array1[2])) & 0xff

@horace hi horace, like I said I don't have the sensor and I based my answer on a stream of bytes that were transmitted with an automatic trigger.

I copied your byte array to a python list and got the same results on the PC and also the ESP 32 as you did, I thought that was a useful exercise, I read somewhere that the calculation of the checksum was the lower byte of the sum byte[0] + byte[1] + byte[2]. That is not critical at this point, if @sdeleon21 can start reliably receiving measurement data I am sure he can figure that out.

the online documentation regarding serial mode is vague to say the least
however, the video @sdeleon21 referenced in post 20 showed sample output data in HEX from a jsn_sr04m using automatic serial mode

which showed the start byte, data bytes and checksum

the protocol is very simple - could be problems if a data byte or the checksum has the value 0xFF - why it is always a good idea to check the checksum

1 Like