B4R Tutorial Ultrasonic Ranging module HC-SR04

Testing the HC-SR04 to measuring distances

ultrasonic_sensor_schema.jpg

physics info.png

The accuraccy of the sensor depends greatly on device (chinese, cheap, etc..); in code, I limited the measurement between 3 cm and 100 cm (probably your device can measure larger distance)

Thanks to inline C code, I've used the PulseIn Arduino function, that measures de Echo Pulse Width (the distance is calculated proportionally from this value)

You can use other digitals pins for trigger and echo if you want.

upload_2016-4-13_18-31-14.png

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #StackBufferSize: 300
#End Region


Sub Process_Globals

   Public Serial1 As Serial
   Private triggerpin,echopin As Pin
   Dim pulsduration As ULong             'Pulse Width on Echo Pin (High to Low)
   Dim distance As Double

   Dim Intervalbtmeasures As Int=2       '2 seconds interval measures
   Dim SendTriggerTimer As Timer    

End Sub

Private Sub AppStart

   Serial1.Initialize(115200)
   Log("AppStart")

   'Configure Pins connection between Arduino and Distance Sensor
   triggerpin.Initialize(13,triggerpin.MODE_OUTPUT)
   echopin.Initialize(12,echopin.MODE_INPUT)
   echopin.DigitalWrite(False)


   'Enable trigger with Timer interval
   SendTriggerTimer.Initialize("SendTriggerTimer_Tick", Intervalbtmeasures*1000) '1000ms = 1 second
   SendTriggerTimer.Enabled = True

   
End Sub


Private Sub SendTriggerTimer_Tick

        'Begin trigger
        triggerpin.DigitalWrite(True)
  
        Log("Begin trigger")
  
        'Trigger Off
        triggerpin.DigitalWrite(False)
  
        'Distance proportional to pulse duration received on Echo Pin
        RunNative("pulseins",echopin.PinNumber)    
        distance=(0.5*pulsduration)/29.1
  
  
        'Discard inaccurate distance values (here between 3 and 100 cm)
        If (distance> 100) Or (distance<3) Then
            Log("Inacurate Distance - place the sensor correctly ")
        Else
            Log("Distance (cm) =",distance)
        End If
 
End Sub

#if C
void pulseins (B4R::Object* o) {
   b4r_main::_pulsduration = pulseIn(o->toULong(),HIGH);
}
#End if
 
Last edited by a moderator:

Eme Fibonacci

Well-Known Member
Licensed User
Amazing. In five minutes I did the same with my arduino UNO and B4R.
Thank you very much.

Thank you @Erel.
 
Last edited:

derez

Expert
Licensed User
I would not try to go without it, or use a simple voltage divider (like signal from HCSR04 -> 5 Kohm -- signal out to ESP -- 10 kohm, -> ground)
The signal from the ESP to the HCSR04 can go directly.
 

Beja

Expert
Licensed User
Thanks a lot for this important tutorial.
Will try it tomorrow
 

rbghongade

Active Member
Licensed User
Dear friends,
It was very easy to interface HC-SR 04 to mega. Thanks to inakigarm. But when I tried the same with WEMOS mini , with level shifting, suggested by derez , the pulsduration returns 0. Arduino sketch however works perfectly. Am confused at this . Can you suggest a solution please?

B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private client As WiFiSocket
    Private wifi As ESP8266WiFi
    Private triggerpin,echopin As Pin
      Dim pulsduration As ULong             'Pulse Width on Echo Pin (High to Low)
       Dim distance As Double
    Dim Intervalbtmeasures As Int=2       '2 seconds interval measures
       Dim SendTriggerTimer As Timer
      Private bc As ByteConverter
    Private d1 As D1Pins
    Private mqtt As MqttClient
    Private serverIp() As Byte = Array As Byte(192, 168, 1, 33)
    Private const serverPort As UInt = 1883
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    If wifi.Connect2("****","********") Then
          client.ConnectIP(serverIp,serverPort)
        Log("Waiting for connection.")
        Log("My ip: ", wifi.LocalIp)
    Else
        Log("Failed to connect to Wifi.")
    End If
    mqtt.Initialize(client.Stream, serverIp, serverPort, "ESP", "Mqtt_MessageArrived", "Mqtt_Disconnected")
    triggerpin.Initialize(d1.D6,triggerpin.MODE_OUTPUT)
       echopin.Initialize(d1.D7,echopin.MODE_INPUT)
       echopin.DigitalWrite(False)
       SendTriggerTimer.Initialize("SendTriggerTimer_Tick", Intervalbtmeasures*1000)
       SendTriggerTimer.Enabled = True
      Connect(0)
End Sub

Sub Connect(unused As Byte)
   If mqtt.Connect = False Then
     Log("trying to connect again")
     CallSubPlus("Connect", 1000, 0)
     Return
   End If
   Log("Connected to broker")
   mqtt.Subscribe("ESP", 0)

End Sub
Sub Mqtt_MessageArrived (Topic As String, Payload() As Byte)
   Log("Message arrived. Topic=", Topic, " payload: ", Payload)
   action(Payload)
End Sub

Sub Mqtt_Disconnected
   Log("Disconnected")
   mqtt.Close

   Connect(0)
End Sub
Sub SendTriggerTimer_Tick
    Dim dist As String
        triggerpin.DigitalWrite(True)
           Log("Begin trigger")
        triggerpin.DigitalWrite(False)
        RunNative("pulseins",echopin.PinNumber) 
        Log(pulsduration)
        distance=(0.5*pulsduration)/29.1
        Log("Distance (cm) =",distance)
        dist=distance
        mqtt.Publish("DIST",bc.stringtobytes(dist))
End Sub

Sub action (Buffer() As Byte)
 
End Sub


#if C
void pulseins (B4R::Object* o) {
   b4r_main::_pulsduration = pulseIn(o->toULong(),'HIGH');
}
#End if


The sketch that works:
B4X:
#define echoPin D7 // Echo Pin
#define trigPin D6 // Trigger Pin
long duration, distance; // Duration used to calculate distance
void setup()
{
Serial.begin (115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop()
{
/* The following trigPin/echoPin cycle is used to determine the
distance of the nearest object by bouncing soundwaves off of it. */
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
//Calculate the distance (in cm) based on the speed of sound.
distance = duration/58.2;
Serial.println(distance);
//Delay 1s before next reading.
delay(1000);
}
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
It should be simple to convert this code to B4R.

B4X:
Sub Process_Globals
  Public Serial1 As Serial
  Private wemos As D1Pins
  Private trigPin, echoPin As Pin
  Private timer1 As Timer
  Private pulsduration As ULong  'ignore
End Sub

Private Sub AppStart
  Serial1.Initialize(115200)
  Log("AppStart")
  timer1.Initialize("timer1_Tick", 1000)
  trigPin.Initialize(wemos.D6, trigPin.MODE_OUTPUT)
  echoPin.Initialize(wemos.D7, echoPin.MODE_INPUT)
  timer1.Enabled = True
End Sub

Private Sub Timer1_Tick
   trigPin.DigitalWrite(False)
   DelayMicroseconds(2)
   trigPin.DigitalWrite(True)
   DelayMicroseconds(10)
   trigPin.DigitalWrite(False)
   RunNative("pulseins", echoPin.PinNumber)
   Dim duration As Long = pulsduration
   Dim distance As Long = duration / 58.2
   Log(distance)
End Sub


#if C
void pulseins (B4R::Object* o) {
  b4r_main::_pulsduration = pulseIn(o->toULong(),HIGH);
}
#End if
 

rbghongade

Active Member
Licensed User
Dear Erel,

Found the problem, finally
The problem was with inline C code:
B4X:
#if C
void pulseins (B4R::Object* o) {
   b4r_main::_pulsduration = pulseIn(o->toULong(),'HIGH');
}
#End if
is the one given by inakigarm
Somehow for ESP8266 we have to change it to:
B4X:
#if C

void pulseins (B4R::Object* o) {
   b4r_main::_pulsduration = pulseIn(o->toULong(),HIGH);
}
#End if
Note the difference 'HIGH' has been changed to HIGH (without quotes!)
 
Last edited:
Top