Estaba trabajando en un proyecto recientemente y fue el primero que participó lo suficiente como para complicar las redes de sensores. Al final, creo que la comunicación fue el cuello de botella en términos de rendimiento general y me pregunto cómo las personas más experimentadas habrían resuelto este problema. Esta es una lectura larga, pero creo que es bastante interesante, así que quédese con ella. El problema era diseñar un dirigible autónomo capaz de navegar una carrera de obstáculos y tirar pelotas de ping pong en objetivos de caja marrón. Aquí va:
Sensores
- Módulo de cámara 4D Systems uCAM-TTL - interfaz UART
- Brújula digital HMC6352 - interfaz I2C
- Maxbotix Sonar ez4 - interfaz analógica de 1 pin
Actuadores
- 2x controladores de motor L293D (conectados a simples motores de pasatiempo): se utilizaron para conducir 6 motores bidireccionalmente. Requerían entradas PWM para variar la velocidad. Ahora 3 de nuestros motores siempre estaban haciendo lo mismo (los que controlaban el movimiento hacia arriba / abajo), por lo que solo requerían 2 salidas PWM de nuestros controladores para controlar los 3 motores. Los otros 3 motores que controlaban el movimiento lateral necesitaban un control individual (para el movimiento omnidireccional), por lo que se necesitaron otras 6 salidas PWM de nuestros controladores.
- Servomotor - interfaz PWM
Controladores
Por razones que quedarán claras más adelante, terminamos usando 2x ATmega328Ps. Usamos un Arduino Uno para programarlos (no teníamos acceso a un ISP) pero fabricamos una PCB personalizada, por lo que no tuvimos que usar placas arduino, ya que eso solo agregaría un peso innecesario a nuestro dirigible. En cuanto a por qué elegimos el ATmega328P, estaba muy familiarizado con el entorno arduino y creo que eso hizo que el desarrollo del código sea mucho más rápido y fácil.
Comunicación y procesamiento
- 2x Xbee Basic
- 2x ATmega328P
- Computadora de escritorio con C ++ con openCV
Como puede ver en el módulo de la cámara, la mayor parte de nuestro proyecto se basó en la visión por computadora. Los dirigibles solo podían cargar tanto peso y no nos sentimos cómodos implementando la visión por computadora en un microcontrolador. Entonces, lo que terminamos haciendo fue usar XBee para retransmitir los datos de la imagen a una computadora de escritorio. Entonces, en el lado del servidor, recibimos datos de imagen y usamos openCV para procesar la imagen y resolver las cosas a partir de ella. Ahora el lado del servidor también necesitaba conocer la información de altura (del sonar) y la información de la brújula.
El primer inconveniente fue que no pudimos controlar la cámara con un microcontrolador por un par de razones. El problema principal era que la memoria interna en el uP no podía manejar el almacenamiento de un marco completo. Es posible que haya habido formas de evitar esto mediante una codificación inteligente, pero a los fines de esta pregunta, supongamos que era imposible. Entonces, para resolver este problema, hicimos que el lado del servidor enviara comandos de la cámara a través del transceptor XBee y el receptor XBee (a bordo del dirigible) tenía su salida conectada a la entrada de la cámara.
El siguiente inconveniente fue que no hay suficientes PWM en un solo ATmega328P para controlar todos los motores PORQUE la interfaz I2C usa uno de los pines PWM (maldición ...). Es por eso que decidimos usar una segunda. De todos modos, el código se prestó perfectamente al procesamiento paralelo porque el control de altura era completamente independiente del control de movimiento lateral (por lo que 2 micros probablemente eran mejores que uno conectado a un controlador PWM). Por lo tanto, U1 fue responsable de 2 salidas PWM (arriba / abajo) y de leer la sonda. U2 fue responsable de leer la brújula, controlar 6 salidas PWM (los motores laterales) y también leer la sonda. U2 también fue responsable de recibir comandos del servidor a través de XBee.
Eso llevó a nuestro primer problema de comunicación. La línea XBee DOUT estaba conectada tanto al microcontrolador como a la cámara. Ahora, por supuesto, diseñamos un protocolo para que nuestros microcomandos ignoren los comandos de la cámara y los comandos de la cámara ignoren los microcomandos, por lo que estuvo bien. Sin embargo, la cámara, al ignorar nuestros microcomandos, enviaría datos NAK en su línea de salida. Dado que el comando estaba destinado al micro, necesitábamos de alguna manera apagar la salida de la cámara al XBee. Para resolver esto, hicimos el micro control 2 FET que estaban entre la cámara y XBee (ese es el primer FET) y también entre U2 y XBee (ese es el segundo FET). Por lo tanto, cuando la cámara intentaba enviar información al servidor, el primer FET estaba "encendido" y el segundo FET estaba "apagado".
Entonces, para darle una idea de cómo funcionó esto, aquí hay algunos ejemplos:
- El servidor solicita una imagen: PIC_REQUEST pasa por XBee y llega a U2 y la cámara. U2 lo ignora y la cámara envía los datos de la imagen.
- El servidor acaba de procesar una imagen y está enviando datos del motor para indicarle a blimp que gire a la derecha: MOTOR_ANGLE (70) pasa por XBee y llega a U2 y la cámara. U2 reconoce como un micro comando y por lo tanto apaga el FET de la cámara (pero tal vez la cámara ya respondió con un NAK ?? quién sabe ...). U2 responde al comando cambiando las salidas PWM del motor. Luego vuelve a encender el FET de la cámara (esta era la configuración predeterminada ya que los datos de la imagen eran los más importantes).
- El servidor se da cuenta de que hemos llegado a un punto en la carrera de obstáculos donde nuestra altura de desplazamiento predeterminada ahora debe ser de 90 pulgadas en lugar de 50 pulgadas. SET_HEIGHT pasa por XBee y sucede lo mismo que en el ejemplo 2. U2 reconoce el comando SET_HEIGHT y desencadena una interrupción en U1. U1 ahora sale de su circuito de control de altura y espera recibir datos seriales de U2. Así es, más datos en serie. En este punto, el FET de U2 está encendido (y el FET de la cámara está apagado), por lo que el servidor recibe la altura que U2 también está enviando a U1. Eso fue para fines de verificación. Ahora U1 restablece su variable interna para height2HoverAt. U2 ahora apaga su FET y vuelve a encender la cámara FET.
Definitivamente omití una buena cantidad de información, pero creo que es suficiente para comprender algunas de las complicaciones. Al final, nuestros problemas fueron simplemente sincronizar todo. A veces quedarían datos en buffers, pero solo 3 bytes (todos nuestros comandos eran secuencias de 6 bytes). A veces perderíamos la conexión con nuestra cámara y tendríamos que volver a sincronizarla.
Entonces mi pregunta es: ¿Qué técnicas sugerirían para que la comunicación entre todos esos componentes sea más confiable / robusta / más simple / mejor?
Por ejemplo, sé que uno hubiera sido agregar un circuito de retardo entre el XBee de a bordo y la cámara para que el micro tuviera la oportunidad de apagar la línea de conversación de la cámara antes de que respondiera a los micro comandos con NAK. ¿Alguna otra idea como esa?
Gracias y estoy seguro de que esto requerirá muchas ediciones, así que estad atentos.
Editar1:Empalmar los datos UART de la cámara a través de uno de los micros no nos parecía posible. Había dos opciones para datos de la cámara, mapa de bits sin formato o JPEG. Para un mapa de bits sin procesar, la cámara solo le envía datos tan rápido como puede. El ATmega328P solo tiene 128 bytes para un búfer en serie (técnicamente esto es configurable, pero no estoy seguro de cómo hacerlo) y no pensamos que seríamos capaces de sacarlo del búfer y pasarlo al XBee lo suficientemente rápido. Eso dejó el método JPEG donde envía cada paquete y espera a que el controlador lo ACK (pequeño protocolo de protocolo de enlace). Lo más rápido que pudo alcanzar fue 115200 baudios. Ahora, por alguna razón, lo más rápido que pudimos transmitir de manera confiable grandes cantidades de datos a través del XBee fue 57600 baudios (esto es incluso después de que hicimos el emparejamiento de nodo / red para permitir la capacidad de reenvío automático). Agregar la parada adicional en nuestra red (cámara a micro a XBee en lugar de solo cámara a XBee) para el micro simplemente disminuyó el tiempo que tomó transferir una imagen demasiado. Necesitábamos una cierta frecuencia de actualización en las imágenes para que nuestro algoritmo de control motor funcionara.