Sonar JSN-SR04T

OK I have hit the jackpot! I finally found the SR04 to i2c code that I knew existed out in the wild. this gives us 2 things, the ability to scale the rangefinder to work in water and the ability to run multiple rangefinders without using lots of gpio, I have edited this version to multiply the range so it shows up correctly when in water. its not as fast or accurate as serial mode but because the scaling is done before it gets to the flight controller it means it can be used for proximity and not just alarms.

// sr04 to apm I2c sonar
// by panxu mail: pxzleo@126.com
// Created 2014
#include <Wire.h>
#include "SR04.h"
#define TRIG_PIN 2
#define ECHO_PIN 3
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
uint16_t reading_cm;
uint16_t tempread;
void setup()
{
  reading_cm=0; 
  Wire.begin(0x70);                // join i2c bus with address #2
  Wire.onRequest(requestEvent); // register event
}

void loop()
{
  tempread=4.126*sr04.DistanceAvg(25,1);
  if (tempread<1500)  
       reading_cm=tempread;  
}
void requestEvent()
{
  byte sendhi;
  byte sendli;
  byte sendbyte[2];
  uint16_t tempreading_cm;
  tempreading_cm=reading_cm;
  sendhi=tempreading_cm>>8;
  sendli=tempreading_cm&0xff;
  sendbyte[0]=sendhi;
  sendbyte[1]=sendli;
  Wire.write(sendbyte,2); 
}

https://www.cnblogs.com/Tranquilty/p/6226469.html

Tes


Tested with my test rig.
https://files.cnblogs.com/files/Tranquilty/ApmSonar.zip

2 Likes

Excellent result, especially since the scaling parameter is not added in the new version(4.2). I also like that it’s on i2c, not on gpio.

yes having it on i2c opens up a lot of options, im adding another 3 under my boat looking forward left and right so I have underwater proximity alerts. you just need to change the i2c address in the arduino sketch to get around address conflicts, I have tested it running 2 so far without issue.

Now you can test and see how stable the sensor behaves.

1 Like

In order to read the sensor at maximum speed you would need read the serial stream directly from the sonar its self. currently there is no native serial driver but this is a serial lua driver that @Yuri_Rage created. its very fast but because the rangefinder is being read into lua but there is currently no lua binding for a rangefinder so it can only work within lua for actions and sending alerts and values it wont work with avoidance or anything like that currently.

local SCRIPT_NAME          = 'Depthfinder'
local MAV_DEPTH_LABEL      = 'DEPTH'
local BOOT_DELAY_MS        = 2000
local RUN_INTERVAL_MS      =  50
local SERIAL_PORT          =    0
local BAUD_RATE            = 9600
local FRAME_SIZE           =    4
local SPEED_RATIO          =    4.126
local INVALID_DEPTH        =   -1
local MAV_SEVERITY_WARNING =    4
local MAV_SEVERITY_INFO    =    6

local port = serial:find_serial(SERIAL_PORT)

port:begin(BAUD_RATE)
port:set_flow_control(0)

local function serial_flush(bytes)
    for i = 0, bytes - 1 do
        port:read()
    end
end

function update()
    local bytes_available = port:available():toint()

    if bytes_available ~= FRAME_SIZE then
        serial_flush(bytes_available)
        gcs:send_named_float(MAV_DEPTH_LABEL, INVALID_DEPTH)
        return update, RUN_INTERVAL_MS
    end

    local data = 0
    for i = 0, bytes_available - 1 do
        data = data << 8 | port:read()
    end

    local sum    = data & 0xFF
    local l_data = data >>  8 & 0xFF
    local h_data = data >> 16 & 0xFF

    if (0xFF + h_data + l_data) & 0xFF ~= sum then
        gcs:send_text(MAV_SEVERITY_WARNING,
                      string.format('%s: Bad checksum', SCRIPT_NAME))
        gcs:send_named_float(MAV_DEPTH_LABEL, INVALID_DEPTH)
        return update, RUN_INTERVAL_MS
    end

    local depth_raw = h_data << 8 | l_data
    --gcs:send_named_float('RAW', depth_raw)
    gcs:send_named_float(MAV_DEPTH_LABEL, depth_raw * SPEED_RATIO * 0.001)

    return update, RUN_INTERVAL_MS
end

gcs:send_text(MAV_SEVERITY_INFO, string.format('%s: Script Active', SCRIPT_NAME))

return update, BOOT_DELAY_MS

I have tweaked the code by swapping the trig and echo pins and redesigned the sonar board mounting to make it as slim as possible.


I have been busy, I wasnt happy with the arduino converter as it was still getting read as a Sr04 rangefinder without all the benefits of serial mode. so this is my latest creation, Using the TFmini>maxbotix i2c adapter @ppoirier made as a start I copied in the serial sonar code from an example script i found and now its working!

I have made another version of the serial i2c adapter that should work with the rangefinder in mode 1 and mode 2, so its only pinging if requested rather than every 100ms. it should give more stable returns as it will be going through all the rangefinders sequentially rather than them all pinging constantly.

latest version is fully operational with averaging and mode selection

found some technical information on the jsn-sr04t

https://www.davidpilling.com/wiki/index.php/JSN

3 Likes

I’d like to include this on a boat that I’m building.

Has any progress been made with the JSN-SR04T?

Is there a writeup somewhere?

At the moment the best way is to make an JSN-SRT04T serial Arduino i2c adapter, that will convert it to a maxbotix compatible i2c sonar and scale it.

Assuming your using an atmega 328p or 168p
5v A5 A4 ground for the i2c cable power SCL and SDA
5v 10 11 ground for the sonar connection RX and TX

1 Like

I also made a mavlink proximity version that should work underwater for fishfinding or collision avoidance.

Thanks. Can you please share some pictures?

Also, which FC are you using and how do you connect the JSN-SRT04T/arduino?

1 Like

there are photos here, the code runs on a STM32blackpill board using stmduino. you will need to lookup the pinout for the board to see what pins are for the serial ports .

I believe A0 is for the position feedback, it connects to the signal out on the servos potentiometer, A1 is for the servo PWM output and the flight controller connects to uart 1 and the sonar to uart 2.

good time of day. I’m not familiar with coding .and I use a translator so I’m sorry if it’s not clear. how to change the code to slightly negative values ( - )


so that the graph has depth and not height

It shows the vehicle height above the terrain when set to orientation 25.

why do you need it negative? there might be other solutions

I created a budget fishing boat from what was. I’m using the old one FlySky FS i6 and there is no lua script. and having received a negative, I could roughly see the relief of the bottom without much expense .

ah ok so you want the graph inverted so it shows the profile of the bottom. how have you got the sensor connected to ardupilot?

using the example given above

using bot ChatGPT added data output to the port monitor.and added add a minus sign to the value of the reading_cm variable ```cpp
#include <Wire.h>
#include “SR04.h”

#define TRIG_PIN 12
#define ECHO_PIN 11

SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
int16_t reading_cm;
uint16_t tempread;

void setup()
{
reading_cm = 0;
Wire.begin(0x70); // join i2c bus with address #2
Wire.onRequest(requestEvent); // register event

Serial.begin(9600); // Start serial communication
}

void loop()
{
tempread = 1 * sr04.DistanceAvg(25, 1);
if (tempread < 1500)
reading_cm = tempread;

Serial.print(“-”); // Print “-” before the reading_cm value
Serial.println(abs(reading_cm)); // Print the absolute value of reading_cm to serial monitor
}

void requestEvent()
{
byte sendhi;
byte sendli;
byte sendbyte[2];
uint16_t tempreading_cm = abs(reading_cm); // Get the absolute value of reading_cm
sendhi = tempreading_cm >> 8;
sendli = tempreading_cm & 0xff;
sendbyte[0] = sendhi;
sendbyte[1] = sendli;
Wire.write(sendbyte, 2);
}

at the request to add a minus sign to the i2c submission, the bot suggested adding reading_cm = -tempread to the line; // setting the minus sign

as a result, Mission Planner outputs values not from negative but 32786

Rangefinders don’t work with negative values, they only show distance to an object .

you could use a lua script to invert the value and create a virtual sensor with the value you want. I was using it to scale the rangefinder for the spee of sound in water but it would work if you want to invert it.

see here