Hacer que un robot vaya recto usando motores codificadores y microcontrolador (Arduino)

Ahora tengo un chasis simple con dos ruedas que funcionan con motores codificadores. Conecté Arduino Uno con el chasis e hice un programa simple para contar el número de señales (en términos simples) de cada uno de los motores del codificador.

Ahora, en teoría, cuando el chasis se mueve en línea recta, ambas lecturas deberían ser exactamente iguales (lo he comprobado, ¡lo son!). Y cuando un motor es más rápido, esa determinada lectura debería ser mayor.

Así que hice un programa simple que controla estas lecturas del codificador y cuando la diferencia excede un cierto valor, apaga un motor hasta que los valores no se igualan y luego enciende ese motor.

Ahora, en teoría, el chasis debería ir en línea recta, pero no lo hace y realiza cosas raras. (El código se adjunta a continuación).

Ahora, a veces, el código se atasca en uno de los bucles while. También he jugado mucho con mi código. Por ejemplo, en lugar de while(left_counter != right_counter)incluso he hechowhile ((left_counter - right_counter) > Certain_Range

El único problema que se me ocurre es que los motores tardan en apagarse y en ese tiempo las interrupciones están causando estragos. (Soy nuevo en la programación de microcontroladores y esas cosas, aunque tengo bastante experiencia en C ++, etc.)

¿Alguien puede explicar por qué este enfoque no funciona para mantener el motor en orden?

Código (Arduino UNO):

int motor_vcc_left = 12; //LEFT TIRE - BLUE
int pull_up_left = 3; //LEFT TIRE - GREEN

int motor_vcc_right = 11; //RIGHT TIRE - ORANGE
int pull_up_right = 2; //RIGHT TIRE - BLUE

int encoder_vcc_pin = 7;

volatile int left_counter = 0;
volatile int right_counter = 0;

void setup() {
  pinMode(motor_vcc_left, OUTPUT);
  pinMode(motor_vcc_right, OUTPUT);

  pinMode(encoder_vcc_pin, OUTPUT);
  digitalWrite(encoder_vcc_pin, HIGH);

  pinMode(3, INPUT_PULLUP); //LEFT TIRE
  attachInterrupt(1, blinkleft, CHANGE); //LEFT TIRE

  pinMode(2, INPUT_PULLUP); //RIGHT TIRE
  attachInterrupt(0, blinkright, CHANGE); //RIGHT TIRE

  digitalWrite(motor_vcc_left, HIGH);
  digitalWrite(motor_vcc_right, HIGH);
}

void loop() {
  if ((left_counter - right_counter) > 10) {
    while (left_counter != right_counter) {
      digitalWrite(motor_vcc_left, LOW);
    }
    digitalWrite(motor_vcc_left, HIGH);
  } else if ((right_counter - left_counter) > 10) {
    while (right_counter != left_counter) {
      digitalWrite(motor_vcc_right, LOW);
    }
    digitalWrite(motor_vcc_right, HIGH);
  }
}

void blinkleft() {
  left_counter++;
}

void blinkright() {
  right_counter++;
}
Si todo fuera perfectamente simétrico, y si las ruedas tuvieran un contacto perfecto con una superficie perfecta, sería posible conducir en línea recta contando las marcas.
Pero según mi código, ¿no se enderezará el robot si se desvía del camino? La pregunta que hago es ¿cuál es el problema con mi enfoque?
¿Cómo sabe que se desvió de la ruta requerida? El principal problema es que las ruedas se deslizan y los contadores de ticks no tienen forma de saberlo. El robot necesita un método para comprobar su posición y orientación absolutas con frecuencia.
El control de rutas no es tan fácil como parece. Ir a la meta es probablemente más práctico, donde no se controla la ruta exacta.
Entiendo que el deslizamiento puede ser un problema, pero ¿no debería funcionar cuando tienes cierto tipo de superficie donde el deslizamiento es extremadamente bajo? Y a través de los clics no se puede saber qué rueda va más rápido y esencialmente hacer que vaya por el camino recto. Inicialmente, este código parece funcionar, pero luego comienza a moverse hacia la izquierda una y otra vez. De hecho, quería controlar de alguna manera su camino. Básicamente, quería asegurarme de que si mi robot puede ir en línea recta y puede dar giros de 90 grados, entonces puedo hacer que siga fácilmente un camino determinado.
Es prácticamente imposible asegurarse de que las ruedas no patinen. También habrá diferencias en los sistemas de transmisión en los cubos. Échale un vistazo a este MOOC ('Control de Robots Móviles' al que aún puedes acceder, aunque finalizó hace más de un año): Coursera.org/course/conrob
Entonces, ¿puede decirme un método muy simple para asegurarse de que un robot vaya en línea recta? Preferiblemente un método relacionado con el que estoy usando.
necesita fuentes externas para que el robot pueda calcular su posición y orientación instantáneas (por ejemplo, triangulación). El propósito de mi publicación original era indicar que lo que estás tratando de lograr no es una tarea simple. ¡No sé si es posible hacerlo usando codificadores de rueda! Si observa las primeras conferencias en el sitio web que di en la publicación anterior, tendrá una idea de cómo se han abordado problemas similares.

Respuestas (2)

Simplemente encender y apagar los motores no lo llevará lejos cuando se trata de conducir en línea recta. Los motores y el propio robot tienen cierta inercia, por lo que no se detendrán en su lugar cuando los apagues. Un enfoque mucho mejor sería implementar un controlador PID , o al menos una parte proporcional de él.

¿Cómo funciona el controlador proporcional?

  • Primero, mide cuántos tics obtiene en un período determinado y constante, es decir, 10 ms, para cada una de las ruedas.
  • Comparas el resultado, con el valor objetivo deseado, digamos 40 ticks.
  • Cuando el valor medido es mayor que el objetivo, reduce un poco la velocidad del motor, cuando es menor, lo acelera.

En Arduino, donde controlas la velocidad de un motor por PWM, se ve así:

void loop() {
  if(micros() - t > PERIOD) {
    error = target - ticks;
    newPWM = error * proportionalGain;
    runMotor(newPWM);
    t = micros();
  }
}

Este ejemplo es para un solo motor, pero espero que tenga una idea general. Tendrá que sintonizar PERIODy proprtionalGainusted mismo. Recuerde que el rango de PWM válido para Arduino es 0-255.

Problemas con los que probablemente se encontrará Incluso cuando tenga el motor funcionando exactamente a la misma velocidad, es posible que observe que el robot gira. Aquí hay algunas razones posibles: - Diámetros de ruedas desiguales - Distribución de masa desigual en el robot (más masa en una rueda que en otra) - Desalineación de las ruedas Aquí hay un gran artículo, sobre un método llamado UMBmark desarrollado por Johann Borenstein, que ayuda a contrarrestar estos errores: http://www-personal.umich.edu/~johannb/Papers/paper60.pdf

Estoy usando la siguiente biblioteca: playground.arduino.cc/Code/PIDLibaryBasicExample Tiene el PID implementado. El problema al que me enfrento es que no sé cuáles son la entrada, la salida y el punto de ajuste. Ahora está eligiendo una entrada analógica y dando una salida PWM. Entonces, ¿mi entrada será una cierta velocidad y el punto de referencia también será una cierta velocidad?
¿O los ticks de Motor_1 serán el punto de ajuste de Motor_2 y lo mismo para el otro motor?
@GeorgeAdams Desea controlar la velocidad, por lo que la entrada será tics según el período elegido, el punto de ajuste será tics según el período que desea obtener y la salida será PWM. Utilice dos controladores PID, uno por cada rueda. Para tener valores más significativos, generalmente escalo mi entrada y salida para que estén en el rango de -100:100, sea su elección.

El uso de la retroalimentación del codificador ofrecerá una ligera mejora con respecto al simple encendido de los motores, pero no logrará un seguimiento perfecto de una línea recta en una larga distancia. Eso requeriría algún otro tipo de mecanismo de retroalimentación. Lo siguiente asume que solo está buscando mejoras menores.

En cuanto a su código, perdería los estados adicionales introducidos por los bucles while y haría algo como:

#define DEAD_BAND 10

void loop() {
  if ((left_counter - right_counter) > DEAD_BAND) {
    // We are pointing too far to the right. Turn right motor on, left motor off.
    digitalWrite(motor_vcc_right, HIGH);
    digitalWrite(motor_vcc_left, LOW);
  } 
  else if ((right_counter - left_counter) > DEAD_BAND) {
    // We are pointing too far to the left. Turn left motor on, right motor off.
    digitalWrite(motor_vcc_right, LOW);
    digitalWrite(motor_vcc_left, HIGH);
  }
  else {
    // Everything seems cool. Continue psuedo-straight.
    digitalWrite(motor_vcc_right, HIGH);
    digitalWrite(motor_vcc_left, HIGH);
  }
}

Mejora adicional: lo anterior tiene algunas debilidades. Una vez que acumulamos algún error y estamos apuntando hacia la derecha, corregimos el conteo inclinando un poco más hacia la izquierda. Sin embargo, es posible que aún nos hayamos movido lateralmente y/o hayamos corregido en un radio de giro diferente al de la fuente del error.

Tomé este enfoque exacto para un viejo proyecto en la escuela secundaria :)