Eher kompliziertes Sensornetzwerk

9

Ich habe kürzlich an einem Projekt gearbeitet und es war das erste, das so involviert war, dass die Sensornetzwerke kompliziert wurden. Letztendlich denke ich, dass die Kommunikation der Engpass in Bezug auf die Gesamtleistung war, und ich frage mich, wie erfahrenere Leute dieses Problem gelöst hätten. Dies ist eine lange Lektüre, aber ich denke, es ist ziemlich interessant, also bleiben Sie bitte dabei. Das Problem bestand darin, ein autonomes Luftschiff zu entwerfen, das in der Lage ist, auf einem Hindernisparcours zu navigieren und Tischtennisbälle in braune Box-Ziele zu werfen. Hier geht:

Sensoren

  • 4D Systems uCAM-TTL-Kameramodul - UART-Schnittstelle
  • HMC6352 Digital Compass - I2C-Schnittstelle
  • Maxbotix Sonar ez4 - 1-polige analoge Schnittstelle

Aktoren

  • 2x L293D-Motortreiber (verbunden mit einfachen Hobby-Motoren) - Diese wurden verwendet, um 6 Motoren bidirektional anzutreiben. Sie benötigten PWM-Eingänge, um die Geschwindigkeit zu variieren. Jetzt machten 3 unserer Motoren immer das Gleiche (diejenigen, die die Auf- / Abbewegung kontrollierten), sodass sie nur 2 PWM-Ausgänge von unseren Controllern benötigten, um alle 3 Motoren zu steuern. Die anderen 3 Motoren, die die seitliche Bewegung steuerten, benötigten alle eine individuelle Steuerung (für eine Bewegung in alle Richtungen), so dass weitere 6 PWM-Ausgänge von unseren Steuerungen benötigt wurden.
  • Servomotor - PWM-Schnittstelle

Controller

Aus Gründen, die später klar werden, haben wir letztendlich 2x ATmega328Ps verwendet. Wir haben ein Arduino Uno verwendet, um sie zu programmieren (wir hatten keinen Zugriff auf einen ISP), aber wir haben eine benutzerdefinierte Platine hergestellt, sodass wir keine Arduino-Boards verwenden mussten, da dies unserem Luftschiff nur unnötiges Gewicht hinzufügen würde. Warum wir uns für den ATmega328P entschieden haben, war mir mit der Arduino-Umgebung sehr vertraut, und ich denke, das hat die Codeentwicklung viel schneller und einfacher gemacht.

Kommunikation & Verarbeitung

  • 2x Xbee Basic
  • 2x ATmega328P
  • Desktop-Computer mit C ++ mit openCV

Wie Sie dem Kameramodul entnehmen können, stützte sich der größte Teil unseres Projekts auf Computer Vision. Die Luftschiffe konnten nur so viel Gewicht tragen und wir fühlten uns nicht wohl dabei, Computer Vision auf einem Mikrocontroller zu implementieren. Am Ende haben wir XBee's verwendet, um die Bilddaten an einen Desktop-Computer weiterzuleiten. Auf der Serverseite haben wir also Bilddaten empfangen und openCV verwendet, um das Bild zu verarbeiten und Dinge daraus herauszufinden. Jetzt musste die Serverseite auch Höheninformationen (vom Sonar) und Kompassinformationen kennen.

Die erste Falte war, dass wir die Kamera aus mehreren Gründen nicht von einem Mikrocontroller steuern konnten. Das Hauptproblem war, dass der interne Speicher auf dem uP nicht in der Lage war, einen gesamten Frame zu speichern. Es mag Wege gegeben haben, dies durch geschickte Codierung zu umgehen, aber für die Zwecke dieser Frage tun wir so, als wäre es unmöglich. Um dieses Problem zu lösen, ließen wir die serverseitigen Kamerabefehle über den XBee-Transceiver senden, und der Ausgang des XBee-Empfängers (an Bord des Luftschiffes) war mit dem Eingang der Kamera verbunden.

Die nächste Falte war, dass es nicht genug PWMs auf einem einzelnen ATmega328P gibt, um alle Motoren zu steuern, WEIL die I2C-Schnittstelle einen der PWM-Pins verwendet (verdammt noch mal ...). Deshalb haben wir uns für einen zweiten entschieden. Der Code bot sich ohnehin perfekt für die Parallelverarbeitung an, da die Höhensteuerung völlig unabhängig von der seitlichen Bewegungssteuerung war (also waren 2 Mikros wahrscheinlich besser als eines, das an einen PWM-Controller angeschlossen war). Daher war U1 für 2 PWM-Ausgänge (auf / ab) und das Lesen des Sonars verantwortlich. U2 war verantwortlich für das Lesen des Kompasses, die Steuerung von 6 PWM-Ausgängen (die seitlichen Motoren) und auch für das Lesen des Sonars. U2 war auch für den Empfang von Befehlen vom Server über XBee verantwortlich.

Das führte zu unserem ersten Kommunikationsproblem. Die XBee DOUT-Leitung wurde sowohl an den Mikrocontroller als auch an die Kamera angeschlossen. Jetzt haben wir natürlich ein Protokoll entworfen, damit unsere Mikrobefehle Kamerabefehle ignorieren und Kamerabefehle Mikrobefehle ignorieren, so dass das in Ordnung war. Wenn die Kamera jedoch unsere Mikrobefehle ignoriert, sendet sie NAK-Daten auf ihrer Ausgangsleitung zurück. Da der Befehl für das Mikro bestimmt war, mussten wir den Kameraausgang zum XBee irgendwie ausschalten. Um dies zu lösen, haben wir die Mikrosteuerung 2 FETs hergestellt, die sich zwischen der Kamera und XBee (das ist der erste FET) und auch zwischen U2 und dem XBee (das ist der zweite FET) befanden. Wenn die Kamera versuchte, Informationen an den Server zurückzusenden, war der erste FET eingeschaltet und der zweite FET ausgeschaltet.

Um Ihnen eine Vorstellung davon zu geben, wie dies hier funktioniert hat, sind einige Beispiele:

  1. Server fordert ein Bild an - PIC_REQUEST durchläuft XBee und erreicht U2 und Kamera. U2 ignoriert es und die Kamera sendet Bilddaten zurück.
  2. Der Server hat gerade die Verarbeitung eines Bildes beendet und sendet Motordaten, um Blimp anzuweisen, nach rechts abzubiegen. MOTOR_ANGLE (70) geht durch XBee und erreicht U2 und Kamera. U2 erkennt als Mikrobefehl und schaltet somit den FET der Kamera aus (aber vielleicht hat die Kamera bereits mit einem NAK geantwortet? Wer weiß ...). U2 reagiert dann auf den Befehl durch Ändern der Motor-PWM-Ausgänge. Anschließend wird der FET der Kamera wieder eingeschaltet (dies war die Standardeinstellung, da Bilddaten am wichtigsten waren).
  3. Der Server erkennt, dass wir an einem Punkt im Hindernisparcours angelangt sind, an dem unsere Standard-Schwebehöhe jetzt 90 Zoll statt 50 Zoll betragen muss. SET_HEIGHT durchläuft XBee und es passiert dasselbe wie in Beispiel 2. U2 erkennt den Befehl SET_HEIGHT und löst einen Interrupt an U1 aus. U1 verlässt nun seinen Höhenregelkreis und wartet auf den Empfang serieller Daten von U2. Das ist richtig, mehr serielle Daten. Zu diesem Zeitpunkt ist der FET des U2 eingeschaltet (und der FET der Kamera ist ausgeschaltet), sodass der Server die Höhe empfängt, die U2 auch an U1 sendet. Das war zu Überprüfungszwecken. Jetzt setzt U1 seine interne Variable für height2HoverAt zurück. U2 schaltet jetzt den FET aus und den Kamera-FET wieder ein.

Ich habe definitiv eine Menge Informationen ausgelassen, aber ich denke, das reicht aus, um einige der Komplikationen zu verstehen. Am Ende haben unsere Probleme einfach alles synchronisiert. Manchmal blieben Daten in Puffern übrig, aber nur 3 Bytes (alle unsere Befehle waren 6-Byte-Sequenzen). Manchmal verlieren wir die Verbindung zu unserer Kamera und müssen sie erneut synchronisieren.

Meine Frage lautet also: Welche Techniken würden Sie vorschlagen, um die Kommunikation zwischen all diesen Komponenten zuverlässiger / robuster / einfacher / besser zu machen?

Ich weiß zum Beispiel, dass man eine Verzögerungsschaltung zwischen dem integrierten XBee-Ausgang und der Kamera hinzufügen musste, damit das Mikro die Gesprächsleitung der Kamera ausschalten konnte, bevor es auf Mikrobefehle mit NAKs reagierte. Irgendwelche anderen Ideen?

Vielen Dank und ich bin sicher, dass dies viele Änderungen erfordern wird. Bleiben Sie also auf dem Laufenden.


Edit1:Das Spleißen der UART-Daten der Kamera durch eines der Mikros schien uns nicht möglich zu sein. Es gab zwei Optionen für Kameradaten: Rohbitmap oder JPEG. Für eine rohe Bitmap sendet die Kamera nur so schnell wie möglich Daten an Sie. Der ATmega328P hat nur 128 Bytes für einen seriellen Puffer (technisch ist dies konfigurierbar, aber ich bin nicht sicher, wie) und wir dachten nicht, dass wir ihn schnell genug aus dem Puffer heraus und zum XBee durchbringen könnten. Damit blieb die JPEG-Methode übrig, bei der jedes Paket gesendet wird und darauf gewartet wird, dass der Controller es bestätigt (kleines Handshaking-Protokoll). Die schnellste Geschwindigkeit war 115200 Baud. Aus irgendeinem Grund war die schnellste Möglichkeit, große Datenmengen zuverlässig über den XBee zu übertragen, 57600 Baud (dies gilt auch, nachdem wir die Knoten / Netzwerk-Kopplung durchgeführt haben, um die automatische erneute Sendefunktion zu ermöglichen). Das Hinzufügen des zusätzlichen Stopps in unserem Netzwerk (Kamera zu Mikro zu XBee im Gegensatz zu nur Kamera zu XBee) für das Mikro verlangsamte einfach die Zeit, die für die Übertragung eines Bildes zu viel benötigt wurde. Wir brauchten eine bestimmte Bildwiederholfrequenz für Bilder, damit unser Motorsteuerungsalgorithmus funktioniert.

NickHalden
quelle
3
Sie geben sich viel Mühe, Ihre Mikrocontroller-Fähigkeiten nicht zu erweitern. Ich habe nichts gegen Arduino, aber dafür ist es einfach nicht sehr angemessen. Können Sie es irgendwann zum Laufen bringen? Wahrscheinlich. Es wäre jedoch viel nützlicher, eine leistungsfähigere Plattform zu erlernen. Wenn Sie sich fragen, wie erfahrene Leute dies tun würden, würde ich so etwas wie einen ARM-SBC für openCV und Steuerung und ein FPGA sagen, das als Brücke zu allen Schnittstellen dient. Das wäre jedoch ein kleiner Sprung, also würde ich vorschlagen, nur eine neue wichtige Sache auszuprobieren ... vielleicht ein 32-Bit-Mikro mit genügend Peripheriegeräten, um an alles anzuschließen?
Darron
Haha ja, ich war sehr bemüht. Sehen Sie, dieses Projekt war eine Schulaufgabe und wir wollten uns darauf konzentrieren, es zum Laufen zu bringen, und nicht dazu, dass einer der beiden EEs im Team eine neue Mikrocontroller-Plattform lernt. Ich denke darüber nach, diesen Sommer in ARM & fortgeschrittenere Mikros einzusteigen. Der andere EE in unserem Team hatte tatsächlich eine Klasse in FPGAs besucht ... Ich werde ihn
anschreien,

Antworten:

4

Ich verstehe, dass Sie eine Entwicklungsumgebung wählen wollten, mit der Sie vertraut waren, damit Sie sofort loslegen können, aber ich denke, der Kompromiss zwischen Hardware und Software hat Sie möglicherweise davon abgehalten, bei Arduino zu bleiben und nicht ein Teil auszuwählen, das alles enthält die Hardware-Peripheriegeräte, die Sie benötigen, und schreiben Sie stattdessen alles in Interrupt-gesteuertes C.

Ich stimme dem Vorschlag von @Matt Jenkins zu und möchte ihn gerne erweitern.

Ich hätte ein uC mit 2 UARTs gewählt. Eine mit dem Xbee und eine mit der Kamera verbunden. Die uC akzeptiert einen Befehl vom Server, um ein Lesen der Kamera zu initiieren, und es kann eine Routine geschrieben werden, um Daten vom UART-Kanal der Kamera auf Byte-pro-Byte-Basis zum XBee-UART-Kanal zu übertragen - also kein Puffer (oder höchstens ein sehr kleiner) eins) benötigt. Ich hätte versucht, die anderen uC insgesamt zu eliminieren, indem ich ein Teil ausgewählt hätte, das auch alle Ihre PWM-Anforderungen erfüllt (8 PWM-Kanäle?), Und wenn Sie bei 2 verschiedenen uCs bleiben wollten, die sich um ihre jeweilige Achse kümmern, dann vielleicht a Eine andere Kommunikationsschnittstelle wäre besser gewesen, da alle anderen UARTs verwendet würden.

Jemand anderes schlug auch vor, auf eine eingebettete Linux-Plattform zu wechseln, um alles (einschließlich openCV) auszuführen, und ich denke, das wäre auch etwas zu erforschen gewesen. Ich war schon einmal dort, ein 4-monatiges Schulprojekt, und Sie müssen es nur so schnell wie möglich erledigen. Es kann nicht durch Analyse vor Lähmungen geschützt werden - ich hoffe, es hat sich für Sie als OK herausgestellt!


EDIT # 1 Als Antwort auf Kommentare @JGord:

Ich habe ein Projekt durchgeführt, das die UART-Weiterleitung mit einem ATmega164p implementiert hat. Es hat 2 UARTs. Hier ist ein Bild von einem Logikanalysator-Capture (Saleae USB Logic Analyzer) dieses Projekts, das die UART-Weiterleitung zeigt: Analyseerfassung

Die obere Zeile enthält die Quelldaten (in diesem Fall Ihre Kamera) und die untere Zeile den UART-Kanal, an den weitergeleitet wird (in Ihrem Fall XBee). Die dazu geschriebene Routine behandelte den UART-Empfangsinterrupt. Würden Sie jetzt glauben, dass Sie während dieser UART-Weiterleitung Ihre PWM-Kanäle problemlos konfigurieren und auch Ihre I2C-Routinen verwalten können? Lassen Sie mich erklären, wie.

Jedes UART-Peripheriegerät (für meinen AVR jedenfalls) besteht aus einigen Schieberegistern, einem Datenregister und einem Steuer- / Statusregister. Diese Hardware erledigt die Dinge selbstständig (vorausgesetzt, Sie haben die Baudrate und dergleichen bereits initialisiert), ohne dass Sie eingreifen müssen, wenn:

  1. Ein Byte kommt herein oder
  2. Ein Byte wird in sein Datenregister gestellt und für die Ausgabe markiert

Von Bedeutung ist hier das Schieberegister und das Datenregister. Nehmen wir an, dass auf UART0 ein Byte eingeht und wir diesen Verkehr an die Ausgabe von UART1 weiterleiten möchten. Wenn ein neues Byte in das Eingangsschieberegister von UART0 verschoben wurde, wird es in das UART0-Datenregister übertragen und ein UART0-Empfangsinterrupt wird ausgelöst. Wenn Sie einen ISR dafür geschrieben haben, können Sie das Byte in das UART0-Datenregister aufnehmen und in das UART1-Datenregister verschieben und dann das Steuerregister für UART1 so einstellen, dass die Übertragung beginnt. Dies weist das UART1-Peripheriegerät an, alles, was Sie gerade in sein Datenregister eingegeben haben, in sein Ausgangsschieberegister zu legen und es zu verschieben. Von hier aus können Sie von Ihrem ISR zurückkehren und zu der Aufgabe zurückkehren, die Ihr uC ausgeführt hat, bevor es unterbrochen wurde. Jetzt UART0, Nach dem Löschen des Schieberegisters und dem Löschen des Datenregisters können neue Daten verschoben werden, sofern dies während des ISR noch nicht geschehen ist, und UART1 verschiebt das gerade eingegebene Byte - all dies geschieht am Es ist ohne Ihr Eingreifen, während Ihr uC eine andere Aufgabe erledigt. Die Ausführung des gesamten ISR dauert Mikrosekunden, da wir nur 1 Byte um einen bestimmten Speicher verschieben. Dies lässt genügend Zeit, um andere Dinge zu erledigen, bis das nächste Byte auf UART0 eingeht (was 100 Mikrosekunden dauert). und UART1 verschiebt das Byte, das Sie gerade eingegeben haben - all dies geschieht von selbst ohne Ihr Eingreifen, während Ihr uC eine andere Aufgabe erledigt. Die Ausführung des gesamten ISR dauert Mikrosekunden, da wir nur 1 Byte um einen bestimmten Speicher verschieben. Dies lässt genügend Zeit, um andere Dinge zu erledigen, bis das nächste Byte auf UART0 eingeht (was 100 Mikrosekunden dauert). und UART1 verschiebt das Byte, das Sie gerade eingegeben haben - all dies geschieht von selbst ohne Ihr Eingreifen, während Ihr uC eine andere Aufgabe erledigt. Die Ausführung des gesamten ISR dauert Mikrosekunden, da wir nur 1 Byte um einen bestimmten Speicher verschieben. Dies lässt genügend Zeit, um andere Dinge zu erledigen, bis das nächste Byte auf UART0 eingeht (was 100 Mikrosekunden dauert).

Das ist das Schöne an Hardware-Peripheriegeräten - Sie schreiben einfach in einige speicherabgebildete Register und es kümmert sich um den Rest von dort und signalisiert Ihre Aufmerksamkeit durch Interrupts wie den oben erläuterten. Dieser Vorgang wird jedes Mal ausgeführt, wenn ein neues Byte in UART0 eingeht.

Beachten Sie, dass die logische Erfassung nur eine Verzögerung von 1 Byte aufweist , da wir immer nur 1 Byte "puffern", wenn Sie dies so sehen möchten. Ich bin mir nicht sicher, wie Sie zu Ihrer O(2N)Einschätzung gekommen sind. Ich gehe davon aus, dass Sie die Funktionen der seriellen Arduino-Bibliothek in einer Blockierungsschleife untergebracht haben, die auf Daten wartet. Wenn wir Faktor in dem Overhead mit einem „Lesekamera“ Befehl auf dem uC zu verarbeiten, das interruptgesteuerte Verfahren ist mehr wie O(N+c)die cumfasst die einzelne Byte - Verzögerung und die „Lese - Kamera“ -Anweisung. Dies wäre extrem klein, da Sie eine große Datenmenge senden (Bilddaten richtig?).

All diese Details über das UART-Peripheriegerät (und jedes Peripheriegerät auf dem uC) werden im Datenblatt ausführlich erläutert und sind in C zugänglich. Ich weiß nicht, ob die Arduino-Umgebung Ihnen so wenig Zugriff bietet, dass Sie mit dem Zugriff beginnen können registriert - und das ist die Sache - wenn nicht, sind Sie durch ihre Implementierung eingeschränkt. Sie haben die Kontrolle über alles, wenn Sie es in C geschrieben haben (noch mehr, wenn es in der Montage ausgeführt wird), und Sie können den Mikrocontroller wirklich auf sein wirkliches Potenzial bringen.

Jon L.
quelle
Ich glaube, ich habe das nicht gut erklärt. Das Problem beim Einsetzen des Mikros zwischen Kamera und XBee war, dass das Mikro dann nichts anderes tun kann, während es die Bilddaten erhält, es sei denn, alles andere ist auf Timer-Interrupts. Wenn Sie davon ausgehen, dass das Erhalten eines Bildes mit N Pixeln 5 Sekunden gedauert hat, dauert das Einsetzen des Mikros jetzt ~ 10 Sekunden. Sicher, es ist immer noch O (N), aber es ist wirklich 2N Laufzeit, was in diesem Fall ausreichte, um unser Ziel der Bildwiederholfrequenz zu ruinieren. Letztendlich war der Speicherplatz nicht wirklich der begrenzende Faktor, sondern hauptsächlich die Geschwindigkeit. Seufz, es scheint die einzig richtige Antwort zu sein ...
NickHalden
war fortgeschrittenere Hardware zu verwenden. Ich hatte gehofft, jemand würde etwas wirklich Kluges vorschlagen, das für all meine Jahre als EE als praktischer Trick dienen würde. Na ja, ich denke, das bedeutet zumindest, dass ich nicht zu dumm war, um an den Trick zu denken = P Oh, und es hat ziemlich gut geklappt.
NickHalden
@JGord, durch Zufall habe ich ein Projekt in der Art und Weise unter Verwendung von UART - Weiterleitung , dass ich zwischen einer Chipkarte und einer Waschmaschine mit einem ATmega164 bin beschreiben jonathan-lee.ca/DC18-Smart-Card.html ich spreche Verwenden von UART-ISRs, um ein einzelnes Byte von einem UART-Datenregister in das Datenregister des anderen UART zu verschieben und dann zurückzukehren. Die UART-Hardware agiert unabhängig und verschiebt die Daten von dort heraus. Der ISR benötigt Mikrosekunden und nach seiner Rückkehr kann der uC tun, was er will, bis das nächste Byte verschoben wird. Bessere Erklärungen in einer Bearbeitung, wenn ich nach Hause komme.
Jon L
Interessant. Wäre Ihr Vorschlag also, den Server nur mit dem Mikro sprechen zu lassen? Dann leitet das Mikro Befehle von Server zu Kamera und Antworten von Kamera zu Server weiter? Im UART0 ISR (Ende des Gesprächs mit dem Server) konnte ich also überprüfen, ob es sich um einen Kamerabefehl handelt oder nicht. Wenn ja, spiegeln Sie UART1 zur Kamera. Wenn nicht, spiegeln Sie nicht und ändern Sie stattdessen einen Wert (seitlicher Winkel, Höhe usw. Eine Variable, gegen die mein Regelkreis prüft). Dann würde der ISR von UART1 darin bestehen, die Bilddaten immer einfach auf UART0 zu spiegeln. Ja, ich denke das würde funktionieren. Also wirklich nur ein Mikro mit 2 UARTs bekommen ...
NickHalden
und genug PWM-Kanäle wären der richtige Weg gewesen. Angenommen, der Server hat eine get_data-Anforderung gesendet, auf die das Mikro mit einer 6-Byte-Sequenz antworten soll, in der es eine Höhe, eine Kompassrichtung und einige ECCs sendet. Aus irgendeinem Grund liest der Server 6 Bytes, aber sie haben nicht das richtige Protokoll, dh die Start- und Endnachrichtenbytes stimmen nicht überein. Wer weiß warum? Würden Sie einfach die Nachricht rauswerfen und erneut anfordern oder was? Denn wenn sich wie ein Dummy-Byte im Puffer befand, würde die 6-Byte-Nachricht nie wieder ausgerichtet werden? Würden Sie empfehlen, nach einer fehlgeschlagenen Nachricht zu spülen?
NickHalden
1

Warum konnten Sie die Kameradaten nicht durch den µC leiten? Ich meine nicht, die Bilder zu puffern, sondern die UART-Daten über den µC weiterzuleiten, damit entschieden werden kann, was zurückgesendet werden soll und was nicht?

Am einfachsten, wenn Sie einen µC mit zwei UARTs haben, der jedoch in Software emuliert werden kann.

Majenko
quelle
Hah, ja, das war eines der Dinge, die ich ausgelassen habe ... jetzt Frage bearbeiten. Gute Idee, wir waren ziemlich aufgeregt, als wir auch daran dachten.
NickHalden
1

Eine andere Option ist mir in den Sinn gekommen, aber diese könnte etwas sperrig und zu schwer für Ihr Projekt sein: -

  • Verwenden Sie einen drahtlosen USB-Server, der mit einem kleinen USB-Hub verbunden ist, mit USB-> RS232-Adaptern, um den verschiedenen Teilen des Systems mehrere Steuerkanäle zuzuweisen.

Ja, sperrig, aber wenn Sie sie abstreifen und wenn möglich USB anstelle von RS232 verwenden, könnten Sie möglicherweise damit durchkommen ...

Majenko
quelle