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++;
}
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?
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 PERIOD
y proprtionalGain
usted 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
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.
Chu
Saim Salmán
Chu
Chu
Saim Salmán
Chu
Saim Salmán
Saim Salmán
Chu