Paso 12: P.3, código: cinemática inversa y otros Bits de código
Al principio, hemos considerado incluir cálculos cinemáticos inversos en nuestro código Objective-C, pero esto resultó para ser una mala idea porque hay un montón de cálculos que hacer en la inicialización, y después de que termine de una vez, no es necesario repetirlos otra vez. Después de todo, el hecho de que los objetos no se mueven alrededor es la base de nuestro esquema de control. En cambio, nos duro código ángulos.
Una pieza muy importante del código es un método que ralentizará el brazo que acerca a su destino, en lugar de empujar todo el camino y esperando que no arranca oscilante (tal vez en un mundo ideal con ideal servos).
En primer lugar, damos una pausa la ejecución de una pequeña cantidad de tiempo para permitir que el servo mover el ángulo que les dan (la primera vez este método se llama, la voluntad del servo no pero estar en movimiento):
[NSThread sleepForTimeInterval:0.03];
Luego, comparamos el servo de posición angular actual a la posición final deseada - si se cierra bastante (que hemos definidos a 2 grados), luego definir la variable que almacena el ángulo actual igual a la posición final deseada (van a ver por qué esto tiene sentido en un momento):
Si (abs(targetAngle-angle) < = 2) {ángulo = targetAngle;}
Ahora, calcular una décima parte la diferencia entre el ángulo actual y el ángulo del objetivo - si el ángulo actual es igual al ángulo objetivo, devolverá cero:
doble diff = (targetAngle - ángulo) * 0.1;
Ahora, mover el servo a la posición angular actual además de la diferencia de una décima parte - si el ángulo actual es igual al ángulo objetivo, esto hará que el servo mover hasta el ángulo del objetivo:
[moveActualTo del:(angle + diff)];
Ver la descripción del vídeo a continuación para obtener una mejor comprensión de cómo cualquiera por qué se hace. Puede encontrar este código en el método de calculateChange en Motor.m, que se adjunta como parte de un fichero zip en el siguiente paso.
La primera versión de nuestro código utilizado el electroimán (esto es lo que nos llevó a regionales - el video fue tomado alrededor 6:00 del día, después de una visita para que funcione!) y parecía algo como esto:
Descripción del vídeo de YouTube:
"Se trata de la primera prueba completa de nuestro brazo robótico para la Olimpíada de Ciencias de Massachusetts. Tuvimos una de las coordenadas en nuestro programa (sí, resultó ser un problema de software - mucho mejor que un fallo aleatorio "MOSFET no se enciende"!), por lo que no pudo recoger uno de los clavos, pero llegamos corregido a tiempo para el evento regional de la tarde y ganó el primer lugar por un deslizamiento de tierra!
Uno de los problemas que teníamos antes (y que muchos de los equipos en regionales) fue oscilante servos y servos que se mueven demasiado rápido y el brazo del oscilación en trayectorias impredecibles. Para solucionar esto, escribimos un algoritmo que ralentiza los servos mientras se acercan a sus destinos finales, dándoles un flujo continuo de coordenadas que son exponencialmente más cerca y más cerca del ángulo del objetivo hasta el servo está dentro de un delta, generalmente uno o dos grados, de este ángulo y suficientemente cerca para sólo ir directamente allí. Cada iteración se calcula mediante la búsqueda de una décima parte del ángulo que el servo queda por viajar con el fin de completar el paso. En lugar de usar recursividad para que el método de cálculo de ángulo de llamar a sí mismo hasta que el paso es completo, que es la opción obvia, utilizamos un NSTimer en su propio hilo para no tener que agregar retrasos a nuestro programa para los cálculos de los servos (los servos moverse mucho más despacio que el ordenador puede escupir de ángulos).
La razón que utiliza decaimiento exponencial en lugar de simplemente ralentizado movimiento lineal es que el brazo actúa esencialmente como un oscilador armónico amortiguado (si asumimos que el término proporcional en regulador de PID interno del servo domina alrededor del punto de ajuste, que parece encajar lo que observé cuando estaba oscilando el brazo), por lo que si conducimos linealmente, que se empieza con energía cinética inicial una vez en el destino y oscilan alrededor de él en lugar de venir a una parada. La única solución (si insistimos en la conducción lineal) es frenar el brazo para reducir la amplitud de la oscilación hasta que consideramos aceptable, que no es deseable cuando se considera que se trata de una competencia de tiempo. En cambio, si fuerza el siguiente ángulo con un patrón exponencial que se decae, debe llegar con muy poca energía cinética, con error causado sólo por el hecho de que le estamos dando datos discretos.
Cada posición que los servos necesitan llegar a se calcula utilizando cinemática inversa y entonces regularse individualmente usando el modo manual de nuestro programa al estar tan correcta como sea posible. Una de las cosas que estamos trabajando en los Estados el próximo mes es control cinemática inversa en tiempo real que nos permitirá mover efectoras de fin de brazo en cualquier ruta de acceso exacta que queramos, en lugar de sólo hacia los servos cada ángulo uno a la vez como hacemos ahora.
Aunque sólo tenemos un electroimán y no un universal pinza o garra, con el cual recoger objetos (así nos obliga a dejar la mitad del tablero sin tocar), control automático significa este brazo son capaces de recoger objetos rápidamente y sin error humano, por lo que ponemos con éxito el 100% de los objetos que pretendemos colocar cada vez ejecute el brazo".