Problema Sensor Ultrasonico en Bastón para Ciegos

Buenas amigos!
tengo un nuevo dilema con mi sensor ultrasonico hc-sr04…
Estoy en un proyecto de colocar un sensor ultrasonico a un bastón blanco para ciegos, para que detecte obstáculos con los que pueda chocar que se encuentran a una altura desde la cintura hasta un poco mas arriba de la cabeza osea en un rango de (1.5 metros), y si encontrara un objeto en ese rango hacer funcionar un motor vibrador que seria como una alerta al invidente…

imagen de referencia:


estuve montando todo y probando por unos días y note que cuando estaba en movimiento el bastón de un lado para el otro hacia funcionar el motor por unos instantes, revise por el monitor serial los datos y note que por un pequeño lapso de tiempo daba lecturas como si encontrara objetos en el rango establecido… cosa que no quiero que ocurra si no es que en verdad hubiera un objeto ahi…

cual seria el problema? o el sensor suele funcionar así, o es el viento, el polvo o es normal eso? desde ya gracias…

mi código:

#include <NewPing.h>

#define TRIGGER_PIN  10  
#define ECHO_PIN     11  
#define MAX_DISTANCE 200 

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

void setup() {
  Serial.begin(115200); 
  pinMode(12, 1);
}

void loop() {
  delay(50);                      
  unsigned int uS = sonar.ping(); 
  Serial.print("Ping: ");
  Serial.print(uS / US_ROUNDTRIP_CM); 
  Serial.println("cm");
  
if (MAX_DISTANCE < 150) {                 
digitalWrite(12, 1);           
   }
else  {            
digitalWrite(12, 0);  
      }
    }

La detección de un objeto a 1.5mts supongo que es rápida, porque no intentas confirmarla al menos varias veces sin que afecte la percepción.
Veamos, velocidad del sonido 1200 m/seg. un objeto a 1.5mts ida y vuelta son 3mts => teco = 3m/1200 m/s = 2.5mseg o 2500 useg.

El problema que veo es que un ciego suele mover el bastón en un movimiento pendular, justamente barriendo la zona frente a él. Eso no da mucho margen para repetir o confirmar un objeto.

Creo que en un segundo barre de izquierda a derecha.
1 seg /2.5msg = 400 lecturas
Supongamos que el movimiento angular que describe corresponde a 60 grados entronces 400/60= 6.66 lecturas por grado.
Que tal tomarse un margen de 5 lecturas x grado o 4 si queremos ser mas conservadores.

Entonces yo implementaria una reconfirmación de 4 lecturas seguidas para confirmar la presencia de un objeto o justamente no confirmar un fallo.
4 lecturas deben dar valores similares o las descarto.

Que opinas?

surbyte:
La detección de un objeto a 1.5mts supongo que es rápida, porque no intentas confirmarla al menos varias veces sin que afecte la percepción.
Veamos, velocidad del sonido 1200 m/seg. un objeto a 1.5mts ida y vuelta son 3mts => teco = 3m/1200 m/s = 2.5mseg o 2500 useg.

El problema que veo es que un ciego suele mover el bastón en un movimiento pendular, justamente barriendo la zona frente a él. Eso no da mucho margen para repetir o confirmar un objeto.

Creo que en un segundo barre de izquierda a derecha.
1 seg /2.5msg = 400 lecturas
Supongamos que el movimiento angular que describe corresponde a 60 grados entronces 400/60= 6.66 lecturas por grado.
Que tal tomarse un margen de 5 lecturas x grado o 4 si queremos ser mas conservadores.

Entonces yo implementaria una reconfirmación de 4 lecturas seguidas para confirmar la presencia de un objeto o justamente no confirmar un fallo.
4 lecturas deben dar valores similares o las descarto.

Que opinas?

Primeramente gracias por responder... la verdad no había pensado en hacer de esa manera, ahora que me cuentas todos estos datos la tengo mas clara porque tengo un familiar que tiene ese problema y siempre le veo con moretones en la cara de los putasos que se da con objetos y decidí fabricar algo para el.
amigo la velocidad del sonido no es 340 m/s? (1200 no son en km?) puedo estar equivocado :frowning:
y tu idea de que re confirme varias veces antes de dar una alerta me parece bárbaro :smiley:

tienes razón 1200 es en km/h o sea estas mas restringido.
3m/340 m/seg= 8.82 mseg
1seg/8.82mseg = 113 lecturas. redondeemos a 110.

110 y un angulo de 55 nos darán 2 lecturas por grado.. mas estrecho

bueno confirma con 2 lecturas y haz movil la parte de confirmación como para poder mover el bastón mas lento. Si mueve mas lento el bastón y le tomara 2 segundos mejoras tu capacidad de confirmar pero si la persona lo mueve mas rápido, ésta empeorará.

Lástima que estoy en fase incial con los ARM, pero sugeriría algo mas avanzado que el clásico bastón con sensor ultrasónico, digo esto para ayudarte en la tarea. Pero hoy no tengo la capacidad para hacerlo.

Lo mas avanzado sería una cámara WEB que lleve la persona, su info va a un Rpi o BBB con OpenCV y un programa de detección de objetos. Formas un zona segura y hasta podría dar mas información.
Pero aun doy mis primeros pasos en BBB (BeagleBone Black + Python + OpenCV).
OpenCV es una librería para tratamiento de imágenes en plataformas grandes.

Pues cada vez se me pone mas dificil la cosa :frowning:
La verdad no soy tan bueno en esto de arduino, recien empieso y lo quiero hacer lo mas sencillo posible, ya te as de haber dado cuenta con mi codigo tan simple...
Pero todo sea por ayudar al projimo
Y como puedo hacer lo de la doble confirmacion para agregar a mi codigo y ver como trabaja?...
Gracias totales

Se me ocurre esto. Veamos si funciona
la parte relevante es esta.

if (us < 150) {     // Acá estaba mal porque pusiste MAX_DISTANCIA < 150 lo que siempre es false
      digitalWrite(12, 1);           
   }
else  {            
      digitalWrite(12, 0);  
      }
    }

Pero antes de activar algo con digitalWrite(12, 1); vamos a confirmar.
Vamos a necesitar un contador y una variable que almacene la distancia.
Luego preguntaremos si la distancia esta alrededor del valor leido, digamos ± 2.
Con esto quiero decir que tomaremos un valor, supongamos que lee 100 y luego lee 99, bueno lo tomamos que que es válido.
Pero si lee 100 y luego lee 130, no activará nada.
Esta explicanción me hizo cambiar un poco como lo estaba encarando.
Ahora bien. Supongamos que el siguiente es 129 entonces si activará el sonido.
Lo que estoy pensando es que el ciego va tanteando y cuando siente un obstaculo lo tantea con su bastón.
Aca al tantear tenemos un sonido, de modo que el sonido cuando reciba datos similares al anterior se debería activar, y de nuevo, se me ocurre que lo mas facil es ver diferencias, entonces, la nueva manera será asi:
vas caminando y recibes datos… cuando no recibes nada las diferencias serán próximas pero cuando encuentre un objeto de nuevo serán proximas con la diferencia de que ahora la distancia es menor a 150.
Entonces tenemos una doble confirmación… primero si detectamos algo mas alla de 150 no le prestamos atención.
Pero si ese algo es menor a 150 leemos todos los resultados y conforme su diferencia sea baja menor a algo es que se trata de un obstáculo.
COn esto incluso puedes ampliar la cantidad de reconfrimaciones porque en torno al sitio del obstáculo la persona, se detiene tantéandola.

Veamos eso en programa.
agrego una variable

#define DELTA 3
int diferencia = 0;

unsigned int uS = sonar.ping()/ US_ROUNDTRIP_CM; // cambia esta linea y luego presentala bien

if ( uS < 150) { 
    diferencia -= uS;
   if (++contador => 2) {
      contador = 1;
      diferencia -= uS;
   }
   if (abs(diferencia) <= DELTA) {
       digitalWrite(12, 1);           // si dos valores consecutivos son menores o iguales a delta entoces suena
    }
    else  {            
        digitalWrite(12, 0);  
    }
}
else {
   contador = 0;
   diferencia = 0;
}

Prueba a ver si funciona. Mira si la logica esta bien.
La idea es que dos valores proximos dan una diferencia en valor absoluto X tal que sea menor igual a DELTA para activar el buzzer.

Ejemplo… no hay objetos, entonces uS > 150 no suena

Ahora si hay un objeto a 90 cmts pero falta confirmar.
diferecia se carga con 90 y abs(diferencia) = 90 > DELTA = 3 no suena.
ahora el siguiente es 88
diferencia = -90 + 88 = -2
abs(diferencia) = 2 < DELTA = 3 => SUENA

prueba a ver si funciona la idea

Ufff mejor explicación imposible pues solo así lograría entender todo este problema, ya que sos el único que me ayuda...
he tratado de incorporar el código que me as facilitado y solo conseguí enrredarlo mas y mas, al compilar me salia que "contador" no estaba declarado y lo coloque así:

#define DELTA 3
int diferencia = 0;
int contador = 0; // lo declare de esta manera, lo hice bien?

después en esta linea me mostraba que la (>) tenia que ir antes del signo igual:

 if (++contador => 2) //lo que hice fue colocarlo delante así (>=)

y en esta parte no se que hacer con el, ni donde colocar :frowning:

unsigned int uS = sonar.ping()/ US_ROUNDTRIP_CM; // cambia esta linea y luego presentala bien

como te comente al tratar de fusionar con mi código que había publicado antes HICE UN DESASTRE...
cual es la forma correcta de hacerlo?
gracias por la paciencia que me tienes :blush:

No estabas muy lejos.
Esto compila, ahora quiero saber si trabaja como lo pensé.

#include <NewPing.h>

#define TRIGGER_PIN  10  
#define ECHO_PIN     11  
#define MAX_DISTANCE 200 
#define DELTA 		 3

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

const byte pinBuzzer = 12;
int diferencia 	= 0;
int contador 	= 0; 
unsigned int uS = 0;
unsigned int anterior;

void setup() {
  Serial.begin(9600); 
  pinMode(pinBuzzer, 1);
}

void loop() {
	char buffer[30];
    
    anterior = uS;                 
	uS = sonar.ping()/ US_ROUNDTRIP_CM; 
	sprintf(buffer, "Ping %d cm ", uS);
	Serial.print(buffer);
	
	if ( uS < 150) { 
		contador++;
		
		if (contador == 2) {
	       contador = 1;

	       diferencia = (int) anterior - uS;
	    }
	    sprintf(buffer, " Dif =%d contador=%d =>", diferencia, contador);
	    Serial.print(buffer);

	    if (abs(diferencia) <= DELTA) {
	       digitalWrite(pinBuzzer, HIGH);
	       Serial.println("SUENA");
	    }
	    else  {            
	       contador = 0;	
	       digitalWrite(pinBuzzer, LOW);
	       Serial.println("NO SUENA");  
	    }
	}
	else {
	   contador = 0;
	   diferencia = 0;
	}
}

El programa no parece estar bien. Al principio calcula bien las diferencias pero luego que la dif es mayor a DELTA se queda como enganchando en esa diferencia.
Al menos con el simulador.

Como tu dices amigo efectivamente no funciona bien, acabo de cargarlo y probarlo, lo que pude notar es que se queda midiendo en una distancia, que lo que puede estar pasando :confused:


No. No se queda midiendo una distancia. Eso te lo aseguro porque lo probé.
Requiere mas trabajo.

Corregido. Veamos si sirve

#include <NewPing.h>

#define TRIGGER_PIN  10  
#define ECHO_PIN     11  
#define MAX_DISTANCE 200 
#define DELTA 		 3

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

const byte pinBuzzer = 12;
int diferencia 	= 0;
int contador 	= 0; 
unsigned int uS = 0;
unsigned int anterior;

void setup() {
  Serial.begin(9600); 
  pinMode(pinBuzzer, 1);
}

void loop() {
	char buffer[40];
    
    anterior = uS;                 
	uS = sonar.ping()/ US_ROUNDTRIP_CM; 
	sprintf(buffer, "Ping %d cm ", uS);
	Serial.print(buffer);
	
	if ( uS < 150) { 

       diferencia = (int) uS - anterior;

       if (abs(diferencia) <= DELTA) {
          digitalWrite(pinBuzzer, HIGH);
          Serial.println("SUENA");
        }
	    else  {            
	       digitalWrite(pinBuzzer, LOW);
	       Serial.print("NO SUENA ");  
	    }
	    //sprintf(buffer, " Dist = %d cm Dif =%d contador=%d =>", uS, diferencia);
	    //Serial.println(buffer);
	}
	else {
	   diferencia = 0;
	   Serial.println();
	
	}
}

surbyte:
No. No se queda midiendo una distancia. Eso te lo aseguro porque lo probé.
Requiere mas trabajo.

Que mala noticia... Y ahora que hago amigo, porque ami esto ya me supera por mucho...

Prueba cambiando esto....

++contador;
if (contador == 2) {
contador = 1;
diferencia = (int) anterior - uS;
}

Por esto otro.....

++contador;
if (contador == 2) {
contador = 0;
diferencia = (int) anterior - uS;
}

Creo que el problema es que cuando se resetea la variable contador hay que hacerlo a 0 (para tener dos medidas).

Saludos,

jjpd00:
Prueba cambiando esto…

++contador;
if (contador == 2) {
contador = 1;
diferencia = (int) anterior - uS;
}

Por esto otro…

++contador;
if (contador == 2) {
contador = 0;
diferencia = (int) anterior - uS;
}

Creo que el problema es que cuando se resetea la variable contador hay que hacerlo a 0 (para tener dos medidas).

Saludos,

Acabo de cambiarlo, y la verdad no note alguna mejoría sigue funcionando como me lo había proporcionado surbyte… porque es tan complicado :confused:

Como no funciona, yo lo probé con mi simulador y parece funcionar mas o menos adecuadamente.

surbyte:
Como no funciona, yo lo probé con mi simulador y parece funcionar mas o menos adecuadamente.

Pues hoy lo estuve probando bien, creo que encontré unos problemas:

MAX_DISTANCE 200;

en el monitor serial me devuelve 0 (ceros) si no hay objetos en ese rango osea 200cm, y eso hace activar mi buzzer, creo que habría que hacer como una condición que si recibe 0 (ceros) no haga nada o eso pienso yo...

otro problema es que si encuentra objetos en el rango establecido el sonido del buzzer es intermitente no es constante, me entiendes?

Si. Claro. dejame ver que se puede hacer

Se me ocurre una idea. Si el problema es el movimiento del bastón, ¿que tal probar con algún dispositivo fijo? algo que se pueda llevar como un colgante, o en el bolsillo de la camisa.

Creo que empiezo a cometer errores de lo que le digo o no a cada uno. Demasiadas respuestas.
Te sugiero esto:

Monta el bastón como elemento fijo, solo para probar el sensor ultrasónico y establece que ocurre cuando no hay nada en 250 cmt (máximo alcance) y que respuesta da el sensor?
Esto es fundamental porque ahora tenemos un problema con la NO DETECCION, y este evento que seguramente es el que mas ocurre y el que mas tiempo involucra debe estar bien establecido.

Asi que cuando el sensor NO DETECTA objetos, dice?
Si dice 0, entonces sabemos que 0 es NO OBJETO, lo descartamos y 1 será un objeto delante suyo, y algo a 249 lo verá como tal o 250 cm.
Verifica esto por favor y vemos si es posible continuar

Espero tu respuesta.

surbyte:
Creo que empiezo a cometer errores de lo que le digo o no a cada uno. Demasiadas respuestas.
Te sugiero esto:

Monta el bastón como elemento fijo, solo para probar el sensor ultrasónico y establece que ocurre cuando no hay nada en 250 cmt (máximo alcance) y que respuesta da el sensor?
Esto es fundamental porque ahora tenemos un problema con la NO DETECCION, y este evento que seguramente es el que mas ocurre y el que mas tiempo involucra debe estar bien establecido.

Asi que cuando el sensor NO DETECTA objetos, dice?
Si dice 0, entonces sabemos que 0 es NO OBJETO, lo descartamos y 1 será un objeto delante suyo, y algo a 249 lo verá como tal o 250 cm.
Verifica esto por favor y vemos si es posible continuar

Espero tu respuesta.

Buenas, en estos días que vengo teniendo el ultrasonico nuevo había probado montón de códigos CON librerías y se me ocurrió probarlo SIN librearía haber que sucedía, y obtuve unos buenos resultados (no tenia el problema de que daba falsas lecturas no daba el fallo como si encontrara objetos...
este es el código:

int pingPin = 9; 
int entradaPin = 8;

int ledRojo = 12; //LED rojo va en pin 12


/*Con esta variable podremos encender el LED rojo cuando
la distancia sea demasiado corta, puede ser
cambiada con solo cambiar el valor, ese valor esta en cm
*/
int zonaSegura = 50;

void setup(){
  
  //Inicializamos los pines como entradas y salidas
  pinMode(pingPin, OUTPUT);
  pinMode(ledRojo, OUTPUT);
  pinMode(entradaPin, INPUT);
  

  
}

void loop(){
  
  //Creamos 2 variables, una para la duracion y otra para la distancia
  long duracion, distanciaEnCm;
  
  /*
  Hacemos un pulso bajo-alto-bajo para encender el sensor
  Al encender y apagar esperamos en microsegundos, de esta
  manera enviaremos nuestra primer onda
  */
  digitalWrite(pingPin, LOW); // Envía un pulso bajo
  delayMicroseconds(2);       // Espera dos microsegundos
  digitalWrite(pingPin, HIGH);// Envía un pulso alto
  delayMicroseconds(5);       // Espera 5 microsegundos
  digitalWrite(pingPin, LOW); // Se queda en espera
  
  /*Obtenemos la duracion de tiempo mientras
  el sensor este recibiendo la informacion
  */
  duracion = pulseIn(entradaPin, HIGH);
  
  /*
  Convertimos la duracion del tiempo a distancia
  La velocidad del sonido es de 340metros/segundo que 
  es igual a 29 microsegundos por centimetro es por es
  que vamos a dividir la duracion entre 29. 
  Despues se divide entre 2 porque es el tiempo que viaja
  el sonido de ida y de vuelta, solo queremos un valor pero
  ambos son iguales, es por eso que solo dividimos
  entre 2
  */
  distanciaEnCm = (duracion/29)/2;
  
  //Imprimimos la distancia en consola

  
  /*Prendemos los LED's, cuando la distancia es
  mayor a la zona segura se prende el LED verde y
  se apaga el rojo. Cuando la distancia es menor
  a la zona segura se prende el LED rojo y se apaga el LED
  verde
  */
  if(distanciaEnCm > zonaSegura){
     
    digitalWrite(ledRojo, LOW);
      
  }
  else{
    
 
    digitalWrite(ledRojo, HIGH);
    
  }
  
delay(50);   //Hacemos un delay antes de volver a sensar

  
}

hasta ahora me funciona bien con objetos grades (ramas, puertas y demás) pero con cosas pequeñas casi no las detecta, sera que el código no esta bien optimizado? o con el sensor es difícil detectar objetos pequeños?

edita tu post, quedó todo como si fuera una cita [.quote]text[./quote]

No se que tan bien trabaja el sensor ultrasónico. Si no funciona como esperas considera usar un sensor IR detector de distancia como el Sharp GP2Y0A21YK o algún otro que lo reemplace.
Este sensor solo llega a 80 cm maximo lo cual no da mucho margen pero si detectalos objetos chicos, será mejor opción.

Este otro funciona desde 20 a 150 cm IR distance sensor includes cable (20cm-150cm) - GP2Y0A02YK