Using an HCSR04 Attached to a Raspberry PI as a Parking Sensor

Celebrating All Saint’s Day Today :D

In this article I’ll show you how to use an HCSR04 Ultrasonic Distance Sensor attached to a Raspberry Pi to act as a parking sensor for a web app.

So your Raspberry Pi needs Wifi Capabilities for this to follow along.

So the Hardware:

And The Schematic which is from the pigpio setup:

HCSR04 Graphical Schematic

Initial Setup for Code

This should be done in you Raspberry Pi

So first create a directory in which to house our code along with initializing npm and installing the pigpio package:

mkdir distance-sensor
cd distance-sensor
npm init // Run through the setup
npm install pigpio

Then create a file called distance-sensor.js with the following code from the pigpio setup:

const Gpio = require('pigpio').Gpio;

// The number of microseconds it takes sound to travel 1cm at 20 degrees celcius
const MICROSECDONDS_PER_CM = 1e6/34321;

const trigger = new Gpio(23, {mode: Gpio.OUTPUT});
const echo = new Gpio(24, {mode: Gpio.INPUT, alert: true});

trigger.digitalWrite(0); // Make sure trigger is low

const watchHCSR04 = () => {
  let startTick;

  echo.on('alert', (level, tick) => {
    if (level == 1) {
      startTick = tick;
    } else {
      const endTick = tick;
      const diff = (endTick >> 0) - (startTick >> 0); // Unsigned 32 bit arithmetic
      console.log(diff / 2 / MICROSECDONDS_PER_CM);
    }
  });
};

watchHCSR04();

// Trigger a distance measurement once per second
setInterval(() => {
  trigger.trigger(10, 1); // Set trigger high for 10 microseconds
}, 1000);

The interesting bit of this code is that it gets the difference between the time the sound reaches the object and the time the sound bounces back to the sensor which all happens in microseconds.

    if (level == 1)
      startTick = tick;
    } else {
      const endTick = tick;
      const diff = (endTick >> 0) - (startTick >> 0); // Unsigned 32 bit arithmetic
      console.log(diff / 2 / MICROSECDONDS_PER_CM);
    }

After that run the file with sudo node distance-sensor.js.

It should give you the distance of any object in front of the sensor through your terminal. Otherwise review the wiring and run it again.

Sample Terminal Output

Server setup

This should be done in another PC, not your Raspberry Pi

You should have mongodb installed in your PC :

For Linux install mongodb through your terminal:

sudo apt-get install mongodb
sudo systemctl start mongodb

For Windows follow this tutorial to setup mongodb

After Installation clone this code, cd to it, run npm run seed and npm start

git clone https://github.com/Pofay/parking-sensor-example-server.git
cd parking-sensor-example-server
npm run seed
npm start

Open a browser and point it to localhost:3000/parking_lot

The web page should display a div element that turns green when vacant and red when occupied in real-time due to socket-io.

Using a tool like Postman point the url localhost:3000/api/parking_lot and set it to PUT

Then send a payload with this structure:

{ status: "vacant" } 

Or

{ status: "occupied" }

web-action

The Parking Sensor Setup

Now back to your Raspberry Pi in this Setup

The Scenario:

When a vehicle is near or on point to a set maximum distance then we send a occupied request. Otherwise a vacant request.

Although we are not going to be using real vehicles since that would be outside the scope of this article just think of this as a stand-in for the actual thing. We will be using toys or solid objects as our test dummies for this concept.

The Initial Code already has the distance calculation (in cm) so we only need to set a maximum distance in a configuration file so that the sensor can send the appropriate request.

To let our current sensor code send API requests to a server we need a http library. We’ll be going with axios for this.

We’ll also be using dotenv for our configuration so that the maximum distance can be set without touching the code.

Inside of your distance-sensor directory install axios and dotenv through npm:

npm install axios dotenv

First create a .env file with the following contents:

MAXIMUM_DISTANCE=7.08
HOST_IP=<IP of PC that runs server code>
PORT=3000

We set the max distance for testing purposes to 7.08 CM.

Also don’t forget to setup the host ip. It should point to your PC’s local ip. Use ipconfig or ifconfig for Windows and Linux respectively.

Then in your distance-sensor.js require both axios and dotenv:

const Gpio = require('pigpio').Gpio;
const axios = require('axios')
require('dotenv').config()

/* Setup Code */

and then on the echo side:

const url = 'http://' + process.env.HOST_IP + ':' + process.env.PORT + '/api/parking_lot'

echo.on('alert', (level, tick) => {
if (level == 1) {
  startTick = tick;
} else {
  const endTick = tick;
  const diff = (endTick >> 0) - (startTick >> 0); // Unsigned 32 bit arithmetic
  const distance = diff / 2 / MICROSECDONDS_PER_CM;
  if(distance <= process.env.MAXIMUM_DISTANCE)
      axios.put(url, { status: 'occupied' })
           .then(res => console.log(res.status))
           .catch(console.err)
  else
      axios.put(url, { status: 'vacant' })
           .then(res => console.log(res.status))
           .catch(console.err)
})

Whenever the object is close to the set MAXIMUM_DISTANCE it sends an occupied put request. Otherwise a vacant put request.

The full code:

If you’ve got it right so far placing an object in front of the sensor (approximately 7 cm) will now cause the div element to turn red. Otherwise its green.

Some Tips

This setup is nice and all, but the sensor keeps on sending put requests every second. Although this might just be one example if you’ve got many requests going through the API then there might be performance drawbacks.

You could use the State Pattern to do one off requests in that it only sends the request once per vacant and occupied change. My parking-sensor uses this approach to limit the number of requests per second.

Or you could use Event-Emitters to do this job.

Anyways I hope you’ve learned something today and happy tinkering and coding!.

Comments