Je travaillais sur un projet récemment et c'était le premier qui était suffisamment impliqué pour compliquer la mise en réseau des capteurs. Au final, je pense que la communication a été le goulot d'étranglement en termes de performances globales et je me demande comment des personnes plus expérimentées auraient résolu ce problème. Ceci est une longue lecture, mais je pense que c'est assez intéressant, alors respectez-la. Le problème était de concevoir un dirigeable autonome capable de naviguer sur un parcours du combattant et de larguer des balles de ping-pong dans des cibles en boîte brune. Voici:
Capteurs
- Module de caméra uCAM-TTL 4D Systems - Interface UART
- HMC6352 Digital Compass - Interface I2C
- Maxbotix Sonar ez4 - Interface analogique 1 broche
Actionneurs
- 2 pilotes de moteur L293D (connectés à de simples moteurs de loisir) - Ils ont été utilisés pour entraîner 6 moteurs dans les deux sens. Ils avaient besoin d'entrées PWM pour faire varier la vitesse. Maintenant, 3 de nos moteurs faisaient toujours la même chose (ceux qui contrôlaient le mouvement haut / bas), ils n'avaient donc besoin que de 2 sorties PWM de nos contrôleurs pour contrôler les 3 moteurs. Les 3 autres moteurs qui contrôlaient le mouvement latéral avaient tous besoin d'un contrôle individuel (pour le mouvement omnidirectionnel), de sorte que 6 autres sorties PWM étaient requises de nos contrôleurs.
- Servomoteur - Interface PWM
Contrôleurs
Pour des raisons qui deviendront claires plus tard, nous avons fini par utiliser 2x ATmega328Ps. Nous avons utilisé un Arduino Uno pour les programmer (nous n'avions pas accès à un FAI), mais nous avons fabriqué un PCB personnalisé, nous n'avons donc pas eu à utiliser de cartes Arduino car cela ne ferait qu'ajouter du poids inutile à notre dirigeable. Quant à la raison pour laquelle nous avons choisi l'ATmega328P, je connaissais très bien l'environnement Arduino et je pense que cela a rendu le développement du code beaucoup plus rapide et plus facile.
Communication et traitement
- 2x Xbee Basic
- 2x ATmega328P
- Ordinateur de bureau exécutant C ++ avec openCV
Comme vous pouvez le constater à partir du module caméra, la plupart de notre projet reposait sur la vision par ordinateur. Les dirigeables ne pouvaient supporter autant de poids et nous ne nous sentions pas à l'aise d'implémenter la vision par ordinateur sur un microcontrôleur. Nous avons donc fini par utiliser XBee pour relayer les données d'image vers un ordinateur de bureau. Donc, côté serveur, nous avons reçu des données d'image et utilisé openCV pour traiter l'image et en extraire des éléments. Maintenant, le côté serveur devait également connaître les informations de hauteur (du sondeur) et les informations de la boussole.
La première ride était que nous ne pouvions pas faire contrôler la caméra par un microcontrôleur pour deux raisons. Le problème principal était que la mémoire interne de l'UP ne pouvait pas gérer le stockage d'une trame entière. Il pourrait y avoir des moyens de contourner cela grâce à un codage intelligent, mais pour les besoins de cette question, supposons que cela était impossible. Donc, pour résoudre ce problème, nous avons demandé au serveur d'envoyer des commandes de caméra via l'émetteur-récepteur XBee et le récepteur XBee (à bord du dirigeable) avait sa sortie câblée à l'entrée de la caméra.
Le problème suivant était qu'il n'y a pas assez de PWM sur un seul ATmega328P pour contrôler tous les moteurs PARCE QUE l'interface I2C utilise l'une des broches PWM (bon sang ...). C'est pourquoi nous avons décidé d'en utiliser un 2ème. Le code se prêtait en fait parfaitement au traitement parallèle de toute façon parce que le contrôle de la hauteur était complètement indépendant du contrôle du mouvement latéral (donc 2 micros étaient probablement meilleurs que celui attaché à un contrôleur PWM). Par conséquent, U1 était responsable de 2 sorties PWM (haut / bas) et de la lecture du sonar. U2 était responsable de la lecture de la boussole, du contrôle de 6 sorties PWM (les moteurs latéraux) et de la lecture du sonar. U2 était également responsable de la réception des commandes du serveur via le XBee.
Cela a conduit à notre premier problème de communication. La ligne XBee DOUT était connectée à la fois au microcontrôleur et à la caméra. Maintenant, bien sûr, nous avons conçu un protocole pour que nos micro-commandes ignorent les commandes de la caméra et les commandes de la caméra ignorent les micro-commandes, ce qui était bien. Cependant, la caméra, en ignorant nos micro-commandes, renverrait des données NAK sur sa ligne de sortie. Étant donné que la commande était destinée au micro, nous avions besoin d'une manière ou d'une autre de désactiver la sortie de la caméra vers le XBee. Pour résoudre ce problème, nous avons fait le micro contrôle 2 FET qui étaient entre la caméra et XBee (c'est le premier FET) et également entre U2 et le XBee (c'est le deuxième FET). Par conséquent, lorsque la caméra essayait de renvoyer des informations au serveur, le premier FET était «activé» et le second FET était «désactivé».
Donc, pour vous donner une idée de la façon dont cela a fonctionné, voici quelques exemples:
- Le serveur demande une image - PIC_REQUEST passe par XBee et arrive à U2 et à la caméra. U2 l'ignore et la caméra renvoie des données d'image.
- Le serveur vient de terminer le traitement d'une image et envoie des données de moteur pour dire au dirigeable de tourner à droite - MOTOR_ANGLE (70) passe par XBee et arrive à U2 et à la caméra. U2 reconnaît comme une micro-commande et désactive donc le FET de la caméra (mais peut-être que la caméra a déjà répondu avec un NAK ?? qui sait ...). U2 répond ensuite à la commande en modifiant les sorties PWM du moteur. Il rétablit ensuite le FET de la caméra (c'était le paramètre par défaut car les données d'image étaient les plus importantes).
- Le serveur se rend compte que nous sommes arrivés à un point dans la course à obstacles où notre hauteur de vol stationnaire par défaut doit maintenant être de 90 pouces au lieu de 50 pouces. SET_HEIGHT passe par XBee et la même chose se produit que dans l'exemple 2. U2 reconnaît la commande SET_HEIGHT et déclenche une interruption sur U1. U1 sort maintenant de sa boucle de contrôle de hauteur et attend de recevoir des données série de U2. C'est vrai, plus de données série. À ce stade, le FET de l'U2 est activé (et le FET de la caméra est désactivé), de sorte que le serveur reçoit la hauteur que U2 envoie également à U1. C'était à des fins de vérification. Maintenant, U1 réinitialise sa variable interne pour height2HoverAt. U2 désactive maintenant son FET et rallume le FET de la caméra.
J'ai définitivement omis une bonne quantité d'informations, mais je pense que cela suffit pour comprendre certaines des complications. En fin de compte, nos problèmes ne faisaient que tout synchroniser. Parfois, il restait des données dans les tampons, mais seulement 3 octets (toutes nos commandes étaient des séquences de 6 octets). Parfois, nous perdions la connexion avec notre caméra et devions la resynchroniser.
Donc ma question est: Quelles techniques suggéreriez-vous pour avoir rendu la communication entre tous ces composants plus fiable / robuste / plus simple / meilleure?
Par exemple, je sais que l'on aurait dû ajouter un circuit de retard entre la sortie XBee intégrée et la caméra afin que le micro ait la possibilité de désactiver la ligne de discussion de la caméra avant de répondre aux micro-commandes avec NAK. D'autres idées comme ça?
Merci et je suis sûr que cela nécessitera de nombreuses modifications, alors restez à l'écoute.
Edit1:L'épissage des données UART de la caméra à travers l'un des micros ne nous a pas paru possible. Il y avait deux options pour les données de caméra, le bitmap brut ou JPEG. Pour un bitmap brut, la caméra vous envoie simplement des données aussi vite que possible. L'ATmega328P n'a que 128 octets pour un tampon série (techniquement, cela est configurable mais je ne sais pas comment) et nous ne pensions pas que nous serions en mesure de le sortir du tampon et de le faire passer assez rapidement vers le XBee. Cela a laissé la méthode JPEG où il envoie chaque paquet et attend que le contrôleur l'acquitte (petit protocole de prise de contact). La vitesse la plus rapide a été de 115200 bauds. Maintenant, pour une raison quelconque, le plus rapide que nous pouvions transmettre de manière fiable de grandes quantités de données sur le XBee était 57600 bauds (c'est même après que nous ayons fait le couplage nœud / réseau pour permettre la capacité de renvoi automatique). L'ajout de l'arrêt supplémentaire dans notre réseau (caméra vers micro vers XBee par opposition à seulement caméra vers XBee) pour le micro a simplement ralenti le temps nécessaire pour transférer trop une image. Nous avions besoin d'un certain taux de rafraîchissement sur les images pour que notre algorithme de contrôle moteur fonctionne.