Di recente stavo lavorando a un progetto ed è stato il primo a essere stato coinvolto abbastanza da complicare la rete dei sensori. Alla fine, penso che la comunicazione sia stata il collo di bottiglia in termini di prestazioni complessive e mi chiedo come persone più esperte avrebbero risolto questo problema. Questa è una lettura lunga, ma penso che sia piuttosto interessante, quindi ti preghiamo di attenerci. Il problema era progettare un dirigibile autonomo in grado di navigare su un percorso ad ostacoli e di lanciare palline da ping pong in bersagli di scatole marroni. Ecco qui:
sensori
- 4D Systems Modulo telecamera uCAM-TTL - Interfaccia UART
- Bussola digitale HMC6352 - Interfaccia I2C
- Maxbotix Sonar ez4 - Interfaccia analogica a 1 pin
attuatori
- 2x driver del motore L293D (collegati a semplici motori hobbistici): sono stati utilizzati per guidare 6 motori in modo bidirezionale. Hanno richiesto input PWM per variare la velocità. Ora 3 dei nostri motori facevano sempre la stessa cosa (quelli che controllavano il movimento su / giù), quindi avevano bisogno solo di 2 uscite PWM dai nostri controller per controllare tutti e 3 i motori. Gli altri 3 motori che controllavano il movimento laterale necessitavano tutti del controllo individuale (per il movimento omnidirezionale), quindi erano necessarie altre 6 uscite PWM dai nostri controller.
- Servomotore - Interfaccia PWM
Controller
Per ragioni che saranno chiarite in seguito, abbiamo finito con l'uso di 2x ATmega328Ps. Abbiamo usato un Arduino Uno per programmarli (non avevamo accesso a un ISP) ma abbiamo creato un PCB personalizzato, quindi non abbiamo dovuto usare le schede Arduino poiché ciò avrebbe aggiunto peso inutile al nostro dirigibile. Per quanto riguarda il motivo per cui abbiamo scelto l'ATmega328P, conoscevo molto l'ambiente di Arduino e penso che abbia reso lo sviluppo del codice molto più rapido e semplice.
Comunicazione ed elaborazione
- 2x Xbee Basic
- 2x ATmega328P
- Computer desktop che esegue C ++ con openCV
Come puoi vedere dal modulo della fotocamera, la maggior parte del nostro progetto si basava sulla visione artificiale. I dirigibili potevano trasportare solo così tanto peso e non ci sentivamo a nostro agio nell'implementare la visione computerizzata su un microcontrollore. Quindi quello che abbiamo finito è stato usare XBee per inoltrare i dati delle immagini a un computer desktop. Quindi sul lato server abbiamo ricevuto i dati delle immagini e abbiamo usato openCV per elaborare l'immagine e ricavarne elementi. Ora anche il lato server doveva conoscere le informazioni sull'altezza (dal sonar) e le informazioni sulla bussola.
La prima ruga è stata che non siamo riusciti a far controllare la fotocamera da un microcontrollore per un paio di motivi. Il problema principale era che la memoria interna su uP non riusciva a gestire la memorizzazione di un intero frame. Potrebbero esserci stati modi per aggirare questo problema attraverso la codifica intelligente, ma ai fini di questa domanda facciamo finta che fosse impossibile. Quindi, per risolvere questo problema, avevamo il lato server che inviava i comandi della telecamera attraverso il ricetrasmettitore XBee e il ricevitore XBee (a bordo del dirigibile) aveva l'output cablato all'ingresso della telecamera.
La ruga successiva è che non ci sono abbastanza PWM su un singolo ATmega328P per controllare tutti i motori PERCHÉ l'interfaccia I2C utilizza uno dei pin PWM (maledizione ...). Questo è il motivo per cui abbiamo deciso di utilizzare un secondo. In realtà il codice si prestava perfettamente all'elaborazione parallela perché il controllo dell'altezza era completamente indipendente dal controllo del movimento laterale (quindi 2 micros erano probabilmente meglio di uno collegato a un controller PWM). Pertanto, U1 era responsabile di 2 uscite PWM (su / giù) e della lettura del sonar. Gli U2 erano responsabili della lettura della bussola, del controllo di 6 uscite PWM (i motori laterali) e della lettura del sonar. Anche U2 era responsabile della ricezione dei comandi dal server tramite XBee.
Ciò ha portato al nostro primo problema di comunicazione. La linea XBee DOUT era collegata sia al microcontrollore che alla videocamera. Ora, naturalmente, abbiamo progettato un protocollo in modo che i nostri micro comandi ignorassero i comandi della fotocamera e i comandi della fotocamera ignorassero i micro comandi, quindi andava bene. Tuttavia, la videocamera, ignorando i nostri micro comandi, inviava i dati NAK sulla sua linea di output. Dal momento che il comando era destinato al micro, in qualche modo avevamo bisogno di spegnere l'uscita della telecamera sull'XBee. Per risolvere questo problema, abbiamo creato i 2 FET di controllo micro che si trovavano tra la telecamera e l'XBee (questo è il primo FET) e anche tra gli U2 e l'XBee (questo è il secondo FET). Pertanto, quando la telecamera cercava di inviare informazioni al server, il primo FET era "acceso" e il secondo FET era "spento".
Quindi per darti un'idea di come ha funzionato qui ci sono alcuni esempi:
- Il server richiede un'immagine: PIC_REQUEST passa attraverso XBee e arriva agli U2 e alla telecamera. Gli U2 lo ignorano e la fotocamera invia indietro i dati dell'immagine.
- Il server ha appena finito di elaborare un'immagine e sta inviando i dati del motore per dire al dirigibile di girare a destra - MOTOR_ANGLE (70) si collega a XBee e arriva a U2 e fotocamera. Gli U2 riconoscono come un micro comando e quindi disattivano il FET della fotocamera (ma forse la fotocamera ha già risposto con un NAK ?? chissà ...). U2 quindi risponde al comando modificando le uscite PWM del motore. Quindi riattiva il FET della fotocamera (questa era l'impostazione predefinita poiché i dati dell'immagine erano più importanti).
- Il server si rende conto che siamo arrivati a un punto nel percorso ad ostacoli in cui la nostra altezza al passaggio del mouse predefinita ora deve essere di 90 pollici anziché 50 pollici. SET_HEIGHT passa attraverso XBee e succede la stessa cosa dell'esempio 2. U2 riconosce il comando SET_HEIGHT e attiva un interrupt su U1. U1 ora esce dal suo circuito di controllo dell'altezza e attende di ricevere dati seriali da U2. Esatto, più dati seriali. A questo punto il FET degli U2 è attivo (e il FET della videocamera è spento), quindi il server riceve l'altezza che U2 sta inviando anche a U1. Questo era a scopo di verifica. Ora U1 ripristina la sua variabile interna per height2HoverAt. Gli U2 ora disattivano il FET e riaccendono il FET della videocamera.
Ho sicuramente lasciato fuori una buona quantità di informazioni, ma penso che sia abbastanza per capire alcune delle complicazioni. Alla fine, i nostri problemi stavano semplicemente sincronizzando tutto. A volte ci sarebbero dati lasciati nei buffer, ma solo 3 byte (tutti i nostri comandi erano sequenze di 6 byte). A volte perdiamo la connessione con la nostra fotocamera e dobbiamo risincronizzarla.
Quindi la mia domanda è: quali tecniche suggerireste di rendere la comunicazione tra tutti questi componenti più affidabile / robusta / semplice / migliore?
Ad esempio, so che uno sarebbe stato quello di aggiungere un circuito di ritardo tra l'uscita XBee integrata e la videocamera in modo che il micro avesse la possibilità di disattivare il talk line della videocamera prima che rispondesse ai micro comandi con i NAK. Altre idee del genere?
Grazie e sono sicuro che ciò richiederà molte modifiche, quindi rimanete sintonizzati.
Edit1:Non ci è stato possibile collegare i dati UART della videocamera tramite uno dei micro. C'erano due opzioni per i dati della fotocamera, bitmap grezza o JPEG. Per una bitmap non elaborata, la fotocamera ti invia i dati il più velocemente possibile. L'ATmega328P ha solo 128 byte per un buffer seriale (tecnicamente questo è configurabile ma non sono sicuro di come) e non pensavamo che saremmo stati in grado di farlo uscire dal buffer e passare all'XBee abbastanza velocemente. Ciò ha lasciato il metodo JPEG dove invia ogni pacchetto e attende che il controller lo ACK (piccolo prototipo di handshaking). Il più veloce a cui è potuto arrivare è stato di 115200 baud. Ora per qualche motivo, il più veloce che abbiamo potuto trasmettere in modo affidabile grandi quantità di dati sull'XBee è stato di 57600 baud (anche dopo aver effettuato l'accoppiamento nodo / rete per consentire la funzionalità di reinvio automatico). L'aggiunta di un ulteriore punto di arresto nella nostra rete (dalla fotocamera al micro su XBee invece della sola fotocamera su XBee) per il micro ha semplicemente rallentato il tempo impiegato per trasferire un'immagine troppo. Avevamo bisogno di una certa frequenza di aggiornamento delle immagini affinché il nostro algoritmo di controllo del motore funzionasse.