Measure distance using an ultrasound sensor in Python

0

I'm trying to measure a distance with the ultrasound sensor and everything looks good, but when I leave the program for a few minutes (3-4 minutes) of work, the program stops measuring the distance.

I need the program to not stop because I need it for a security alarm. The program collects every second a distance and shows it in scree. But if the distance is more than 10, the program displays an alert message and does not show the distance until it is less than 10. Below you can see the code:

import time
import RPi.GPIO as GPIO


# Usamos la referencia BOARD para los pines GPIO
GPIO.setmode(GPIO.BOARD)

# Definimos los pines que vamos a usar
GPIO_TRIGGER = 11
GPIO_ECHO = 13
GPIO_LED = 15

# Configuramos los pines como entradas y salidas
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo
GPIO.setup(GPIO_LED ,GPIO.OUT) #Led


# -----------------------
# Definimos algunas funciones
# -----------------------

def medida():
  # Esta funcion mide una distancia
  GPIO.output(GPIO_TRIGGER, True)
  time.sleep(0.00001)
  GPIO.output(GPIO_TRIGGER, False)
  start = time.time()

  while GPIO.input(GPIO_ECHO)==0:
    start = time.time()

  while GPIO.input(GPIO_ECHO)==1:
    stop = time.time()

  elapsed = stop-start
  distancia = (elapsed * 34300)/2

  return distancia

def media_distancia():
  # Esta funcion recoge 3 medidas
  # y devuelve la media de las 3.
  distancia1=medida()
  time.sleep(0.1)
  distancia2=medida()
  time.sleep(0.1)
  distancia3=medida()
  distancia = distancia1 + distancia2 + distancia3
  distancia = distancia / 3
  return distancia


# -----------------------
# Programa principal
# -----------------------


print ("Medida con sensor de ultrasonidos")

# Ponemos el Trigger en falso (low)
GPIO.output(GPIO_TRIGGER, False)
# Ponemos el Led en falso (low)
GPIO.output(GPIO_LED, False)

# Metemos el bloque principal en un Try para asi poder
# comprobar si el usuario presiona Ctrl + C
# y poder ejecutar una limpieza del GPIO, esto tambien
# evita el usuario tener que ver muchos mensajes de error
try:
  while True: # Este bucle se repite siempre

# Lo primero que hago es medir la distancia
      distancia = media_distancia()
# Compruebo si la distancia es menor que 10
# Si es menor que 10 muestro la distancia por pantalla

      if distancia < 10:
        distancia = media_distancia() # Medidos la distancia 
        print ("Distancia: %.1f" % distancia, " - " , "Fecha:", time.strftime("%c")) # Mostramos la distancia por pantalla
        GPIO.output(GPIO_LED, False)
        time.sleep(1) # Esperamos 1 segundo
        distancia = media_distancia()
        a = 0 # Utilizo la variable a para poder para el proceso mas adelante

# Pregunto si la variable a es igual a 1
# Si lo es no hago nada y repito el if anterior
      if a == 1:
        pass
# Pero si no es 1 le asigno el valor 0
# Para poder seguir con el IF siguiente
      else: 
        a = 0
      if distancia > 10 and a == 0: # Si la distancia es mayor que 10cms
           print ("La distancia es mayor de 10 cms. Alarma activada!!", " - ", "Fecha:", time.strftime("%c")) # Se interrumpe el bucle y se muestra un aviso
           GPIO.output(GPIO_LED, True)  
           a = 1 # Pongo la variable en 1 para parar el proceso y que no se repita 
           distancia = media_distancia() # Seguimos midiento la distancia
           while distancia < 10: # Pero si la distancia vuelve a ser menor de 10
             break # Se termina este bucle y volvemos al principio nuevamente

except KeyboardInterrupt: # Si el usuario presiona crtl + C

  # Limpiamos los pines GPIO y salimos del programa

  print ("Apagando LED")
  time.sleep(1)
  GPIO.output(GPIO_LED, False)
  print ("Limpiando GPIO")
  GPIO.cleanup()
  print ("GPIO limpio")
  print ("Saliendo...")
  time.sleep(1)

Why does the program stop after a few minutes? In reality, it continues to work but stops taking action. But if I press control + c to end if it shows me the program closing sequence. Thank you very much

    
asked by Sergio Muñoz 05.05.2017 в 14:53
source

2 answers

0

Your idea is correct but you have complicated without necessity. What you want is that every second you get a distance (an average of three measures actually). The reading of the mean and the sleep should be done only in the cycle while main, not conditional. In this way the cycle iterates every second obtaining an average. Obtained the average there are four possibilities:

  • Distance less than or equal to 10 with alarm deactivated : we only print the distance and the date.

  • Distance less than or equal to 10 with alarm activated : we deactivate the alarm and print the distance and date.

  • Distance greater than 10 and alarm deactivated : we activate the alarm (led on and a = 1) and print the alert.

  • Distance greater than 10 and alarm activated : we do nothing.

For the above, your code would simply be:

import time
import RPi.GPIO as GPIO


# Usamos la referencia BOARD para los pines GPIO
GPIO.setmode(GPIO.BOARD)

# Definimos los pines que vamos a usar
GPIO_TRIGGER = 11
GPIO_ECHO = 13
GPIO_LED = 15

# Configuramos los pines como entradas y salidas
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo
GPIO.setup(GPIO_LED ,GPIO.OUT) #Led

# -----------------------
# Definimos algunas funciones
# -----------------------

def medida():
    # Esta funcion mide una distancia
    GPIO.output(GPIO_TRIGGER, True)
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
    start = time.time()

    while GPIO.input(GPIO_ECHO)==0:
        start = time.time()

    while GPIO.input(GPIO_ECHO)==1:
        stop = time.time()

    elapsed = stop-start
    distancia = (elapsed * 34300)/2

    return distancia

def media_distancia():
    # Esta funcion recoge 3 medidas
    # y devuelve la media de las 3.
    distancia1=medida()
    time.sleep(0.1)
    distancia2=medida()
    time.sleep(0.1)
    distancia3=medida()
    distancia = distancia1 + distancia2 + distancia3
    distancia = distancia / 3
    return distancia

# -----------------------
# Programa principal
# -----------------------

print ("Medida con sensor de ultrasonidos")

# Ponemos el Trigger en falso (low)
GPIO.output(GPIO_TRIGGER, False)
# Ponemos el Led en falso (low)
GPIO.output(GPIO_LED, False)

try:
    a = False #Definimos la variable de estado y le damos valor False (desactivada)
    while True:
        distancia = media_distancia()

        if distancia <= 10:
            #Si la distancia es menor de 10 siempre imprimimos
            print ("Distancia: %.1f" % distancia, " - " , "Fecha:", time.strftime("%c"))

            #Debemos comprobar si la alarma está activada, de estarlo debemos desactivarla ya que la distancia es menor de 10
            if a:
                GPIO.output(GPIO_LED, False)
                a = False

        elif not a:
            #Si la alarma esta desactivada y la distancia es mayor de 10 activamos la alarma
            print ("La distancia es mayor de 10 cms. Alarma activada!!", " - ", "Fecha:", time.strftime("%c")) # Se interrumpe el bucle y se muestra un aviso
            GPIO.output(GPIO_LED, True)
            a = True

        #Esperamos 1 segundo antes de tomar la nueva medida
        time.sleep(1)

except KeyboardInterrupt:
    print ("Apagando LED")
    time.sleep(1)
    GPIO.output(GPIO_LED, False)
    print ("Limpiando GPIO")
    GPIO.cleanup()
    print ("GPIO limpio")
    print ("Saliendo...")
    time.sleep(1)

The elif is only executed if the if previous does not. This implies that it will only be executed if the distance is greater than 10.

We can simulate the previous program by creating an iterator with invented averages to emulate your code without the sensor. In the following example we simulate different means with two activations of the alarm and its subsequent reset:

import time


medias = iter((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1,2,3,4,5,6,7,8,9,10,11,1,2))

try:
    a = False
    while True:

        try:
            distancia = next(medias)
        except StopIteration:
            break

        if distancia <= 10:
            print ("Distancia: %.1f" % distancia, " - " , "Fecha:", time.strftime("%c"))
            if a:
                a = False
        elif not a:
            print ("La distancia es mayor de 10 cms. Alarma activada!!", " - ", "Fecha:", time.strftime("%c"))
            a = True

        time.sleep(1)

except KeyboardInterrupt:
    pass

Exit:

Distancia: 1.0  -  Fecha: Fri May  5 20:40:52 2017
Distancia: 2.0  -  Fecha: Fri May  5 20:40:53 2017
Distancia: 3.0  -  Fecha: Fri May  5 20:40:54 2017
Distancia: 4.0  -  Fecha: Fri May  5 20:40:55 2017
Distancia: 5.0  -  Fecha: Fri May  5 20:40:56 2017
Distancia: 6.0  -  Fecha: Fri May  5 20:40:57 2017
Distancia: 7.0  -  Fecha: Fri May  5 20:40:58 2017
Distancia: 8.0  -  Fecha: Fri May  5 20:40:59 2017
Distancia: 9.0  -  Fecha: Fri May  5 20:41:00 2017
Distancia: 10.0  -  Fecha: Fri May  5 20:41:01 2017
La distancia es mayor de 10 cms. Alarma activada!!  -  Fecha: Fri May  5 20:41:02 2017
Distancia: 1.0  -  Fecha: Fri May  5 20:41:07 2017
Distancia: 2.0  -  Fecha: Fri May  5 20:41:08 2017
Distancia: 3.0  -  Fecha: Fri May  5 20:41:09 2017
Distancia: 4.0  -  Fecha: Fri May  5 20:41:10 2017
Distancia: 5.0  -  Fecha: Fri May  5 20:41:11 2017
Distancia: 6.0  -  Fecha: Fri May  5 20:41:12 2017
Distancia: 7.0  -  Fecha: Fri May  5 20:41:13 2017
Distancia: 8.0  -  Fecha: Fri May  5 20:41:14 2017
Distancia: 9.0  -  Fecha: Fri May  5 20:41:15 2017
Distancia: 10.0  -  Fecha: Fri May  5 20:41:16 2017
La distancia es mayor de 10 cms. Alarma activada!!  -  Fecha: Fri May  5 20:41:17 2017
Distancia: 1.0  -  Fecha: Fri May  5 20:41:18 2017
Distancia: 2.0  -  Fecha: Fri May  5 20:41:19 2017

I recommend to always use 4 spaces to devise as recommended by PEP8 and never use tabs. You facilitate the reading, editing and execution of your code by other users and avoid errors of indentation caused by the use of tabulations in other editors. Four spaces are always the same in any editor, a tab depends.

    
answered by 05.05.2017 в 20:21
0

The description of the problem is link and the solution is link

# Si el objeto está muy cerca u ocurre una reprogramación
# es posible que ya se haya recibido el eco en cuyo caso
# este bucle nunca termina a menos que le digamos que termine
# después de un tiempo.
count=time.time()
while GPIO.input(GPIO_ECHO)==0 and time.time()-count<0.1:
     start = time.time()

...

# Si el objeto no es detectado algunos medidores
# no bajan la linea de eco en cuyo caso este bucle
# nunca termina a menos que le digamos que termine
# después de un tiempo.
stop = time.time()
count=time.time()
while GPIO.input(GPIO_ECHO)==1 and time.time()-count<0.1:
      stop = time.time()
    
answered by 08.05.2017 в 15:21