Apuntando Con Servicio Visual
- Puedes apuntar tu robot con precisión y rapidez usando solo una limelight y tu sistema de conducción.
- Todo esto se puede lograr en menos de 1 hora.
Usando seguimiento visual de alta velocidad de fotogramas, ahora es posible usar 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 sistema de conducció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 sistema de conducción de 6 ruedas con ruedas colson. Aquí hay una imagen de nosotros agregando una limelight al robot para hacer esta prueba.
Luego agregamos código al robot que se ejecutaría cuando el conductor mantiene presionado un botón en el joystick. Este robot usaba conducción estilo "tanque", por lo que la función OperatorControl generaba un valor 'left_command' y un valor 'right_command' para controlar los lados izquierdo y derecho del sistema de conducció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;
}
Desde el principio, esto funcionó en su mayoría. El robot gira en la dirección del objetivo automáticamente cuando 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 se alineaba perfectamente con el objetivo. En algunos juegos con objetivos pequeños (como 2016 y 2017), esto no sería 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 error de apuntado grande, pero simplemente no puede apuntar 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 hacia adelante y hacia atrás mientras sobrepasa el objetivo:
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.