Lectura de sonar HC-SR04

Me he mirado por encima lo que es pixy2 cam.

Sin haber analizado la programación del pixy, diría que podría ser un conflicto con los timer que usa el pulseIn().

Tiene sentido, porque el dato recogido de esa función es 0. Y no deberia. Como se puede contar el tiempo de otra forma?

timers de pulsein? Que yo sepa usa millis() entre flancos o estados de un pin o peor ciclos de reloj de instrucciones determinadas.

Este es el pulsein del IDE 1.0 ha pasado mucha agua bajo el puente pero todos los comentarios indican que trabaja mas o menos igual, no usa timers ni millis() como yo suponía

/*
  wiring_pulse.c - pulseIn() function
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2005-2006 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/

#include "wiring_private.h"
#include "pins_arduino.h"

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure.  Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
 // cache the port and bit of the pin in order to speed up the
 // pulse width measuring loop and achieve finer resolution.  calling
 // digitalRead() instead yields much coarser resolution.
 uint8_t bit = digitalPinToBitMask(pin);
 uint8_t port = digitalPinToPort(pin);
 uint8_t stateMask = (state ? bit : 0);
 unsigned long width = 0; // keep initialization out of time critical area

 // convert the timeout from microseconds to a number of times through
 // the initial loop; it takes 16 clock cycles per iteration.
 unsigned long numloops = 0;
 unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;

 // wait for any previous pulse to end
 while ((*portInputRegister(port) & bit) == stateMask)
 if (numloops++ == maxloops)
 return 0;

 // wait for the pulse to start
 while ((*portInputRegister(port) & bit) != stateMask)
 if (numloops++ == maxloops)
 return 0;

 // wait for the pulse to stop
 while ((*portInputRegister(port) & bit) == stateMask) {
 if (numloops++ == maxloops)
 return 0;
 width++;
 }

 // convert the reading to microseconds. The loop has been determined
 // to be 20 clock cycles long and have about 16 clocks between the edge
 // and the start of the loop. There will be some error introduced by
 // the interrupt handlers.
 return clockCyclesToMicroseconds(width * 21 + 16);
}

O sea es algo poco preciso. Usas micros() y tendras mejor precisión ni hablar con Timers.

Entonces me recomiendas quitar todos los delay() del codigo como digiste antes verdad?

Con el tema del pulsein? Recomiendas quitarlo y poner otra opcion?

Muchas gracias

Tienes para mi mucho trabajo Empieza con pixy que ya esta y no tienes mucha opción. Okay pixy llama a 1 de 3 rutinas

Yo comencé con tu código y luego vi que es para un buen rato y lo dejé

esto hice

void loop() {
  Serial.println("ITXAROTEN");
  pixy.ccc.getBlocks();     //Lee los datos de la cámara
  
  if (pixy.ccc.numBlocks) { // Averigua si se ha detectado algo
      while(pixy.ccc.blocks[0].m_signature) {
          case 1: Abat();  // Ir a un lugar
                  break;
          case 2: Abi();   Ir a dos lugares
                  break;
          case 3: digitalWrite(30,HIGH);
                  break;  
      }
  }
}

Ahora hay que trabajar con Abat() y Abi()

Haciendolos mas veloces.. cómo, usando millis() y creando máquina de estados.

Tu crees que haciendo Abat y Abi mas veloces la medicion del sonar ya no sera nula?

Porque antes con el mismo programa pero eligiendo el sitio al que ir a mano, sin la cámara, funcionaba bien, teniendo en cuenta todos los delays.

Yo creia que era mas la relación entre la Pixy2 y el sonar por eso pensaba que el tema del pulsein tendría sentido. Ya que la duración recibida del echo es 0.

Tu crees que haciendo Abat y Abi mas veloces la medicion del sonar ya no sera nula?

No claro que no. Una cosa no tiene que ver con la otra. Yo me alarmo por el código en general, no por la rutina del ultrasónico.

A ver si podemos trabajar de un modo sistemático, de lo contrario desde acá se hace dificil aconsejarte al menos para mi.

En procedimiento o rutina void JATORRItikAP() tienes este llamado al sonar.

distancia = SONAR(angelua);
  Serial.print("Neurtuta: ");
  Serial.print(distancia);

Funciona?

Establece por favor en cada caso si lo hace o no.

Como has tomado códigos de uno y otro lado, pixy descartemos porque sabemos que esta bien pero el otro código en lo personal me resulta complicado de seguir.

Entonces empecemos de nuevo si me permites la sugerencia porque con este código yo no voy a aconsejarte porque desde el comienzo al no poder entender o tener que traducir cada línea (tarea que te corresponde a ti si es que lo entiendes) prefiero comenzar por otro lado.

Tenemos un ROVER que tiene una camara pixy que detecta objetos, un sonar que le dirá cuando deterse luego que un objeto es identificado. Y claro el movimiento adelante, atras, izquierda, derecha y stop. Esto ultimo esta hecho muchas veces y como ahi es donde veo estan los problemas es que prefiero rehacer las cosas con ALGO entendible.

Espero tu comentario.

Si estas de acuerdo, te propongo que hagas un detalle aunque se lee en el código de como son las conexiones a tus drivers. Solo para que el novato que lea esto lo entienda mejor. Y de paso lo explicas un poco.

La llamada al sonar esta bien, entra en su subrutina. El problema es que da lectura 0. En el momento de realizar duracion=pulseIn ese resultado es 0. La variable duración da 0. Pero las llamadas y todos los demas movimientos que reaiza con los motores funcionan bien.

El único problema es que al conectar la camara Pixy2 la lectura obtenida desde el pulseIn es 0. Y por eso luego al compararlo con la distancia mínima se para. Porque cree que hay un objeto.

He estado indagando por internet y creo que se podria probar a crear una funcion que haga lo mismo que pulseIn mediante digitalWrite y micro(). Como lo ves? Podria llegar a funcionar?

Perdona por mi respuesta pero parece que no lees lo que he escrito antes.

O sea es algo poco preciso. Usas micros() y tendras mejor precisión ni hablar con Timers.

Tanto ELEspanol como yo te dijismos como hacerlo. Ahora. Solo estas reinventando la rueda. Existen librerías para manejar el sensor que obviamente desconoces.

NewPing es la librería mas usada pero hay otras.

Obviamente leo lo que escribís. ElEspañol me hizo pensar en que el problema esta ahi. Pero solo preguntaba que si se podia sustituirlo por un digitalwrite.

Por otro lado, si que conocia newping pero preferí hacerlo sin librerías. Es mas preciso hacerlo con la NewPing y crees que asi funcionaria?

Porque no te autorespondes probando con NewPing y vemos que resulta?

Porqué en la rutina del sonar mueves el servo?

long SONAR( int angelua) // Subrutina del sonar
{ 

   servoMotor.attach(10);         // <== Porque lo defines a cada momento?
   long duracion, distancia ;
   
   servoMotor.write(angelua);   // <== esto no debería estar acá y lo anterior menos
   delay(50);
   digitalWrite(52,HIGH);
   digitalWrite(trigPin, LOW);        // Nos aseguramos de que el trigger está desactivado
   delayMicroseconds(2);              // Para asegurarnos de que el trigger esta LOW
   digitalWrite(trigPin, HIGH);       // Activamos el pulso de salida
   delayMicroseconds(10);             // Esperamos 10µs. El pulso sigue active este tiempo
   digitalWrite(trigPin, LOW);        // Cortamos el pulso y a esperar el echo
   duracion = pulseIn(echoPin, HIGH) ;
   distancia = duracion / 2 / 29.1  ;
   //Serial.println(String(distancia) + " cm.") ;

   return distancia;
}

Observa los comentarios que hago para el servo.

Yo también uso newping.h, que yo sepa no bloquea o al menos tiene un timeout muy corto, porque puedes indicar una distancia máxima.

Vale, mañana probare a usar el NewPing. No lo he hecho antes porque hasta mañana no tengo acceso al material. Por eso preguntaba...

Lo del servo lo hago cada vez que entra para que vaya al angulo deseado que se quiere analizar la distancia. Cierto es que la definición no deberia estar ahi y que lo otro se puede poner en otro sitio.

Ya lo tengo casi hecho. Un momento y te lo paso.

Pregunta:

AF_DCMotor traseraDerecha(    1,MOTOR12_64KHZ); // Rueda trasera derecha

Significa que esta conectado al pin 1? Si es asi busca otro pin porque el 1 esta afectado al monitor Serie y por eso tal vez falle el código.

Como creo que ese era el problema te dejo el código hasta donde llegué. Espero funcione. Debes instalar NewPing desde el Gestor de librerías.

#include 
#include 
#include 
#include    // https://bitbucket.org/teckel12/arduino-new-ping/downloads/

#define led          46
#define TRIGGER_PIN  50  // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN     48  // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
   
// PI-ren ezarpena
#define PI 3.141592
     
int encoderPos=0;
AF_DCMotor delanteraIzquierda(4,MOTOR34_64KHZ); // Rueda delantera izquierda
AF_DCMotor delanteraDerecha(  3,MOTOR34_64KHZ); // Rueda delantera derecha
AF_DCMotor traseraDerecha(    1,MOTOR12_64KHZ); // Rueda trasera derecha
AF_DCMotor traseraIzquierda(  2,MOTOR12_64KHZ); // Rueda trasera izquierda
Servo servoMotor;
Pixy2 pixy;

void setup() {
  Serial.begin(9600);

  pinMode(led, OUTPUT);
  pinMode(52,OUTPUT);
  attachInterrupt(2, interrupcion, FALLING);
  pixy.init();                    // Inicializacion de la camara Pixy2
  servoMotor.attach(10);          // aca defino al servo.
}

void loop() {
  Serial.println("ITXAROTEN");
  pixy.ccc.getBlocks();     //Lee los datos de la cámara

  if (pixy.ccc.numBlocks) { // Averigua si se ha detectado algo
      while(pixy.ccc.blocks[0].m_signature) {
          case 1: Abat();  // Ir a un lugar
                  break;
          case 2: Abi();   Ir a dos lugares
                  break;
          case 3: digitalWrite(30,HIGH);
                  break; 
      }
  }
}

void interrupcion() {
  encoderPos++;
}

void JATORRItikAP() {

  int angulo;     // angulo del servo
  int aldaketa;   // variable para cambiar el angulo
  double minimoa; // distancia mínima para colision

  // establecer velocidades
  fijoVelocidades(100);

  long distancia;
  distancia=0;
  encoderPos=0;
  angulo=90;
  aldaketa=-5;
  delay(1000);
  
  do   {
      //moverse
      muevoRuedas(FORWARD);
      // Serial.println(encoderPos);
      distancia = SONAR(angulo);
      Serial.print("Medido: ");
      Serial.print(distancia);
      minimoa = distanciaMinimaColision(angulo);
      Serial.print(" DMIN: ");
      Serial.println(minimoa);

      if (distancia < minimoa) {
          muevoRuedas(RELEASE);
          do {
              distancia = SONAR(angulo);
              Serial.print("RIESGO!");
              Serial.print(" DMIN: ");
              Serial.print(minimoa);
              Serial.print(" VERDADERO: ");
              Serial.println(distancia);
          } while(distancia 90) {
      radianetan = angulo*(2*PI/360);
      minimo=(-7.5/cos(radianetan))+0.5;
  }
  if (angulo == 90) {
      minimo=25; // 90º cos()-a error,
  }

  // limitar la distancia mínima
  if (minimo>25) {
      minimo=25;
  }

  return minimo;
}

Posicionar el servo antes de medir distancia esta mal hecho.

Primero el delay(50) a lo mejor no es suficiente para llegar a la posición correcta. Y el delay por si esta mal. Nunca uses delay, solo existen pocas excepciones. Tu caso es ninguna de ellas.

Hay una librería que se llama mobatools.h, esta muchísimo mejor que la original servos.h En esta puedes enterarte si el servo aún se mueve. Y hacer la medición de distancia cuando ya no se mueve el servo.

surbyte: AF_DCMotor traseraDerecha(    1,MOTOR12_64KHZ); // Rueda trasera derecha

Significa que esta conectado al pin 1? Si es asi busca otro pin porque el 1 esta afectado al monitor Serie y por eso tal vez falle el código.

Ese 1 significa que ese motor esta conectado a uno de los 4 conexiones que tiene el adafruit motorshield. Por eso cada rueda tiene un número del 1 al 4

ElEspanol: Posicionar el servo antes de medir distancia esta mal hecho.

Primero el delay(50) a lo mejor no es suficiente para llegar a la posición correcta. Y el delay por si esta mal. Nunca uses delay, solo existen pocas excepciones. Tu caso es ninguna de ellas.

Hay una librería que se llama mobatools.h, esta muchísimo mejor que la original servos.h En esta puedes enterarte si el servo aún se mueve. Y hacer la medición de distancia cuando ya no se mueve el servo.

Okey, gracias. Intentare probar esto que me dices. Me parece un punto muy importante a tener en cuenta.

Igualmente no tiene nada que ver el uso de Servos con que tu ultrasonico no reporte la lectura.

Buenas,

He probado a usar la libreria NewPing para la lectura del sonar, y al igual que pasaba antes, sin camara todo va genial, pero con ella la lectura del sonar es 0.

He depurado el codigo como me lo habeis recomendado. A ver si asi podeis ayudarme a saber que pasa.

#include 
#include 
#include 
#include 


// SONARRAREN PINAK
     #define trigPin 50 // Arduino pin tied to trigger pin on the ultrasonic sensor.     
     #define echoPin 48    // Arduino pin tied to echo pin on the ultrasonic sensor. 
     #define led 46
    
// PI-ren ezarpena
     #define PI 3.1415926535897932384626433832795
      
int encoderPos=0;
AF_DCMotor aurezk(4,MOTOR34_64KHZ); // Aurreko ezkerreko gurpila
AF_DCMotor auresk(3,MOTOR34_64KHZ); // Aurreko eskumako gurpila
AF_DCMotor atzesk(1,MOTOR12_64KHZ); // Atzeko ezkerreko gurpila
AF_DCMotor atzezk(2,MOTOR12_64KHZ); // Atzeko eskumako gurpila
Servo servoMotor;
NewPing sonar(trigPin,echoPin,500);
Pixy2 pixy; // Pixy objetuaren deklarazioa



void setup() 
{
           Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results.
           pinMode(trigPin, OUTPUT);
           pinMode(echoPin, INPUT); 
           pinMode(led, OUTPUT);
           pinMode(52,OUTPUT);
           digitalWrite(52,HIGH);
           attachInterrupt(2, interrupcion, FALLING);
           servoMotor.attach(10);      
           pixy.init(); // Kamera hasierarazi  
}

void loop() 
{
  Serial.println("ITXAROTEN");
  pixy.ccc.getBlocks(); //Leer datos de la cámara
  if(pixy.ccc.numBlocks) // Chequear si detecta algún objeto
  {
     
    if(pixy.ccc.blocks[0].m_signature==1)
    {
      Abat(); // Ir a A1
    }
    else if(pixy.ccc.blocks[0].m_signature==2)
    {
      Abi();   // Ir a A2
    }
    else if(pixy.ccc.blocks[0].m_signature==3)
    {
      digitalWrite(30,HIGH);
    }
    
  }
}


 void interrupcion() // Interrupcion del encoder para saber cuanta distancia anda
 {
  encoderPos++;
 }


void JATORRItikAP() // Subrutina para ir a A'
{
  
int angelua; // angulo
int aldaketa; // cambio
double minimoa; // distancia minima
long distancia; // distancia medida

abiadurak(100); // Poner velocidades
distancia=0;
encoderPos=0;
angelua=90;
aldaketa=-5;

itxaron(1000); // Esperar 1000 milisegundos

do
{
aurrerantza(); // Ir hacia delante

distancia=SONAR(angelua); // Medir distancia mediante sonar
minimoa=kalminimoa(angelua); // Calcular distancia minima para colision

Serial.print("Angelua: ");
Serial.print(angelua);
Serial.print(" Distantzia minimoa: ");
Serial.print(minimoa);
Serial.print(" Distantzia erreala: ");
Serial.println(distancia);

  if(distancia90)
{
radianetan=angelua*(2*PI/360); 
minimo=(-7.5/cos(radianetan))+1; 

}
if (angelua==90)
{
  minimo=25; // Cos de 90º es 0 por eso se establece a mano
}

// Si la distancia minima da muy alta se limita a 25
if (minimo>25)
{
  minimo=25;
}

  return minimo; //Distantzia minimoa itzuli.
}


void abiadurak(int v) //Subrutina para establecer velocidades
{
  atzezk.setSpeed(v); 
  atzesk.setSpeed(v);
  aurezk.setSpeed(v);
  auresk.setSpeed(v);
}

void gelditu() //Subrutina para parar
{
  atzezk.run(RELEASE);
  atzesk.run(RELEASE);
  auresk.run(RELEASE);
  aurezk.run(RELEASE);
}

void aurrerantza() //Subrutina para avanzar
{
  atzezk.run(FORWARD); // Aurrerantza
  atzesk.run(FORWARD);
  auresk.run(FORWARD);
  aurezk.run(FORWARD);
}

void itxaron(int t) // Subrutina para esperar, simular un delay()
{
  unsigned long A=0;
  unsigned long B=0;
  B=millis();
  do{
    A=millis();
  }while(A

Gracias, porque eso quiere decir que todo el trabajo que me tomé rehaciendo tu código y hasta traduciendolo no sirvió de nada ni para que lo leas.

Vaya que desilusión.