Go Down

Topic: 6 Sensores de Ultrasonido HC SR04 para detectar Matriz (Read 2135 times) previous topic - next topic

dmaurot

Hola!! estoy trabajando con seis sensores HC SR04 ubicados cada 30cm, alineados en el piso, puestos hacia el techo, contra un muro (ver imagen) simulando una matriz de 5 x 7 en el muro.

https://www.dropbox.com/s/vvvedvgldluq7rc/IMG-20150713-WA0012_resize.jpeg?dl=0

OBJETIVO: Enviar un caracter específico por el puerto serie si el sensor me detecta un objeto en un rango determinado (ver gráfico abajo)

Code: [Select]
    _______________________________
    | a | q | / | l | l | ; | p | 0 |  120 a 150cm
    |---|---|---|---|---|---|---|---|
    | s | w | 2 | . | . | l | o | 9 |  90 a 120cm
    |---|---|---|---|---|---|---|---|
    | d | e | 3 | , | , | k | i | 8 |  60 a 90cm
    |---|---|---|---|---|---|---|---|
    | e | r | 4 | m | m | j | u | 7 |  30 a 60cm
    |---|---|---|---|---|---|---|---|
    | f | t | 5 | n | n | h | y | 6 |  0 a 30cm
    '---'---'---'---'---'---'---'---'
         s0  s1  s2  s3  s4  s5  ---> Sensores mirando hacia arriba


Los problemas son:
1. Al nivel del piso no detecta más de 1.6mts y sobre una mesa detecta hasta 2.4mts.
2. Las medidas dan saltos muy grandes, he pensado en implementar la mediana (estadística) para comparar el último valor con los 10 valores anteriores verificando cuál se repite más... respecto a éste creo que ya me encuentro en un bloqueo mental que no me permite avanzar.

Las preguntas son:
1. Alguien conoce alguna implementación de la mediana estadística en Arduino? he estado buscando pero no veo cómo implementar una
2. Alguien sabe por qué el rango de medición baja tanto? está programado para medir más de 3mts y solo llega a 1.6mts. El código para la distancia es básico y sin librerías para poder controlar cada variable.

Code: [Select]
void loop() {
/* Desde acá controlamos distintas variables con entradas desde el teclado
en el monitor Serial para evaluar el comportamiento de los sensores con diferentes delay y timeout
*/
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    if (incomingByte == 97){  // caracter que corresponde a la 'a'
      Serial.print("delayms: "); delayms = delayms+1;  Serial.println(delayms); }
    else if (incomingByte == 115){  // caracter que corresponde a la 's'
      Serial.print("delayms: "); delayms = delayms-1;  Serial.println(delayms); }
    else if (incomingByte == 113){  // caracter que corresponde a la 'q'
      Serial.print("timeout: "); timeout = timeout+1000;  Serial.println(timeout); }
    else if (incomingByte == 119){  // caracter que corresponde a la 'w'
      Serial.print("timeout: "); timeout = timeout-1000;  Serial.println(timeout); }
  }
  
  //Cálculo de la distancia de cada sensor
  for (int i=0; i<SONAR_NUM; i++){ Sonar(i); }

  //Verificación en el monitor serial
  for (int i=0; i<SONAR_NUM; i++){ Print(i);  }
  Serial.println();
}

void Sonar(int sensorN){
  //Me cercioro de que el resto de sensores se apaguen
  for (int x=0; x<SONAR_NUM; x++){ digitalWrite(trig[x], LOW); }

  int x = sensorN;
  
  digitalWrite(trig[x], LOW);
  delayMicroseconds(2);
  digitalWrite(trig[x], HIGH);   // genera el pulso de triger por 10us
  delayMicroseconds(10);
  digitalWrite(trig[x], LOW);

  ds[x] = pulseIn(echo[x], HIGH, timeout);  // duración del pulso del echo (el timeout puede variar)
  ds[x] = ds[x]/58;  // calcula la distancia en centimetros (duracion/29)/2
  delay(delayms);  
}

void Print(int sensorPrint){
  int x = sensorPrint;
  if (ds[x]>150 || ds[x]<5){  //Imprime solo el guión si está por fuera del rango de 5 a 150cm
    Serial.print(" - ");
  }
  else{
    Serial.print(ds[x]); // Imprime el valor registrado en el rango de 5 a 150
    Serial.print(": ");
  }
}


Gracias!!
DMT

carmeloco

Creo que los sensores se están "escuchando los unos a los otros". No sé hasta que punto, se pueden llegar a interferir entre ellos, pero es una posibilidad que no descartaría. Empieza haciendo pruebas solo con uno a ver que pasa.

Además, esa pared tan cerca de los sensores, también puede influir en el error.

La media de la medición, la puedes hacer con un bucle for.

dmaurot

Hola... muchas gracias... ya hice pruebas de uno en uno y funcionan bien... pero necesito tener los 6 conectados al mismo tiempo... el muro no afecta tanto realmente; con las pruebas que he hecho me ha afectado más el hecho de que los sensores estén en el piso, sin importar que estén al lado del muro. Cuando los pongo sobre una mesa el rango de medición aumenta.

No sé si por hardware pueda crear algún filtro o a través del programa...
DMT

carmeloco

Si por separado funcionan bien, haz una lectura secuencial de uno en uno de los sensores, activando solo uno de ellos cada vez

surbyte

Comparto lo que dice carmeloco, te estas olvidando del ángulo solido que se genera y se agranda generando interferencia en los demas sensores.
Nunca me puse a pensar en el diametro que termina recibiendose luego de 2 mts de ida y vuelta. Pero debe ser tal que interfiera en los sensores vecinos.

Sugerenica 1: Restringir la interferencia posible
Intenta ver si puedes restringir la dispersión del transductor, metiendolo en un tubo pero esto será a costa de perder algo de distancia.
Supongamos que le pusieras un tubo de pvc del diametro del emisor y lo mismo para el receptor.
Solo es una idea.
No se si es posible y si pueda darte una mejora y bloquear un rebote o si este rebote no ingresará rebotando aun mas.

Sugerencia 2: Accionarlos en secuencias tales que no se interfieran.
Otra alternativa es probar en forma simultanea si hay interferencia activandolos en secuencias tales que no interfieran entre si. Algo que deberias probar por tu cuenta.
Yo vería que ocurre si accionas dos sensores contiguos.
Si generan interferencia intento accionarlo alternados.
Tal vez asi no se molesten y recuperes tus 2.51mts máximos.


Sugrencia 3: La que ya dijo carmeloco
La mejor alternativa es que midas 1 a 1.
El poleo de 35 sensores puede ser importante en tiempo para leer todos.

firius2010

#5
Jul 14, 2015, 09:06 pm Last Edit: Jul 16, 2015, 05:06 am by firius2010
Hola dmaurot, como ya te comento carmeloco y surbyte, lo mas probable es que haya interferencia entre uno y otro y pues ya deberias de acatar las recomendaciones que ellos te dan.

Yo escribo con respecto a lo que preguntaste de extrarle la mediana  a los datos, mira en la libreria New_Ping que se diseño para manejar este tipo de sensores tienen una ejemplo hasta con 15 sensores deberias pegarle una miradita y existe un metodo que te hace la medida recibiendo como parametros la cantidad de repeticiones que deseas y retorna la mediana de los datos tomados, ya he trabajado con esta libreria es muy buena ahi te dejo el link si quieres darle una miradita.

http://playground.arduino.cc/Code/NewPing#Methods

dmaurot

Por Hardware logré controlar un poco el ruido conectando una resistencia de 10k con un capacitor 104 a cada trigger y echo...

firius2010, muchas gracias por la recomendación... probé la librería New_Ping pero me daba medidas más aleatorias... por eso decidí implementar el código desde cero para poder tener control completo sobre él... incluso estuve mirando los códigos fuente de la librería pero me toca jugar con los valores manualmente y estar reprogramando la tarjeta. Por ello en el código aparece el código para recibir caracteres por la consola para ir calibrando y observando el comportamiento en tiempo real de los sensores.
Respecto a la mediana, tuve un error conceptual y realmente me sirve más aplicar la moda estadística... con la mediana me da el valor central de un grupo de valores, con la moda  hallo el valor con una mayor frecuencia en la distribución de los datos, pero ésto me cuesta más tiempo de procesamiento y necesito detectar cuando un balón pega en el muro y el tiempo que demora procesando es mayor que el tiempo de rebote del balón en el mismo.

surbyte, probé las alternativas 2 y 3... con la alternativa 2 hice pruebas accionando los sensores en diferentes secuencias (en el orden de conexión, alternando un sensor de por medio, y alternando dos sensores de por medio) pero el resultado en distancia sigue siendo el mismo. Así mismo, con la alternativa 3 probé dos sensores con la distancia que me permite el board y me detectaba un rango de distancia de hasta 3mts. No he probado aún la alternativa de restringir la interferencia físicamente.

carmeloco, en el código hago la validación de apagar todos los sensores antes de enviar el pulso del trigger al que le corresponde; no sé si de pronto te referías a ello o es algo más...

Muchas gracias a todos... seguiré probando a ver qué pasa...

DMT

firius2010

Hola dmaurot, por ahora solo te comento desde mi punto de vista que puede que la moda no sea el mejor estadístico dado que usualmente mediciones repetitivas no son las mismas en ese caso deberías de verificar la frecuencia por intervalos siendo mas eficiente computacionalmente la mediana para ello usarías el método de la burbuja sin embargo eso ya depende de tus necesidades.

Por lo anterior para esta aplicación considero como mejor estadístico la mediana pero ya tu lo decidirás, una preguntica, ¿cuanto has investigado es el tiempo que durara el rebote?

Me parece curioso que con la citada libreria te den datos mas aleatorios, dado que en mi trabajo de grado estoy trabajando con ella y nunca he visto ningún problema en las medidas, con respecto a la opcion que comentaba surbyte de usar tuberias para intentar canalizar mas el haz de sonido y servir de filtro físico, sinceramente considero que traería mas inconvenientes que beneficios.

Estaré pendiente si te puedo servir de algo.

surbyte

Aca te paso unos links que estan en tu misma dirección, tal vez puedas tomar ideas de ellos.
Virtual touch screen con ultrasonicos usa 4. Los maneja 1 a 1 como en tu caso.

Este otro con 15 sensores
Code: [Select]
15 Sensors Example Sketch
// ---------------------------------------------------------------------------
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>

#define SONAR_NUM     15 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).

unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM];         // Where the ping distances are stored.
uint8_t currentSensor = 0;          // Keeps track of which sensor is active.

NewPing sonar[SONAR_NUM] = {     // Sensor object array.
  NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
  NewPing(43, 44, MAX_DISTANCE),
  NewPing(45, 20, MAX_DISTANCE),
  NewPing(21, 22, MAX_DISTANCE),
  NewPing(23, 24, MAX_DISTANCE),
  NewPing(25, 26, MAX_DISTANCE),
  NewPing(27, 28, MAX_DISTANCE),
  NewPing(29, 30, MAX_DISTANCE),
  NewPing(31, 32, MAX_DISTANCE),
  NewPing(34, 33, MAX_DISTANCE),
  NewPing(35, 36, MAX_DISTANCE),
  NewPing(37, 38, MAX_DISTANCE),
  NewPing(39, 40, MAX_DISTANCE),
  NewPing(50, 51, MAX_DISTANCE),
  NewPing(52, 53, MAX_DISTANCE)
};

void setup() {
  Serial.begin(115200);
  pingTimer[0] = millis() + 75;           // First ping starts at 75ms, gives time for the Arduino to chill before starting.
  for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop() {
  for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
    if (millis() >= pingTimer[i]) {         // Is it this sensor's time to ping?
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;  // Set next time this sensor will be pinged.
      if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
      sonar[currentSensor].timer_stop();          // Make sure previous timer is canceled before starting a new ping (insurance).
      currentSensor = i;                          // Sensor being accessed.
      cm[currentSensor] = 0;                      // Make distance zero in case there's no ping echo for this sensor.
      sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
    }
  }
  // Other code that *DOESN'T* analyze ping results can go here.
}

void echoCheck() { // If ping received, set the sensor distance to array.
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
  // The following code would be replaced with your code that does something with the ping results.
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}


Este es el hilo oficial de New Ping Library

Go Up