I am working on an embedded systems project these days which the core program is written in java to work on a raspberry pi 3 model b in raspbian os. We needed to connect few ultrasonic sensors for that device so i have written a java class to interface the HC-SR04 ultrasonic sensor with the raspberry pi using GPIO pins. I have used the pi4j library to controll the GPIO pins of the raspberry pi.

Read http://pi4j.com/ to learn to to setup that library.

For the following test program, i have used GPIO pin 0 as the ECHO PIN and GPIO pin 1 as the TRIG PIN.

The third argument is REJECTION_START (long). To explain you what is the purpose of this argument, let me breifly explain you how we measure a distance from the HC-SR04 module. In order to get a distance reading from the ultrasonic sensor we need to keep the TRIG pin high state for 10us. If the TRIG pin kept high state for 10us, the sensor generate 8 cycle ultrasonic burst and put the ECHO pin state to high. The ECHO pin state change to low state once the echo reaches the sensor. Some times for various reasons eventhough we give signal to tigger the sensor it may not trigger that properly. In that case we would trigger that and wait so long  and read incorrect reading. That is way i introduced the REJECTION_START parameter. What it will do is, after sending the trigger signal it will wait for REJECTION_START number of nano seconds and see whether the sensor identified that as a real trigger. If not, reading return you a negetive value.


The fourth arugument is the REJECTION_TIME (long). Practically HC-SR04 has a maximum distance limit. In order to get accurate results we need to make sure our sensor reads and returns the mesurement if only whithin that range. So looking at the datasheets of your sensor, and considering about your need calculate a maximum allowable time for the echoed signal and put that value in nano seconds here.

See The GitHub Code

Test Program

public class Test_Ultrasonic{
	public static void main(String[] args) throws Exception{
		PiJavaUltrasonic sonic=new PiJavaUltrasonic(
			0,//ECO PIN (physical 11)
			1,//TRIG PIN (pysical 22)
			1000,//REJECTION_START ; long (nano seconds)
			23529411 //REJECTION_TIME ; long (nano seconds)
			System.out.println("distance "+sonic.getDistance()+"mm");
			Thread.sleep(1000); //1s

Sensor Java Class

 * 	TelepresenceBot - Ultrasonic sensor - worked well, return in mm
 * 	author: chandimab.github.io
 * 	pins are GPIO

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.*;

public class PiJavaUltrasonic{
	//bcm, GPIO_#
	private int PIN_ECHO,PIN_TRIG;
	private long REJECTION_START=1000,REJECTION_TIME=1000; //ns

	private GpioController gpio;//gpio controller ; using io.gpio
	private GpioPinDigitalOutput//gpio output pins; using io.gpio, digital pins
	private GpioPinDigitalInput
	public PiJavaUltrasonic(int ECHO, int TRIG, long REJ_START,long REJ_TIME){ //GPIO
		gpio=GpioFactory.getInstance();// create gpio controller , io.gpio
		pin_trig=gpio.provisionDigitalOutputPin(RaspiPin.getPinByAddress(PIN_TRIG), "pin_trig", PinState.HIGH);//pin,tag,initial-state
		pin_trig.setShutdownOptions(true, PinState.LOW);
	public int getDistance() throws Exception{ //in milimeters
			int distance=0; long start_time, end_time,rejection_start=0,rejection_time=0;
			//Start ranging- trig should be in high state for 10us to generate ultrasonic signal
			//this will generate 8 cycle sonic burst.
			// produced signal would looks like, _|-----|
			pin_trig.low(); busyWaitMicros(2);
			pin_trig.high(); busyWaitMicros(10);
			//echo pin high time is propotional to the distance _|----|
			//distance calculation
			while(pin_echo.isLow()){ //wait until echo get high
				busyWaitNanos(1); //wait 1ns
				if(rejection_start==REJECTION_START) return -1; //something wrong
			while(pin_echo.isHigh()){ //wait until echo get low
				busyWaitNanos(1); //wait 1ns
				if(rejection_time==REJECTION_TIME) return -1; //infinity
			distance=(int)((end_time-start_time)/5882.35294118); //distance in mm
			//distance=(end_time-start_time)/(200*29.1); //distance in mm
			return distance;
	public static void busyWaitMicros(long micros){
        long waitUntil = System.nanoTime() + (micros * 1_000);
        while(waitUntil > System.nanoTime()){
    public static void busyWaitNanos(long nanos){
        long waitUntil = System.nanoTime() + nanos;
        while(waitUntil > System.nanoTime()){

GitHub Code