which mode are you using
3. Automatic Serial Port Mode
4. Low Power Serial Port Mode
I had assumed auto serial
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
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
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???
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
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
# 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)
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