Estoy haciendo un proyecto que consta de un rover 4x4 que a través de la Pixy2 identifica colores de diferentes objetos y los lleva cada uno a un determinado lugar. Ademas, le he puesto el sonar HC-SR04 para detectar objetos y detenerse si encuentra alguno.
El caso es que el sonar daba lecturas correctas y todo funcionaba de maravilla hasta que metí la Pixy2 para determinar que rutina elegir (para ir a un sitio o a otro).
La subrutina del sonar es la misma de antes y ahora no funciona.
Os adjunto la subrutina del sonar y como utilizo la Pixy2.
HC-SR04
long SONAR( int angelua) // SONARRAREN AZPIPROGRAMA
{
servoMotor.attach(10);
long duracion, distancia ;
servoMotor.write(angelua);
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;
}
PIXY2:
void loop()
{
Serial.println("ITXAROTEN");
pixy.ccc.getBlocks(); // Kamerako datuak irakurri
if(pixy.ccc.numBlocks) // Zerbait detektatu duen jakiteko
{
if(pixy.ccc.blocks[0].m_signature==1)
{
Abat(); // A bat lekura joatea
}
else if(pixy.ccc.blocks[0].m_signature==2)
{
Abi(); // A bi lekura joatea
}
else if(pixy.ccc.blocks[0].m_signature==3)
{
digitalWrite(30,HIGH);
}
}
}
Hola @Liskarra0, bienvenido al foro Arduino en Español.
Te invito a que leas las Normas del foro y luego edites tu post inicial
Si observas, he modificado tu segundo post porque repites lo que se lee en el primero. No lo hagas, eso se considera una falta menor pero falta al fin a las normas.
Manten el hilo limpio de comentarios repetidos.
Solo usa quote o cita para resaltar un párrafo de quien te responda, pero no TODA su respuesta.
Simple no?
Bueno, las cosas no funcionan porque se han agregado tiempos y éstos alternan los comportamientos que conocías.
Igualmente colocas los dos codigos por separado pero no se ve el código de como esta ahora el conjunto.
Usa etiquetas.
No entiendo a que te refieres con añadir tiempos. Como ya comente el programa funcionaba perfectamente cuando en el loop escribía yo que rutina utilizar. Sin embargo al añadir la pixy2 para la elección de la rutina las mediciones del sonar eran erroneas.
Adjunto el código entero para que puedas entender mejor el programa.
Muchas gracias de antemano.
#include <AFMotor.h>
#include <Servo.h>
#include <Pixy2.h>
// 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); // Rueda delantera izquierda
AF_DCMotor auresk(3,MOTOR34_64KHZ); // Rueda delantera derecha
AF_DCMotor atzesk(1,MOTOR12_64KHZ); // Rueda trasera derecha
AF_DCMotor atzezk(2,MOTOR12_64KHZ); // Rueda trasera izquierda
Servo servoMotor;
Pixy2 pixy;
void setup()
{
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(led, OUTPUT);
pinMode(52,OUTPUT);
attachInterrupt(2, interrupcion, FALLING);
pixy.init(); // Inicializacion de la camara Pixy2
}
void loop()
{
Serial.println("ITXAROTEN");
pixy.ccc.getBlocks(); // Recoger datos de la camara
if(pixy.ccc.numBlocks) // Para comprobar si ha detectado algo
{
if(pixy.ccc.blocks[0].m_signature==1) // Color uno detectado
{
Abat(); // Ir a A1
}
else if(pixy.ccc.blocks[0].m_signature==2) // Color dos detectado
{
Abi(); // Ir a A2
}
else if(pixy.ccc.blocks[0].m_signature==3) // Color. 3 detectado
{
digitalWrite(30,HIGH);
}
}
}
void interrupcion()
{
encoderPos++;
}
void JATORRItikAP()
{
int angelua; //angulo del servo
int aldaketa; // variable para cambiar el angulo
double minimoa; //distancia mínima para colision
// establecer velocidades
atzezk.setSpeed(100);
atzesk.setSpeed(100);
aurezk.setSpeed(100);
auresk.setSpeed(100);
long distancia;
distancia=0;
encoderPos=0;
angelua=90;
aldaketa=-5;
delay(1000);
do
{
//moverse
atzezk.run(FORWARD); // Hacia delante
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
//Serial.println(encoderPos);
distancia=SONAR(angelua);
Serial.print("Neurtuta: ");
Serial.print(distancia);
minimoa=kalminimoa(angelua);
Serial.print(" DMIN: ");
Serial.println(minimoa);
if(distancia<minimoa)
{
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
do
{
distancia=SONAR(angelua);
Serial.print("ARRISKUA!");
Serial.print(" DMIN: ");
Serial.print(minimoa);
Serial.print(" REALA: ");
Serial.println(distancia);
}while(distancia<minimoa);
atzezk.run(FORWARD); // hacia delante
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
}
angelua=angelua+aldaketa; //actualizar variable del angulo
if(angelua==155)
{
aldaketa=-5;
angelua=145;
}
if(angelua==40)
{
aldaketa=5;
angelua=40;
}
}while(encoderPos<=405);
//Parar
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
void APtikA1()
{
int angelua;
int aldaketa;
long distancia;
double minimoa;
minimoa=0;
distancia=0;
angelua=90;
aldaketa=-5;
encoderPos=0;
// Abiadurak ezarri
atzezk.setSpeed(100);
atzesk.setSpeed(100);
aurezk.setSpeed(100);
auresk.setSpeed(100);
delay(1000);
do
{
//Mugitzen hasi
atzezk.run(FORWARD);
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
distancia=SONAR(angelua);
minimoa=kalminimoa(angelua);
if(distancia<minimoa)
{
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
do
{
distancia=SONAR(angelua);
}while(distancia<minimoa);
atzezk.run(FORWARD); // Aurrerantza
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
}
angelua=angelua+aldaketa;
}while(encoderPos<=405);
//Gelditu
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
void APtikA2()
{
int angelua;
int aldaketa;
long distancia;
double minimoa;
minimoa=0;
distancia=0;
angelua=90;
aldaketa=-5;
encoderPos=0;
// Abiadurak ezarri
atzezk.setSpeed(100);
atzesk.setSpeed(100);
aurezk.setSpeed(100);
auresk.setSpeed(100);
delay(1000);
do
{
//Mugitzen hasi
atzezk.run(FORWARD); // Aurrerantza
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
distancia=SONAR(angelua);
minimoa=kalminimoa(angelua);
if(distancia<minimoa)
{
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
do
{
distancia=SONAR(angelua);
}while(distancia<minimoa);
atzezk.run(FORWARD); // Aurrerantza
atzesk.run(FORWARD);
auresk.run(FORWARD);
aurezk.run(FORWARD);
}
angelua=angelua+aldaketa;
}while(encoderPos<=560);
//Gelditu
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
void Abat()
{
JATORRItikAP();
BIRAKETA();
APtikA1();
delay(5000);
KONTRABIRAKETA();
APtikA1();
BIRAKETA2();
JATORRItikAP();
KONTRABIRAKETA();
}
void Abi()
{
JATORRItikAP();
}
void KONTRABIRAKETA() // Para girar 360° el Rover
{
//Abiadurak ezarri
atzezk.setSpeed(120);
atzesk.setSpeed(120);
auresk.setSpeed(120);
aurezk.setSpeed(120);
encoderPos=0;
delay(1000);
do{
//Mugitzen hasi
atzezk.run(FORWARD);
aurezk.run(FORWARD);
atzesk.run(BACKWARD);
auresk.run(BACKWARD);
Serial.print(encoderPos);
}while(encoderPos<=135);
//Gelditu
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
void BIRAKETA2() // Para girar 90 grados el. Rover
{
//Abiadurak ezarri
atzezk.setSpeed(120);
atzesk.setSpeed(120);
auresk.setSpeed(120);
aurezk.setSpeed(120);
encoderPos=0;
delay(1000);
do{
//Mugitzen hasi
atzezk.run(FORWARD);
aurezk.run(FORWARD);
atzesk.run(BACKWARD);
auresk.run(BACKWARD);
Serial.print(encoderPos);
}while(encoderPos<=60);
//Gelditu
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
void BIRAKETA() // Para girar 90°. Rover
{
//Abiadurak ezarri
atzezk.setSpeed(120);
atzesk.setSpeed(120);
auresk.setSpeed(120);
aurezk.setSpeed(120);
encoderPos=0;
delay(1000);
do{
//Mugitzen hasi
atzezk.run(BACKWARD);
aurezk.run(BACKWARD);
atzesk.run(FORWARD);
auresk.run(FORWARD);
Serial.print(encoderPos);
}while(encoderPos<=60);
//Gelditu
atzezk.run(RELEASE);
atzesk.run(RELEASE);
auresk.run(RELEASE);
aurezk.run(RELEASE);
}
long SONAR( int angelua) // Subrutina del sonar
{
servoMotor.attach(10);
long duracion, distancia ;
servoMotor.write(angelua);
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;
}
float kalminimoa(int angelua) // subrutina para calcular distancia minima de colision
{
float radianetan;
float minimo;
radianetan=0;
minimo=0;
if(angelua<90)
{
radianetan=angelua*(2*PI/360); // angulos a radianes
minimo=(7.5/cos(radianetan))+0.5; // Distancia minima kalkuloa + 0.5 margen de seguridad
}
if(angelua>90)
{
radianetan=angelua*(2*PI/360);
minimo=(-7.5/cos(radianetan))+0.5;
}
if (angelua==90)
{
minimo=25; // 90º cos()-a error,
}
// limitar la distancia mínima
if (minimo>25)
{
minimo=25;
}
return minimo;
}
En un código donde usas control de motores y dispositivos que deben captar "algo" para enviar una orden hay que hacer las cosas con mucha prolijidad aunque vaya a un sitio de internet y copie un código ese código no me asegura que está todo lo depurado que se requiere.
Estoy escribiendo sin haberlo leído, cosa que haré ahora.
Me pongo a ver el programa y encuentro cosas primero en un idioma que no entiendo aunque traduje 2 o 3 sentencias no vale la pena el esfuerzo. Hazlo tu.
Bueno, evidentemente el código tiene muchos delay() o sea tiempos perdidos, y tiene loops como ese
do {} while(encoderPos<=405);
y me quedo corto...
me encuentro que las indicaciones del Pixy conducen a cosas como esta
void Abat()
{
JATORRItikAP();
BIRAKETA();
APtikA1();
delay(5000); // Itxaroteko, gero kamara bidez objeturik ez dagoenenan gertatuko da.
KONTRABIRAKETA();
APtikA1();
BIRAKETA2();
JATORRItikAP();
KONTRABIRAKETA();
}
donde no solo cada uno tiene loop con delays de 1000 mseg sino que en el medio tienes otro delay() de 5 segundos. Todo estos son los tiempos a los que me refería.
Si no lo sabías delay() es una instrucción que DESTRUYE un programa como el tuyo donde esperas la acción de otros sensores Pixy, ultrasónico, etc.
Delay() solo sirve cuando la tarea es secuencial al punto que no importa si me detengo o no a hacer algo.
Entiendo lo que dices, pero el programa entra sin ningún problema a la subrutina del sonar donde hace el calculo. Ahi no hay delays, mas que los de la salida del Trigger. Una vez ahi dentro los demás delay tienen repercusión?
En vez de usar un delay() recomendarias el uso de millis()??
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.
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.
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;
}