4

I need to connect 6 ultrasonic sensors to one raspberry pi and all six sensors should take the distance measurement same time. I have written the code and made the thread also but only two sensors takes measurement and it is also random. Here is the code.

import RPi.GPIO as GPIO
import time
from threading import Thread
from multiprocessing import Process


GPIO.setmode(GPIO.BCM)

GPIO.setwarnings(False) # for disable warnings in terminal

# time for sensor to settle
SENSOR_SETTLE_TIME = 0.00001

MEASURE_INTERVAL_TIME = 0.1 # time delay to measure (min 15miliseconds)                 

# max distance threshold for sensors to react (in cm)
MAX_DISTANCE_THRESHOLD = 5.0

# Speed of sound at sea level = 343 m/s or 34300 cm/s
MEASURE_REFERENCE = 17150

# list of sensors
sensors = []

# sensor1 with pin configuration
sensor1 = {'ID': 'sensor1', 'TRIG': 17, 'ECHO': 4, 'LED_PIN': 27 }
sensors.append(sensor1) # add to the list
# sensor2 with pin configuration
sensor2 = {'ID': 'sensor2', 'TRIG': 22, 'ECHO': 5, 'LED_PIN': 6 }
sensors.append(sensor2) # add to the list
# sensor3 with pin configuration
sensor3 = {'ID': 'sensor3', 'TRIG': 18, 'ECHO': 23, 'LED_PIN': 24 }
sensors.append(sensor3) # add to the list
# sensor4 with pin configuration
sensor4 = {'ID': 'sensor4', 'TRIG': 20, 'ECHO': 16, 'LED_PIN': 21 }
sensors.append(sensor4) # add to the list



def initPins():
    if len(sensors) > 0:
        for sensor in sensors:
            #Sensor's echo pins shoud be in
            GPIO.setup( sensor['ECHO'], GPIO.IN );

            #Sensor's trig pins should be out
            GPIO.setup( sensor['TRIG'], GPIO.OUT );

            #Sensor's out_pin
            GPIO.setup( sensor['LED_PIN'], GPIO.OUT );
            GPIO.output( sensor['LED_PIN'], GPIO.LOW ); # Turn off in the begining

def turnOnLed(led_pin):
    #Turn on led only if it is off for some safety mesures
    if GPIO.input(led_pin) == GPIO.LOW:
        GPIO.output(led_pin, GPIO.HIGH)

def turnOffLed(led_pin):
    #Turn off led only if it is ON for some safety mesures
    if GPIO.input(led_pin) == GPIO.HIGH:
        GPIO.output(led_pin, GPIO.LOW)

def measure(sensor):
    print "Measurement started for " + sensor['ID'] + ", Ctrl+z to cancle the measurement";

    while True:
        GPIO.output( sensor['TRIG'], GPIO.LOW);

        time.sleep(MEASURE_INTERVAL_TIME); #DELAY

        GPIO.output(sensor['TRIG'], GPIO.HIGH);

        time.sleep(SENSOR_SETTLE_TIME);

        GPIO.output(sensor['TRIG'], GPIO.LOW);

        while GPIO.input(sensor['ECHO']) == 0:
            pulse_start = time.time();

        while GPIO.input(sensor['ECHO']) == 1:
            pulse_end = time.time();

        pulse_duration = pulse_end - pulse_start;

        distance = pulse_duration * MEASURE_REFERENCE;
        distanceRound = round(distance, 2);

        if(distanceRound < MAX_DISTANCE_THRESHOLD):
            turnOnLed(sensor['LED_PIN'])
        else:
            turnOffLed(sensor['LED_PIN'])

        print "Distance of sensor "+ sensor['ID'] + " : ", distanceRound, "cm";


def main():
    initPins()

    if len(sensors) > 0:
        for sensor in sensors:
            Process(target=measure, args=(sensor, )).start()


if __name__ == '__main__':

I would really appreciate your help and thanks in advance.

  • 2
    How do you deal with echos being picked up by the wrong sensor? – joan Jan 11 '17 at 20:10
  • I want to do this to but with four. How did you come up with this code? Did you follow a tutorial or is it all you? – John Demetriou Jan 12 '17 at 9:03
  • yeah its all me. Where do you want to use (four sensors) – brakesoft Jan 16 '17 at 21:24
6

The following code will scale to multiple sensors.

If you want all triggers to be at exactly the same time then connect the same GPIO to each of the triggers. Use that GPIO for the last sonar's trigger. Give all the other sonars the trigger None. It should work unless you have a silly number of sensors on the same trigger.

#!/usr/bin/env python

# srte.py
# 2017-01-11
# Public Domain

import time
import pigpio # http://abyz.me.uk/rpi/pigpio/python.html

SOS=340.29

class sonar:
   """
   Class to read distance using a sonar ranger.

   Instantiate with the Pi, trigger GPIO, and echo GPIO.

   Trigger a reading with trigger().

   Wait long enough for the maximum echo time and get the
   reading in centimetres with read().   A reading of 999.9
   indicates no echo.

   When finished call cancel() to tidy up.
   """
   def __init__(self, pi, trigger, echo):
      self.pi = pi
      self.trig = trigger

      self._distance = 999.9
      self._one_tick = None

      if trigger is not None:
         pi.set_mode(trigger, pigpio.OUTPUT)

      pi.set_mode(echo, pigpio.INPUT)

      self._cb = pi.callback(echo, pigpio.EITHER_EDGE, self._cbf)

   def _cbf(self, gpio, level, tick):
      if level == 1:
         self._one_tick = tick
      else:
         if self._one_tick is not None:
            ping_micros = pigpio.tickDiff(self._one_tick, tick)
            self._distance = (ping_micros * SOS) / 2e4
            self._one_tick = None

   def trigger(self):
      self._distance = 999.9
      self._one_tick = None

      if self.trig is not None:
         self.pi.gpio_trigger(self.trig, 15) # 15 micros trigger pulse

   def read(self):
      return self._distance

   def cancel(self):
      self._cb.cancel()

if __name__ == "__main__":

   import time
   import pigpio
   import srte

   pi = pigpio.pi()

   if not pi.connected:
      exit()

   S=[]
   S.append(srte.sonar(pi, None, 20))
   S.append(srte.sonar(pi,   26, 21))

   end = time.time() + 30.0

   r = 1

   try:
      while time.time() < end:

         for s in S:
            s.trigger()

         time.sleep(0.03)

         for s in S:
            print("{} {:.1f}".format(r, s.read()))

         time.sleep(0.2)

         r += 1

   except KeyboardInterrupt:
      pass

   print("\ntidying up")

   for s in S:
      s.cancel()

   pi.stop()

srte separate trigger GPIO

Separate trigger GPIO per sonar


srte single trigger

Single trigger GPIO (26) per sonar


moving plot

A plot showing the returns from two sensors mounted on the same platform as the platform is moved to and fro between two walls. Nominally ten readings per second are being taken with each sensor. Horizontal axis time, vertical axis reported distance in centimetres.


  • I did not understood anything at all. but thanks for the nice presentation – brakesoft Jan 16 '17 at 21:27
  • May i ask you to post a plan of the wiring? i am new to this topic an i am npt totaly sure about it. – michael-mammut Mar 19 '17 at 20:33
3

Your measure() function basically polls the sensor repeatedly to determine the pulse length. This inherently limits the number of sensors active at the same time to the number of simultaneously running threads, which in turn corresponds to the number of available CPU cores.

Unless you deal with very fast moving objects, you should consider taking your distance measurements sequentially, one sensor at a time. That would also eliminate possible interference issues between the sensors.

Also, there is no way this would work 100% reliably in a multitasking environment such as Linux, since your threads can be stopped and resumed by the OS at any time. Real-time stuff is better done by MCU boards such as Arduino.

  • I need to use rapsberry pi and they should measure distance at same time. What is the solution for the current suitation other than using arduino? – brakesoft Jan 16 '17 at 21:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.