I am running a JSN-SRO4T with a pico that will sense a water tank level. I keep getting phantom readings of the max out 24cm like every 2nd or 3rd reading at 1sec loop. I need this to be stable so it doesnt trigger a full reading which will trigger a solenoid valve to turn on or off. Can anybody help Im very new to this stuff..
It requires a clean and stable 5V supply. If you’re running it directly off the Pico’s 5V pin and the power dips, it could cause intermittent failures.
Hey there @Nicholas290601!
Could you send some images or diagrams of your setup? It should help to figure out how these false readings are being triggered, or help us figure out a way to detect which readings are false.
Hi Zach,
I am running 2 picos to create a meshtastic node, pico A is the sensor and pico B has a waveshare sx1262 lora hat
Pico A-
gp2 - trig of jsnsro4t
gp3- (voltage divider 2x 100k resistors brings 5v down to 2.5v) -echo of jsnsro4t
vsys is powered by 5v out of waveshare solar module D or 5v from usb when connected via serial (still glitches with usb power but worse maybe with bat power)
gp8(tx)- 1k resistor to gp9 (rx)picoB (UART)
gp9(rx)- gp8(tx) pico b (UART)
gnd pica A - pico B- Waveshare solar module D GND
3.3out - to vsys PicoB
gp4 - sda OLED (debug)
gp5 - scl OLED
gp26- voltage divider 2x 100k resistors conected to LiPo battery
Hope that gives you a clear enough picture mate, thanks!
this is the code I am using:
from machine import Pin, UART, ADC, reset
from PiicoDev_SSD1306 import *
from PiicoDev_Unified import sleep_ms
import time
=== UART SETUP ===
uart = UART(1, baudrate=115200, tx=Pin(8), rx=Pin(9)) # TX=GP8, RX=GP9
=== OLED SETUP ===
display = create_PiicoDev_SSD1306() # I2C0, SDA=GP4, SCL=GP5
=== JSN-SR04T Sensor Pins ===
trigger_pin = Pin(2, Pin.OUT)
echo_pin = Pin(3, Pin.IN)
=== Tank Dimensions ===
TANK_DEPTH_CM = 200 # Distance from sensor to bottom
SENSOR_MIN_CM = 25 # Sensor reading when tank is full
=== Battery Voltage Setup ===
adc = ADC(26) # GP26 (ADC0)
VOLTAGE_DIVIDER_RATIO = 2 # Adjust if your divider is different
=== State Memory ===
last_valid_distance = None
last_valid_voltage = 0
last_adc_raw = 0
show_sent1 = True # Toggle flag
=== Battery Voltage Setup ===
adc = ADC(26) # GP26 (ADC0)
VOLTAGE_DIVIDER_RATIO = 2 # Adjust if your divider is different
CALIBRATION_FACTOR = 1.02 # Set this after comparing with multimeter
# CALIBRATION_FACTOR = actual_voltage / measured_voltage
def read_battery_voltage():
try:
raw = adc.read_u16()
voltage = (raw / 65535) * 3.3 * VOLTAGE_DIVIDER_RATIO * CALIBRATION_FACTOR
return round(voltage, 2), raw
except Exception as e:
print(“Battery read error:”, e)
return None, 0
def measure_distance(retries=3):
for _ in range(retries):
try:
trigger_pin.value(0)
time.sleep_us(2)
trigger_pin.value(1)
time.sleep_us(10)
trigger_pin.value(0)
timeout = time.ticks_add(time.ticks_us(), 30000)
while echo_pin.value() == 0:
if time.ticks_diff(timeout, time.ticks_us()) <= 0:
return None
start_time = time.ticks_us()
timeout = time.ticks_add(time.ticks_us(), 30000)
while echo_pin.value() == 1:
if time.ticks_diff(timeout, time.ticks_us()) <= 0:
return None
end_time = time.ticks_us()
duration = time.ticks_diff(end_time, start_time)
return round((duration / 2) * 0.0343)
except Exception as e:
print("Sensor read error:", e)
time.sleep(0.1)
return None
=== Main Loop ===
while True:
try:
# — Battery Reading —
voltage, raw = read_battery_voltage()
if voltage is not None:
last_valid_voltage = voltage
last_adc_raw = raw
battery_uart_line = “battery_tank:{:.1f}”.format(voltage)
uart.write(battery_uart_line + “\n”)
else:
battery_uart_line = “battery_tank:ERROR”
uart.write(battery_uart_line + “\n”)
# --- Distance Reading ---
distance = measure_distance()
if distance is not None:
last_valid_distance = distance
# --- Calculate Tank Percentage ---
if distance <= SENSOR_MIN_CM:
percent_full = 100
elif distance >= TANK_DEPTH_CM:
percent_full = 0
else:
percent_full = int(((TANK_DEPTH_CM - distance) / (TANK_DEPTH_CM - SENSOR_MIN_CM)) * 100)
tank_uart_line = "tank_level:{}".format(distance)
percent_uart_line = "tank_percent:{}".format(percent_full)
uart.write(tank_uart_line + "\n")
uart.write(percent_uart_line + "\n")
else:
tank_uart_line = "tank_level:ERROR"
percent_uart_line = "tank_percent:ERROR"
uart.write(tank_uart_line + "\n")
uart.write(percent_uart_line + "\n")
# --- OLED Display ---
display.fill(0)
display.text("Bat: {:.1f}V".format(last_valid_voltage), 0, 0)
display.text("ADC: {}".format(last_adc_raw), 0, 10)
if last_valid_distance is None:
display.text("Dist: Waiting...", 0, 25)
else:
display.text("Dist: {} cm".format(last_valid_distance), 0, 25)
display.text("Full: {}%".format(percent_full), 0, 35)
# Alternate which UART line is shown every loop
if show_sent1:
display.text("Sent1:", 0, 45)
display.text(battery_uart_line[:21], 0, 55)
else:
display.text("Sent2:", 0, 45)
display.text(tank_uart_line[:21], 0, 55)
display.show()
show_sent1 = not show_sent1 # Flip toggle for next cycle
time.sleep(5)
except Exception as e:
print("‼️ CRITICAL ERROR:", e)
display.fill(0)
display.text("‼️ SYSTEM ERROR", 0, 0)
display.text("ERR:", 0, 15)
display.text(str(e)[0:20], 0, 30)
display.text("Still Running", 0, 50)
display.show()
time.sleep(5)
chat GPT recommends a 0.1uf ceramic cap in series with a 10uf electrolytic cap to keep the power stable and clean, sound ok? ive ordered some and will try it.
Hi Nicholas
Just butting in a bit here
No it does not sound OK. I believe they should be in parallel. I assume you know the difference between series and parallel. If your statement is a verbatim copy of what chatGPT published I would hope it is a typo, either by you or chat. Otherwise I must have doubts on anything else attributed to chatGPT.
They will help “clean up” any induced interference but 10µF is not going to cure any instability of the supply itself. Need to fix any of that at the source ie; the power supply itself.
This helps if you have long wires or a rats nest of wiring laying around which can act as an antenna and pick up all sorts of funny things. The biggest enemy of AM broadcast radio reception is 240VAC LED down lights. Very “noisy”.
Cheers Bob
My typo, was abit tired when i wrote that! Yes its meant to be parallel, not series. Thanks for the heads up!
How would you suggest I clean up the power source?
Hi Nicholas
Happy about that. My faith has been restored and you have been made aware of the mistake.
When your capacitors arrive by all means fit them. They might improve things but don’t be too disappointed if they don’t. They can’t do any harm anyway.
Firstly what makes you think there is something wrong with your power source that you can “clean up”.
What are you using for this Power source?
If it is a “phone charger” as against a dedicated power supply then some crap on the voltage rail won’t matter for charging and if that is what it is designed for I don’t think much can be done about it.
If you suspect this as causing you grief try changing it for a “proper” power supply of adequate capacity to verify.
I stress “adequate capacity” here as if your existing supply is border line you might get some ripple under higher load conditions. Some of these RPi devices seem to be very fragile when it comes to a bit of voltage sag which will happen under higher load conditions along with ripple.
Cheers Bob
Hi bob,
The power source is a 1100mAH LiPo battery charged by solar, through a Waveshare Solar power Module D, I didnt think that it would have dirty power, but chatGPT recommended the capacitors to filter any unwanted frequencies (which I thought would be harmless at worst) but also, would even out any power spikes or current sags, which I thought is what capicitors do, yes?
Hi Nicholas
To some extent but it depends on a few things. 10µF might help the odd little glitch which might not cause much bother anyway and you would have to be using only a few mA at most. If a bit of current is used then the electrolytic cap would have to be probably in the many thousands of µF as it is this cap that has to supply the current when the voltage is not there. The Waveshare module has probably got a fair chunk of capacitor on its output anyway and might not appreciate much more as the charging inrush current could be a bit much for it to handle.
I don’t know anything about this Waveshare device.
I would guess the caps chatGPT are suggesting would get rid of most interference the wiring picks up which could cause problems but I don’t believe they could do much for sags or partial “brown outs”. They have to be fixed at the source.
Fit these caps anyway, they would probably do more good than harm. just don’t expect miracles.
Is your supply 5V or 3.3V. In other words does the Waveshare module step up the battery or step down. If stepping up the 1100mA @ 3.7V will not be 1100mA at 5V. It will be (1100 x 3.7)/5 multiplied by the conversion factor which could be up to 85%. Using this conversion factor this equates to 692mAhr @ 5V, ((1100 x 3.7)/5)x 0.85. Quite a bit different to 1100.
Most people forget this conversion, especially with power banks. I have one that is rated 15000mAhr BUT THAT IS AT THE BATTERY. When converted this becomes about 11000mAhr @ 5V. I have confirmed this by measurement.
Cheers Bob
Hi all, just throwing something to consider.
The way I have read the issue is some readings are “max” and not the actual reading from the sensor.
“…gp3- (voltage divider 2x 100k resistors brings 5v down to 2.5v) -echo of jsnsro4t…”
I assume the voltage divider is to bring the 5V from the echo pin to a safer <= 3.3V (or in this case 0-2.5V) for the input into the controller.
I have not double check this so correct me if I am wrong:
“…minimum high level voltage is 1.3v …”
So that would mean that while the voltage on the echo pin on the controller is >= 1.3 V it would give your firmware a “High” level.
the data sheets comments that the echo pin is held high for X amount of time relative to the measurement.
I am wondering if the voltage divider is causing some issue, e.g. slowing down the drain of power for +Vcc to ground to trigger the end of pulse. i.e. if held high longer then needed the pulse would appear to be longer.?
I would really like to see an oscilloscope capture of the echo signal at the pico input pin.
Hi Michael
So would everyone else like to see oscilloscope pics of most problems in the Forum.
An oscilloscope is one of the most useful instruments behind a multimeter you can own. Once having learned how to use it it becomes an invaluable tool.
Unfortunately this device seems in very short supply within the hobbyist/maker community but to be useful it doesn’t have to be an expensive all singing and dancing mixed mode 4 channel job. A 2 channel 25 or 50MHz instrument would do 99% of jobs on most work benches. As long as you are aware of an instruments limitations you can work around most situations.
Cheers Bob
PS: I actually have 2. One is pretty old and a bit suspect and the X/Y function no longer works.
According to the code the voltage divider is used to provide a battery voltage reading (alternating with the tank level reading). There is no indication it is associated with powering the sensor.
From above
“…gp3- (voltage divider 2x 100k resistors brings 5v down to 2.5v) -echo of
jsnsro4t…”
So the voltage divider is been the sensor and the pico, GP3 and ECHO (on the sensor)
So on this line
Which means its dropping the 5V from the sensor echo out to 0-2.5V at the pico end.
there may be others in the project, but that is the one I was talking about.
No. The voltage divider is between the battery and ground and feeds pin 26. It could be used to determine the maximum level of the echo pulse, but I can’t see anywhere in the code it is actually used for this. The divider ration and calibration fact are hard wired.
If its used used as a level shifter, then it wont show in code.
And it is clearly stated as been between echo on the sensor and the pico in the description from above as i quoted.
Hi Nicholas and all
Just had a quick look at what is on offer when Googled "JSN-SRO4T ".
Everything (including library) seems to revolve around Arduino and an operating voltage of 5V. The JSN-SRO4T-2 would appear to handle 3V - 5,5V.
So why not ditch all this 3.3V fiasco and go for something like the Arduino NanoEvery or get the “-2” version of your sensor. Saves all this headache.
During my quick look I noted the sample sketches seem all for Arduino.
The NanoEvery I think is a bit smaller than Pico.
I have used a few of these and they all do what I want quite reliably and have shown no sign of failure yet.
Cheers Bob
I would assume that the tank is enclosed, the phantom results that you’re getting could be echos from the earlier sample. 1 second is pretty quick for reading a tank I’d suggest bringing that up to around 5-10 seconds to see if that fixes the issue.
Hi all, yes to confirm, there is a voltage divider from battery to adc26, AND a voltage divider on the Echo pin to bring it down from 5v so it wont fry the picos Pin. Bob the JSN-SRO4T is powered by 5v direct from the Waveshare module. I have since purchased a threadead pressure sensor that is designed for water tank level sensing. I need reliability for this project and I dont think the JSN-SRO4T is going to do that for me. but it would be good to still get to the bottom of this for future endevours/ reference for others..