Seguidor de línea con Arduino y sensores IR

Hola gente del foro...

Estoy construyendo un seguidor de linea basado en Arduino Nano v3.0, sensores hechos por mi basados en el QTR-8A los cuales dispuse de 8 emisores IR, 8 receptores IR y 8 bc548b, el driver de los motores comenzo siendo un puente h pero tuve que eliminarlo por las fallas que generaba, ahora dispongo simplemente de dos transistores.

El codigo que uso es el siguiente:






Código:
#include <QTRSensors.h>

#define STANDBY          9  // pin STANDBY del Motor Driver
#define MOTORLEFT_DIR_A  7  // pin 1 de dirección del Motor Izquierdo
#define MOTORLEFT_DIR_B  8  // pin 2 de dirección del Motor Izquierdo
#define MOTORLEFT_PWM    6  // pin PWM del Motor Izquierdo
#define MOTORRIGHT_DIR_A  4  // pin 1 de dirección del Motor Derecho
#define MOTORRIGHT_DIR_B  3  // pin 2 de dirección del Motor Derecho
#define MOTORRIGHT_PWM    10  // pin PWM del Motor Derecho

#define NUM_SENSORS             8    // número de sensores usados


// cant. lecturas analógicas que serán leídas por sensor

#define NUM_SAMPLES_PER_SENSOR  4    
#define EMITTER_PIN             11   // pin emisor del QTR

#define ENCODERPIN 12               // pin del encoder
#define LEDPIN     13                // número del pin de test
#define BUTTONPIN  2                 // boton externo

// función para pulsar el botón y esperar que deje de pulsarlo
#define esperarBoton() while(!digitalRead(BUTTONPIN)); while(digitalRead(BUTTONPIN))

// estructura para los sensores
QTRSensorsAnalog qtra((unsigned char[]) 
  { A7, A6, A5, A4, A3, A2, A1, A0 }
, NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN);

// arreglo para almacenamiento de valores por sensor
unsigned int sensorValues[NUM_SENSORS];

// función Velocidad Motor Izquierdo
void setMotorLeft(int value)
{
  if ( value >= 0 )
  {
    // si valor positivo vamos hacia adelante
    digitalWrite(MOTORRIGHT_DIR_A,HIGH);
    digitalWrite(MOTORRIGHT_DIR_B,LOW);
  }
  else
  {
    // si valor negativo vamos hacia atras
    digitalWrite(MOTORRIGHT_DIR_A,LOW);
    digitalWrite(MOTORRIGHT_DIR_B,HIGH);
    value *= -1;
  }

  // Setea Velocidad
  analogWrite(MOTORRIGHT_PWM,value);
}

// función Velocidad Motor Derecho
void setMotorRight(int value)
{  
  if ( value >= 0 )
  {
    // si valor positivo vamos hacia adelante
    digitalWrite(MOTORLEFT_DIR_A,HIGH);
    digitalWrite(MOTORLEFT_DIR_B,LOW);
  }
  else
  {
    // si valor negativo vamos hacia atras
    digitalWrite(MOTORLEFT_DIR_A,LOW);
    digitalWrite(MOTORLEFT_DIR_B,HIGH);
    value *= -1;
  }    

  // Setea Velocidad
  analogWrite(MOTORLEFT_PWM,value);
}

// función Velocidad Motores
void setMotors(int left, int right)
{
  digitalWrite(STANDBY,HIGH);
  setMotorLeft(left);
  setMotorRight(right);
}

// función Freno en Motores
void setBrake(boolean left, boolean right, int value)
{
  // pin STAND BY
  digitalWrite(STANDBY,HIGH);

  if ( left )
  {
    // pines LEFT motor
    digitalWrite(MOTORRIGHT_DIR_A,HIGH);
    digitalWrite(MOTORRIGHT_DIR_B,HIGH);
    analogWrite (MOTORRIGHT_PWM, value);
  }

  if ( right )
  {
    // pines RIGHT motor
    digitalWrite(MOTORLEFT_DIR_A,HIGH);
    digitalWrite(MOTORLEFT_DIR_B,HIGH);
    analogWrite (MOTORLEFT_PWM, value);
  }
}

void setup()
{
  // inicializar pines de salida
  pinMode(LEDPIN          ,OUTPUT);
  pinMode(STANDBY         ,OUTPUT);
  pinMode(MOTORRIGHT_DIR_A ,OUTPUT);
  pinMode(MOTORRIGHT_DIR_B ,OUTPUT);
  pinMode(MOTORRIGHT_PWM   ,OUTPUT);
  pinMode(MOTORLEFT_DIR_A ,OUTPUT);
  pinMode(MOTORLEFT_DIR_B ,OUTPUT);
  pinMode(MOTORLEFT_PWM   ,OUTPUT);
  pinMode(BUTTONPIN       ,INPUT);

  // presiona botón para activar calibración
  while ( !digitalRead(BUTTONPIN) );

  // calibrar sensores QTRA, titilando LED como guía
  for ( int i=0; i<70; i++)
  {
    digitalWrite(LEDPIN, HIGH); delay(20);
    qtra.calibrate();
    digitalWrite(LEDPIN, LOW);  delay(20);
  }

  // apagar LED
  digitalWrite(LEDPIN, LOW);

  // presionar botón para correr el robot
  while ( !digitalRead(BUTTONPIN) );

  // esperar 5 segundos 
  delay(1000);
  
  // mover el robot suave para ganar inercia
  setMotors(90, 90);
  
  // durante 0.3 segundos
  delay(300);
}

unsigned int position = 0; // posición actual de los sensores
int derivative = 0;        // derivada
int proportional = 0;      // proporcional
int power_difference = 0;  // velocidad diferencial

// Máxima velocidad en el poder diferencial
int max = 120;

// Ultima Proporcional
int last_proportional;

// Constantes Proporcional y Derivativa
float KP = 0.17;
float KD = 2.2;

// Constante para Rango de Freno (Range Brake)
#define RANGEBRAKE 3500

void loop()
{   
  // Obtiene la posición de la linea
  // Aquí no estamos interesados ​​en los valores 
  // individuales de cada sensor
  position = qtra.readLine(sensorValues);

  // El término proporcional debe ser 0 cuando estamos en línea
  proportional = ((int)position) - 3500;

  // Si entra en el rango de freno, aplicarlo en la 
  // direccion de la curva
  if ( proportional <= -RANGEBRAKE )
  {
    setMotorRight(0);
    setBrake(true,false,255);
    delay(1);
  }
  else if ( proportional >= RANGEBRAKE )
  {
    setMotorLeft(0);
    setBrake(false,true,255);
    delay(1);
  }

  // Calcula el término derivativo (cambio) de la posición
  derivative = proportional - last_proportional;

  // Recordando la última posición
  last_proportional = proportional;

  // Calcula la diferencia entre la potencia de los dos motores [ m1 - m2 ]. 
  // Si es un número positivo, el robot gira a la [ derecha ] 
  // Si es un número negativo, el robot gira a la [ izquierda ]
  //  y la magnitud del número determina el ángulo de giro.
  int power_difference = ( proportional * KP ) + ( derivative * KD );

  // Si velocidad diferencial es mayor a la posible tanto positiva como negativa,
  // asignar la máxima permitida
  if ( power_difference > max ) power_difference = max; 
  else if ( power_difference < -max ) power_difference = -max;

  // Asignar velocidad calculada en el poder diferencial de los motores
  ( power_difference < 0 ) ? 
    setMotors(max+power_difference, max) : setMotors(max, max-power_difference);
}





Al iniciar las pruebas del robot mantengo las ruedas elevadas para probar si el programa funciona al mover los sensores por la linea y lo hace correctamente, una deja de girar o baja su velocidad casi al minimo mientras que la otra gira al maximo.
El problema surge cuando dejo el robot apoyado sobre la linea... Este no varia la velocidad de las ruedas y acelera a la maxima velocidad en linea recta sin girar ni 1°...

Descarte la idea de que puede ser por no disponer de un puente h haciendo que una de las dos ruedas no pueda frenar y no se de el giro del robot por el echo de que si lo hago en el aire la rueda se detiene casi de inmediato...

Alguno sugiere algun problema que pueda tener? Muchas gracias
 
Hola gente del foro...

Estoy construyendo un seguidor de linea basado en Arduino Nano v3.0, . . .

. . . Al iniciar las pruebas del robot mantengo las ruedas elevadas para probar si el programa funciona al mover los sensores por la linea y lo hace correctamente, una deja de girar o baja su velocidad casi al minimo mientras que la otra gira al maximo.
El problema surge cuando dejo el robot apoyado sobre la linea... Este no varia la velocidad de las ruedas y acelera a la maxima velocidad en linea recta sin girar ni 1°. . . .

Esa falla parece mas problema de enfoque de sensores que de programa. :unsure:
 
Hols buen día si fuese problema de código, no andaria bien boca arriba, cuando lo apoyas a una superficie, este necesita mas fuerza de arrastre, conclusión problema en los Driver o poca tracción torque en los motorreductores, eso te pasa por no usar un Driver adecuado de buena potencia.

MK.
 
Gracias por responder...

Fogonazo:

Probe creando un programa con variables BYTE para cada sensor y que lo muestre en el monitor serial. No crea una diferencia de 255 cuando esta en la parte blanca y 0 cuando esta en la negra pero se puede identificar la diferencia grande. Esta prueba la hice con el robot apoyado para dar directamente el valor en funcionamiento. En cuestiones de construccion, puse el emisor IR perpendicular a la placa y a 45° el receptor IR porque lei que era mucho mejor la lectura que si se disponian en paralelo.

No descarto la idea que pueda ser eso pero me sorprenderia mucho que lo sea, dado que cuando hago la medición funcionan bien.


Makitronica:

los motores que utilizo consumen 300mA a 5v con carga, te aseguro que torque no le falta ya que el robot en si es liviano y los motores tienen potencia suficiente. Los drivers con transistores soportan 1A.
El motorreductor lo realice con dos ruedas que tenia un auto RC que tenian un engranaje en la rueda adherido y otro engranaje en el eje. La reduccion calculada a 1000rpm es de 3:1. Con las pruebas en el aire parece que la reduccion es mas que suficiente. No descarto ese problema pero al igual que con el comentario de fogonazo resultaria raro que lo sea ya que funciona perfecto en el aire.
 
Hola, gente. Reabro el tema por algunas dudas que me surgen con el código.

Estoy teniendo los mismos problemas que antes de que no gire en las curvas, para eso creé un puente H, el cual ''detendría'' uno de los motores para que el otro haga girar el robot. Salto de línea.
Para hacerlo funcionar, tardé mucho en hacer funcionar el circuito y por eso no agregué nada más en este tema...

Las pruebas las realicé con las ruedas en el aire y haciendo que el robot lea los sensores que están sobre una línea y dispuse de LEDs en las salidas del arduino (entradas del puente H) que determinan el sentido de giro. Salto de línea.
Esto lo hice para que al llegar a una posible curva el LED que indica esa parada de motor (giro inverso del motor) se encienda, pero no se detiene nunca, solamente gira en un sentido.

Otra de las dudas, es que al girar hacia la derecha el robot tendría que girar con más velocidad la rueda izquierda y la derecha detenerse para que vuelva a la línea y en vez de detenerse gira más lento.
Cosa que no hace al apoyar las ruedas en el piso, y al girar el robot a la izquierda, la rueda derecha baja tanto su velocidad que queda detenida, pero no de un golpe como tendría que ser con el puente H.

Al dejar el robot en la pista que creé para probar el robot, primero presiono el pulsador para que lea la línea, voy moviéndolo para hacer un reconocimiento y después enciendo los motores presionando otra vez.

Esto lo hago siempre sobre una línea recta y al llegar a la curva sigue derecho sin siquiera doblar un grado el robot, por eso pensaba...

¿Será un problema de código, que al llegar a la curva no detiene una de las ruedas y por consiguiente no gira el robot?

El motor tiene motoreductor y potencia. Dudo que le falte. Salto de línea
Los sensores, luego de probarlos por separado, leen bien la linea, la tensión es correcta, el puente H funciona y el arduino da bien sus salidas. Salto de línea

P
or eso me queda revisar el código, el cual puede tener algún tipo de problema.

Gracias de antemano.
 
Última edición por un moderador:
Hola gente del foro.

Estoy teniendo problemas con el Arduino... Al tiempo de estar ejecutando el programa correctamente, la placa crea un bugg generando lo siguiente:

Comienza en que a un tiempo (variable) de estar ejecutando correctamente el programa este envía el máximo valor de pwm (255 en este caso) a una de las ruedas y la otra la deja en 0, generando asi que gire hacia una dirección a toda velocidad sin tener registro de los valores de los sensores... la única respuesta es la tensión máxima a la entrada de PWM.

La placa arduino se conecta bien a la pc y puedo subir programas sin problemas. A que se le puede atribuir este bugg repentino en el funcionamiento?

Gracias! ...
 
Atrás
Arriba