Zeichenroboter
Zeichenroboter
In diesem Projekt bauen Sie einen Roboter, der auf einem Whiteboard zeichnen kann. Wenn Sie fertig sind, kann Ihr Roboter ein Bild eines Whiteboards aufnehmen (oder ein vorhandenes Bild laden), die Linien aus diesem Bild extrahieren, die Zeichnung auf den zeichnungsfähigen Bereich Ihres Whiteboards skalieren und dann die Zeichnung reproduzieren. Dabei lernen Sie wichtige Konzepte aus den Bereichen Technik, Physik und Programmierung kennen, die für eine Vielzahl von Anwendungen nützlich sind.
In den Übungen, aus denen sich dieses Projekt zusammensetzt, werden Sie lernen:
- Sich mit einem Arduino-basierten Roboter aus MATLAB heraus zu verbinden
- MATLAB-Anwendungen, -Funktionen und –Skripte zu schreiben, um Ihren Roboter zu steuern
- Konzepte aus Geometrie, Physik, symbolischer Mathematik und Bildverarbeitung zu verstehen und anzuwenden
- Sie automatisieren einen kompletten Anwendungs-Workflow von Anfang bis Ende.
Bevor Sie mit dem Programmieren beginnen, sollten Sie den Roboter gemäß den Anweisungen, die Sie weiter unten sehen können, montiert haben:
Wenn Sie feststellen, dass das Zahnrad Schritte überspringt oder sich verklemmt, können Sie ein Gummiband an den Stifthalterungen um den Servomotor herum verwenden. In unseren Tests haben wir festgestellt, dass die Verwendung nur eines der mitgelieferten Gummibänder, welches doppelt um die Teile gewunden wird, zuverlässig funktioniert hat.
ÜBUNG 1:
4.1 Einführung in den Drawing Robot
Sobald Sie den Roboter zusammengebaut haben, sollten Sie sich mit Ihrem Roboter verbinden um sicherzustellen, dass Sie alle seine Teile steuern können. In dieser Übung werden alle dafür notwendigen Befehle vorgestellt.
In dieser Übung werden Sie lernen:
- Eine Verbindung zum montierten Roboter herzustellen
- Mit den verschiedenen Komponenten des Roboters zu kommunizieren
Verbindung zum Roboter herstellen
Sie verbinden sich mit Ihrem Roboter, wie Sie es im Abschnitt Erste Schritte getan haben. Verbinden Sie den MKR1000 mit Ihrem Computer und führen Sie den Befehl arduinosetup an der MATLAB-Eingabe aus. Dadurch wird die Arduino Hardware-Setup-Schnittstelle gestartet.
>> arduinosetup
Wählen Sie die Option USB. Klicken Sie auf Next. Fügen Sie auf dem folgenden Bildschirm die Arduino/MKRMotorCarrier-Bibliothek sowie I2C, SPI und Servo hinzu. Wählen Sie aus der Port-Dropdown-Liste den Port, mit dem der Arduino verbunden ist (COM## für Windows, /dev/ttyACM### für Linux, /dev/tty.usbmodem### für OSX). Klicken Sie auf Program, um das Programm auf das Board hochzuladen.
Hinweis: Dies kann einige Minuten dauern. Wenn Sie eine Fehlermeldung erhalten, die sich darauf bezieht, dass die Quelle für die Arduino / MKRMotorCarrier-Bibliothek nicht gefunden wurde, geben Sie edit ArduinoKitHardwareSupportReadMe.txt im MATLAB-Befehlsfenster ein und folgen Sie den Anweisungen in dieser Textdatei.
Wenn der Upload abgeschlossen ist, testen Sie die Verbindung auf dem nächsten Bildschirm mit der Schaltfläche Test Connection. Schließen Sie die Setup-Schnittstelle.
Verbinden mit der Hardware
Zuerst verbinden Sie sich mit dem Arduino Board aus MATLAB. Öffnen Sie das Live-Skript Task1.mlx durch Eingabe:
>> edit Task1
Dann führen Sie den Code Connect to the hardware section aus.
Servo Steuerung
Der Zeichenroboter verfügt über zwei verschiedene Farbmarkierungen, die mittels eines Servomotors angehoben und abgesenkt werden können. In diesem Abschnitt erfahren Sie, wie Sie über die Software die Einschränkungen für den Antrieb des Motors aufgrund der physikalischen Konstruktion des Roboters beherrschen können.
Sie müssen in der Lage sein, mit dem Servomotor zu kommunizieren und ihn anzuweisen, die beiden Markierungen anzuheben und abzusenken. Dies ist ein Trial-and-Error-Prozess, bei dem Sie experimentieren müssen, um die Servopositionen zu bestimmen, die die Marker absenken. Dabei darf der Motor nicht über die Grenzen der Markierungskanäle hinaus bewegt werden.
Das Task1.mlx Live-Skript enthält Code, mit dem Sie sich mit dem Servomotor verbinden und ihn anweisen können, sich zu bewegen. Verbinden Sie sich zunächst mit dem Motor, indem Sie die Abschnitte unter der Überschrift Control the servo im Live-Skript Task1.mlx ausführen.
Der folgende Codeabschnitt enthält eine numerische Schieberegler-Steuerung, die die pos Variable definiert. Wann immer Sie den Wert des Schiebers ändern, wird dieser Codeabschnitt ausgeführt und befiehlt dem Servo, eine neue Position anzufahren. Um die Einschränkungen für die Position herauszufinden, müssen Sie den Wert von pos in kleinen Schritten ändern, bis Sie feststellen, dass die Servoposition dem vollständig abgesenkten Whiteboard-Marker entspricht. Nehmen Sie diesen Wert auf und wiederholen Sie dann den Vorgang für den anderen Marker. Da der Roboter nur einen Servomotor zum Steuern beider Markierungen verwendet, müssen Sie lediglich die Position schrittweise in die andere Richtung ändern, bis Sie die Servoposition zum Absenken dieses Markers finden. Wenn Sie den Roboter gemäß der Montageanleitung montiert haben, sollte der linke Marker an einer Servoposition um 0,6 und der rechte Marker an einer Position um 0 abgesenkt werden, und Sie sollten nach der Aufnahme dieser Werte auch überprüfen, ob ein Wert von pos in der Mitte zwischen diesen beiden Extremen beide Marker oben positioniert. Auf diese Weise haben Sie einen einzigen physischen Treiber, den Servomotor, um drei verschiedene Zustände des Zeichenmechanismus zu steuern: kein Marker zeichnet, Marker 1 zeichnet oder Marker 2 zeichnet.
Geben Sie im letzten Codebereich unter der Überschrift Steuerung des Servos Ihre experimentell ermittelten Werte für die Servoposition beim Absenken des linken und rechten Whiteboard-Markers ein. Siehe folgenden Screenshot, welche Werte aktualisiert werden sollen. Führen Sie diesen Codeabschnitt aus, um diese Werte in einer MAT-file zu speichern, damit Sie sie für zukünftige Übungen laden können.
Steuerung des Gleichstrommotors
Nachdem Sie die Whiteboard-Marker gesteuert haben, ist der nächste Schritt, herauszufinden, wie man die beiden Gleichstrommotoren steuert. Diese bewegen den gesamten Zeichenroboter über das Whiteboard.
In diesem Versuch verbinden Sie MATLAB mit den Motoren und den Encodern der Motoren. Sie bestimmen die Versorungsspannung der Motoren und betreiben die Motoren für etwa drei Sekunden. Lesen Sie zunächst die Abschnitte von Task1.mlx unter der Überschrift Control the DC motors. In diesem Code ist Vset eine Soll-Motorspannung und Vmax ist die Batteriespannung. Diese Parameter werden verwendet, um einen Drehzahlwert (Speed Value) für die Motoren zwischen 0 und 1 zu berechnen. Der Wert 1 ist dabei die maximale Drehzahl und 0 steht für keine Spannung Motor. Führen Sie jeden der Abschnitte des Live-Skripts unter der Überschrift Control the DC motors aus.
Auslesen des Encoder
Wie Sie inzwischen wissen, benötigen DC-Motoren externe Steuermechanismen, um sicherzustellen, dass sie sich wie erwartet verhalten. In diesem Fall werden wir Drehgeber verwenden, um den Winkel und die Drehzahl der Motoren während des Betriebs zu messen. Nachdem Sie die Motoren aus ihren Ausgangspositionen verschoben haben, können Sie den Zählwert von den Encodern ablesen, um festzustellen, wie weit sich jeder Motor gedreht hat (Einheit: Encoderzahl). Die Umrechnung von Encoderzahl in physikalische Entfernungen wird in einer späteren Übung gezeigt. Führen Sie den Code im Abschnitt Read the encoder des Live-Skripts Task1.mlx aus.
Files
- Task1.mlx
Learning by Doing
Erstellen Sie ein neues MATLAB-Skript. Schreiben Sie eine Reihe von Befehlen, die den linken Motor drei Sekunden lang laufen lassen und dann stoppen. Danach den rechten Motor drei Sekunden drehen lassen. Anschließend sollen die Motoren in der gleichen Reihenfolge drei Sekunden in der gegengesetzten Drehrichtung bewegt werden um schließlich zu stoppen. Führen Sie Ihr Skript aus und überprüfen Sie, ob es wie erwartet funktioniert. Lesen Sie die Zählerstände von jedem der Encoder ab. Wie nah sind die Motoren an ihren Ausgangspositionen? Was könnte den Unterschied ausmachen? Setzen Sie die Encoderzahl zurück und führen Sie das Skript erneut aus, um zu sehen, wie konsistent dieses Ergebnis ist.
Hängen Sie den Roboter an das Whiteboard. Der linke Motor soll sich mit einer Spannung von 4 Volt für 2 Sekunden vorwärts drehen und anschließend mit einer Spannung von -4 für 2 Sekunden entgegengesetzt drehen. Wie weit hat es sich der Roboter jedes Mal bewegt? In welche Richtung hat es sich schneller bewegt? Warum? Inwiefern unterscheidet sich das Verhalten vom Verhalten eines flach auf dem Tisch liegenden Roboters?
ÜBUNG 2:
4.2 Whiteboard-Koordinatensystem
In dieser Übung definieren Sie Koordinaten, die die Position des Roboters auf dem Whiteboard beschreiben. Sie hängen den Roboter an das Whiteboard und bewegen ihn mit einer App. Anschließend berechnen Sie die neue Position des Roboters in x-y-Koordinaten basierend auf Encodermessungen.
In dieser Übung werden Sie lernen:
- wie Sie integrierte UI-Funktionen verwenden, um Benutzereingaben zu erhalten
- wie Sie Geometriekonzepte auf die Programmierung anwenden
- wie Sie MATLAB-Anwendungen nutzen
- wie Sie MATLAB-Funktionen schreiben.
Definieren Sie Koordinaten auf dem Whiteboard
Stellen Sie sich vor, Sie hängen den Roboter auf das Whiteboard. Definieren Sie die Werte x, y, Base, Z1 und Z2 wie in der folgenden Abbildung dargestellt. Die schwarzen Kreise auf beiden Seiten des Diagramms stellen die Riemenscheiben dar, an denen Sie den Roboter aufhängen. Der Roboter befindet sich in der Mitte des Bildes und hängt an zwei Strängen, die mit den Roboterarmen verbunden sind. An den Roboterarmen sind die Motoren angeordnet. Beachten Sie, wie die Schnüre vom Roboterarm zur Riemenscheibe und zurück zum Motor führen. Beachten Sie auch, dass die x- und y-Positionen auf der Tafel in Bezug auf die linke Riemenscheibe gemessen werden. Dabei ist x der horizontale Abstand rechts von der Riemenscheibe und y der vertikale Abstand zwischen der Verbindungslinie der Aufhängungen und den Whiteboard-Markern ist.
Wir können ${ Z1}$ in den Motorarm $L_{\text{arm}}$ teilen und dann von der Schnur vom Motor zur Riemenscheibe (${ L1}$) führen. Wir werden das Gleiche für ${ Z2}$ mit $L_{\text{arm}}$ und ${ L2}$ tun.
Der Satz des Pythagoras zur Positionsberechnung
Bevor wir mit der Bewegung des Roboters beginnen, müssen wir ${ Base}$, ${ L1}$, und ${ L2}$ messen. Wir werden einen bekannten Wert von $L_{\text{arm}}$ verwenden, um ${ Z1}$ und ${ Z2}$ . zu berechnen. Während sich der Roboter auf dem Whiteboard bewegt, werden wir ${ Z1}$ und ${ Z2}$ basierend auf den Encodermessungen aktualisieren. Um die Werte von ${x}$ und ${y}$ zu erhalten, können wir diese bekannten Werte von ${ Z1}$, ${ Z2}$ und Base zusammen mit dem Pythagoreischen Satz verwenden. Wenn Sie eine senkrechte Linie vom Marker auf die Linie zwischen den beiden Riemenscheiben projizieren, entstehen zwei rechtwinklige Dreiecke. (siehe folgendes Diagramm)
Die Seiten der Dreiecker verhalten sich wie folgt.
$Z_1^2=x^2+y^2$
$Z_2^2=({Base}-x)^2+y^2$
Wenn wir die zweite Gleichung für ${ y^2}$ lösen, kann die erste Gleichung umgestellt werden in
$Z_1^2=x^2+[Z_2^2-({Base}-x)^2]$
Wenn wir diese Gleichung erweitern und für x lösen, kommen wir zu den folgenden Gleichungen. Damit können wir jeweils x und y sequentiell errechnen.
$x=\frac{{Base}^2+Z_1^2-Z_2^2}{2\ast {Base}}$
$y=\sqrt{Z_1^2-x^2}$
Eingabedialoge verstehen
Eine einfache Möglichkeit, einem Benutzer die Interaktion mit Ihrem MATLAB-Programm zu ermöglichen, besteht in einem Dialogfeld (dialog box). Dialog boxen sind einfache Anwendungen, die Nachrichten anzeigen, die Dateneingabe ermöglichen oder dem Benutzer die Interaktion mit dem Dateisystem ermöglichen können. In der MATLAB-Dokumentation zu Dialog Boxes finden Sie eine Liste der in MATLAB verfügbaren dialog boxes. Um Eingaben von einem Benutzer anzufordern, verwenden Sie einen Eingabedialog. Diese kann mit der Funktion inputdlg erstellt werden. Es gibt mehrere Optionen für die Konfiguration dieses Dialogfensters. Daher sollten Sie die Dokumentation dazu lesen, um die verfügbare Syntax besser zu verstehen. Öffnen Sie die Dokumentationsseite direkt aus der MATLAB-Befehlszeile, indem Sie Folgendes eingeben:
>> doc inputdlg
Lesen Sie die Abschnitte Syntax und Description auf dieser Dokumentationsseite, um alle zulässigen Eingabeargumente für diese Funktion zu verstehen.
Scrollen Sie dann nach unten zum Abschnitt Examples. Einer der Vorteile, die das Öffnen der Dokumentation aus MATLAB heraus gegenüber dem Online-Betrieb bietet, besteht darin, dass Sie Beispiele direkt von der Dokumentationsseite aus ausführen können. Markieren Sie den Code aus Example 1, klicken Sie dann mit der rechten Maustaste und wählen Sie Evaluate Selection.
Geben Sie beim Start des Dialogs neue Werte für die Matrixgröße und den Namen der Farbkarte ein. Klicken Sie auf OK.
Kehren Sie zum MATLAB Command Window zurück. Beachten Sie, dass der von Ihnen ausgewertete Beispielcode sowohl hier als auch in Ihrer Command Historyangezeigt wird. Beachten Sie auch, dass es eine neue answer-Variable im Arbeitsbereich gibt. Überprüfen Sie den Wert.
Versuchen Sie nun, den Code aus anderen Beispielen auszuführen oder schreiben Sie Ihren eigenen Code um Eingaben von einem Benutzer anzufordern. Im nächsten Abschnitt werden Sie einen Eingabedialog verwenden, um die Robotermessungen zu aktualisieren, ohne dass Sie Ihren Code bei jeder Ausführung bearbeiten müssen.
Eine Ausgangsposition definieren
Öffnen Sie das Live-Skript Task2.mlx, indem Sie in das Command Window eingeben:
>> edit task2
Messen Sie die Abstände von Base, L1 und L2 auf Ihrem Roboter mit einem Messstab, Lineal oder Bandmaß. Folgen Sie dann den Anweisungen der ersten vier Abschnitte von Task2.mlx unter der Überschrift Find starting position und geben Sie diese Werte gegebenenfalls ein. Bitte beachten Sie, dass alle Messungen in Metern angegeben werden sollten. Auf diese Weise können Sie die Start-x-y-Position des Roboters auf dem Whiteboard berechnen.
Verbindung mit der Hardware und zeichnen auf dem Whiteboard
Wie in der vorherigen Übung, verbinden Sie sich nun mit dem Arduino und steuern die Motoren. Diesmal werden Sie jedoch eine interaktive Anwendung (oder App) in MATLAB verwenden, um die Motoren zu starten und zu stoppen und ihre Spannungen festzulegen. MATLAB-Anwendungen verfügen in der Regel über eine grafische Benutzeroberfläche und Code, um eine bestimmte Aufgabe auszuführen. Das Zeichenroboterprojekt stellt eine App namens SimplePlotterApp zur Verfügung, mit der die Motoren des Roboters interaktiv gesteuert werden können. Führen Sie den Code im Abschnitt Connect to the hardware und Draw on the whiteboard sections im Live-Skript Task2.mlx aus. Dadurch wird eine App mit Schaltflächen gestartet, mit der Sie jeden der Motoren interaktiv starten und stoppen und seine Geschwindigkeit ändern können. Achten Sie darauf, dass Sie die Motoren nicht zu schnell bewegen oder den Roboter bis zur Oberseite des Whiteboards ziehen, wo die Motoren stehen bleiben können.
Berechnen einer neuen Roboterposition
Mit den bisher vorliegenden Informationen ist es nun möglich, die neue Position des Roboters auf dem Whiteboard in x-y-Koordinaten zu berechnen. Sie können nun die neuen Encoderzahlen ablesen, diese Werte in Winkel umwandeln und dann diese Winkel in Abstände umwandeln. Schließlich können Sie mit der Robotergeometrie die Abstände auf dem Whiteboard in eine x-y-Position umwandeln. Lesen Sie zunächst den aktuellen Zählwert für die beiden Encoder ab. Sie können dann die Hardware-Variablen in MATLAB löschen, da Sie sie für diese Übung nicht mehr benötigen. Führen Sie die ersten beiden Abschnitte von Task2.mlx unter der Überschrift Calculate new robot position aus. Führen Sie dann diese Abschnitte aus.
Sie haben die Motorpositionen in Zähleinheiten. Wie wird diese in eine x-y-Position umgewandelt? Erstens können Sie die Position in eine Winkelposition umwandeln. Sie kennen die Anzahl der Zählungen pro Umdrehung aus dem Motordatenblatt. Die Winkellage des Motors wird daher wie folgt berechnet:
$C_{{rad}}\frac{{counts}}{{rad}}=\left(1204.44\frac{{counts}}{{rev}}\right){\cdot}\left(\frac{{rev}}{2\pi {rad}}\right)$
$\theta =\frac{C{counts}}{C_{{rad}}\frac{{counts}}{{rad}}}$
Die Menge der von den Motoren aufgespulten oder abgewickelten Schnur hängt vom Winkel ab, um den sie sich gedreht haben, und dem Radius der Spule ab. Somit kann man sie mit der Definition der Bogenlänge berechnen.
${\Delta}{StringLength}=r_{{spool}}\cdot\theta$
Beim Roboter verläuft die Schnur über die Riemenscheibe und zurück zum Roboterkörper. Da die Schnur verdoppelt wird, entspricht die resultierende Abstandsänderung zu den Riemenscheiben (Z1 oder Z2) der Hälfte der Änderung der gesamten Schnurlänge. Aus dieser Beziehung kann die neuen Z-Längen berechnet werden.
${\Delta}Z=\frac{{\Delta}{StringLength}} 2$
$Z={\Delta}Z+Z_i$
Die neue Roboterposition wird vollständig durch die Längen der Basis, Z1 und Z2 definiert. Wie bereits zuvor in dieser Übung, können diese Werte verwenden werden, um die aktuellen Werte von x und y zu berechnen.
$x=\frac{{Base}^2+Z_1^2-Z_2^2}{2\ast {Base}}$
$y=\sqrt{Z_1^2-x^2}$
Um diese Berechnungen im Code durchzuführen, führen Sie die restlichen Abschnitte von Task2.mlx unter der Überschrift Calculate new robot position aus.
Code in Funktionen einbauen
Wir werden einige der in dieser Übung durchgeführten Aufgaben in Zukunft noch einmal wiederholen wollen. Um unseren Code besser zu organisieren, Wiederholungen zu reduzieren und diese Probleme in Zukunft einfach zu lösen, können wir MATLAB-Funktionen erstellen, die bestimmte Aufgaben erfüllen.
Schreiben Sie zunächst eine MATLAB-Funktion, um die Messungen der Länge der Schnur vom Benutzer anzufordern. Wählen Sie im MATLAB Desktop New>Script. Dadurch wird eine leere MATLAB-Datei erstellt. Geben Sie den folgenden Code ein und speichern Sie die Datei als initialPosition.m.
function Z_i = initialPosition()
str = inputdlg({'L1 (meters)','L2 (meters)'},'Enter initial string lengths.',[1 50]);
L1_i = str2double(str{1}); %meters
L2_i = str2double(str{2});%meters
L_arm = 0.075; %meters Z_i = [L1_i L2_i] + L_arm; %meters
Probieren Sie es aus. Rufen Sie Ihre neue Funktion im MATLAB Command Window auf, geben Sie die Werte für die Schnurlänge ein, klicken Sie auf OK und beobachten Sie das Ergebnis.
>> Z_i = initialPosition
Beachten Sie, dass wir jetzt eine einzige Variable Z_i verwenden, die sowohl Z1_i als auch Z2_i enthält. Diese Variable hat die Größe 1x2 und kann mit der Syntax Z_i(1) und Z_i(2) indiziert werden, um ihre Komponenten zu extrahieren. Lassen Sie uns auch unsere Variablen counts1 und counts2 zu einer einzigen Variablenanzahl zusammenfassen. Dies wird unseren Code sehr vereinfachen. Führen Sie die folgende Zeile an der MATLAB-Befehlszeile aus, um die Variable counts zu erstellen.
>> counts = [counts1 counts2]
Schreiben Sie anschließend eine Funktion zur Umrechnung der gemessenen Encoder-Zählungen in eine x-y-Position auf der Pinnwand. Erstellen Sie eine neue Funktion namens countsToXY.m und fügen Sie den folgenden Code ein.
funcfunction xy = countsToXY(counts,Z_i,Base) % Define constants
countsPerdRadian = countsPerRevolution/(2*pi);
r_spool = 0.0045; % Convert counts to angle
phi = counts/countsPerRadian; % Convert angle to change in string length
dStringLength = r_spool*phi; % Convert change in string length to change in Z
dZ = dStringLength/2; %Add change in Z to initial Z to get current Z
z = z_i + dz; % Compute x and y from Z1 and Z2
x = (Base^2 + z(1)^2 - z(2)^2)/(2*Base);
y= sqrt(z(1)^2-x^2); xy = [x y];
end
Vergewissern Sie sich, dass sich diese Funktion korrekt verhält. Sie sollten immer noch die Variablen Counts, Z_i und Base in Ihrem Arbeitsbereich haben. Führen Sie Folgendes an der Eingabeaufforderung aus und überprüfen Sie, ob die x-y-Position korrekt ist.
>> xy = countsToXY(counts,Z_i,Base)
FILES
- Task2.mlx2
- countsToXY.m
- initialPosition.m
LEARN BY DOING
Wenn Sie im Eingabefenster auf Cancel statt OK klicken, was passiert dann? Was passiert, wenn Sie den Code weiter ausführen? Ist es das, was Sie erwarten würden? Beschreiben Sie das gewünschte Verhalten und wie Sie Ihren Code schreiben würden, dass er sich ebenso verhält, wenn ein Benutzer auf die Schaltfläche Cancel klickt. Verwenden Sie nur die SimplePlotterApp-App und versuchen Sie, den Roboter zu steuern und eine Form zu zeichnen. Welche Formen lassen sich leicht zeichnen? Welche Formen sind schwierig?
Führen Sie ein Experiment durch, um den Radius der Spule zu messen. Setzen Sie den Geber zurück. Dann schreiben Sie ein Skript, das den Motor für ein paar Sekunden in die Richtung dreht, dass die Schnur abgewickelt wird. Halten Sie die Schnur fest und lassen Sie sie nicht vom Rand der Spule rutschen. Wenn der Motor stoppt, messen Sie (mit einem Lineal), wie viel Schnur herausgelassen wurde. Lesen Sie die Encoderzahl aus, um zu sehen, wie weit der Motor gedreht hat, und wandeln Sie diesen Wert in einen Winkel um. Verwenden Sie nun die Gleichung für die Bogenlänge, um zu berechnen, wie der Radius für einen Kreis sein muss, der diese Fadenlänge aufwickelt und sich um diesen Winkel gedreht hat. Vergleichen Sie Ihren experimentell bestimmten Radius mit dem in der Übung angegebenen Radius.
ÜBUNG 3:
4.3 Bewegen zu bestimmten Punkten auf dem Whiteboard
In dieser Übung wählen Sie bestimmte Positionen auf dem Whiteboard aus und bewegen den Roboter zu ihnen. Sie werden komplexere MATLAB-Funktionen kennenlernen und diese Funktionen zur Steuerung des Roboters nutzen. An Ende werden Sie einen kurzen Algorithmus erhalten, der den Marker anheben und absenken und mit dem Sie einfache Formen zeichnen können.
In dieser Übung werden Sie lernen zu:
- Einfache MATLAB-Algorithmen zu entwickeln
- Vektorisierten Code zu schreiben
- Verschachtelte Ablaufsteuerung zu verwenden (for, while, break)
Wählen Sie eine Position auf dem Whiteboard die angesteuert werden soll
Lassen Sie uns mit der nächsten Übung fortfahren. Hängen Sie den Roboter an das Whiteboard und achten Sie darauf, dass sich beide Riemenscheiben über der gleichen horizontalen Linie befinden. Wählen Sie eine Zielposition auf dem Whiteboard, an die Sie den Marker verschieben möchten. Stellen Sie sicher, dass es sich um einen Punkt handelt, der für den Roboter erreichbar ist. Messen Sie die x- und y-Koordinaten dieses Punktes mit dem Whiteboard-Koordinatensystem, wobei x der horizontale Abstand rechts von der linken oberen Riemenscheibe und y der vertikale Abstand nach unten von der Verbindungslinie der Riemenscheiben ist. Öffnen Sie das Live-Skript Task3.mlx.
>> edit Task3
Im ersten Teil die sogenannte Choose position to move to in x-y auswählen, zu der in x-y bewegt werden soll. Ersetzen Sie die Werte von x und y durch die Werte für den Punkt, zu dem Ihr Roboter fahren soll. Achten Sie darauf, dass alle Messungen der Koordinaten in Metern erfolgen. Führen Sie diesen Abschnitt aus.
Zielposition in Encoderwerte umwandeln
Als nächstes verwenden Sie die gleichen Beziehungen zwischen Werten, Winkeln und Whiteboardabständen, die Sie in der vorherigen Übung verwendet haben. Anstatt jedoch gemessene Werte zu nehmen und eine x-y-Koordinate zu berechnen, wählen Sie eine x-y-Zielkoordinate und berechnen die Encoderwerte für diese Position. Dafür verwenden Sie die gleichen Gleichungen wie bei der vorherigen Übung. Sie kehren aber die Reihenfolge um. Ausgehend von der x-y-Koordinate können Sie mit dem Pythagoras-Satz die Längen Z1 und Z2 berechnen.
$Z_1=\sqrt{x^2+y^2}$
$Z_2=\sqrt{\left({Base}-x\right)^2+y^2}$
Dann können Sie die Änderungen in Z berechnen und in eine Änderung der Schnurlänge umwandeln.
${\Delta}Z=Z-Z_i$
${\Delta}{StringLength}=2{\cdot}{\Delta}Z$
Die Bogenlängendefinition ermöglicht es Ihnen, die Längenänderung in eine Winkeländerung der Motorspule umzuwandeln.
$\theta =\frac{{\Delta}{StringLength}}{r_{{spool}}}$
Sie wenden schließlich das bekannte Verhältnis der Schritte pro Bogenmaß an, um den gewünschten Schrittwert für jeden Motor zu berechnen.
$C=\theta {rad}{\cdot}C_{{rad}}\frac{{counts}}{{rad}}$
Um diese Berechnungen im Code durchzuführen, führen Sie die Codeabschnitte unter der Option Convert target position to encoder counts in den Task3.mlx ein.
Entwickeln einer Funktion zum Konvertieren der Position in Motordrehungen
Wie in der vorherigen Übung können Sie den Code, den Sie geschrieben haben, um ein bestimmtes Problem zu lösen, in eine Funktion einbauen. Genau wie bei der Konvertierung von Schritten in Positionen können Sie nun eine Funktion schreiben, die Positionen in Schritte umwandelt. Erstellen Sie eine neue Funktion namens xyToCounts.m und fügen Sie den folgenden Code ein.
function counts = xyToCounts(xy,Z_i,Base)
% Define constants
r_spool = 0.0045;
countsPerRevolution = 1200;
countsPerRadian = countsPerRevolution/(2*pi);
% Convert x and y to Z1 and Z2
x = xy(:,1);
y = xy(:,2);
Z(:,1) = sqrt(x.^2 + y.^2);
Z(:,2) = sqrt((Base-x).^2 + y.^2);
% Subtract initial Z to get change in Z
dZ = Z - Z_i;
% Convert change in Z to change in string length
dStringLength = 2*dZ;
% Compute change in string length to angle
phi = dStringLength/r_spool;
% Convert angle to counts
counts = phi*countsPerRadian;
Beachten Sie, dass es einen kleinen Unterschied zwischen dem Code in dieser Funktion und dem Code gibt, den Sie in Task3.mlx ausgeführt haben. Hier indizieren wir die Variablen xy und Z mit Indizes (:,1) und (:,2) in den folgenden Zeilen:
x = xy(:,1);
y = xy(:,2);
Z(:,1) = hypot(x,y);
Z(:,2) = hypot(Base-x,y);
Diese Syntax ermöglicht es Ihnen, auf alle Werte in der ersten bzw. zweiten Spalte dieser Variablen zu verweisen. Dies ermöglicht es Ihnen, die xyToCounts-Funktion nicht nur auf eine x-y-Koordinate zu verwenden, sondern auf einen Satz von x-y-Positionen, die in einem Nx2-Array definiert sind. Dabei hat die erste Spalte alle x-Positionen und die zweite Spalte alle y-Positionen. Sie werden am Ende dieser Übung ein Beispiel dafür anwenden können. Speichern Sie die Funktion xyToCounts.m und testen Sie sie dann, indem Sie den Abschnitt von Task3.mlx mit dem Header Convert position to counts using a function ausführen. Stellen Sie sicher, dass die Werte für die Schritte die gleichen sind, die Sie zuvor erhalten haben. Dies wird beweisen, dass Ihre Funktion wie erwartet funktioniert.
Konzept: für Schleifen, if-Anweisungen und break-Anweisungen
Es gibt mehrere Arten von Ablaufsteuerungsstrukturen, die beim Schreiben von Code wichtig sind. In diesem Abschnitt werden wir nach Schleifen, while-Schleifen, if-Anweisungen und dem Schlüsselwort break suchen. Eine for-Schleife wird verwendet, wenn Sie einen Abschnitt Ihres Codes mehrmals für eine bestimmte Anzahl ausführen möchten. Wenn Sie wissen, dass Sie eine Schleife 5 mal ausführen möchten, können Sie eine for-Schleife mit einer Schleifenvariablen im Bereich von 1 bis 5 schreiben. Beachten Sie den folgenden Code:
for ii = 1:5
disp("Iteration " + ii)
end
Erstellen Sie eine neue MATLAB-Datei und führen Sie den obigen Code in MATLAB aus. Sie sehen die folgende Ausgabe.
Iteration 1
Iteration 2
Iteration 3
Iteration 4
Iteration 5
Stellen Sie sich vor, Sie wissen nicht im Voraus, wie oft Sie Ihren Code wiederholen möchten. Vielleicht möchten Sie etwas laufen lassen, bis eine Bedingung erfüllt ist. Dazu kannst du eine while-Loop verwenden. Die Bedingung einer while-Loop wird durch logische Ausdrücke definiert. Führen Sie den folgenden Code m MATLAB Command Window aus, um zu sehen, wie diese logischen Ausdrücke funktionieren.
>> x = 1
>> x > 64
>> x = 100
>> x > 64
Sie sollten die folgende Ausgabe sehen.
Ein logischer Ausdruck in MATLAB ist einer, der einen logischen Wert von 1 oder 0 (wahr oder falsch) zurückgibt. In einer While-Loop läuft die Schleife so lange weiter, wie die Bedingung 1 (true) zurückgegeben wird. Wenn die Bedingung fehlschlägt und 0 (falsch) zurückgegeben wird, endet die Schleife. Ersetzen Sie den Code in der Code-Datei, in der Sie eine for-Loop geschrieben haben, durch Folgendes:
x = 1;
while x < 64
x = x*2;
disp("Current value of x: " + x)
end
Anstatt die Schleife nun eine bestimmte Anzahl auszuführen, führen Sie sie aus, bis die logische Bedingung x < 64 nicht mehr wahr ist. Wenn Sie diesen Code in MATLAB ausführen, sollten Sie die folgende Ausgabe sehen:
Current value of x: 2
Current value of x: 4
Current value of x: 8
Current value of x: 16
Current value of x: 32
Current value of x: 64
Eine if-Anweisung ist eine andere Ablaufsteuerungsstruktur, die eine logische Bedingung überprüft. Sie wird einmalig ausgeführt, wenn die Bedingung wahr ist, aber nicht bei falscher Bedingung. Ersetzen Sie Ihre while-Loop durch den folgenden Code. Ändern Sie die erste Zeile in verschiedene Werte und führen Sie den Code aus, um zu sehen, wann die Anzeigezeile ausgeführt wird oder nicht.
x = 1;
if x > 5
disp("x = " + x + " passed the test")
end
Ändern Sie den Wert von x auf 6 und führen Sie den Code erneut aus. Welche Ergebnisse erhalten Sie?
Eine while-Loop überprüft ihren Status jedes Mal, wenn sie das Ende der Schleife erreicht und erneut beginnt. Manchmal möchten Sie vielleicht, dass die Schleife irgendwo in der Mitte endet, sobald eine Bedingung erfüllt ist. Dies ist mit dem Schlüsselwort break möglich. Aktualisieren Sie Ihren Code wie folgt:
x = 1;
while true
x = x* 2;
if x >= 64
break
end
disp("Current value of x: " + x)
end
Die Bedingung der while-Loop wird auf wahr gesetzt, so dass diese Schleife nie beendet würde, wenn sie nicht den break-Befehl erreicht hätte. Wenn jedoch die Bedingung der if-Anweisung erfüllt ist, wird die Schleife sofort unterbrochen, ohne den Rest des Codes auszuführen. Was wird Ihrer Meinung nach die letzte angezeigte Ausgabezeile sein? Führen Sie den Code aus, um Ihre Vorhersage zu überprüfen.
Im nächsten Abschnitt sehen Sie eine Funktion, die diese Konzepte verwendet, um den Whiteboard-Roboter zu verschiedenen Punkten zu fahren und die Schleife sofort zu verlassen, wenn er seinen Zielpunkt erreicht hat.
Die Funktion moveToCounts, Zeile für Zeile
Um den Roboter durch eine Reihe von vorgegebenen Positionen zu bewegen, die in Endcoder-Zählungen bestimmt sind, steht Ihnen die Funktion moveToCounts zur Verfügung. Lesen Sie die folgende Beschreibung der Teile der Funktion durch, um zu sehen, wie sie kontinuierlich die aktuelle Position gemessen und die Sollgeschwindigkeit jedes Motors aktualisiert wird, wodurch der Roboter in die richtige Richtung bewegt wird. Die Werte für die Parameter wRef und hitRadius haben bei unseren Tests gut mit dem Roboter funktioniert. Sie können die Funktion bearbeiten und anpassen, um den Roboter auf Ihre Gegebenheiten abzustimmen, indem Sie Ihre Werte als Startpunkt verwenden.
Bei dieser Funktion wird eine Liste von Encoder-Zählungen erstellt, zu denen der Roboter bewegt wird.
Sie verwendet auch die Variablen für vorhandene Motore und Encoder.
function moveToCounts(counts,m1,m2,e1,e2)Legen Sie eine Soll-Winkelgeschwindigkeit für die Motoren fest, wRef. Legen Sie eine maximale Entfernung
zum Zielpunkt fest, hitRadius. Starten Sie die Motoren.
wRef = 20; %rpm
hitRadius = 20; %counts
start(m1)
start(m2)Richten Sie eine for-Schleife ein, die sich durch alle Zielpunkte bewegt. Definieren Sie in jeder
Iteration den Zielpunkt als countTarget.
% Loop through all points
nPoints = size(counts,1);
for ii = 1:nPoints
% Determine destination point
countTarget = counts(ii,:);Verwenden Sie eine while-Schleife, um den Roboter weiter zu bewegen, bis er am Zielpunkt ist.
Messen Sie in dieser Schleife zunächst die aktuelle Position.
% Loop until at destination
while true
% Update count measurement
countNew = [readCount(e1) readCount(e2)];Vergleichen Sie die aktuelle Position mit der Zielposition. Wenn die Entfernung kleiner als hitRadius ist,
brechen Sie sofort die while-Schleife ab.
% Check distance to final position and break if close enough
countRemain = countTarget - countNew;
countNorm = sqrt(sum((countRemain).^2));
if countNorm <= hitRadius
break
endWenn sich der Roboter noch nicht am Zielpunkt befindet, normalisieren Sie die verbleibenden Entfernungen
und skalieren Sie mit der Sollgeschwindigkeit. Diese Geschwindigkeiten werden mit der setSpeed-Methode
auf jeden Motor angewendet.
% Compute and set target angular speed for each motor
wSet = (countRemain/countNorm)*wRef;
stop(m1),start(m1),setSpeed(m1,round(wSet(1)));
stop(m2),start(m2),setSpeed(m2,round(wSet(2)));
endWenn alle Zielpunkte erreicht wurden, beenden Sie die for-Loop und stoppen Sie die beiden Motoren.
end
stop(m1)
stop(m2)
endBewegen des Roboters in die Zielposition
mit Anbindung an die Hardware, Motoren und Encoder von MATLAB. Verwenden Sie dabei die moveToCounts Funktion um den Roboter zur festgelegten x-y_Position zu bewegen. Dazu führen Sie den Code in den Abschnitten Connect to Hardware und Move to target position von Task3.mlx aus.
Bewegen des Roboters zu eíner neuen Zielposition
Sie können nun den Roboter anweisen, sich an verschiedene Stellen auf dem Board zu bewegen. Dies erfordert nur noch ein paar Zeilen Code, da Sie nun die Funktionen xyToCounts und moveToCounts haben. Wählen Sie im Codebereich mit dem Namen Move to new target position neue Werte für x und y. Führen Sie dann diesen Abschnitt aus, um den Roboter dorthin zu bewegen. Sie können dies mehrfach mit anderen x- und y-Positionen durchführen.
Bewegen des Roboters auf eine Abfolge von Positionen
Die Funktionen xyToCounts und moveToCounts können auch Listen von Punkten aufnehmen. Wenn Sie Ihre Ziel-x-y-Punkte als Nx2-Array definieren, wobei die erste Spalte die x-Koordinaten und die zweite Spalte die y-Koordinaten enthält, können Sie den Roboter anweisen, sich zu einer Reihe von Punkten zu bewegen. Der Abschnitt Move to a sequence of positions in Task3.mlx enthält ein Beispiel für Koordinaten, die ein Rechteck bilden. Überprüfen Sie, ob diese Punkte in den Zeichenbereich Ihres Whiteboards fallen und ändern Sie sie, wenn sie nicht fallen. Beachten Sie, dass dieser Code auch eine Reihe von Aktionen beinhaltet, die zum Zeichnen von Formen erforderlich sind. Er hebt den Marker an, fährt zum ersten Punkt, senkt den Marker, fährt durch alle Punkte und hebt den Marker wieder an.
Führen Sie diesen Abschnitt des Codes aus.
FILES
- Task3.mlx
- xyToCounts.m
- moveToCounts.m
LEARN BY DOING
Im letzten Abschnitt dieser Übung haben Sie gesehen, wie Sie den Marker zwischen dem Bewegen auf die Positionen anheben und absenken können. Versuchen Sie, mit diesem Ansatz ein mehrzeiliges Segment zu zeichnen, indem Sie die Markierung zwischen den Linien anheben. Zeichnen Sie einen Großbuchstaben E. Dazu definieren Sie die Koordinaten aller sechs Segmentendpunkte. Sie können die drei äußeren Segmente zusammenziehen, dann den Marker anheben und die Mittellinie zeichnen.
Verwenden Sie in MATLAB die Gleichung eines Kreises, um x-y-Positionen für acht Punkte auf einem Kreis zu definieren. (Dies bildet ein Achteck.) Zeichne diese Form auf das Whiteboard.
ÜBUNG 4
4.4 Positionsgrenzen identifizieren
Wenn Sie versuchen, den Roboter zur Oberseite des Whiteboards zu bewegen, hat er nicht genug Energie, um sich über einen bestimmten Punkt hinaus zu bewegen. Wenn Sie versuchen, ihn zu nahe an die Riemenscheiben zu bewegen, kollidiert er mit den Scheiben und bleibt stecken. An der Unterseite Ihres Whiteboards befindet sich möglicherweise eine Markierung, in die der Roboter nicht hineinlaufen soll. In dieser Übung bestimmen Sie, welche Teile des Whiteboards der Roboter erreichen kann. Sie bestimmen, zu welchen Bereichen sich der Roboter nicht bewegen kann.
Sie werden die physikalischen Grundlagen kennenlernen, die Ihnen helfen, die Belastung der Motoren an jeder Stelle auf dem Whiteboard zu bestimmen. Sie führen dann die Berechnungen selbst durch und erstellen Visualisierungen, um zu sehen, wie viel Last an jeder Position vorhanden ist und wo die Last am größten ist.
In dieser Übung werden Sie lernen:
- Motorstallgleichungen anzuwenden
- Symbolische Mathematik-API zu verwenden, um Einheiten zu konvertieren
- Frei-Körper-Diagramme zu erstellen
- Kräfte auf statische Körper zu berechnen
- An jedem Punkt eines Gitters eine Funktion anzuwenden
- Oberflächen und Bilder in MATLAB grafisch darzustellen
Motorgleichungen und Abriss-Bedingungen verstehen
Für einen Gleichstrommotor kann eine mathematische Gleichung verwendet werden, um den Zusammenhang zwischen Motorlast (Drehmoment), Versorgungsspannung und Drehzahl zu beschreiben. Dies wird manchmal als DC-Motor-Drehmomentgleichung bezeichnet:
$\tau =\frac{V-{\omega \cdot k}} R{\cdot}k$
In dieser Gleichung ist $\tau$ das Motordrehmoment oder die Motorlast, $V$ ist die Versorgungsspannung und $\omega$ ist die Winkelgeschwindigkeit. (Beachten Sie, dass in einigen Versionen dieser Gleichung die Variable $T$ als Drehmoment verwendet wird. Für unser Projekt werden wir $T$ reservieren, um es für Spannungen zu nutzen.) $R$ ist der Widerstand in den Motorwicklungen, und $k$ ist die Motorkonstante. Sowohl $R$ als auch $k$ sind für einen bestimmten Motor konstant. Es gibt zwei Sonderfälle, die wir für diese Gleichung berücksichtigen können. Einer davon ist der Fall, wenn der Motor nicht belastet wird. In diesem Fall ist $\tau = 0$, und die Gleichung vereinfacht sich wie folgt:
$V=\omega _{{free}}\cdot k$
Der zweite Sonderfall ist, wenn der Motor den Stillstand erreicht. Hier ist die Last so hoch, dass sich der Motor nicht drehen kann. In diesem Fall ist $\omega = 0$, und die Gleichung vereinfacht sich wie folgt:
$\tau _{{stall}}=\frac{{Vk}} R$
Berechnen Sie die maximal zulässige Last
Zunächst überprüfen Sie die für den Motor angegebenen Spezifikationen. Sie sind hier oder hier. Der Motor ist für 12 V ausgelegt. Notieren Sie die angegebene Spannung, Freilaufdrehzahl und das Stillstandsdrehmoment im Code. Rechnen Sie dies in SI-Einheiten um. Symbolic Math Toolbox bietet eine nützliche Funktion namens unitConversionFactor, die Ihnen den Umrechnungsfaktor für die Umrechnung von kg-cm in N-m liefern kann. Der Code für diese Schritte ist im Live-Skript Task4.mlx . enthalten. Öffnen Sie diese Datei. Führen Sie dann den Codeabschnitt unter der Überschrift Define motor specifications aus.
Sie können die Spannungs-Drehmoment-Beziehung des Motors verwenden, um die Konstanten $k$$k$ und $R$ für den Motor zu bestimmen. Verwenden Sie zunächst die Motorgleichung unter Freilaufbedingungen, bei denen $\tau$ 0 ist, um $k$ zu berechnen. Verwenden Sie dann die Motorgleichung unter Abrissbedingungen, bei denen $\omega$ 0 ist, um $R$ zu berechnen. Führen Sie den Abschnitt des Codes unter der Überschrift Calculate motor constants from specs in Task4.mlx aus.
Ihr Roboter wird die Motoren nicht mit der Nennspannung betreiben. Stattdessen haben Sie im Kit eine Batterie mit einer Nennspannung von 11,1 V. Dies führt zu einer Einschränkung des Abriss-Drehmoments für Ihre Betriebsbedingungen. Außerdem ist es ratsam, den Motor nicht mit mehr als 30% des Abriss-Drehmoments zu betreiben. (weitere Informationen hier). Verwenden Sie die Motorgleichung unter Stillstandsbedingungen, um das Abriss-Drehmoments Ihrer Batterie zu berechnen, und wählen Sie dann 30% dieses Wertes als maximal zulässiges Drehmoment für die Motoren Ihres Roboters. Wir werden diese Variable TauMax nennen. Um diesen Wert zu berechnen, führen Sie den Codeabschnitt in Task4.mlx unter der Überschrift Calculate torque limit für verfügbare Spannung aus.
Das Frei-Körper-Diagramm verstehen
Denken Sie darüber nach, den Roboter an verschiedenen Stellen des Whiteboards aufzuhängen. Glauben Sie, dass die Motoren schwerer drehen werden, wenn sie oben oder unten sind? Ist es einfacher, sich auf dem Whiteboard nach oben oder unten zu bewegen? Welcher Motor hat die größere Last, wenn sich der Roboter ganz am linken Rand des Whiteboards befindet?
In der Physik und Technik ist es oft sinnvoll, die Kräfte auf ein Objekt berechnen zu können. Für den Whiteboard-Roboter können uns diese Kräfte sagen, wie viel Last auf jeden der Motoren wirkt. Dies geschieht durch die Erstellung eines so genannten Frei-Körper-Diagramms. Dieses Diagramm zeigt einen Körper mit Kräften, die in verschiedene Richtungen auf ihn einwirken. Am Roboter befinden sich zwei Fäden, die zur linken Riemenscheibe ziehen. Diese sollten jeweils mit der gleichen Spannung $T_1$ gezogen werden damit wir sie als eine einzige Kraft $F_1$ behandeln können, deren Wert zweimal $T1$ ist. Ebenso können die beiden Fäden, die zur rechten Riemenscheibe $T_2$ ziehen, als eine einzige Kraft $F_2$ betrachtet werden, wobei $F_2 = 2 \cdot T_2$. Schließlich gibt das ein Gewicht, welches nach unten zieht.
In einem Frei-Körper-Diagramm ist es auch sinnvoll, die Kräfte in ihre x- und y-Komponenten zu zerlegen. Definieren Sie zunächst $\theta_1$ als den Winkel von $F_1$ von vertikal und $\theta_2$ als den Winkel von $F_2$ von vertikal, wie im folgenden Diagramm dargestellt. Die Beziehung zwischen $F_1$, $F_2$ und $Weight$ wird in den folgenden Abschnitten erläutert. Vorerst konzentrieren wir uns darauf, wie man die Werte dieser Kräfte in Form von Winkeln der Schnüre ausdrückt, die von der Position des Roboters auf dem Whiteboard abhängen.
Verwenden Sie dann die Trigonometrie, um jede Kraft $F_1$ und $F_2$ wie gezeigt in ihre x- und y-Komponente zu zerlegen.
$F_{1,x}=-F_1\sin \theta _1$
$F_{1,y}=F_1\cos \theta _1$
$F_{2,x}=F_2\sin \theta _2$
$F_{2,y}=F_2\cos \theta _2$
Sobald Sie diese Gleichungen haben, ist es ziemlich einfach, die Frage zu beantworten, ob die Motoren an verschiedenen Stellen des Whiteboards die gleichen Kräfte erleiden werden, zumindest im stationären Zustand. Im nächsten Abschnitt wird auf diesen Fall eingegangen.
VERSTÄNDNIS DES KRAFTAUSGLEICHS AUF EINEM STATISCHEN KÖRPER
Das dritte Bewegungsgesetz von Newton sagt uns, wie sich ein Objekt verhält, während Kräfte auf es wirken. Die Summe der auf das Objekt einwirkenden Kräfte entspricht der Masse des Objekts mal der Beschleunigung des Objekts.
$\Sigma \overrightarrow F=m\overrightarrow a$
Diese Gleichung kann in ihre Komponenten zerlegt werden, in diesem Fall x und y.
$\Sigma F_x=ma_x$
$\Sigma F_y=ma_y$
Wenn sich der Roboter nicht bewegt, ist die Beschleunigung in jede Richtung Null. Das bedeutet, dass die linke Seite jeder Gleichung die Summe der Kräfte in dieser Richtung ist und die rechte Seite der Gleichung 0 ist, was für den Whiteboard-Roboter die folgenden beiden Gleichungen ergibt.
$-F_1\sin \theta _1+F_2\sin \theta _2=0$
$F_1\cos \theta _1+F_2\cos \theta _2-{Weight}=0$
Die algebraische Lösung dieses Gleichungssystems für die unbekannten Kräfte $F_1$ und $F_2$ ergibt folgendes:
$F_1={Weight}{\cdot}\frac{\sin \theta _2}{\sin \theta _1\cos \theta _2+\sin \theta _2\cos \theta _1}$
$F_2={Weight}{\cdot}\frac{\sin \theta _1}{\sin \theta _1\cos \theta _2+\sin \theta _2\cos \theta _1}$
Bisher haben wir die Zusammenhänge zwischen der Geometrie des Roboters und den verschiedenen Kräften am Roboter untersucht. Die Gleichungen des Motors werden jedoch in Form von Drehmoment und nicht von Kraft ausgedrückt. Im nächsten Abschnitt werden wir alle bisherigen Gleichungen zusammenfassen und ein Verhältnis zwischen Drehmoment und Kraft herstellen, das alles miteinander verbindet. Auf diese Weise können Sie feststellen, unter welcher Last die Motoren an jeder Stelle des Whiteboards stehen.
Ableitung von Gleichungen zur Berechnung des Drehmoments aus der x-y-Position
Für jede x-, y-Position auf dem Whiteboard ist es möglich, das Drehmoment am Motor zu berechnen. Verwenden Sie zunächst die Position x, y, um die Hypotenusen der Dreiecke zu berechnen, die aus der Hängeposition des Roboters, $Z_1$, $Z_2$ gebildet werden. Verwenden Sie diese Werte, um die Winkel der Schnüre zu berechnen, $\theta_1$,$\theta_2$ . Dann berechne $F_1$, $F_2$ und $T_1$, $T_2$. Verwenden Sie schließlich $T_1$, $T_2$, um $\tau_1$, $\tau_2$ zu ermitteln. Hier haben Sie die zu verwendenden Gleichungen. Um $Z_1$, $Z_2$ von x-y zu berechnen, verwenden Sie einfach den Satz des Pythagoras, wie Sie es zuvor getan haben.
$Z_1=\sqrt{x^2+y^2}$
$Z_2=\sqrt{\left({Base}-x\right)^2+y^2}$
Um $\theta_1$,$\theta_2$ von $x$, $y$, $Z_1$, und $Z_2$ zu berechnen, verwenden Sie den Sinus. Sie erhalten für jedes Dreieck folgendes:
$\frac a{{sinA}}=\frac b{{sinB}}=\frac c{{sinC}}$
In diesem Fall können wir die Beziehung zwischen dem rechten Winkel jedes Dreiecks und dem unbekannten Winkel $\theta$ jedes Dreiecks verwenden. Daraus ergeben sich die folgenden Gleichungen:
$\frac x{\sin \theta _1}=\frac{Z_1}{\sin \pi /2}$
$\frac{{Base}-x}{\sin \theta _2}=\frac{Z_2}{\sin \pi /2}$
Da $\sin \frac \pi 2$ 1 macht, vereinfachen diese Gleichungen zu:
$\theta _1=\sin ^{-1}\frac x{Z_1}$
$\theta _2=\sin ^{-1}\frac{{Base}-x}{Z_2}$
Um $F_1$, $F_2$ aus $\theta_1$,$\theta_2$ zu berechnen, verwenden Sie die im vorherigen Abschnitt abgeleiteten Gleichungen:
$F_1={Weight}{\cdot}\frac{\sin \theta _2}{\sin \theta _1\cos \theta _2+\sin \theta _2\cos \theta _1}$
$F_2={Weight}{\cdot}\frac{\sin \theta _1}{\sin \theta _1\cos \theta _2+\sin \theta _2\cos \theta _1}$
Um $T_1$, $T_2$ von $F_1$, $F_2$ zu berechnen, erinnern Sie sich, dass die Gesamtkraft, die den Roboter in Richtung einer Riemenscheibe zieht, gleich der doppelten Spannung an der Schnur über dieser Riemenscheibe ist. Denn es gibt zwei Punkte, an denen die Schnur an dem Roboter zieht.
$T_1=F_1/2$
$T_2=F_2/2$
Abschließend berechnen Sie das Drehmoment aus der Spannung an der Schnur. Die Schnur zieht den Motor in eine Richtung senkrecht zur Linie von der Mitte der Spule bis zu dem Punkt, an dem die Schnur den Motor berührt, wie in der folgenden Abbildung dargestellt.
Hierbei wird die Größe des Drehmoments als Produkt aus der Kraft und dem Abstand zwischen der Drehachse und dem Punkt, an dem die Kraft aufgebracht wird, angegeben. In diesem Fall ist der Abstand der Radius der Spule, so dass wir die folgenden Gleichungen erhalten:
$\tau _1=T_1r_{{spool}}$
$\tau _2=T_2r_{{spool}}$
Bei allen in diesem Abschnitt vorgestellten Gleichungen ist es möglich, Winkel in Bezug auf Lage, Kräfte in Bezug auf Winkel, Spannung in Bezug auf Kräfte und Drehmoment in Bezug auf Spannung zu berechnen. Das bedeutet, dass es eine Möglichkeit gibt, das Drehmoment mit der Lage auf der Tafel in Beziehung zu setzen. Wie Sie sich vorstellen können, ist es ein langer Prozess, eine Karte der Drehmomente am Roboter für das gesamte Whiteboard zu erstellen. Durch die Gleichungen und die Verwendung von MATLAB könnten diese Vorgänge jedoch automatisiert werden, wie in den folgenden Abschnitten gezeigt wird.
ERSTELLEN SIE EIN GITTER ALLER MÖGLICHEN BOARD-POSITIONEN
Um zu beschreiben, zu welchen Teilen des Whiteboards sich der Roboter bewegen darf, definieren Sie ein Gitter, das das gesamte Board abdeckt und berechnen das Drehmoment überall auf diesem Gitter. Der erste Schritt bei der Erstellung dieses Rasters besteht darin, die Abmessungen des Whiteboards zu bestimmen.
Messen Sie mit einem Meterstab oder Maßband die Höhe des Whiteboards, von den Rollen bis zur Unterseite des Boards. Den Codeabschnitt in Task4.mlx finden Sie unter der Überschrift Define whiteboard dimensions. Ändern Sie in der ersten Zeile des Codes den Wert von Hboard so, dass er gleich Ihrer gemessenen Höhe ist, definiert in Metern.
Sie haben zuvor den Abstand zwischen den beiden Riemenscheiben gemessen. Dieser ist in der Variablen Base definiert, die Sie in einer MAT-file gespeichert haben sollten. Führen Sie den Abschnitt Define whiteboard dimensions in dem Programmabschnitt aus, um die Whiteboardhöhe (H_board) zu definieren und die gemessene Basis (Base) zu laden. Mit der Funktion meshgrid kann in MATLAB ein Datentabelle mit Koordinatenpositionen erstellt werden. Eine einfache Möglichkeit, diese Funktion aufzurufen, besteht darin, Arrays aus den x-Werten und y-Werten zu definieren, die im Raster enthalten sein sollen. Der nächste Abschnitt des Codes definiert diese Arrays über den gesamten Bereich der X- und Y-Werte in einem Abstand von 1 mm. Führen Sie den Programmabschnitt unter der Überschrift Create a grid of all possible board positions in Task4.mlx aus.
Öffnen Sie die Variablen X und Y im Variablen-Editor durch Doppelklick im Arbeitsbereich. Beachten Sie, dass diese die gleiche Größe haben, die Spalten von X alle gleich sind und die Spalten von Y alle gleich sind. So definiert jedes Paar von Positionen X(i,j), Y(i,j) eine eindeutige Position auf dem Whiteboard.
Wir können nun diese Koordinatennetze verwenden, um die früher erhaltenen Gleichungen auszuwerten und die Ergebnisse in einer Zeichnung zu visualisieren.
Berechnen des Drehmoments an jeder Position und der Fläche des Plots
Zusätzlich zu den aktuell definierten Variablen müssen wir auch ein paar zusätzliche Werte kennen, bevor wir die Motordrehmomente an jedem Punkt auf des Whiteboards berechnen können. Um die Zugkraft auf jeden Strang zu berechnen, müssen wir das Gewicht des Roboters kennen. Um die Zugkraft in Drehmoment umzuwandeln, müssen wir den Radius der Spule kennen. Diese sind beide für das jeweilige Roboterkit definiert. Um diese im MATLAB-Code zu definieren, führen Sie den Codeabschnitt unter der Überschrift Define robot constants for calculating torque aus.
Anschließend verwenden Sie MATLAB, um die abgeleiteten Gleichungen zur Umwandlung der x-y-Position in Drehmoment anzuwenden. Berechnen Sie zunächst $Z_1$ und $Z_2$ für jede Position auf dem Whiteboard. Wende dann die trigonometrischen Gleichungen an, um die Winkel $\theta_1$ und $\theta_2$ basierend auf den gebildeten Dreiecken zu berechnen. Verwenden Sie die Kraftbilanz-Gleichungen, um die Kraft in jede Richtung und die Spannung auf jede Schnur zu berechnen. Berechnen Sie dann die Drehmomentbelastung jedes Motors an jeder Position. Schließlich definieren Sie eine einzige Variable Tau, die den größeren der beiden Drehmomentwerte an jeder Position enthält. Sie dürfen den Roboter niemals an einen Ort bewegen, an dem dieser Wert größer als TauMax ist. Führen Sie den Codeabschnitt unter der Überschrift Compute torque at every position in Task4.mlx aus.
Nachdem nun an jeder Stelle des Whiteboards die Motorlast Tau definiert ist, können Sie diese in MATLAB visualisieren. Erstellen Sie ein einfaches Flächendiagramm mit der Surf-funktion in MATLAB. Führen Sie dazu den Codeabschnitt in Task4.mlx unter der Überschrift Plot torque at every position aus.
Erkunden Sie diese Graphik. Klicken Sie auf das Symbol mit der Aufschrift Rotate . Klicken und ziehen Sie dann den Graphen, um die Oberfläche von allen Seiten zu betrachten und einen besseren Eindruck davon zu bekommen, wie das Drehmoment an verschiedenen Positionen auf dem Whiteboard wirkt.
Entfernen schlechter Bereiche und Plotbilder
Erstellen Sie nun einen Plot, der die Bereiche entfernt, in die sich der Roboter nicht bewegen soll. Dazu gehören zwei Arten von Regionen. Entfernen Sie zunächst die Bereiche, in denen das Drehmoment zu hoch ist. Entfernen Sie dann die Bereiche, in welche der Roboter nicht fahren kann, weil er sich zu dicht an den Riemenscheiben oder am Boden des Whiteboards nährt.
Um diese Bereiche aus unserer Darstellung zu "entfernen", definieren wir eine Transparenzmaske für die Darstellung. Die Darstellung ist sichtbar in Bereichen, die der Roboter erreichen kann, und transparent in Bereichen, die der Roboter nicht erreichen kann. In MATLAB werden die Daten, die diese Bereiche definieren, AlphaData genannt. Um eine Opazitäsvariable zu erstellen und die nicht erreichbaren Bereiche zu entfernen, führen Sie den Codeabschnitt unter der Überschrift Eliminate bad regions aus.
Nun können Sie die opacity-variable in einem Plot verwenden. Erstellen Sie ein Bilddiagramm, um die Tau-Daten in 2D anzuzeigen und fügen Sie die opacity-variable als AlphaData des Diagramms hinzu. Außerdem können Sie die Farbgrenzen so anpassen, dass sie auf den Maximalwert des sichtbaren Bereichs und nicht auf den Maximalwert über ganz Tau skaliert werden. Dieses 2D-Diagramm zeigt Ihnen, welche Teile des Whiteboards der Roboter erreichen kann und welche nicht. Die transparenten Bereiche stellen diejenigen dar, die der Roboter nicht erreichen kann. Erstellen Sie diesen Plot, indem Sie den Code im Abschnitt Plot torque in allowable regions in Task4.mlx ausführen.
Definieren und speichern von Zeichnungsgrenzen für Ihr Whiteboard
Als nächstes definieren Sie den Teil des Whiteboards, auf dem Sie dem Roboter erlauben, zu zeichnen. Sie können wählen, wo die minimalen x- und y-Werte für Ihren Zeichenbereich liegen sollen. Diese werden wahrscheinlich irgendwo entlang der Kurve fallen, welche definiert, wie nah der Roboter an die linke Riemenscheibe kommen kann. Verwenden Sie das Data Cursor Werkzeug im Live-Skript, um einen Punkt auszuwählen und seine x-y-Koordinaten zu überprüfen.
Speichern Sie die X- und Y-Werte aus dem Plot im Code. Den nächsten Abschnitt von Task4.mlx finden Sie unter der Überschrift Choose drawable region limits and visualize. Ersetzen Sie die Werte der Variablen pickX und pickY durch die Werte, die Sie im Plot ausgewählt haben.
Sie können den zeichnungsfähigen Bereich des Whiteboards visualisieren, indem Sie ein Rechteck auf dem zuvor erstellten Plot überlagern. Um den vorherigen Plot zu behalten und zu ergänzen, verwenden Sie den Befehl hold on. Verwenden Sie die rectangle funktion, um das Rechteck zu zeichnen. Um dies zu tun und zu überprüfen, ob Ihr zeichnungsfähiger Bereich korrekt aussieht, führen Sie den Code unter der Überschrift Choose drawable region limits and visualize Sie in Task4.mlx.
Wenn Sie mit der Größe und Form des ausgewählten rechteckigen Bereichs zufrieden sind, sollten Sie die Werte von xLim und yLim in einer MAT-Datei zur späteren Verwendung speichern. Führen Sie den Codeabschnitt unter der Überschrift Save chosen drawing limits in Task4.mlx aus, damit Sie diese Werte in zukünftigen Übungen verwenden können.
FILES
- Task4.mlx
LEARN BY DOING
Wir haben die Variable Tau erstellt, um die größte Last auf die jeweiligen Motoren an jeder Position auf dem Whiteboard zu übernehmen. Erstellen Sie eine neue Variable mit Tau2 - Tau1, die den Lastunterschied zwischen dem rechten und linken Motor an jeder Stelle auf dem Whiteboard beschreibt. Zeichnen Sie das genau so auf, wie Sie Tau gezeichnet haben. Wo ist die Belastung des rechten Motors größer als die des linken? Wo befindet sich eine geringere Last am rechten Motor als am linken?
Verwenden Sie die App SimplePlotterApp, um den Roboter wie in einer früheren Übung um das Whiteboard zu fahren. Bestätigen Sie, was Sie in den Plots in dieser Übung gesehen haben. Bei einer gegebenen Spannung laufen die Motoren bei höherer Last langsamer. Überprüfen Sie, wie schnell die Motoren oben auf dem Whiteboard und unten laufen. Überprüfen Sie, wie schnell jeder Motor links auf dem Whiteboard und rechts läuft. Entspricht dies den von Ihnen erstellten Plots?
Die Größe und Abmessungen des zeichnungsfähigen Whiteboard-Bereichs können durch mathematische Gleichungen definiert werden. Nehmen wir an, Sie wollten einen quadratischen Bereich mit gleicher Breite und Höhe. Verwenden Sie die definierten Gleichungen, um die Werte von pickedX und pickedY zu berechnen, die Ihnen einen quadratisch zeichnungsfähigen Bereich geben würden. Geben Sie diese Werte in das Live-Skript Task4.mlx ein und führen Sie das Skript dann erneut aus, um die Genauigkeit Ihrer Berechnungen zu überprüfen.
ÜBUNG 5:
4.5 Vorverarbeitete Bilder zeichnen
Lassen Sie uns ein Bild von etwas Reellem zeichnen. In dieser Lektion werden Sie einige Daten laden, die die Linienverläufe aus einem realen Bild speichern. Sie werden lernen, wie man diese Daten interpretiert und einen Algorithmus entwickelt, der den Roboter anweist, jedes einzelne Liniensegment zu zeichnen und dann die Markierung anzuheben und zum nächsten Liniensegment zu wechseln. Sie werden lernen, wie Sie die Größe der Linienzeichnung so skalieren, dass sie die zeichenbare Fläche auf Ihrem Whiteboard ausfüllt. Schließlich erstellen Sie eine MATLAB-Funktion, die alle diese Schritte ausführen kann.
In dieser Übung werden Sie lernen:
- Plotten von Bilddaten in MATLAB
- Durchschleifen und Manipulieren von Daten in einem Zellenarray
- Konvertieren von Daten von Pixeln in physikalische Abstände
- Entwerfen eines Algorithmus zum Zeichnen eines Bildes in mehreren Segmenten mit einer Loop
Bilder in MATLAB einlesen
MATLAB kann mit Bildern in gängigen Bilddateiformaten arbeiten. Der allgemeine Arbeitsablauf ist der, dass als Erstes das Bild in eine MATLAB-Variable eingelesen wird. Dann können Sie Funktionen anwenden, um das Bild zu ändern oder zu visualisieren, und Sie können das Bild in eine neue Datei schreiben.
Um ein Bild in MATLAB einzulesen, verwenden Sie die Funktion imread. Ein Bild, das mit MATLAB geliefert wird, befindet sich in der Datei peppers.png. Lesen Sie dies, indem Sie in der MATLAB-Befehlszeile Folgendes eingeben.
>> RGB = imread('peppers.png');
Untersuchen Sie die RGB-Variable in Ihrem Workspace. Beachten Sie, dass diese dreidimensional ist und vom Typ uint8 ist. Sie ist dreidimensional, so dass jede der Grundfarben 8 Bit erhält, um diese Komponente darzustellen. Das bedeutet, dass Sie mit Bildern mit einer Farbtiefe von 24 Bit arbeiten können (8 Bit oder 1 Byte für jedes einzelne davon).
Zeigen Sie das Bild mit der imshow-Funktion an. Führen Sie die folgende Anweisung an der Eingabeaufforderung aus.
>> imshow(RGB)
Die drei Dimensionen der Variablen stellen die roten (R), grünen (G) und blauen (B) Daten des Bildes dar. Man kann sich das als drei übereinander gestapelte Datenraster vorstellen, eines für jede Farbebene. Um einen Eindruck davon zu bekommen, was das bedeutet, können Sie nur eine Ebene des Bildes visualisieren. Um eine Darstellung der Daten der roten Ebene zu sehen, verwenden Sie den folgenden Befehl, um die Bildbereiche anzuzeigen, die die meisten roten aufweisen:
>> imshow(RGB(:,:,1))
Beachten Sie, wie die Darstellung einer einzelnen Farbebene eines Bildes zu einem Graustufenbild führt. Das kann verwirrend sein. Alternativ können Sie ein Bild in MATLAB anzeigen, ohne es überhaupt in eine Variable zu laden, indem Sie einfach imshow auf der Datei selbst aufrufen. Führen Sie dazu den folgenden Befehl aus, um dies mit dem Paprika-Bild zu tun.
>> imshow('peppers.png')
Das Ergebnis ist das gleiche wie bei der Anzeige der Vollfarbmatrix.
Zeichnen Sie ein Bild einer Zeichnung, um es zu replizieren
Der Roboter ist nicht in der Lage, vollständige RGB-Ebenen und nicht einmal Graustufenbilder zu zeichnen. Das aktuelle Design benötigt Vektorgrafiken als Eingabe. Dies bedeutet, dass jedes Bild, das Sie zeichnen möchten, zuerst eine Bildverarbeitung durchlaufen muss, um es in die richtige Form zu bringen.
Einige Musterlinienzeichnungen wurden in eine zeichenbare Form gebracht und für Sie bereitgestellt. (In der nächsten Übung lernen Sie, wie Sie diese selbst generieren können). Der Ordner Images enthält sowohl die Originalbilder als auch die entsprechenden MAT-Dateien mit dem zu zeichnenden Pfad. Suchen Sie die Datei MathWorksLogo.jpg. Klicken Sie mit der rechten Maustaste darauf im aktuellen Ordner und wählen Sie Open Outside MATLAB, um zu sehen, wie es aussieht.Beachten Sie, dass verschiedene Betriebssysteme unterschiedliche Bildbetrachter haben.
Im nächsten Schritt wird geprüft, ob die verarbeitete Datei dem Originalbild ähnelt. Dazu öffnen Sie das Live-Skript Task5.mlx:
>> edit Task5
und führen Sie den Code im Abschnitt Plot sample image aus, um zu sehen, wie dieses Bild in MATLAB dargestellt wird.
Wie Sie sehen können, ist das Ergebnis des Plots eine vektorisierte Version des Originalbilds. Diese Art von Bild kann leicht in motorische Bewegungen übersetzt werden. Befolgen Sie die Schritte zum Erreichen dieser Art von Bild von jedem Bild aus, das Sie möglicherweise als Ausgangspunkt haben. Zunächst müssen wir jedoch einige grundlegende Werkzeuge in MATLAB verstehen, mit denen Sie die erforderlichen Operationen ausführen können.
Verstehen Sie die Cell-Arrays in MATLAB
Bisher haben Sie mit verschiedenen Arten von Variablen in MATLAB gearbeitet. Sie haben Objekte erstellt, um den Arduino und seine Komponenten darzustellen. Sie haben numerische Einzelwerte und Vektoren erstellt, um numerische Werte zu speichern. Und Sie haben sich 3-dimensionale uint8-Daten angesehen, welche Bilder darstellen.
Manchmal ist es sinnvoll, mehrere Daten in einer einzigen Variablen zu kombinieren. Dies kann nützlich sein, um Daten unterschiedlicher Größe oder Art zu gruppieren. Dazu können Sie einen Datencontainer verwenden, der als Cell-Array bezeichnet wird. Es gibt viele verschiedene Gründe, warum Cell-Arrays nützlich sein können. Für die Zwecke dieser Übung werden wir uns jedoch darauf konzentrieren, sie zu verwenden, um numerische Arrays unterschiedlicher Größe zu speichern.
Um zu sehen, wie Cell-Arrays funktionieren, erstellen Sie zunächst einige numerische Arrays unterschiedlicher Größe. Führen Sie den folgenden Code im MATLAB Command Window aus, um drei verschiedene magische Quadrate zu erstellen.
>> a = magic(3)
>> b = magic(4)
>> c = magic(5)
Beachten Sie, dass die resultierenden Arrays jeweils unterschiedliche Abmessungen haben. Erstellen Sie nun eine einzelne Variable, die die Daten von a, b und c im ersten, zweiten und dritten Element speichert. Verwenden Sie dazu ein Cell-Array. Beachten Sie, dass Sie geschweifte Klammern {} verwenden, um Cell-Arrays zu erstellen. Führen Sie den folgenden Code aus:
>> C = {a b c}
Das Cell-Array C hat die Größe 1x3, aber jedes Element enthält ein numerisches Array. Das Auslesen von Daten aus einer Variablen wird als Indizierung bezeichnet. Bei einem numerischen Array verwenden Sie Klammern (), um die numerischen Elemente herauszuziehen. Bei einem Zellenarray ziehen Sie die Zellenelemente heraus, wenn Sie runde Klammern verwenden. Vergleichen Sie die Ergebnisse der folgenden Punkte:
>> a(1,1)
>> C(1,1)
Wenn Sie in einer Zelle die darin enthaltenen Daten auslesen möchten, können Sie diese mit geschweiften Klammern {} indizieren. Um zu den in der Zelle C(1,1) enthaltenen Daten zu gelangen, gehen Sie wie folgt vor:
>> C{1,1}
Sie können den Inhalt eines Zellarrays auch durch Doppelklicken im Arbeitsbereich untersuchen, wodurch er im Variable Editor angezeigt wird.
Doppelklicken Sie auf eine Zelle, um den Inhalt dieser Zelle anzuzeigen.
In den folgenden Abschnitten werden Sie Cell-Arrays verwenden, um Koordinatenlisten unterschiedlicher Größe in einer einzigen MATLAB-Variablen zu speichern. Wir werden unseren Code sauber halten. Denken Sie daran, dass es eine gute Praxis ist, Ihren Code so zu erstellen, dass er von anderen leicht gelesen werden kann.
Laden und Plotten von Koordinaten eines vorhandenen Bildes
Die Koordinaten der zu plottenden Punkte werden in einem Zellenarray gespeichert. Führen Sie den Abschnitt Load pathways for sample image in Task5.mlx aus, um die Daten in MATLAB zu übernehmen.
Doppelklicken Sie auf die Variable segmentsPix im Arbeitsbereich, um sie im Variablen-Editor zu öffnen. Beachten Sie, dass es sich um ein Cell-Array mit drei Elementen handelt, von denen jedes ein zweispaltiges Doppelarray mit einer unterschiedlichen Anzahl von Zeilen enthält.
Mit anderen Worten, es gibt drei verschiedene Linienverläufe in dieser Bilddatei. Doppelklicken Sie auf eines dieser Elemente, um die in der Zelle enthaltenen Daten anzuzeigen. Diese Werte stellen die Pixelkoordinaten im Bild für die ausgewählte Linienspur dar.
Auf das n-te Element der Variable segmentsPix Cell-Array kann mit geschweiften Klammern zugegriffen werden, wie im folgenden Befehl:
>> data = segmentsPix{n};
Finden Sie den Abschnitt in Task5.mlx unter der Überschrift Plot pixels chosen from sample image. Beachten Sie, dass dieser Codeabschnitt eine for-Schleife mit Schleifenindex ii enthält. In jeder Iteration der Schleife wird das ii-te Element von segmentsPix extrahiert und dargestellt. Führen Sie diesen Abschnitt aus, um die in dieser Variable gespeicherten Verläufe anzuzeigen.
Wie Sie im Bild sehen können, werden die verschiedenen Pfade in verschiedenen Farben gezeichnet. Wenn wir unseren eigenen Algorithmus entwerfen, haben wir ein ähnliches Ergebnis wie das aufgenommene Bild: es gibt verschiedene Wege, die, wenn sie zusammengefügt werden, das gesamte Bild darstellen.
Skalierung von physikalischen Objekten
Um zu entscheiden, wo Sie ein Bild auf dem Whiteboard zeichnen möchten, müssen Sie die Daten von Pixeln in Meter umwandeln. Die maximalen und minimalen Whiteboardpositionen in Metern werden in xLim und yLim für x bzw. y gespeichert. Sie können xRange und yRange als Differenz zwischen diesen Maximal- und Minimalwerten definieren, wie in der folgenden Abbildung dargestellt.
In ähnlicher Weise werden beim Betrachten des Bildes auf dem Bildschirm, bei dem die Abstände in Pixeln gezählt werden, die maximalen und minimalen Pixelpositionen in x und y für das zu zeichnende Bild in den Variablen xLimPix und yLimPix gespeichert. Wir definieren xRangePix und yRangePix als Differenz zwischen diesen Maximal- und Minimalwerten, wie im folgenden Diagramm gezeigt.
Um von Pixeln zu Entfernungen zu konvertieren, müssen Sie die Pixelwerte mit einem Skalierungsfaktor multiplizieren. Dieser Skalierungsfaktor ist eine der beiden folgenden Größen:
${xScaleFactor}=\frac{{xRange}}{{xRangePix}}$
${yScaleFactor}=\frac{{yRange}}{{yRangePix}}$
Da wir ein zweidimensionales Bild haben und die Zeichenfläche nicht durch das Design mit der Bildgröße verbunden ist, erhalten wir zwei verschiedene Werte: einen, der der Verschiebung des Bildes auf die Tafel in Richtung der x-Achse entspricht. und eine andere für die y-Achse. Wir müssen uns für einen der beiden möglichen Skalierungsfaktoren entscheiden. Die Wahl des Skalierungsfaktors hängt davon ab, welcher kleiner ist. Dies hängt mit dem Seitenverhältnis der Whiteboard-Zeichnungsfläche zum zu zeichnenden Bild zusammen. Betrachten Sie eine relativ quadratische Zeichenfläche und ein kurzes und breites Bild. In diesem Fall sollten Sie den Skalierungsfaktor x verwenden, wie in der folgenden Abbildung dargestellt:
Wenn das Bild hoch und schmal ist, sind Sie durch die Höhe des Bildes begrenzt und müssen es um den y-Skalierungsfaktor skalieren, wie in der folgenden Abbildung dargestellt:
Mit anderen Worten, Ihr Algorithmus muss entscheiden, wie das Bild am besten von Pixeln in Meter umgewandelt wird. Der hier vorgestellte Ansatz skaliert das Bild so, dass so viel wie möglich von der zeichnungsfähigen Fläche ausgefüllt wird, ohne das Bild zu verzerren.Verzerrungen sollten Sie jedoch zu einem späteren Zeitpunkt berücksichtigen, insbesondere, wenn der Zeichenbereich groß ist.
Die Funktion transformPixelsToMeters - Zeile für Zeile
Die folgende Funktion konvertiert Pixel in Meter. Notieren Sie sich beim Durchlesen, wie das Programm entscheidet, welchen Skalierungsfaktor verwendet werden soll, wie es das Bild in der Mitte der Zeichenfläche zentriert und wie es die Messungen jeder Linie umwandelt und sie im neuen Koordinatensystem neu positioniert.
Die Funktion ermöglicht es dem Benutzer auch, anzugeben, wie viel Prozent des verfügbaren Platzes zum Zeichnen des Bildes verwendet werden soll. Dies wird durch das fraction-Eingabe-Argument angegeben.
Diese Funktion berechnet den Skalierungsfaktor für die Umwandlung von Pixeln in Meter und konvertiert
dann alle Segmente in segmentsPix in Meter.
function segmentsMeters = transformPixelsToMeters(segmentsPix,xLim,yLim,xLimPix,yLimPix,fraction)Erstellen Sie zunächst Variablen zur Darstellung der Bereiche xRange, yRange, xRangePix, und yRangePix.
xMinM = xLim(1);
yMinM = yLim(1);
xRangeM = diff(xLim);
yRangeM = diff(yLim);
% Determine the range of the coordinates to draw
xMinPix = xLimPix(1);
yMinPix = yLimPix(1);
xRangePix = diff(xLimPix);
yRangePix = diff(yLimPix);Berechnen Sie die beiden möglichen Skalierungsfaktoren. Der fraction-Faktor gibt an,
wie viel Prozent des verfügbaren Raums genutzt werden sollen.
% Scale from pixels to real world units (meters)
xScaleFactor = fraction*xRangeM/xRangePix;
yScaleFactor = fraction*yRangeM/xRangePix;Wählen Sie den kleineren der beiden Skalierungsfaktoren.
% Pick the smaller scale factor. If both are NaN, pick
0.
pix2M = min(xScaleFactor,yScaleFactor);
if isnan(pix2M)
pix2M = 0;
endIdentifizieren Sie anhand des gewählten Skalierungsfaktors und der Bereichswerte den neuen
Ursprung für die skalierte Zeichnung, so dass die vollständige Zeichnung in der Mitte des zeichnungsfähigen
Bereichs zentriert wird.
% Identify origin position of scaled drawing
centerMeters = [xMinM yMinM] + [xRangeM yRangeM]/2;
drawingOriginM = centerMeters - pix2M*[xRangePix yRangePix]/2;Durchlaufen Sie alle Segmente und transformieren Sie Pixelwerte in Meter für alle Koordinaten.
Subtrahieren Sie den Pixelursprung, multiplizieren Sie ihn mit dem Skalierungsfaktor
und addieren Sie den Zeichnungsursprung hinzu.
segmentsMeters = cell(size(segmentsPix));
nSegments = length(segmentsPix);
for ii = 1:nSegments
% Scale all segments by the computed scaling factor
coordsPix = segmentsPix{ii};
coordsPix = fliplr(coordsPix); %Convert from row,col to x,y
coordsMeters = pix2M*(coordsPix-[xMinPix yMinPix]) + drawingOriginM;
segmentsMeters{ii} = coordsMeters;
endÜbertragen von Pixel-Werten in physikalische Entfernungen und Zeichnen
Jetzt, da Sie wissen, wie es funktioniert, können Sie die Funktion transformPixelsToMeters nutzen, um die Daten, die Sie aus dem Beispielbild geladen haben, zu konvertieren. Sie verwenden die Whiteboard x-Grenzen und y-Grenzen, die Sie in der vorherigen Übung festgelegt haben. Dann konvertieren Sie für jedes Segment die Pixel aus diesem Segment in Meter und speichern die neuen Segmentdaten in einer Cell-Array-Variablen namens segmentsMeters. Führen Sie dazu die Codeabschnitte unter der Überschrift Convert pixel coordinates to physical distances aus.
Als nächstes erstellen Sie ein Diagramm der Daten in der Variablen segmentsMeters, genau wie Sie die Daten in der Variablen segmentsPix zuvor dargestellt haben. Die resultierende Darstellung sollte gleich aussehen, aber Einheiten von Metern und in einem Bereich innerhalb der Grenzen Ihres Whiteboards liegen. Führen Sie den Code im Abschnitt Plot paths in meters von Task5.mlx aus.
Wenn Sie in dieses Diagramm hineinzoomen und den Datencursor verwenden, sehen Sie, dass die zu zeichnenden Punkte sehr nahe beieinander liegen (in diesem Fall sind die meisten Punkte weniger als 1 mm voneinander entfernt).
Wenn der Roboter versucht, jeden Punkt auf jedem Segment zu zeichnen, dauert es sehr lange, bis die Zeichnung abgeschlossen ist. Im nächsten Abschnitt erfahren Sie, wie Sie die Segmente filtern, um die Zeichenzeit zu verkürzen und gleichzeitig die Grundform des Bildes beizubehalten.
VERSTEHEN SIE DIE REDUZIERUNGSFUNKTION, LINIE FÜR LINIE
Die Funktion reduceSegment reduziert die Anzahl der Punkte in einem Segment, indem Punkte innerhalb eines angegebenen Radius entfernt werden. Mit anderen Worten, es werden Punkte herausgefiltert, wodurch die Anzahl der zu zeichnenden Teilsegmente verringert wird. Die Funktion akzeptiert zwei Eingaben: das Segment, das reduziert werden soll, und einen Radiuswert. Der Radiuswert ist der gewünschte Mindestabstand zwischen zwei beliebigen Punkten auf dem Segment. Beachten Sie beim Lesen, wie die Funktion einige der zuvor erlernten Konzepte anwendet, z. B .: while-Loop und logische Indizierung.
function reducedSegment = reduceSegment(segment, radius)Erstellen Sie zunächst Variablen, anhand derer entschieden wird, welche Punkte im reduceSegment
beibehalten werden sollen.
% Initialize variables needed
nPoints = size(segment,1);
keepPoint = true(nPoints,1);
reference = 1;
test = 2;Durchlaufen Sie das Segment und entscheiden Sie, welche Punkte entfernt werden sollen.
Standardmäßig werden alle Punkte in die Ausgabe einbezogen.
% Select points to keep and remove such that each consecutive point
% remaining is separated by a minimum distance from the previous point
while test < nPointsÜberprüfen Sie, ob der Abstand zwischen dem Referenzpunkt und dem aktuellen Testpunkt kleiner
als der angegebene Mindestradius ist. Ist dies der Fall, markieren Sie den zu entfernenden Testpunkt
und testen Sie den nächsten Punkt im Segment.
% Check if test point is within given radius of reference point
if norm(segment(test,:) - segment(reference,:)) < radius
% If so, mark test point for removal and test the next point
keepPoint(test) = false;
test = test + 1;Wenn der Abstand zwischen den beiden Punkten den angegebenen Radius überschreitet,
legen Sie den Testpunkt als neuen Referenzpunkt fest und testen Sie den nächsten Punkt im Segment.
else
% If not, update reference and test points
reference = test;
test = reference + 1;
end
endErstellen Sie die Ausgabe, indem Sie nur die Punkte beibehalten, die nicht zum Entfernen markiert sind.
% Keep all points not marked for removal
reducedSegment = segment(keepPoint,:);SEGMENTGRÖSSEN UND GRUNDSTÜCK REDUZIEREN
Führen Sie die Funktion reduceSegment in einer for-Loop aus, um die Anzahl der Punkte in jedem Segment dieses Bildes zu verringern. Führen Sie den Codeabschnitt unter der Überschrift Größe jedes Segments reduzieren aus. Führen Sie dann den Codeabschnitt unter der Überschrift Verkleinerter Pfad in Metern aus, um die aktualisierten Pfade anzuzeigen.
Dies ist ein dritter Plot, in dem Sie viel weniger Punkte sehen, was die Zeit zum Drucken eines solchen Bildes mit dem Roboter erheblich verkürzt.
Hinweis: Der empirisch ermittelte Radiuswert von 2 mm funktionierte gut für Bilder auf unserem Whiteboard. Wenn das Bild auf Ihrem Whiteboard so aussieht, als ob wichtige Funktionen fehlen, verringern Sie den Radius und führen Sie die letzten beiden Codeabschnitte erneut aus. Wenn Ihr Bild nicht viele feine Details aufweist, können Sie es möglicherweise noch schneller zeichnen, indem Sie einen größeren Radius auswählen. Die Auswahl eines Radiuswerts, der die Zeichengeschwindigkeit und die Wiedergabegenauigkeit in Einklang bringt, ist derzeit ein Prozess des Versuchs und Irrtums. Sie können diesen Algorithmus auf verschiedene Arten verbessern: indem Sie herausfinden, wie unterschiedlich ein Bild ist, und indem Sie einen dynamischen Radius in Abhängigkeit vom geschätzten Fehler zwischen Original- und verkleinerten Bildern festlegen.
Umwendlung der gewünschten Positionen in Encoderzahlen
Wie in einer früheren Übung, werden Sie nun mit der Funktion xyToCounts die Zielpositionen in Metern in Encoderzahlen umwandeln. Bevor Sie diese Funktion ausführen können, müssen Sie die Ausgangsposition des Roboters bestimmen. Messen Sie die Länge jeder Schnur, wie Sie es in früheren Übungen getan haben. Führen Sie dann den Codeabschnitt unter der Überschrift Identify initial position in Z aus und geben Sie diese Längen im Dialogfenster ein.
Da die Daten in einem Cell-Array gespeichert sind, müssen Sie das Array mit einer for-Schleife durchlaufen und die Pfade nacheinander konvertieren. Speichern Sie die resultierenden Ziele für die Encoderzahl in einem Zellenarray namens segmentsCounts. Führen Sie den Code unter der Überschrift Convert distances to encoder counts umwandeln in Task5.mlx.
Liniensegmente auf dem Whiteboard zeichnen
Jetzt, da Sie den Encoder für alle Positionen, an die Sie den Roboter bewegen möchten, haben, können Sie damit jeden Pfad zeichnen, genau wie in einer vorherigen Übung. Verbinden Sie sich wie bisher zuerst mit der Hardware. Führen Sie die Codeabschnitte unter der Überschrift Connect to hardware in Task5.mlx aus.
Schauen Sie sich den Code im Abschnitt Draw image on whiteboard zeichnen an. Es wird eine for-Schleife verwendet, um durch die Variable segmentsCounts zu gehen. Überlegen Sie, was in der Schleife passiert. Jede Iteration der Schleife gilt für eine der Linienspuren im Bild. Dabei werden die Encoder-Zählungen für diese Linienspur extrahiert, der Roboter wird in die erste Position bewegt, der Marker wird abgesenkt, der Roboter wird dann in alle Positionen dieser Linienspur bewegt und schließlich wird der Marker angehoben. Dies wird für jede der drei Spuren im Bild wiederholt. Führen Sie diesen Codeabschnitt aus, um das Bild auf der Whiteboard zu zeichnen.
Erstellen einer Funktion zum Zeichnen eines Bildes aus Pixeln
Sie haben nun eine Aufgabe abgeschlossen, die mit Daten über die Pixel in einem Bild begann und mit dem Zeichnen des Bildes auf einer Pinnwand endete. Wenn Sie alle diese Schritte noch einmal durchführen möchten, ist es sinnvoll, diesen Code in einer Funktion zu bündeln. Erstellen Sie eine neue MATLAB-Funktion und nennen Sie sie drawImageFromPix.m. Die Funktion nimmt Pixeldaten und die Ausgangsposition des Whiteboards als Eingaben und zeichnet dann das Bild. Fügen Sie den folgenden Code in die Funktion ein und speichern Sie ihn. .
function drawImageFromPix(segmentsPix,xLimPix,yLimPix,Z_i)
nSegments = length(segmentsPix);
% Define whiteboard limits
load WhiteboardLimits.mat xLim yLim
% Convert pixel coordinates to physical distances and then to encoder counts
fraction = 0.7;
segmentsMeters = transformPixelsToMeters(segmentsPix,xLim,yLim,xLimPix,yLimPix,fraction);
% Reduce size of each segment
radius = 0.002; %Max distance between points to draw (meters)
for ii = 1:nSegments
segmentsMeters{ii} = reduceSegment(segmentsMeters{ii},radius);
end
load RobotGeometry.mat Base
segmentsCounts = cell(size(segmentsMeters));
for ii = 1:nSegments
segmentsCounts{ii} = xyToCounts(segmentsMeters{ii},Z_i,Base);
end
% Connect to hardware
a = arduino;
carrier = addon(a, 'Arduino/MKRMotorCarrier' );
s = servo(carrier,3);
m1 = dcmotor(carrier,2);
m2 = dcmotor(carrier,1);
e1 = rotaryEncoder(carrier,2);
e2 = rotaryEncoder(carrier,1);
resetCount(e1)
resetCount(e2)
% Define up and down positions for servo motor
load ServoPositions.mat LeftMarker NoMarker
% Draw image on whiteboard
writePosition(s,NoMarker)
for ii = 1:nSegments
% Get counts for current segment
countList = segmentsCounts{ii};
% Move to first position and lower marker
moveToCounts(countList(1,:),m1,m2,e1,e2)
writePosition(s,LeftMarker)
% Move to all positions of current segment
moveToCounts(countList,m1,m2,e1,e2)
% Raise marker
writePosition(s,NoMarker)
end
Die Variablen segmentsPix, xLimPix, yLimPix und Z_i sollten sich noch in Ihrem Arbeitsbereich befinden. Führen Sie Ihre neue Funktion an der MATLAB-Befehlszeile aus, um das Bild erneut zu zeichnen und zu bestätigen, dass die Funktion wie erwartet funktioniert.
>> drawImageFromPix(segmentsPix,xLimPix,yLimPix,Z_i)
FILES
- Task5.mlx
- transformPixelsToMeters.m
- drawImageFromPix.m
LEARN BY DOING
In dieser Übung haben Sie ein Bild mit Daten aus der MathWorksLogo.mat MAT-Datei erstellt. Es wurden Ihnen weitere MAT-Dateien zur Verfügung gestellt, die die Linienspuren aus anderen Bildern enthalten. Aktualisiere deinen Code, um einige dieser anderen Bilder zu zeichnen. Sehen Sie sich eine Vorschau an, wie sie in MATLAB aussehen werden. Zeichnen Sie sie dann auf dem Whiteboard.
Für eine anspruchsvollere Aufgabe sollten Sie versuchen, zwei Bilder nebeneinander zu zeichnen. Laden Sie die MAT-Datei-Daten für beide Bilder. Aktualisieren Sie dann die Daten aus dem zweiten Bild, so dass seine Pixelkoordinaten rechts von allen Punkten im ersten Bild stehen. Dann verketten Sie die Zellreihen von Pixelpositionen. Aktualisieren Sie schließlich die Variablen xLimPix und yLimPix, damit sie die Pixelgrenzen für den neuen kombinierten Satz von Pfaden genau beschreiben.
ÜBUNG 6:
4.6 Zeichne ein beliebiges Bild
In der vorherigen Übung haben Sie eine Anzahl von Pixelpositionen festgelegt, die die Verläufe in einem Bild beschrieben und mit dem Zeichenroboter diese Verläufe gezeichnet. Jetzt lernen Sie, wie Sie ein Foto machen und das Bild bearbeiten, um die Pixelpositionen und die zu zeichnenden Verläufe zu identifizieren. Sie verwenden Techniken zur Bildkonvertierung, Filterung und Analyse. Wenn Sie fertig sind, können Sie mit Ihrem Roboter jedes Bild mit einer Linienzeichnung nachbilden. Probieren Sie, die mitgelieferten Beispielbilder zu zeichnen oder eigene zu erstellen.
In dieser Übung werden Sie lernen:
- Konvertieren, filtern und analysieren von Bildern mit Bildverarbeitungsfunktionen
- Rekursive Funktionen konstruieren
- Vereinfachen des Codes durch gleichzeitiges Arbeiten mit dem gesamten Array
- Schreiben eines Hauptskripts zur Ausführung des gesamten Workflows
Verständnis der Bildverarbeitung, Filterung und Analyse
Die Bildbearbeitungs-Toolbox bietet eine große Auswahl an Funktionen für die Bildverarbeitung, Analyse, Visualisierung und Algorithmenentwicklung. In diesem Projekt werden Sie einige dieser Funktionen nutzen, um ein Bild einer Liniendarstellung zu erstellen und die Linienzüge zu extrahieren.
In einer früheren Übung haben Sie gesehen, dass ein Bild in MATLAB als MxNx3-Array mit uint8-Werten dargestellt werden kann, was ideal ist, wenn Sie alle Informationen über ein Bild erhalten möchten. Dies ist nur eine von mehreren Möglichkeiten, ein Bild darzustellen. Wir können die Komplexität eines Bildes reduzieren, um die spezifischen Informationen zu extrahieren, die uns interessieren. Hier sind einige andere Möglichkeiten, wie ein Bild in MATLAB dargestellt werden kann.
- Ein Farbbild kann auch als 2-dimensionales MxN-Array mit einer entsprechenden Farbkarte wiedergegeben werden. Aber wir werden nicht mit dieser Art von Farbbild arbeiten.
- Ein Graustufenbild kann einfach als MxN-Array dargestellt werden. Dies ist nützlich für Bildverarbeitungsfunktionen, die auf einem 2D-Datenraster arbeiten, wie z.B. Filterung.
- Ein Binärbild kann als MxN-Array mit logischen (wahren oder falschen) Werten dargestellt werden. Dies ist sinnvoll, um Merkmale bestimmter Bereiche in einem Bild zu extrahieren.
Wenn Sie weitere Informationen zur Bildverarbeitung wünschen, können Sie dieses Buch lesen.
Lassen Sie uns ein Bild untersuchen und in Graustufen umwandeln. Führen Sie den folgenden Code im MATLAB Command prompt aus, um das Paprikabild in MATLAB zu laden und anzuzeigen:
>> RGB = imread('peppers.png');
>> imshow(RGB);
Konvertieren Sie nun das Bild in Graustufen und betrachten Sie es. Beachten Sie auch die Abmessungen des neuen Bildes im MATLAB-Arbeitsbereich.
>> I = rgb2gray(RGB);
>> imshow(I)
Binäre Bilder sind Bilder, bei denen jedes Pixel entweder ein- oder ausgeschaltet ist. Diese werden in reinem Schwarz-Weiß visualisiert, was für die Beschreibung bestimmter Bereiche oder Objekte in einem Bild nützlich sein kann. Ein Graustufenbild kann mit der Imbinarize-Funktion in ein Binärbild umgewandelt werden. Diese Funktion ersetzt alle Werte oberhalb eines bestimmten Schwellenwerts durch 1 und diejenigen unterhalb dieses Schwellenwerts durch 0. Der Schwellenwert kann global oder regional sein. Konvertieren Sie das Paprika-Bild in ein Binärbild und betrachten Sie es. Beachten Sie auch den Datentyp des Binärbildes.
>> BW = imbinarize(I);
>> imshow(BW)
Es gibt viele Möglichkeiten, wie Sie Binärbilder verarbeiten können, um die gewünschten Funktionen zu extrahieren. Ein Ansatz ist die Verwendung morphologischer Operationen wie Dilatation und Erosion. Der nützlichste von diesen für die Extraktion von Linienbahnen ist der Ausdünnungsvorgang. Dadurch können Objekte im Bild bis hinunter zu Linien verdünnt werden. Testen Sie dies am Paprika-Bild, um zu sehen, welche Linienspuren die dünnste Version der in diesem Bild gezeigten Objekte darstellen.
>> BW2 = bwmorph(BW,'thin',inf);
>> imshow(BW2)
Auf den folgenden MATLAB-Dokumentationsseiten finden Sie weitere Informationen zu diesen und anderen Bildverarbeitungsfunktionen:
In den folgenden Abschnitten werden die gleichen Techniken zur Extraktion von Linienspuren aus Rasterbildern angewandt.
Vorhandenes Bild aus Datei laden
Sie können die Funktionalität der Bildverarbeitungs-Toolbox verwenden, um jedes Bild in eine Form zu konvertieren, die von dem Roboter gezeichnet werden kann. Probieren Sie dies zunächst an den mitgelieferten Beispielbildern aus. Später können Sie versuchen, Ihre eigenen Fotos zu verwenden.
Beginnen Sie mit dem Laden eines Bildes in MATLAB. Wir verwenden eine Linienzeichnung des MathWorks-Logos. Öffnen Sie Task6.mlx in MATLAB.
>> edit Task6
Führen Sie den ersten Abschnitt des Live-Skripts unter der Überschrift Load image from file aus.
Zeilenspuren aus dem Bild extrahieren
Bearbeiten Sie das Bild so, dass es nur die dünnen Spuren von Linien enthält. Verwenden Sie Bildverarbeitungsfunktionen, um das Bild in Graustufen zu konvertieren, es in binäres Schwarz-Weiß zu konvertieren, isolierte Pixel zu entfernen und dünne Objekte in Linien zu verwandeln. Dazu führen Sie den Abschnitt von Task6.mlx unter der Überschrift Extract line traces from image aus. Die Ausgabe des Live-Skripts zeigt, wie das Bild nach jedem Schritt aussieht.
Rekursive Funktionen verstehen
Bislang sollten Sie mit MATLAB-Funktionen vertraut sein, die Eingaben übernehmen und Ausgaben zuruckgeben. Manchmal kann eine andere Variante dieser Funktion innerhalb einer Funktion aufgerufen werden. Dies wird als rekursive Funktion bezeichnet. Rekursive Funktionen können nützlich sein, wenn Sie ein Problem lösen wollen, indem Sie es iterativ in eine einfachere Version von sich selbst zerlegen. Wenn Sie zum einfachsten oder Basisszenario gelangen, geben Sie den einfachsten Wert zurück. Um zu veranschaulichen, wie dies in der Praxis funktioniert, betrachten Sie, wie Sie eine Fakultät berechnen. Dies wird durch eine Produktreihe definiert:
$n!=\prod_{i=1}^ni=1{\cdot}2{\cdot}3{\cdot}{\dots}{\cdot}n-1{\cdot}n$
Beachten Sie, dass diese Definition die Definition von ( n - 1)! enthält.
$n!=1{\cdot}2{\cdot}3{\cdot}{\dots}{\cdot}n-1{\cdot}n=\left(n-1\right)!{\cdot}n$
Daher ist eine mögliche Möglichkeit, n! zu berechnen, die iterative Berechnung von n - 1)!, bis Sie den einfachen Fall erreichen, bei dem n = 1. In MATLAB könnte eine rekursive Funktion dazu wie folgt beschrieben werden:
function out = myFactorial(n)
if n > 1
out = n*myFactorial(n-1);
else
out = 1;
end
Diese Funktion multipliziert n mit der Fakultät von n - 1. Wenn MATLAB jedoch die Fakultät von n – 1 berechnen muss, erzeugt es dazu eine neue Instanz der myFactorial-Funktion. Dies wiederholt sich, bis die Funktion den Faktorwert für 1 berechnet. Dann, anstatt eine neue rekursive Instanz zu erstellen, gibt sie einfach 1 zurück und geht dann den Stapel zurück, bis das Ergebnis berechnet und für den ersten Aufruf von myFactorial zurückgegeben wird. Um zu sehen, wie das funktioniert, erstellen Sie die obige Funktion in MATLAB und fügen Sie der ersten Zeile einen Haltepunkt hinzu, indem Sie auf den Bindestrich (-) neben der Zeilennummer klicken.
Rufen Sie nun die Funktion aus der MATLAB-Befehlszeile auf:
>> myFactorial(4)
Der Debugging Haltepunkt wird angefahren. Klicken Sie auf die Schaltfläche Step auf der Editor-Toolstrip, um durch den Code zu navigieren und den Haltepunkt bei nachfolgenden aufgerufenen Instanzen von myFactorial weiterhin zu drücken. Nach jedem Schritt überprüfen Sie den Arbeitsbereich, um die aktuellen Werte von n und out zu sehen. Sie können auch den Funktions-Call-Stack überprüfen, um zu sehen, welche Version von myFactorial gerade ausgeführt wird.
Beachten Sie, dass dies nur eine Veranschaulichung der Rekursion ist und nicht der effizienteste Weg, um eine Fakultät zu berechnen. In MATLAB ist dies einfach möglich, indem Sie die Funktion prod einfach auf die gesamte Sequenz 1 bis n anwenden.
>> prod(1:4)
Die getCoords-Funktion Zeile für Zeile verstehen
Um die Verläufe aus einem Bild in Form von Koordinatenwertpaaren, welche Kurven bilden, zu extrahieren, haben wir die Funktion getCoords erstellt. Es handelt sich um eine rekursive Funktion, die sich weiterhin selbst aufruft, während noch Pixel auf einem Binärbild vorhanden sind. Sie verkettet sie zu einem einzigen Array.
Diese Funktion ruft bwboundaries rekursiv auf, entfernt die äußeren Pixelgrenzen
jedes Mal aus dem Bild und verkettete sie.
function curvePoints = getCoords(shapeImage)Rufen Sie zunächst bwboundaries auf, um die Grenzen jeder einzelnen Region zu ermitteln.
% Detect boundary points
[curves,~,N] = bwboundaries(shapeImage);
curves = curves(1:N); % Ignore hole boundariesHolen Sie sich die Pixel von den Rändern.
% Get the points from the boundary detected
curvePoints = cell2mat(curves);Wenn es doppelte Pixel gibt, entfernen Sie diese und behalten Sie nur eindeutige Pixel.
% Remove all duplicate points from the curve
curvePoints = unique(curvePoints,'rows','stable');Entfernen Sie in dem zu analysierenden Bild alle Pixel, die von bwboundaries erfasst wurden.
Möglicherweise sind noch Pixel im Bild vorhanden.
% Remove curves from the image
curveInd = sub2ind(size(shapeImage),curvePoints(:,1), curvePoints(:,2));
shapeImage(curveInd) = 0;Überprüfen Sie das Bild, um zu sehen, ob irgendwelche Pixel übrig geblieben sind.
Wenn keine Pixel mehr übrig sind, geben Sie die ermittelten curvePoints als Rückgabewert zurück.
Wenn es mehr Pixel gibt, rufen Sie diese Funktion erneut auf und fügen Sie curvePoints zu den
zusätzlichen Pixeln hinzu, die durch den rekursiven Aufruf gefunden wurden.
% Call getCoords recursively if there are other curves remaining
if any(shapeImage(:))
curvePoints = [curvePoints; getCoords(shapeImage)];
endRekursive Extraktion von Pixeln in der richtigen Reihenfolge
Jetzt können Sie getCoords auf dem Bild aufrufen, um die ausgewählten Pixel aus dem Bild in einer Reihenfolge zu extrahieren, die benachbarte Pixel nebeneinander stellt. Die Ausgabe ist ein Nx2-Array von Pixelkoordinaten, das das Ergebnis jeder Iteration von getCoords enthält. Diese werden übereinander gestapelt. N ist die Anzahl der im Bild identifizierten Pixel. Sie können diese Pixelkoordinaten auch in einem Streudiagramm visualisieren. Führen Sie den Abschnitt des Live-Skripts Task6.mlx unter der Überschrift Extract pixels in order aus.
Die Funktion coords2segments - Zeile für Zeile verstehen
Ausgehend von einer Folge von Datenpaaren, die mit der Funktion getCoords erhalten wurden, müssen wir die verschiedenen Pixelgruppen identifizieren. Dies geschieht, indem man jedes Pixelpaar überprüft, um zu sehen, ob es benachbart ist. Anschließend werden sie getrennt, wenn sie es nicht sind. Alle resultierenden Elemente werden in einer einzigen Zellenanordnung gespeichert.
Diese Funktion betrachtet jedes Pixelpaar und bestimmt, wo es nicht benachbart ist.
Es teilt dann coordsPix in Sätze von zusammenhängenden Pixeln auf und speichert jedes in einer
separaten Zelle als Teil des Cell-Arrays segmentsPix.
function segmentsPix = coords2segments(coordsPix)Zuerst müssen Sie die Stellen finden, an denen aufeinanderfolgende Pixel nicht benachbart sind.
Erstellen Sie eine breaks-Variable, die ein logischer Index mit 1 ist, wenn es einen Versatz gibt,
und 0, wenn Pixel benachbart sind.
% Find discontinuous locations in coordsPix
consecutiveDistance = abs(diff(coordsPix));
breaks = any(consecutiveDistance > [1 1],2);Verwenden Sie die Variable breaks, um die Indizes für Anfang und Ende jedes Segments zu konstruieren.
Dann durchschleifen Sie die Segmente und erstellen Sie ein Cell-Array segmentsPix,
wobei jede Zelle alle Pixelkoordinaten für dieses Segment enthält.
% Build cell array of each segment of adjacent pixel coordinates
numSegments = sum(breaks)+1;
segmentsPix = cell(numSegments,1);
breakInds = [0; find(breaks); size(coordsPix,1)];
for ii = 1:numSegments
segmentsPix{ii} = coordsPix(breakInds(ii)+1:breakInds(ii+1),:);
endKoordinatenliste in fortlaufende Segmente aufteilen
Jetzt rufen Sie coords2segments auf dem Array der im vorherigen Schritt extrahierten Pixelkoordinaten auf. Dies gibt ein Cell-Array zurück, in dem jedes Element eine Liste zusammenhängender Pixel ist. Zeichne jede Gruppe von Pixeln auf, um zu sehen, welche davon zusammen organisiert sind. Führen Sie den Abschnitt des Live-Skripts Task6.mlx unter der Überschrift Break coordinates list into contiguous segments aus.
Beachten Sie, wie die rote und blaue Leiterbahn einen gemeinsamen Endpunkt am linken Ende teilen. Im nächsten Abschnitt werden wir sehen, wie man diese zu einer einzigen Linienspur kombiniert.
Die Funktion connectSegments Zeile für Zeile verstehen
Angesichts der Ergebnisse der vorherigen Funktion kann es Segmente mit benachbarten Endpunkten geben, die miteinander verbunden werden können. Dies kann die Gesamtzahl der Segmente im Bild reduzieren.
Die Funktion connectSegments bewirkt zwei Dinge. Zuerst schließt es alle Segmente, die sich
selbst schneiden. Anschließend werden alle Segmente zusammengeführt, deren Endpunkte benachbart sind.
function segments = connectSegments(segments)Wenn sich ein Segment selbst überschneidet, wie beispielsweise im Buchstaben "O", endet es an einem Punkt,
der an ein anderes Pixel in diesem Segment angrenzt. Dadurch entsteht eine kleine Lücke,
wenn man auf dem Whiteboard zeichnet. Um dies zu korrigieren, fügen Sie das letzte benachbarte Pixel
an das Ende dieses Segments an, so dass die Linie geschlossen wird. Dieser Codeabschnitt untersucht
jedes Segment, findet alle Selbstüberschneidungen und schließt sie. p1 ist der erste Punkt in einem Segment.
pN ist der letzte Punkt im Segment. Fügen Sie alle Punkte nahe p1 an den Anfang des Segments hinzu.
Fügen Sie am Ende des Segments alle Punkte nahe pN hinzu.
% Close any segments that self-intersect (like an "O" or a "P")
for ii = 1:length(segments)
points = segments{ii};
p1 = points(1,:);
pN = points(end,:);
% Add any points near p1 to beginning of segment ii
nearP1 = isadjacent(p1,points(4:end,:)); %Don't check first 3 points
if any(nearP1)
idx = find(nearP1,1)+3;
points = [points(idx,:); points]; %#ok<*AGROW>
end
% Add any points near pN to end of segment ii
nearPN = isadjacent(pN,points(1:end-3,:)); %Don't check last 3 points
if any(nearPN)
idx = find(nearPN,1);
points = [points; points(idx,:)];
end
segments{ii} = points;
endDieser Code führt alle Segmente mit benachbarten Endpunkten zusammen. Es betrachtet jedes
Paar der Segmente ii und jj. Nehmen Sie den ersten und letzten Punkt jedes Segments im Paar
(insgesamt vier Punkte) und überprüfen Sie, ob es benachbarte Punkte gibt. Wenn irgendwelche Nachbarschaften
gefunden werden, ersetzen Sie die beiden Segmente durch ein einziges Segment, das einen kontinuierlichen
Weg durch beide Segmente beschreibt.
% Merge segments with adjacent endpoints
for ii = 1:length(segments)-1
jj = ii + 1;
% Check all combinations of 2 segments ii and jj
while jj <= length(segments)
points_i = segments{ii};
points_j = segments{jj};
pi1 = points_i(1,:);
piN = points_i(end,:);
pj1 = points_j(1,:);
pjN = points_j(end,:);
% Compare points 1 and N from segments ii and jj
if isadjacent(pi1,pj1)
segments{ii} = [flipud(points_j); points_i];
segments(jj) = [];
elseif isadjacent(pi1,pjN)
segments{ii} = [points_j; points_i];
segments(jj) = [];
elseif isadjacent(piN,pj1)
segments{ii} = [points_i; points_j];
segments(jj) = [];
elseif isadjacent(piN,pjN)
segments{ii} = [points_i; flipud(points_j)];
segments(jj) = [];
end
jj = jj + 1;
end
end
endDie Unterfunktion isadjacent schafft eine komfortable Möglichkeit, zu überprüfen,
ob zwei Punkte nebeneinander liegen. Als Unterfunktion kann sie nur innerhalb der Funktion
connectSegments aufgerufen werden.
% Subfunction to define if points are adjacent
function tf = isadjacent(p1,p2)
tf = all(abs(p1-p2) <= [1 1],2);
endVerbundene Segmente zusammenführen und Grenzwerte erhalten
Nun rufen Sie connectSegments im Cell-Array der im vorherigen Schritt erstellten Pixelgruppen auf. Dies gibt ein neues Cell-Array mit Pixelgruppen zurück. In dieser neuen Zellenanordnung können einige der Gruppen zusammengeführt werden, wenn sie zu einem einzigen Pfad verbunden werden können. Jede Gruppe von Pixeln in diesem Cell-Array steht für eine Linie, die vom Roboter gezeichnet wird. Dieser hebt den Marker an, bevor er den nächsten Linienzug zeichnet. Zeichne jede Gruppe von Pixeln auf, um alle Wege zu visualisieren, die der Roboter zurücklegen wird. Führen Sie den Abschnitt des Live-Skripts Task6.mlx unter der Überschrift Merge connected segments aus.
Erstellen Sie auch neue Variablen xLimPix und yLimPix als schnellen Weg, um die maximale und minimale Pixelposition zu speichern, welche beim Zeichnen des Bildes auf dem Whiteboard verwendet werden. Denken Sie daran, dass sie bei der Schätzung der Skalierbarkeit des Bildes für die Anpassung an das Whiteboard benötigt werden. Führen Sie den Codeabschnitt mit der Überschrift Store x and y pixel limits aus.
Eine Funktion zur Konvertierung von Bildern in Pixelsegmente
Der Code, den Sie bisher ausgeführt haben, nimmt ein Bild auf und erzeugt Gruppen von Pixelpositionen. Sie können alle diese Schritte in einer Funktion zusammenfassen, um sie einfach auf jedem Bild auszuführen. Die Funktion gibt die Variablen segmentsPix, xLimPix und yLimPix zurück, die Sie berechnet haben. Erstellen Sie eine neue MATLAB-Funktion und nennen Sie sie imageToPixelSegments.m. Fügen Sie den folgenden Code in die Funktion ein und speichern Sie ihn.
function [segmentsPix,xLimPix,yLimPix] = imageToPixelSegments(img)
% Extract line traces from image
img2 = ~imbinarize(rgb2gray(img), 'adaptive' , 'ForegroundPolarity' , 'dark' );
img3 = bwmorph(img2, 'clean' );
img4 = bwmorph(img3, 'thin' ,inf);
% Extract pixels in order
coordsPix = getCoords(img4);
% Break coordinates list into contiguous segments
segmentsPix = coords2segments(coordsPix);
% Clean data and merge connected segments
segmentsPix = connectSegments(segmentsPix);
% Store x and y pixel limits
xLimPix = [min(coordsPix(:,2)) max(coordsPix(:,2))];
yLimPix = [min(coordsPix(:,1)) max(coordsPix(:,1))];
Überprüfen Sie nun, ob sich der Code in der Funktion imageToPixelSegments genauso verhält wie der Code, den Sie bisher ausgeführt haben. Führen Sie dazu die Funktion aus und vergleichen Sie das Ergebnis mit den Variablen segmentsPix, xLimPix und yLimPix in Ihrem Arbeitsbereich. Führen Sie den Abschnitt Test function imageToPixelSegments in Task6.mlx aus.
Zeichnen des Bildes auf dem Whiteboard
In der vorherigen Übung haben Sie eine Funktion drawImageFromPix geschrieben, die ein Zellenarray von Pixelpfaden auswertet und auf das Whiteboard zeichnet. Nun können Sie diese Funktion aufrufen, um das MathWorks-Logo auf dem Whiteboard wiederzugeben. Führen Sie den Abschnitt von Task6.mlx mit der Überschrift Draw image using function previously created aus.
Schreiben des Hauptskripts, um den gesamten Workflow auszuführen
Um eine Anwendung mit vielen Schritten auszuführen, ist es üblich, ein Hauptskript zu erstellen. Dies ist ein Skript, das auf höchster Ebene arbeitet und einen kompletten Workflow von Anfang bis Ende ausführt. Wir können ein Hauptskript erstellen, um alle Aufgaben auszuführen, die Sie in dieser Übung durchgeführt haben. Dabei stützen wir uns auf die Funktionen, die Sie bisher erstellt haben.
Erstellen Sie ein neues leeres MATLAB-Skript. Füge den folgenden Code hinzu und speichere die Datei als main6.m:
% Load image from file
img = imread( 'Images/MathWorksLogo.jpg' );
% Convert image to pixel segments
[segmentsPix,xLimPix,yLimPix] = imageToPixelSegments(img);
% Identify initial position on whiteboard
Z_i = initialPosition();
% Draw image
drawImageFromPix(segmentsPix,xLimPix,yLimPix,Z_i)
FILES
- Task6.mlx
- getCoords.m
- coords2segments.m
- connectSegments.m
- imageToPixelSegments.m
- main6.m
LEARN BY DOING
Nutzen Sie Ihr Verständnis von rekursiven Funktionen, um eine neue MATLAB-Funktion zu schreiben, welche rekursiv den neunten Wert der Fibonacci-Sequenz berechnet. Denken Sie daran, dass die n-te Fibonacci-Zahl die Summe der beiden vorherigen Fibonacci-Zahlen ist und die ersten beiden 0 und 1 sind, Ihre rekursive Funktion sollte zwei Stoppbedingungen haben (wenn n = 1 oder n = 2). In allen anderen Fällen sollte sich Ihre Funktion rekursiv zweimal aufrufen.
In dieser Übung laden Sie ein Bild aus einer Datei, bearbeiten es und zeichnen es dann sofort. Sie können aber auch einfach Ihre Bilder bearbeiten, die extrahierten Linienspuren in der Vorschau ansehen und diese Pixeldaten in einer MAT-Datei speichern und später laden und zeichnen. Schreiben Sie zu diesem Zweck eine Funktion. Beim Speichern der Daten in einer MAT-Datei müssen Sie einen Dateinamen angeben. Es gibt zwei Möglichkeiten. Einer davon ist, den Namen basierend auf dem Dateinamen des Bildes auszuwählen. Verwenden Sie matlab.lang.makeValidName, um sicherzustellen, dass der Name gültig ist. Die zweite Möglichkeit besteht darin, den Benutzer über den Dialog uiputfile nach einem Namen zu fragen.
In Ihrem main6.m-Skript haben Sie den Namen der zu verarbeitenden Bilddatei fest programmiert. Um das Skript benutzerfreundlicher zu gestalten und Ihnen das Zeichnen verschiedener Arten von Bildern zu ermöglichen, können Sie dies ändern, so dass der Benutzer interaktiv das zu zeichnende Bild auswählen kann. Ändern Sie den Anfang von main6.m so, dass der Benutzer aufgefordert wird, eine Datei auszuwählen, anstatt sie im Code zu definieren. Hierfür steht Ihnen der Dialog uigetfile zur Verfügung.
ÜBUNG 7:
4.7 Live-Bilder aufnehmen und zeichnen
Mittlerweile ist Ihr Zeichenroboter ziemlich leistungsfähig. Es kann jede beliebige Bilddatei verwenden und das Bild auf einem Whiteboard wiedergeben. All dies wird im Code automatisiert. Aber es gibt noch einige manuelle Schritte, die die Erstellung des Bildes, die Übertragung der Datei auf Ihren Computer und die Angabe dieser Datei als die, die Sie zeichnen möchten, beinhalten. In dieser Übung automatisieren Sie auch diese Schritte, indem Sie das Bild mit einer Webcam aufnehmen und direkt in MATLAB übertragen, analysieren und mit dem Roboter zeichnen.
In dieser Übung werden Sie lernen:
- Mit einer Webcam verbinden
- Aktualisieren eines Hauptskripts
Verbindung mit einer Webcam
Neben Arduino-Geräten kann MATLAB auch mit vielen anderen Hardwaretypen kommunizieren. Um Bilder direkt in MATLAB zu erfassen, können Sie eine USB-Webcam verwenden. Die Webcam-Schnittstelle von MATLAB kann sich mit Webcams verbinden, eine Vorschau der Bilder anzeigen und Momentaufnahmen erstellen, die das aktuelle Bild direkt in MATLAB übertragen. Für diese Funktionalität ist das MATLAB Support Package for USB Webcams erforderlich, das Sie bei der Einrichtung Ihrer gesamten MATLAB- und Simulink-Software installiert haben sollten. Wenn Sie das Support Package noch nicht installiert haben, installieren Sie es jetzt. Suchen Sie die im Lieferumfang enthaltene USB-Webcam und schließen Sie diese an Ihren Computer an. Öffnen Sie das Live-Skript Task7.mlx.
>> edit Task7
bearbeiten um die Webcam in MATLAB zu identifizieren und mit ihr zu verbinden. Führen Sie den Codeabschnitt unter der Überschrift Connect to webcam aus.
Vorschau für Webcam-Bilder
Eine Voransicht für das Webcam-Bild in MATLAB erhalten Sie durch Ausführen des Codeabschnitts mit der Überschrift Preview webcam image.
Bewegen Sie die Webcam herum, um sicherzustellen, dass sie eine klare Sicht auf die zu betrachtenden Bilder hat.
Das aktuelle Bild aufnehmen
Mit einem schwarzen Marker erstellen Sie eine einfache Linienzeichnung auf Ihrem Whiteboard, die Ihr Roboter nachbilden soll. Richten Sie die Kamera auf das Whiteboard und überprüfen Sie das Vorschaufenster, um sicherzustellen, dass die Zeichnung klar ist, dass sich nichts anderes im Blickfeld der Kamera befindet. Außerdem darf es keine Blendung oder ungleichmäßige Beleuchtung auf dem Whiteboard geben. Alternativ können Sie auch eine Kugelschreiberzeichnung auf einem weißen Blatt Papier verwenden.
Nehmen Sie ein Bild der Zeichnung auf. Führen Sie den Codeabschnitt in Task7.mlx mit der Überschrift Capture the current image aus.
Verarbeitung und Überprüfung des Bildes
Um sicherzustellen, dass Ihr Bild mit dem Roboter korrekt gezeichnet wird, führen Sie Ihre Bildverarbeitungsfunktion imageToPixelSegments aus und überprüfen Sie, ob die extrahierten Linien im Bild den Erwartungen entsprechen. Führen Sie den Abschnitt von Task7.mlx unter der Überschrift Process and verify image aus. Wenn die bearbeitete Version nicht korrekt aussieht, nehmen Sie ein neues Bild und versuchen Sie es erneut.
Aktualisieren des Hauptskripts für Livebilde
In der vorherigen Übung haben Sie ein Hauptskript erstellt, um die gesamte Anwendung auszuführen. Dieses Skript hat das gewünschte Bild aus einer Datei geladen. Jetzt modifizieren Sie dieses Skript, damit es das Bild von der Kamera übernehmen kann. Öffnen Sie die Datei main6.m . Speichern Sie eine neue Version der Datei als main7.m. Löschen Sie die erste Zeile des Codes aus main6.m, die das Bild aus der Datei lädt. Ersetzen Sie es durch einen Code, der eine Verbindung zur Webcam herstellt. Dieser ermöglicht auch eine Vorschau des Bildes und wartet, bis Sie eine Taste drücken, um einen Schnappschuss des aktuellen Bildes zu machen und mit dem Skript fortzufahren. Das vollständige main7.m-Skript sollte wie folgt aussehen:
% Capture image from webcam
w = webcam;
preview(w)
pause
img = snapshot(w);
clear w
% Convert image to pixel segments
[segmentsPix,xLimPix,yLimPix] = imageToPixelSegments(img);
% Identify initial position on whiteboard
Z_i = initialPosition();
% Draw image
drawImageFromPix(segmentsPix,xLimPix,yLimPix,Z_i)
Ausführen des Hauptskripts, um ein Bild zu zeichnen, das live aufgenommen wurde
Jetzt probieren Sie es mit Ihrem Roboter aus. Führen Sie an der MATLAB-Befehlszeile Ihr Hauptskript aus.
>> main7
Es öffnet sich ein Webcam-Vorschaufenster. Richten Sie Ihre Kamera auf einen weißen Bereich des Whiteboards mit einer einfachen Linie darauf. Vergewissern Sie sich, dass sich nichts anderes im Bildausschnitt befindet und keine Blendung oder Farbveränderung im gesamten Bild vorliegt. Drücken Sie eine beliebige Taste in MATLAB, um fortzufahren. Der Roboter skaliert das aufgenommene Bild auf das gesamte Whiteboard und versucht, es zu reproduzieren.
FILES
- Task7.mlx
- main7.m
LEARN BY DOING
Am Ende dieser Aufgabe sollten Sie in der Lage sein, ein Bild von einer USB-Webcam aufzunehmen und es sofort mit Ihrem Roboter zu zeichnen. Eine weitere mögliche Anwendung für die Webcam könnte darin bestehen, eine ganze Reihe von Bildern von Whiteboard-Zeichnungen aufzunehmen, um sie später mit dem Roboter zu reproduzieren. Beginnen Sie mit dem Code, den Sie bereits haben, erstellen Sie ein Skript, mit dem Sie ein Webcam-Bild aufnehmen können. Fordern Sie den Benutzer auf, einen Dateinamen einzugeben, und speichern Sie das Bild unter diesem Namen. Siehe auch die Funktionen uiputfile und imwrite für Hilfe bei diesen Aufgaben an.
4.8 Zusammenfassung - Lessons Learned
In this chapter you were introduced to these following topics:
APPLY TRIGONOMETRIC THEORY TO CONTROL THE MOVEMENTS OF THE ROBOT.
In this project you have learned how to decompose movements through trigonometry to calculate the distances that allow the robot to draw on the whiteboard. As well, you combined the trigonometry with motion equations to move the robot to some specific points in your whiteboard. You did it using MATLAB scripts and searching the information of the motors in its datasheets.
KNOWING THE LIMITATIONS OF THE ROBOT MOVEMENTS
Nachdem Sie wissen, wie man die Roboterbewegungen programmiert, haben Sie gelernt, wo die Begrenzungen liegen, warum der Roboter nicht bestimmte Positionen erreichen kann und welche die erlaubten Bereiche zum Zeichnen sind.
Bildverarbeitung
Sie haben auch gelernt, wie man ein Bild verarbeitet, um die benötigten Daten zu erhalten, um es auf dem White Board zu zeichnen. Um dies zu tun, haben Sie erfahren, wie man einige Bildfilter anwendet, wie man die Linien der Zeichnung erhält, wie man die Pixel in Meter umwandelt und wie man Abschnitte erstellt, um die Bewegungsbahn des Roboters zu erstellen.
4.9 Letzte Herausforderung
Während dieses Projekts haben Sie mit nur einem Marker Bilder auf das Whiteboard gezeichnet. Ihr Zeichenroboter kann jedoch zwei Marker aufnehmen. Es wäre schön, wenn Sie Bilder zeichnen könnten, die mehr als eine Farbe haben. Wie könnten Sie das anstellen?
er einfachste Ansatz wäre es, die Farben für jeden Linienabschnitt zu wechseln. Ein anderer Ansatz könnte darin bestehen, die Objekte im Bild zu gruppieren, basierend darauf, wie nah sie aneinander liegen, und jede Gruppe mit der gleichen Farbe zu zeichnen. Oder kombinieren Sie zwei verschiedene Bilder und zeichnen Sie jedes in einer anderen Farbe. Vielleicht könnten Sie Linien verschiedener Farben in einem einzigen Bild identifizieren und separat zeichnen. Wie würden Sie das mit der Bildverarbeitung machen? Versuchen Sie, die App Color Thresholder aus der Image Processing Toolbox zu verwenden. Ihre letzte Herausforderung besteht darin, eine interessante Möglichkeit zu finden, Zeichnungen zu erstellen, die mehrere Markierungsfarben verwenden. Sie können eine der aufgeführten Ideen ausprobieren oder sich eigene ausdenken. Implementieren Sie die Lösung in MATLAB und zeichnen Sie dann mit Ihrem Roboter ein mehrfarbiges Bild.