Saltar al contenido principal

Apuntando con Servicio Visual

  1. Puedes apuntar tu robot con precisión y rapidez usando solo una limelight y tu tren de transmisión.
  2. Todo esto se puede lograr en menos de 1 hora.

Usando seguimiento visual de alta velocidad de fotogramas, ahora es posible utilizar el pipeline de visión directamente como el "sensor" en un bucle de control PID para guiar tu robot o torreta. Para probar esta idea, agregamos una limelight a nuestro robot FRC 2017 y lo hicimos apuntar a objetivos de visión usando nada más que el tren de transmisión y los datos de la tabla de redes reportados por la limelight.

En este ejemplo, nuestro candidato de prueba fue un robot FRC 2017 que usa un tren de transmisión de 6 ruedas con ruedas Colson. Aquí hay una imagen de nosotros agregando una limelight al robot para hacer esta prueba.

CS_aim_limelight_mounted

Luego agregamos algo de código al robot que se ejecutaría cada vez que el conductor mantiene presionado un botón en el joystick. Este robot usaba un estilo de conducción "tanque", por lo que la función OperatorControl estaba generando un valor 'left_command' y un valor 'right_command' para controlar los lados izquierdo y derecho del tren de transmisión. Después del código de control normal, agregamos un bloque de código como este:

float Kp = -0.1f;  // Constante de control proporcional

std::shared_ptr<NetworkTable> table = NetworkTable::GetTable("limelight");
float tx = table->GetNumber("tx");

if (joystick->GetRawButton(9))
{
float heading_error = tx;
steering_adjust = Kp * tx;

left_command+=steering_adjust;
right_command-=steering_adjust;
}

De entrada, esto funcionó en su mayoría. El robot gira en la dirección del objetivo automáticamente cada vez que mantienes presionado el botón. Si mueves el objetivo, el robot gira para seguirlo. Sin embargo, usando la transmisión de video en vivo en el tablero, pudimos ver que había un gran problema: el robot no siempre lograba alinearse perfectamente con el objetivo. En algunos juegos con objetivos pequeños (como 2016 y 2017), esto no sería lo suficientemente bueno.

Lo que hemos implementado hasta ahora es un simple bucle de control proporcional. Calculamos el error en la dirección y lo multiplicamos por una constante, creando así un comando de motor que es proporcional al error. A medida que el error se acerca a cero, nuestro comando se acercará a cero. El problema es que hay mucha fricción involucrada cuando el robot intenta girar. Los comandos muy pequeños no harán girar el robot en absoluto. En ángulos pequeños, el comando puede volverse demasiado pequeño para mover realmente el robot. Podrías encontrar que tu robot alcanza bien su objetivo cuando comienzas con un gran error de apuntado, pero simplemente no puede apuntar en absoluto si comienzas muy cerca.

Hay algunas formas de resolver este problema, pero aquí hay una solución realmente simple. Usamos un concepto de "comando mínimo". Si el error es mayor que cierto umbral, simplemente agrega una constante a tu comando de motor que represente aproximadamente la cantidad mínima de potencia necesaria para que el robot realmente se mueva (en realidad quieres usar un poco menos que esto). El nuevo código se ve así:

float Kp = -0.1f;
float min_command = 0.05f;

std::shared_ptr<NetworkTable> table = NetworkTable::GetTable("limelight");
float tx = table->GetNumber("tx");

if (joystick->GetRawButton(9))
{
float heading_error = -tx;
float steering_adjust = 0.0f;
if (Math.abs(heading_error) > 1.0)
{
if (heading_error < 0)
{
steering_adjust = Kp*heading_error + min_command;
}
else
{
steering_adjust = Kp*heading_error - min_command;
}
}
left_command += steering_adjust;
right_command -= steering_adjust;
}

Ten cuidado, si estableces Kp o min_command demasiado alto, tu robot puede volverse inestable y puede oscilar de un lado a otro mientras sobrepasa el objetivo:

CS_aim_bad

Después de algunos ajustes en Kp y min_command, deberías lograr que tu robot apunte directamente al objetivo con mucha precisión y rapidez.

CS_aim_good