Zeit-, Entfernungs- und Gewichtsschätzung: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
 
(72 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 23: Zeile 23:


== Anforderungen ==
== Anforderungen ==
Im nachfolgenden werden die testbaren Anforderungen gezeigt welche den korrekten Betrieb der Zeit-, Entfernungs- und Gewichtsschätzung sicherstellen.
Im nachfolgenden werden die testbaren Anforderungen gezeigt welche den korrekten Betrieb der Zeit-, Entfernungs- und Gewichtsschätzung sicherstellen und [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/01_Projektplan/ hier] hinterlegt sind.
{| class="wikitable"
{| class="wikitable"
|+ style = "text-align: left"|Tabelle 1: Anforderungen an das Escape Game
|+ style = "text-align: left"|Tabelle 1: Anforderungen an das Escape Game
|-
|-
! ID  !! Inhalt !! Prio!! Ersteller !! Datum !! Geprüft von !! Datum
! ID  !! Inhalt !! Prio!! Ersteller !! Datum !! Geprüft von !! Datum !! Umsetzung der Anforderung in %
|-
|-
| 1  || Das Escape Game muss in 4-5 Minuten lösbar sein                                                          || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 1  || Das Escape Game muss in 4-5 Minuten lösbar sein                                                          || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 2  || Der Spieler muss den Button für 10 Sekunden +-1 s Sekunde gedrückt halten um zum zweiten Rätsel der Abstandsmessung zu gelangen. || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 2  || Der Spieler muss den Button für 10 Sekunden +-1 s Sekunde gedrückt halten um zum zweiten Rätsel der Abstandsmessung zu gelangen. || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 3  || Wenn die Zeit falsch geschätzt wurde, wird die tatsächlich gedrückte Zeit auf dem Display angezeigt.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 3  || Wenn die Zeit falsch geschätzt wurde, wird die tatsächlich gedrückte Zeit auf dem Display angezeigt.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||  
|-
|-
| 4  || Wenn die Zeit falsch geschätzt wurde, beginnt das Spiel von vorne.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 4  || Wenn die Zeit falsch geschätzt wurde, beginnt das Spiel von vorne.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||  
|-
|-
| 5  || Wenn die Zeit falsch geschätzt wurde, wird eine traurige Melodie abgespielt.  || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024
| 5  || Wenn die Zeit falsch geschätzt wurde, wird eine traurige Melodie abgespielt.  || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||
|-
|-
| 6  || Ist die Zeit richtig geschätzt, blinkt eine LED, alle 500 ms, bei der Entfernungsschätzung um dem Benutzer zu zeigen wo es weitergeht.|| Hoch  || Niklas Reeker  || 02.10.2024 || Oliver Scholze||02.10.2024   
| 6  || Ist die Zeit richtig geschätzt, blinkt eine LED, alle 500 ms, bei der Entfernungsschätzung, um dem Benutzer zu zeigen wo es weitergeht.|| Hoch  || Niklas Reeker  || 02.10.2024 || Oliver Scholze||02.10.2024  ||
|-
|-
| 7  || Ist die Zeit richtig geschätzt, beginnt die Entfernungsschätzung von 10 cm +-1 cm.                        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 7  || Ist die Zeit richtig geschätzt, beginnt die Entfernungsschätzung von 10 cm +-1 cm.                        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||  
|-
|-
| 8  || Wenn die Entfernung falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung.        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 8  || Wenn die Entfernung falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung.        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 9  || Wenn die Entfernung falsch geschätzt wird, wird die tatsächlich geschätzte Entfernung auf dem Bildschirm in cm angezeigt.        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 9  || Wenn die Entfernung falsch geschätzt wird, wird die tatsächlich geschätzte Entfernung auf dem Bildschirm in cm angezeigt.        || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 10  || Wenn die Entfernung falsch geschätzt wird, wird eine traurige Melodie abgespielt.        || Mittel  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024
| 10  || Wenn die Entfernung falsch geschätzt wird, wird eine traurige Melodie abgespielt.        || Mittel  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024|| 
|-
|-
| 11  || Ist die Entfernung richtig geschätzt, leuchtet eine LED, bei der Gewichtsschätzung um dem Benutzer zu zeigen wo es weitergeht.|| Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024   
| 11  || Ist die Entfernung richtig geschätzt, blinkt eine LED, alle 500 ms, bei der Gewichtsschätzung, um dem Benutzer zu zeigen wo es weitergeht.|| Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  ||
|-
|-
| 12  || Ist die Entfernung richtig geschätzt, beginnt die Gewichtsschätzung von 100 g +-10%.                        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024   
| 12  || Ist die Entfernung richtig geschätzt, beginnt die Gewichtsschätzung von 100 g +-10%.                        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  ||
|-
|-
| 13  || Wenn das Gewicht falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung.        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024   
| 13  || Wenn das Gewicht falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung.        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  ||
|-
|-
| 14  || Wenn das Gewicht falsch geschätzt wird, wird das tatsächliche Gewicht auf dem Bildschirm in g angezeigt.        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  
| 14  || Wenn das Gewicht falsch geschätzt wird, wird das tatsächliche Gewicht auf dem Bildschirm in g angezeigt.        || Hoch  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024 ||
|-
|-
| 15  || Wenn das Gewicht falsch geschätzt wird, wird eine traurige Melodie abgespielt.        || Mittel  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024   
| 15  || Wenn das Gewicht falsch geschätzt wird, wird eine traurige Melodie abgespielt.        || Mittel  || Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  ||
|-
|-
| 16  || Bei richtiger Zeitschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024
| 16  || Bei richtiger Zeitschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024|| 
|-
|-
| 17  || Bei richtiger Entfernungsschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 17  || Bei richtiger Entfernungsschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||  
|-
|-
| 18  || Bei richtiger Gewichtsschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024  
| 18  || Bei richtiger Gewichtsschätzung wird eine Siegesmelodie abgespielt. || Mittel|| Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024 ||
|-
|-
| 19  || Die Zeitmessung wird bei der Ausgabe auf ganze Sekunden gerundet (Bsp: 12,6 s entspricht 13 s). || Hoch|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 19  || Die Zeitmessung wird bei der Ausgabe auf ganze Sekunden gerundet (Bsp: 12,6 s entspricht 13 s). || Hoch|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 20  || Die Entfernungsmessung wird bei der Ausgabe auf ganze Entfernungen in cm gerundet (Bsp: 12,6 cm entspricht 13 cm). || Hoch|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 20  || Die Entfernungsmessung wird bei der Ausgabe auf ganze Entfernungen in cm gerundet (Bsp: 12,6 cm entspricht 13 cm). || Hoch|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 21  || Die Gewichtsmessung wird bei der Ausgabe auf ein ganzzahliges Gewicht in g gerundet (Bsp: 105,2 g entspricht 105 g). || Hoch|| Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024
| 21  || Die Gewichtsmessung wird bei der Ausgabe auf ein ganzzahliges Gewicht in g gerundet (Bsp: 105,2 g entspricht 105 g). || Hoch|| Johann Kismann  || 11.10.2024 || Oliver Scholze|| 11.10.2024||
|-
|-
| 22  || Bei richtiger Gewichtsschätzung wird der dreistellige Code für das Schloss auf dem Display ausgegeben. || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 22  || Bei richtiger Gewichtsschätzung wird der dreistellige Code für das Schloss auf dem Display ausgegeben. || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 23  || Das Spiel muss ohne visuelle Hilfsmittel zur Zeit-, Entfernungs- und Gewichtsmessung (wie Uhren, Lineale oder Waagen) funktionieren.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 23  || Das Spiel muss ohne visuelle Hilfsmittel zur Zeit-, Entfernungs- und Gewichtsmessung (wie Uhren, Lineale oder Waagen) funktionieren.  || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 24  || Die Interaktion erfolgt über einen einfachen Knopf und einen Display für Rückmeldungen.          || Mittel || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 24  || Die Interaktion erfolgt über einen einfachen Knopf und einen Display für Rückmeldungen.          || Mittel || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 25  || Das System muss benutzerfreundlich und für Kinder wie Erwachsene geeignet sein.                    || Mittel || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 25  || Das System muss benutzerfreundlich und für Kinder wie Erwachsene geeignet sein.                    || Mittel || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024 ||  
|-
|-
| 26  || Das Arduino-System wird über Simulink gesteuert.                || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024   
| 26  || Das Arduino-System wird über Simulink gesteuert.                || Hoch  || Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024  ||
|-
|-
| 27  || Das Escape Game muss in einen Schuhkarton passen.                                              || Gering|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024
| 27  || Das Escape Game muss in einen Schuhkarton passen.                                              || Gering|| Niklas Reeker  || 02.10.2024  || Oliver Scholze  || 02.10.2024|| 
|-
|-
|}
|}
Zeile 109: Zeile 109:
|+ style = "text-align: left"| Tabelle 2: Materialliste
|+ style = "text-align: left"| Tabelle 2: Materialliste
|-
|-
! Nr. !! Anz.    !! Beschreibung !! Bestellstatus
! Nr. !! Anz.    !! Beschreibung  
|-
|-
|1 || 1 || [[Arduino|Funduino Arduino Mega]] ||
|1 || 1 || [[Arduino|Funduino Arduino Mega]]  
|-
|-
|2 || 1 || Taster ||
|2 || 1 || Taster  
|-
|-
|3  || 3 || 7-Segment-Display ||
|3  || 3 || 7-Segment-Display  
|-
|-
|4  || 1 || (Lochrasterplatine) || Vorhanden --> Überlegung Platine zu designen und zu fräsen
|4  || 1 || (Lochrasterplatine)  
|-
|-
|5  || 1 || Verbindungskabel || Vorhanden
|5  || 1 || Verbindungskabel  
|-
|-
|6 || 3 || 7-Segment-Decoder ||
|6 || 3 || 7-Segment-Decoder  
|-
|-
|7  || 1 || Summer ||
|7  || 1 || Summer  
|-
|-
|8  || 2 || LED grün ||
|8  || 2 || LED grün  
|-
|-
|9  || 2 || Widerstand 10kOhm ||
|9  || 2 || Widerstand 10kOhm  
|-
|-
|10  || 1 || Netzteil + Kabel ||
|10  || 1 || Netzteil + Kabel  
|-
|-
|11  || 1 || Gehäuse 3D-Druck ||
|11  || 1 || Gehäuse 3D-Druck  
|-
|-
|12  || 2 || Widerstand 150Ohm ||
|12  || 2 || Widerstand 150Ohm  
|-
|-
|13  || 1 || IR-Sensor ||
|13  || 1 || IR-Sensor  
|-
|-
|14  || 1 || Drucksensor ||
|14  || 1 || Drucksensor  
|}
|}


Zeile 317: Zeile 317:
| Pin 3||  Masse (GND); 0 V ||  Masse (GND); 0 V
| Pin 3||  Masse (GND); 0 V ||  Masse (GND); 0 V


|}
== Funktionsweise und Kalibrierung der Sensoren ==
=== Drucksensor ===
Der ARD SEN PRESSURE Drucksensor für Arduino funktioniert auf Basis piezoresistiver Technologie, was bedeutet, dass er Druckkräfte über eine Widerstandsänderung misst und in ein elektrisches Signal umwandelt. Wenn eine Kraft auf den Sensor ausgeübt wird, verformt sich ein empfindliches Material im Inneren des Sensors, was zu einer Änderung des elektrischen Widerstands führt. Dieser Widerstand variiert also direkt in Abhängigkeit von der aufgebrachten Kraft.
Diese Widerstandsänderung erzeugt ein elektrisches Signal, das als analoge Spannung ausgegeben wird. Die Spannung ist proportional zur Kraft, die auf den Sensor wirkt. Je höher der ausgeübte Druck, desto stärker verändert sich der Widerstand und damit auch das Ausgangssignal des Sensors. Bei Verbindung des Sensors mit einem analogen Eingang eines Arduino-Boards kann dieser die analoge Spannung lesen und in einen digitalen Wert umwandeln, der die Stärke des Drucks repräsentiert.
Da der Sensor für einen Messbereich von 20 g bis 10 kg ausgelegt ist, kann die analoge Spannung durch Kalibrierung in eine konkrete Gewichtskraft umgerechnet werden. Dazu muss eine Lookup-Tabelle erstellt werden, welche die verschiedenen Spannungswerte in die entsprechenden Gewichtswerte umwandelt. Um diese Tabelle zu erstellen, müssen zu bestimmten Gewichten die entsprechenden Spannungswerte notiert werden.
{| class="wikitable"
|+ style = "text-align: left"| Tabelle 6: Kalibrierung des Drucksensors
|-
! style="font-weight: bold;" | Gewicht in kg
! style="font-weight: bold;" | Spannung in V
|-
| - || -
|-
| - || -
|-
| - || -
|- 
| - || -
|}
=== IR-Sensor ===
Der IR-Abstandssensor mit einem Messbereich von 40 bis 300 mm nutzt Infrarottechnologie, um den Abstand zu einem Objekt zu messen. Der Sensor sendet einen Infrarotstrahl aus, der von einem Objekt in seinem Erfassungsbereich reflektiert wird. Ein integrierter Empfänger im Sensor erfasst das reflektierte Infrarotlicht. Basierend auf der Zeit und dem Winkel, unter dem das Licht reflektiert wird, berechnet der Sensor die Entfernung zum Objekt.
Der Abstandssensor gibt eine analoge Spannung aus, die proportional zur gemessenen Entfernung ist. Wenn der Abstand zum Objekt geringer ist, ist die ausgegebene Spannung höher; bei größerem Abstand ist die Spannung niedriger. Diese analoge Spannung kann an einen analogen Eingang eines Arduino-Boards angeschlossen werden. Der Arduino liest die Spannung, wandelt sie in einen digitalen Wert um und berechnet daraus die Distanz zum Objekt.
Für eine genaue Messung ist eine Kalibrierung erforderlich, da sich die analoge Spannung je nach reflektiertem Signal leicht verändern kann. Indem man bekannte Abstände misst und die Spannungen erfasst, kann eine Zuordnung erstellt werden, die dem Arduino hilft, die Spannung korrekt in eine Entfernung umzurechnen. Daraus lässt sich dann ein Lookup-Tabelle erstellen, die die Spannungswerte in die entsprechenden Entfernungen umwandelt.
{| class="wikitable"
|+ style = "text-align: left"| Tabelle 7: Kalibrierung des IR-Sensors
|-
! style="font-weight: bold;" | Entfernung in cm
! style="font-weight: bold;" | Spannung in V
|-
| - || -
|-
| - || -
|-
| - || -
|- 
| - || -
|}
|}


== Umsetzung HW (mechanisch) ==
== Umsetzung HW (mechanisch) ==
== Umsetzung HW (elektrisch) ==
== Umsetzung HW (elektrisch) ==


=== Verdrahtungsplan ===
 
=== Schaltplan ===
=== Verdrahtungsplan und Schaltplan ===
 
{| class="mw-datatable"
! style="font-weight: bold;" |
! style="font-weight: bold;" |
|+ style = "text-align: left"|
|-
|[[Datei:VerdrahtungsplanZeitAbstandGewichts.jpg|mini|338px|Abb. 14: Verdrahtungsplan ]]
|[[Datei:Schaltplan zum Projekt.jpg|mini|550px|Abb. 16: Schaltplan (mit Multisim (siehe Versionen))]]
|}<br>
 
In dem gezeigten Schaltplan in Abbildung 16 dienen die Netzbezeichnungen zur logischen Verbindung und Organisation der Signale zwischen verschiedenen Bauteilen. Diese Netzbezeichnungen ermöglichen es, dass elektrische Signale klar und übersichtlich an verschiedenen Stellen des Schaltplans verwendet werden können, ohne dass jede Leitung physisch durchgezeichnet werden muss. Dadurch wird der Schaltplan übersichtlicher, da wichtige Signalpfade und Verbindungen benannt und nachvollziehbar gestaltet werden. Die einzelnen Komponenten wurden zu Gruppen geordnet und mit deren Funktion beschriftet.
 
=== Anbindung des Tasters ===
[[Datei:AbbildungPullUp.png|right|mini|200px|Abb. XX: Pullup-Widerstand [2] ]]
Im Schaltplan ist die Anbindung des Tasters dargestellt. Um im nicht-geschaltetem Zustand ein definiertes Potential zu gewährleisten, wird ein Pullup-Widerstand von 10 kOhm verwendet, die die Leitung auf einen logischen High-Pegel bzw. 5V ziehen. Bei Betätigung des Tasters wird die Spannung auf GND gezogen, was einen logischen LOW-Pegel am entsprechenden digitalen Pin des Arduinos Mega bewirkt, wie es in Abbildung '''XX''' dargestellt ist [2].
 
=== Berechnung der Vorwiderstände der LEDs ===
=== Berechnung der Vorwiderstände der LEDs ===


Zeile 342: Zeile 404:


== Umsetzung SW ==
== Umsetzung SW ==
==== Umrechnung des Digitalwerts in Millivolt (mV) der beiden Sensoren (Drucksensor und IR-Sensor) ====
'''Verwendete Toolbox:''' DSP System Toolbox, Simulink Support Package für Arduino Hardware
==== Zusammenspiel der Komponenten und Module ====
 
{| class="mw-datatable"
! style="font-weight: bold;" |
! style="font-weight: bold;" |
|+ style = "text-align: left"|
|-
|Simulink Modell
|[[Datei:Zeit-,Entfernungs- und Gewichtsschätzung sQ.png|mini|150px|Abb. '''XX''':  PaP von der Zeit-,Entfernungs- und Gewichtsschätzung [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/03_Programmablaufplan/ (hier hinterlegt)] ]]
|}
 
==== Umrechnung des Digitalwerts in Volt der beiden Sensoren (Drucksensor und IR-Sensor) ====


Im Simulink-Modell werden die analogen Sensorwerte als Digitalwert erfasst und durch ein Gain, innerhalb von Matlab Simulink, in Volt umgerechnet. Die Sensoren liefern einen 10-Bit-Digitalwert, der von 0 bis 1023 reicht und mit einer Referenzspannung von 5V arbeitet. Dieser Wert wird vom Analog-Digital-Wandler (ADC) des Arduino aufgenommen. Um den Digitalwert in Volt umzurechnen, wird folgender Berechnungsschritt durchgeführt:
Im Simulink-Modell werden die analogen Sensorwerte als Digitalwert erfasst und durch ein Gain, innerhalb von Matlab Simulink, in Volt umgerechnet. Die Sensoren liefern einen 10-Bit-Digitalwert, der von 0 bis 1023 reicht und mit einer Referenzspannung von 5V arbeitet. Dieser Wert wird vom Analog-Digital-Wandler (ADC) des Arduino aufgenommen. Um den Digitalwert in Volt umzurechnen, wird folgender Berechnungsschritt durchgeführt:
Zeile 351: Zeile 425:


==== Signalverarbeitung für den IR-Sensor (GP2Y0A41SK0F)====
==== Signalverarbeitung für den IR-Sensor (GP2Y0A41SK0F)====
 
{| class="mw-datatable"
[[Datei:SpannungDistanz.png|right|mini|450px|Abb. XX: Zusammenhang zwischen Spannung und Distanz des GP2Y0A41SK0F ]]
! style="font-weight: bold;" |
Das analoge Ausgangssignal des Sensors wird vom Arduino in ein Digitalwort umgewandelt. Dieses Digitalwort wird anschließend in eine Spannung konvertiert, wie zuvor beschrieben. Um das Signal zu glätten und Störspitzen zu eliminieren, erfolgt eine Filterung. Im nächsten Schritt wird die Spannung unter Zuhilfenahme des Sensors-Datenblatts in einen Abstand in Zentimetern umgerechnet. Das Datenblatt enthält eine Kennlinie (siehe Abbildung '''XX'''), die den Zusammenhang zwischen Spannung und Distanz beschreibt. Dieser Zusammenhang wird in Simulink durch eine 1D-Lookup-Tabelle abgebildet, welche die Zuordnung der gemessenen Spannung zur entsprechenden Distanz vornimmt.
! style="font-weight: bold;" |
|+ style = "text-align: left"|
|-
|[[Datei:AbstandssensorikProjekt.png|mini|465px|Abb. '''XX''': Simulink Modell der Abstandssensorik]]
|[[Datei:SpannungDistanz.png|mini|300px|Abb. '''XX''': Zusammenhang zwischen Spannung und Distanz des GP2Y0A41SK0F]]
|}
Das analoge Ausgangssignal des Sensors wird vom Arduino am Pin 2 in ein Digitalwort umgewandelt, wie es in der Abbildung '''XX''' dargestellt ist. Dieses Digitalwort wird anschließend in eine Spannung konvertiert, wie zuvor beschrieben. Um das Signal zu glätten und Störspitzen zu eliminieren, erfolgt eine Filterung mithilfe eines Medianfilters. Im nächsten Schritt wird die Spannung unter Zuhilfenahme des Sensors-Datenblatts in einen Abstand in Zentimetern umgerechnet. Das Datenblatt enthält eine Kennlinie (siehe Abbildung '''XX'''), die den Zusammenhang zwischen Spannung und Distanz beschreibt. Dieser Zusammenhang wird in Simulink durch eine 1D-Lookup-Tabelle abgebildet, welche die Zuordnung der gemessenen Spannung zur entsprechenden Distanz vornimmt.


Werte für die Lookup Table '''(in diesem Fall wird die Kennlinie für das graue Messobjekt verwendet)''':
Werte für die Lookup Table '''(in diesem Fall wird die Kennlinie für das graue Messobjekt verwendet)''':
Zeile 363: Zeile 443:
  IR_voltages_gray = [3.03, 2.99, 2.71, 2.33, 2.02, 1.75, 1.56, 1.395, 1.275, 1.05, 0.861, 0.8, 0.7, 0.63, 0.5, 0.4, 0.3, 0.28]; % in V
  IR_voltages_gray = [3.03, 2.99, 2.71, 2.33, 2.02, 1.75, 1.56, 1.395, 1.275, 1.05, 0.861, 0.8, 0.7, 0.63, 0.5, 0.4, 0.3, 0.28]; % in V


'''Verwendete Toolbox:''' DSP System Toolbox, Simulink Support Package für Arduino Hardware
==== Signalverarbeitung des Tasters ====
{| class="mw-datatable"
! style="font-weight: bold;" |
! style="font-weight: bold;" |
|+ style = "text-align: left"|
|-
|[[Datei:TasterProjekt.png|mini|525px|Abb. '''XX''': Simulink Modell der Tasterauswertung]]
|[[Datei:AbbildungTaster.png|right|mini|200px|Abb. XX: Eingangssignal des Tasters mit und ohne Entprellung [2]]]
|[[Datei:Taster_Signal.png|right|mini|350px|Abb. XX: Taster-Signal]]
|}
Das vorgestellte Modell "Tasterauswertung.slx" dient der Auswertung eines mechanischen Tasters, der an einem Arduino-Mikrocontroller angeschlossen ist. Dabei wird das analoge Signal des Tasters am Pin A0 eingelesen und in eine digitale Ausgabe übersetzt. Zunächst erfolgt eine Umwandlung des digitalen Eingangswerts (Bereich 0–1023) in eine Spannung in Volt, indem das Signal mit einem Faktor von 5/1023 skaliert wird. Anschließend wird der umgerechnete Spannungswert in einer Statusabfrage mit einem Schwellenwert von 2V verglichen. Wenn der Spannungswert kleiner oder gleich 2V ist, wird ein LOW-Zustand erkannt, andernfalls ein HIGH-Zustand. Das Ergebnis wird als digitales Signal weitergegeben und kann für die Steuerung anderer Prozesse genutzt werden.
 
Eine zusätzliche Entprellung des Tasters ist in diesem Modell nicht implementiert, da der verwendete Taster bereits durch einen 10-kOhm-Pullup-Widerstand hardwareseitig entprellt wird. Dieser Pullup-Widerstand sorgt dafür, dass der Eingang des Mikrocontrollers im unbetätigten Zustand zuverlässig auf HIGH gezogen wird und beim Betätigen des Tasters auf LOW schaltet. Mechanische Prellvorgänge, die durch Vibrationen der Tasterkontakte entstehen können, werden durch die Stabilisierung des Signals mithilfe des Widerstands minimiert. Da die durch den Widerstand erreichte Stabilisierung ausreicht, wird das Signal bereits so geglättet, dass der Mikrocontroller keine Mehrfachimpulse registriert. Daher ist eine zusätzliche Entprellung in der Software überflüssig. Das daraus entstehende Signal des Tasters ist aus Abbildung XX zu entnehmen. Diese effiziente Hardwarelösung spart Speicherplatz und Rechenleistung, während sie gleichzeitig eine zuverlässige Funktionalität gewährleistet [2].


==== Signalverarbeitung des Tasters ====
==== Signalverarbeitung des Drucksensors====
==== Signalverarbeitung des Drucksensors====
{| class="mw-datatable"
! style="font-weight: bold;" |
! style="font-weight: bold;" |
|+ style = "text-align: left"|
|-
|[[Datei:GewichtProjekt.png|mini|625px|Abb. '''XX''': Simulink Modell der Gewichtsmessung]]
|
|}
Das gezeigte Simulink-Modell dient der Verarbeitung von Drucksensor-Daten, die über einen Arduino eingelesen werden, um sie in Gewichtswerte umzuwandeln. Zunächst wird das analoge Signal des Sensors vom Arduino als digitaler Wert erfasst (0–1023). Dieser Wert wird dann mithilfe eines Gain-Blocks in eine Spannung von 0V bis 5V umgerechnet. Um Messrauschen zu reduzieren, durchläuft das Signal anschließend einen Median-Filter, der unerwünschte Störimpulse entfernt und das Signal glättet.
Die gefilterte Spannung wird schließlich durch eine 1-D Lookup Table in ein Gewicht umgewandelt. Diese Tabelle weist Spannungswerten von 0V bis 5V lineare Gewichtswerte von 0 kg bis 10 kg zu, sodass eine einfache und präzise Kalibrierung erfolgt. Das resultierende Gewichtssignal ist stabil und kann weiterverwendet oder angezeigt werden.
==== Ansteuerung der 7-Segment-Anzeigen  ====
Die Ansteuerung der 7-Segment-Anzeige erfolgt über einen 7-Segment-Decoder, wie den 74HC47, der in Abbildung 14 des Schaltbildes dargestellt ist. Diese Decoder sind dafür konzipiert, binäre Eingaben (BCD – Binary Coded Decimal) in Steuersignale für die sieben Segmente (1-8) der Anzeige umzuwandeln. Die genaue Zuordnung und Ansteuerung der Pins ist in Tabelle 03 aufgeführt.
Die Tabelle zeigt die Steuerung einer 7-Segment-Anzeige. Sie enthält Binärwerte (D3, D2, D1, D0), die die verschiedenen Ziffern von 0 bis 9 darstellen, und gibt an, welche Segmente (a bis g) der Anzeige aktiviert ("H" = High) oder deaktiviert ("L" = Low) sind, um die jeweilige Ziffer anzuzeigen.
* D3 bis D0 sind die BCD-Eingaben (binär codierte Dezimalzahlen).
* a bis g repräsentieren die Segmente der 7-Segment-Anzeige, die durch die jeweilige Kombination von High- und Low-Signalen angesteuert werden.
* Die letzte Spalte „Display“ zeigt die entsprechende Zahl, die auf der Anzeige dargestellt wird.
Zum Beispiel:
* Für „0“ (D3: L, D2: L, D1: L, D0: L) werden die Segmente a, b, c, d, e und f aktiviert, g bleibt deaktiviert.
*  Für „1“ (D3: L, D2: L, D1: L, D0: H) sind nur die Segmente b und c aktiviert.
{| class="wikitable"
|+ style="text-align: left" | Tabelle XX: Funktionale Tabelle zur Ansteuerung
|-
! style="font-weight: bold; background-color: #e0e0f1;" | D3
! style="font-weight: bold; background-color: #e0e0f1;" | D2
! style="font-weight: bold; background-color: #e0e0f1;" | D1
! style="font-weight: bold; background-color: #e0e0f1;" | D0
! style="font-weight: bold;" | a
! style="font-weight: bold;" | b
! style="font-weight: bold;" | c
! style="font-weight: bold;" | d
! style="font-weight: bold;" | e
! style="font-weight: bold;" | f
! style="font-weight: bold;" | g
! style="font-weight: bold; background-color: #ccffcf;" | Display
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | L || H || H || H || H || H || H || L || style="background-color: #ccffcc;" | 0
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" | H || L || H || H || L || L || L || L || style="background-color: #ccffcc;" |1
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |L || style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || H || H || L || H || H || L || H || style="background-color: #ccffcc;" |2
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |L || style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |H || H || H || H || H || L || L || H || style="background-color: #ccffcc;" |3
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |L || L || H || H || L || L || H || H || style="background-color: #ccffcc;" |4
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || H || L || H || H || L || H || H || style="background-color: #ccffcc;" |5
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || L || L || H || H || H || H || H || style="background-color: #ccffcc;" |6
|-
| style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |H || H || H || H || L || L || L || L || style="background-color: #ccffcc;" |7
|-
| style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |L || H || H || H || H || H || H || H || style="background-color: #ccffcc;" |8
|-
| style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || style="background-color: #e0e0ff;" | L || style="background-color: #e0e0ff;" |H || H || H || H || L || L || H || H || style="background-color: #ccffcc;" |9
|-
| style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || style="background-color: #e0e0ff;" | H || style="background-color: #e0e0ff;" |L || L || L || L || L || L || L || L || style="background-color: #ccffcc;" |blank
|}
Diese Tabelle wird mithilfe einer S-Funktion in Matlab-Simulink umgesetzt, dazu wird das S-Function Basic Template (sfuntmpl_basic.c) von Simulink verwendet und erweitert. Die erweiterte Funktion mit der Bezeichnung sfun_SetLogicalValueForSevenSegementDisp ließt eine Zahl ein, und separiert die einzelnen Ziffern und setzt daraufhin die Bits. Hier ist der C-Code der S-Function hinterlegt:
<div style="width:1200px; height:500px; overflow:scroll; border: hidden">
<syntaxhighlight lang="cpp" style="border: none; background-color: #EFF1C1; font-size:larger">
//%*************************************************************** *
//%                  Hochschule Hamm-Lippstadt                    *
//%*************************************************************** *
//% Modul         : sfun_SetLogicalValueForSevenSegementDisp.c  *
//%                                                                *
//% Datum          : 18.11.2024                                  *
//%                                                                *
//% Funktion        : Drei 7-Segment-Decoder steuern und die      *
//%                  jeweiligen vier Bits setzten für das Output  *
//%                                                                *
//% Implementation  : MATLAB 2023b                                *
//%                                                                *
//% Req. Toolbox    : -                                            *
//%                                                                *
//% Author          : Oliver Scholze, Niklas Reeker, Johann Kismann*
//%                                                                *
//% Anpassung in    : mdlInitializeSizes(SimStruct *S)            *
//%                  mdlOutputs(SimStruct *S, int_T tid)          *
//%                                                                *
//% Letzte Änderung : 18.11.2024                                  *
//%****************************************************************
/*
* Modul: sfun_SetLogicalValueForSevenSegementDisp
* Funktion: Vier Bits der 7-Segement-Decoder setzen
* Angepasste Funktionen: static void mdlInitializeSizes(SimStruct *S);
*/
/*
* You must specify the S_FUNCTION_NAME as the name of your S-function
* (i.e. replace sfuntmpl_basic with the name of your S-function).
*/
#define S_FUNCTION_NAME  sfun_SetLogicalValueForSevenSegementDisp
#define S_FUNCTION_LEVEL 2
/*
* Need to include simstruc.h for the definition of the SimStruct and
* its associated macro definitions.
*/
#include "simstruc.h"
/* Error handling
* --------------
*
* You should use the following technique to report errors encountered within
* an S-function:
*
*      ssSetErrorStatus(S,"Error encountered due to ...");
*      return;
*
* Note that the 2nd argument to ssSetErrorStatus must be persistent memory.
* It cannot be a local variable. For example the following will cause
* unpredictable errors:
*
*      mdlOutputs()
*      {
*        char msg[256];        {ILLEGAL: to fix use "static char msg[256];"}
*        sprintf(msg,"Error due to %s", string);
*        ssSetErrorStatus(S,msg);
*        return;
*      }
*
*/
/*====================*
* S-function methods *
*====================*/
/* Function: mdlInitializeSizes ===============================================
* Abstract:
*    The sizes information is used by Simulink to determine the S-function
*    block's characteristics (number of inputs, outputs, states, etc.).
*/
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        /* Return if number of expected != number of actual parameters */
        return;
    }
    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);
    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, 1);
    ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/
    /*
    * Set direct feedthrough flag (1=yes, 0=no).
    * A port has direct feedthrough if the input is used in either
    * the mdlOutputs or mdlGetTimeOfNextVarHit functions.
    */
    ssSetInputPortDirectFeedThrough(S, 0, 1);
    if (!ssSetNumOutputPorts(S, 12)) return;
    ssSetOutputPortWidth(S, 0, 1);
    ssSetOutputPortWidth(S, 1, 1);
    ssSetOutputPortWidth(S, 2, 1);
    ssSetOutputPortWidth(S, 3, 1);
    ssSetOutputPortWidth(S, 3, 1);
    ssSetOutputPortWidth(S, 5, 1);
    ssSetOutputPortWidth(S, 6, 1);
    ssSetOutputPortWidth(S, 7, 1);
    ssSetOutputPortWidth(S, 8, 1);
    ssSetOutputPortWidth(S, 9, 1);
    ssSetOutputPortWidth(S, 10, 1);
    ssSetOutputPortWidth(S, 11, 1);
    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);
    /* Specify the operating point save/restore compliance to be same as a
    * built-in block */
    ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT);
    ssSetOptions(S, 0);
}
/* Function: mdlInitializeSampleTimes =========================================
* Abstract:
*    This function is used to specify the sample time(s) for your
*    S-function. You must register the same number of sample times as
*    specified in ssSetNumSampleTimes.
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);
}
#define MDL_INITIALIZE_CONDITIONS  /* Change to #undef to remove function */
#if defined(MDL_INITIALIZE_CONDITIONS)
  /* Function: mdlInitializeConditions ========================================
  * Abstract:
  *    In this function, you should initialize the continuous and discrete
  *    states for your S-function block.  The initial states are placed
  *    in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S).
  *    You can also perform any other initialization activities that your
  *    S-function may require. Note, this routine will be called at the
  *    start of simulation and if it is present in an enabled subsystem
  *    configured to reset states, it will be call when the enabled subsystem
  *    restarts execution to reset the states.
  */
  static void mdlInitializeConditions(SimStruct *S)
  {
  }
#endif /* MDL_INITIALIZE_CONDITIONS */
#define MDL_START  /* Change to #undef to remove function */
#if defined(MDL_START)
  /* Function: mdlStart =======================================================
  * Abstract:
  *    This function is called once at start of model execution. If you
  *    have states that should be initialized once, this is the place
  *    to do it.
  */
  static void mdlStart(SimStruct *S)
  {
  }
#endif /*  MDL_START */
/* Function: mdlOutputs =======================================================
* Abstract:
*    In this function, you compute the outputs of your S-function
*    block.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
    const real_T *number = (const real_T*) ssGetInputPortSignal(S,0);
    real_T      *Xxx_D3 = ssGetOutputPortSignal(S,0);
    real_T      *Xxx_D2 = ssGetOutputPortSignal(S,1);
    real_T      *Xxx_D1 = ssGetOutputPortSignal(S,2);
    real_T      *Xxx_D0 = ssGetOutputPortSignal(S,3);
    real_T      *xXx_D3 = ssGetOutputPortSignal(S,4);
    real_T      *xXx_D2 = ssGetOutputPortSignal(S,5);
    real_T      *xXx_D1 = ssGetOutputPortSignal(S,6);
    real_T      *xXx_D0 = ssGetOutputPortSignal(S,7);
    real_T      *xxX_D3 = ssGetOutputPortSignal(S,8);
    real_T      *xxX_D2 = ssGetOutputPortSignal(S,9);
    real_T      *xxX_D1 = ssGetOutputPortSignal(S,10);
    real_T      *xxX_D0 = ssGetOutputPortSignal(S,11);
    /* Nummer in ihre Ziffern aufteilen und Gleitkommazahl zu Ganzzahl casten */
    int num_Xxx = (int)number[0] / 100;          // Erste Ziffer (Hunderterstelle)
    int num_xXx = ((int)number[0] / 10) % 10;    // Zweite Ziffer (Zehnerstelle)
    int num_xxX = (int)number[0] % 10;          // Dritte Ziffer (Einerstelle)
  /* Switch Case Anweisung für die erste Zahl Xxx */ 
    switch (num_Xxx) {
        case 0:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 0;
          break;
        case 1:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 1;
          break;
        case 2:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 1;
          Xxx_D0[0] = 0;
          break;
        case 3:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 1;
          Xxx_D0[0] = 1;
          break;
        case 4:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 1;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 0;
          break;
        case 5:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 1;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 1;
          break;
        case 6:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 1;
          Xxx_D1[0] = 1;
          Xxx_D0[0] = 0;
          break;
        case 7:
          Xxx_D3[0] = 0;
          Xxx_D2[0] = 1;
          Xxx_D1[0] = 1;
          Xxx_D0[0] = 1;
          break;
        case 8:
          Xxx_D3[0] = 1;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 0;
          break;
        case 9:
          Xxx_D3[0] = 1;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 0;
          Xxx_D0[0] = 1;
          break;
      default:
          /* Bei ungültiger Zahl blank Anzeigen */
          Xxx_D3[0] = 1;
          Xxx_D2[0] = 0;
          Xxx_D1[0] = 1;
          Xxx_D0[0] = 0;
          break;}
    /* Switch Case Anweisung für die zweite Zahl xXx */                                         
    switch (num_xXx) {
        case 0:
          xXx_D3[0] = 0;
          xXx_D2[0] = 0;
          xXx_D1[0] = 0;
          xXx_D0[0] = 0;
          break;
        case 1:
          xXx_D3[0] = 0;
          xXx_D2[0] = 0;
          xXx_D1[0] = 0;
          xXx_D0[0] = 1;
          break;
        case 2:
          xXx_D3[0] = 0;
          xXx_D2[0] = 0;
          xXx_D1[0] = 1;
          xXx_D0[0] = 0;
          break;
        case 3:
          xXx_D3[0] = 0;
          xXx_D2[0] = 0;
          xXx_D1[0] = 1;
          xXx_D0[0] = 1;
          break;
        case 4:
          xXx_D3[0] = 0;
          xXx_D2[0] = 1;
          xXx_D1[0] = 0;
          xXx_D0[0] = 0;
          break;
        case 5:
          xXx_D3[0] = 0;
          xXx_D2[0] = 1;
          xXx_D1[0] = 0;
          xXx_D0[0] = 1;
          break;
        case 6:
          xXx_D3[0] = 0;
          xXx_D2[0] = 1;
          xXx_D1[0] = 1;
          xXx_D0[0] = 0;
          break;
        case 7:
          xXx_D3[0] = 0;
          xXx_D2[0] = 1;
          xXx_D1[0] = 1;
          xXx_D0[0] = 1;
          break;
        case 8:
          xXx_D3[0] = 1;
          xXx_D2[0] = 0;
          xXx_D1[0] = 0;
          xXx_D0[0] = 0;
          break;
        case 9:
          xXx_D3[0] = 1;
          xXx_D2[0] = 0;
          xXx_D1[0] = 0;
          xXx_D0[0] = 1;
          break;
      default:
          /* Bei ungültiger Zahl blank Anzeigen */
          xXx_D3[0] = 1;
          xXx_D2[0] = 0;
          xXx_D1[0] = 1;
          xXx_D0[0] = 0;
          break;}
    /* Switch Case Anweisung für die dritte Zahl xxX */                                         
    switch (num_xxX) {
        case 0:
          xxX_D3[0] = 0;
          xxX_D2[0] = 0;
          xxX_D1[0] = 0;
          xxX_D0[0] = 0;
          break;
        case 1:
          xxX_D3[0] = 0;
          xxX_D2[0] = 0;
          xxX_D1[0] = 0;
          xxX_D0[0] = 1;
          break;
        case 2:
          xxX_D3[0] = 0;
          xxX_D2[0] = 0;
          xxX_D1[0] = 1;
          xxX_D0[0] = 0;
          break;
        case 3:
          xxX_D3[0] = 0;
          xxX_D2[0] = 0;
          xxX_D1[0] = 1;
          xxX_D0[0] = 1;
          break;
        case 4:
          xxX_D3[0] = 0;
          xxX_D2[0] = 1;
          xxX_D1[0] = 0;
          xxX_D0[0] = 0;
          break;
        case 5:
          xxX_D3[0] = 0;
          xxX_D2[0] = 1;
          xxX_D1[0] = 0;
          xxX_D0[0] = 1;
          break;
        case 6:
          xxX_D3[0] = 0;
          xxX_D2[0] = 1;
          xxX_D1[0] = 1;
          xxX_D0[0] = 0;
          break;
        case 7:
          xxX_D3[0] = 0;
          xxX_D2[0] = 1;
          xxX_D1[0] = 1;
          xxX_D0[0] = 1;
          break;
        case 8:
          xxX_D3[0] = 1;
          xxX_D2[0] = 0;
          xxX_D1[0] = 0;
          xxX_D0[0] = 0;
          break;
        case 9:
          xxX_D3[0] = 1;
          xxX_D2[0] = 0;
          xxX_D1[0] = 0;
          xxX_D0[0] = 1;
          break;
      default:
          /* Bei ungültiger Zahl blank Anzeigen */
          xxX_D3[0] = 1;
          xxX_D2[0] = 0;
          xxX_D1[0] = 1;
          xxX_D0[0] = 0;
          break;}
}
#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)
  /* Function: mdlUpdate ======================================================
  * Abstract:
  *    This function is called once for every major integration time step.
  *    Discrete states are typically updated here, but this function is useful
  *    for performing any tasks that should only take place once per
  *    integration step.
  */
  static void mdlUpdate(SimStruct *S, int_T tid)
  {
  }
#endif /* MDL_UPDATE */
#define MDL_DERIVATIVES  /* Change to #undef to remove function */
#if defined(MDL_DERIVATIVES)
  /* Function: mdlDerivatives =================================================
  * Abstract:
  *    In this function, you compute the S-function block's derivatives.
  *    The derivatives are placed in the derivative vector, ssGetdX(S).
  */
  static void mdlDerivatives(SimStruct *S)
  {
  }
#endif /* MDL_DERIVATIVES */
/* Function: mdlTerminate =====================================================
* Abstract:
*    In this function, you should perform any actions that are necessary
*    at the termination of a simulation.  For example, if memory was
*    allocated in mdlStart, this is the place to free it.
*/
static void mdlTerminate(SimStruct *S)
{
}
/*=============================*
* Required S-function trailer *
*=============================*/
#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"      /* Code generation registration function */
#endif
</syntaxhighlight>
</div>
<br clear=all>
</div>
<br clear=all>


== Komponententest ==
== Komponententest ==
In den Komponententests werden sämtliche Funktionalitäten des Projekts einzeln geprüft, um sicherzustellen, dass jede Komponente ordnungsgemäß funktioniert, bevor der Stateflow validiert werden kann. Die Tabelle '''XX''' dokumentiert die einzelnen Komponententests, einschließlich der jeweiligen Komponente, der durchgeführten Testmethoden, der erwarteten Ergebnisse sowie der gemessenen Ergebnisse. Dies ermöglicht eine umfassende Überprüfung der Funktionalität jeder Komponente.
Die Tests werden von einem Erstprüfer durchgeführt, wobei die Freigabe durch einen Zweitprüfer erfolgt. Zur besseren Nachvollziehbarkeit und Verständlichkeit des Prüfprozesses wird außerdem der Messaufbau detailliert dokumentiert.
{| class="wikitable"
|+ style = "text-align: left"| Tabelle '''XX''': Durchführung der Komponententest
|-
! style="font-weight: bold;" | Komponente
! style="font-weight: bold;" | Durchführung
! style="font-weight: bold;" | Erwartendes Ergebnis
! style="font-weight: bold;" | Gemessenes Ergebnis
! style="font-weight: bold;" | Erstprüfer
! style="font-weight: bold;" | Zweitprüfer
! style="font-weight: bold;" | Messaufbau
|-
| Taster || Überprüfung der Betätigungsdauer eines mechanischen Tasters und Vergleich der gemessenen Zeiten zwischen einem externen Timer und der Softwaremessung. || 5s+-10%, 10s+-10%, 15s+-10% || || Johann Kismann || Niklas Reeker ||
|-
| IR-Sensor|| Überprüfung der Genauigkeit eines Infrarot-Abstandssensors durch Vergleich der gemessenen Abstände zwischen einem externen Messgerät (Lineal) und der Softwaremessung des Sensors. || 8cm+-10%, 10cm+-10%, 15cm+-10% || || Johann Kismann || Oliver Scholze ||
|-
| Drucksensor|| Überprüfung der Gewichtsmessung eines Drucksensors durch den Vergleich der gemessenen Gewichte mit externen Referenzgewichten und der Softwaremessung des Drucksensors.|| 50g+-10%, 150g+-10%, 200g+-10% || || Niklas Reeker || Oliver Scholze ||
|-
| LEDs|| Überprüfung der Funktionalität von LEDs in dem System, um sicherzustellen, dass sie ordnungsgemäß leuchten.|| zwei LEDs leuchten || || Oliver Scholze || Johann Kismann
||
|-
| 7-Segment-Anzeigen|| Überprüfung der korrekten Ausgabe einer dreistelligen Zahl durch das System, um sicherzustellen, dass die Zahl korrekt dargestellt und ohne Fehler übergeben wird. ||580 || || Oliver Scholze || Niklas Reeker ||
|-
| Ton || Überprüfung der Tonausgabe eines Buzzers, indem eine Gewinner- und eine Verlierer-Melodie abgespielt wird. Ziel ist es sicherzustellen, dass der Buzzer die Melodien korrekt und klar wiedergibt. || Melodie gewonnen und verloren || || Niklas Reeker || Johann Kismann ||
|}
Anschließend erfolgt die Integration des Stateflows und ein vollständiger Systemtest mit allen Funktionen.


== Ergebnis ==
== Ergebnis ==
Zeile 376: Zeile 1.046:


== Projektunterlagen ==
== Projektunterlagen ==
[[Datei:ProjektPlan.png|mini|800px|Abb. XX: Gantt Projektplan für das Projekt "Zeit-, Entfernungs- und Gewichtsschätzung“]]
=== SVN-Projektdaten ===
*[https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/ Projektordner]
# [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/ Dokumentation]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/01_Projektplan/ Projektplan]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/02_Lastenheft_Anforderungsliste/ Lastenheft/ Anforderungsliste]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/03_Programmablaufplan/ Programmablaufplan]
# [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/HW_Elektronik/ HW Elektrotechnik]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/HW_Elektronik/ Schaltplan]
## Fritzing Verdrahtungsplan
# [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/HW_Mechanik/ HW Mechanik]
# [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Software/ Software]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Software/bibliotheken/ Bibliotheken]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Software/darstellung/ Darstellung]
## [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Software/funktionen/ Funktionen]
## [https://svn.hshl.de/usvn/project/Elektrotechnik_Fachpraktikum/browser Parameter]
## start.m
# [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Unterlagen_Datenblätter/ Unterlagen und Datenblätter]
=== Projektplan ===
=== Projektplan ===
[[Datei:ProjektPlan.png|mini|800px|Abb. XX: Gantt Projektplan für das Projekt "Zeit-, Entfernungs- und Gewichtsschätzung“]]
Der Projektplan in Abbildung '''XX''' zeigt den zeitlichen Ablauf eines Projekts von Oktober 2024 bis Januar 2025. Verschiedene Aufgaben sind in einem Gantt-Diagramm als Balken dargestellt, die die Start- und Enddaten visualisieren. Aufgaben wie die mechanische Vorinstallation, die Installation des Schutzhauses und Systemtests sind aufgeführt. Abhängigkeiten zwischen den Aufgaben werden durch Pfeile verdeutlicht. Das Projekt endet Anfang Januar 2025 mit der abschließenden Dokumentation und der Vorbereitung für die Projektmesse. Der Projektplan ist [https://svn.hshl.de/svn/Elektrotechnik_Fachpraktikum/trunk/Projekte/172-184/180_Zeit_Entfernungs_und_Gewichtsschaetzung/Dokumentation/01_Projektplan/ hier] hinterlegt.
Der Projektplan in Abbildung '''XX''' zeigt den zeitlichen Ablauf eines Projekts von Oktober 2024 bis Januar 2025. Verschiedene Aufgaben sind in einem Gantt-Diagramm als Balken dargestellt, die die Start- und Enddaten visualisieren. Aufgaben wie die mechanische Vorinstallation, die Installation des Schutzhauses und Systemtests sind aufgeführt. Abhängigkeiten zwischen den Aufgaben werden durch Pfeile verdeutlicht. Das Projekt endet Anfang Januar 2025 mit der abschließenden Dokumentation und der Vorbereitung für die Projektmesse.


=== Projektdurchführung ===
=== Projektdurchführung ===
Zeile 388: Zeile 1.076:
== Literatur ==
== Literatur ==
* [1] E<span style="font-variant:small-caps">lektronik Kompendium</span>:  Vorwiderstand Berechnen. URL: https://www.elektronik-kompendium.de/sites/grd/1006011.htm, 11. Oktober 2024
* [1] E<span style="font-variant:small-caps">lektronik Kompendium</span>:  Vorwiderstand Berechnen. URL: https://www.elektronik-kompendium.de/sites/grd/1006011.htm, 11. Oktober 2024
 
* [2] W<span style="font-variant:small-caps">ührt Elektronik Kompendium</span>: Kontakt-Entprellschaltung für Taster. URL: https://www.we-online.com/catalog/media/o185485v410%20SN015b%20DE.pdf, 25.10.2024


<!-- Fügen Sie diesen Footer hinzu.  -->
<!-- Fügen Sie diesen Footer hinzu.  -->
----
----
→ zurück zur Übersicht: [[:Kategorie:ProjekteET_MTR_BSE_WS2024|WS 24/25: Escape Game]]
→ zurück zur Übersicht: [[:Kategorie:ProjekteET_MTR_BSE_WS2024|WS 24/25: Escape Game]]

Aktuelle Version vom 23. November 2024, 12:34 Uhr

→ zurück zur Übersicht: WS 24/25: Escape Game

Autoren: Niklas Reeker, Oliver Scholze und Johann Kismann
Betreuer: Marc Ebmeyer
Abb. 01: Skizze des Projekts Zeitschätzung

Einleitung

Bereits im Grundschulalter versuchen wir Kindern ein Gefühl für Zeit zu vermitteln. Indem sie Zeitintervalle schätzen und dabei oft feststellen, wie sehr sie danebenliegen können, erkennen sie die Bedeutung von Zeit und beginnen Uhren zu tragen. Als Erwachsene haben wir zwar ein besseres Zeitgefühl entwickelt, doch die genaue Schätzung von Zeit und Entfernungen bleibt eine Herausforderung.

Unser Escape Game greift diese Phänomene auf spannende Weise auf. Die Aufgabe klingt einfach, erweist sich jedoch als knifflig: Halten Sie Ihren Finger genau 10 Sekunden lang auf einen Knopf – ohne Hilfsmittel zur Zeitmessung. Sobald diese erste Aufgabe erfolgreich abgeschlossen ist, müssen Sie zusätzlich eine Entfernung von 10 cm abschätzen. Zur Entfernungsmessung wird ein IR-Sensor verwendet, der die Genauigkeit der Schätzung ermittelt. Eine LED über dem IR-Sensor beginnt zu blinken, um anzuzeigen, dass die Entfernung nun geschätzt werden soll. Sobald Sie glauben, die richtige Entfernung gefunden zu haben, müssen Sie erneut den Knopf drücken, um Ihre Schätzung zu bestätigen. Ist diese Aufgabe korrekt gemeistert, erleuchtet die nächste LED über dem Drucksensor und es muss das dritte und damit auch das letzte Rätsel gelöst werden. Dies umfasst eine Gewichtsschätzung über einen Drucksensor. Dabei muss bei einer Auswahl von drei verschiedenen Gewichten (50 g/100 g/150 g) das Gewicht mit 100 g ausgewählt und auf den Drucksensor gestellt werden. Auch hier stellt ein erneuter Knopfdruck die Bestätigung der Auswahl dar.

Lassen Sie den Knopf zu früh oder zu spät los, schätzen Sie die Entfernung falsch oder wählen Sie das falsche Gewicht, ertönt eine traurige Melodie und die tatsächlich gedrückte Zeit, die geschätzte Entfernung oder das ausgewählte Gewicht werden angezeigt. So erfahren Sie genau, wie weit Sie von den Zielwerten entfernt waren und ob Ihre Schätzungen zu kurz oder zu lang waren. Treffen Sie jedoch die richtigen Werte, werden Sie mit einer Siegermelodie belohnt, und der Code für das Schloss erscheint auf dem Display. Nur mit diesem Code können Sie das Escape-Schloss öffnen und erfolgreich entkommen. Wichtig: Es wird immer erst die, dann die Entfernung und anschließend das Gewicht geschätzt. Ist eine der drei Schätzungen falsch, müssen Sie von vorne beginnen, beginnend mit der Zeitmessung.

Dieses Spiel verbindet Spaß und Spannung und zeigt auf unterhaltsame Weise, wie herausfordernd es sein kann, sowohl Zeit als auch Entfernungen präzise einzuschätzen. Stellen Sie Ihr Gefühl auf die Probe und finden Sie heraus, ob Sie den Code knacken können!

Anforderungen

Im nachfolgenden werden die testbaren Anforderungen gezeigt welche den korrekten Betrieb der Zeit-, Entfernungs- und Gewichtsschätzung sicherstellen und hier hinterlegt sind.

Tabelle 1: Anforderungen an das Escape Game
ID Inhalt Prio Ersteller Datum Geprüft von Datum Umsetzung der Anforderung in %
1 Das Escape Game muss in 4-5 Minuten lösbar sein Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
2 Der Spieler muss den Button für 10 Sekunden +-1 s Sekunde gedrückt halten um zum zweiten Rätsel der Abstandsmessung zu gelangen. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
3 Wenn die Zeit falsch geschätzt wurde, wird die tatsächlich gedrückte Zeit auf dem Display angezeigt. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
4 Wenn die Zeit falsch geschätzt wurde, beginnt das Spiel von vorne. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
5 Wenn die Zeit falsch geschätzt wurde, wird eine traurige Melodie abgespielt. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
6 Ist die Zeit richtig geschätzt, blinkt eine LED, alle 500 ms, bei der Entfernungsschätzung, um dem Benutzer zu zeigen wo es weitergeht. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
7 Ist die Zeit richtig geschätzt, beginnt die Entfernungsschätzung von 10 cm +-1 cm. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
8 Wenn die Entfernung falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
9 Wenn die Entfernung falsch geschätzt wird, wird die tatsächlich geschätzte Entfernung auf dem Bildschirm in cm angezeigt. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
10 Wenn die Entfernung falsch geschätzt wird, wird eine traurige Melodie abgespielt. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
11 Ist die Entfernung richtig geschätzt, blinkt eine LED, alle 500 ms, bei der Gewichtsschätzung, um dem Benutzer zu zeigen wo es weitergeht. Hoch Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
12 Ist die Entfernung richtig geschätzt, beginnt die Gewichtsschätzung von 100 g +-10%. Hoch Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
13 Wenn das Gewicht falsch geschätzt wird, beginnt das Spiel von vorne mit der Zeitmessung. Hoch Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
14 Wenn das Gewicht falsch geschätzt wird, wird das tatsächliche Gewicht auf dem Bildschirm in g angezeigt. Hoch Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
15 Wenn das Gewicht falsch geschätzt wird, wird eine traurige Melodie abgespielt. Mittel Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
16 Bei richtiger Zeitschätzung wird eine Siegesmelodie abgespielt. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
17 Bei richtiger Entfernungsschätzung wird eine Siegesmelodie abgespielt. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
18 Bei richtiger Gewichtsschätzung wird eine Siegesmelodie abgespielt. Mittel Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
19 Die Zeitmessung wird bei der Ausgabe auf ganze Sekunden gerundet (Bsp: 12,6 s entspricht 13 s). Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
20 Die Entfernungsmessung wird bei der Ausgabe auf ganze Entfernungen in cm gerundet (Bsp: 12,6 cm entspricht 13 cm). Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
21 Die Gewichtsmessung wird bei der Ausgabe auf ein ganzzahliges Gewicht in g gerundet (Bsp: 105,2 g entspricht 105 g). Hoch Johann Kismann 11.10.2024 Oliver Scholze 11.10.2024
22 Bei richtiger Gewichtsschätzung wird der dreistellige Code für das Schloss auf dem Display ausgegeben. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
23 Das Spiel muss ohne visuelle Hilfsmittel zur Zeit-, Entfernungs- und Gewichtsmessung (wie Uhren, Lineale oder Waagen) funktionieren. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
24 Die Interaktion erfolgt über einen einfachen Knopf und einen Display für Rückmeldungen. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
25 Das System muss benutzerfreundlich und für Kinder wie Erwachsene geeignet sein. Mittel Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
26 Das Arduino-System wird über Simulink gesteuert. Hoch Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024
27 Das Escape Game muss in einen Schuhkarton passen. Gering Niklas Reeker 02.10.2024 Oliver Scholze 02.10.2024

Funktionaler Systementwurf/Technischer Systementwurf

Abb. 02: Funktionaler Systementwurf
Abb. 03: Technischer Systementwurf

Funktionaler Systementwurf

Das Eingabegerät wird durch den/die Spieler/in aktiviert, wie in Abbildung 02 dargestellt, woraufhin die Zeitmessung beginnt. Die Aufgabe für den/die Spieler/in besteht darin, das Gerät für eine vorgegebene Dauer zu bedienen, basierend auf der Einschätzung, wann die geforderte Zeit erreicht wurde.

Sobald diese Zeitspanne erfolgreich eingehalten wurde, wird der/die Spieler/in aufgefordert, eine Entfernung von 10 cm +-1 cm zu schätzen. Ist auch diese Aufgabe korrekt absolviert, wird der/die Spieler/in aufgefordert, ein Gewicht von 100 g zu schätzen. Alle drei Schätzungen dürfen jedoch nur ohne Hilfsmittel bestimmt werden. Erst wenn alle drei Aufgaben – Zeit-, Entfernungs- und Gewichtsschätzung – korrekt abgeschlossen wurden, erhält der/die Spieler/in einen Code, der es ermöglicht, mit dem nächsten Escape-Spiel fortzufahren.

Sollten die Zeitvorgabe, die Entfernung oder das Gewicht nicht korrekt geschätzt werden, ist es erforderlich, den Vorgang zu wiederholen, beginnend mit der Zeitmessung, bis alle drei Herausforderungen erfolgreich gemeistert wurden.

Technischer Systementwurf

Die Steuerung und Überwachung des gesamten Spielablaufs obliegt einem Mikrocontroller, wie im funktionalen Systementwurf unter Abbildung 03 ersichtlich ist. Dieser ist direkt an die Spannungsversorgung angeschlossen, um eine kontinuierliche Funktionstüchtigkeit zu gewährleisten. Das Eingabegerät für den/die Spieler/in wird über einen Taster realisiert, der unmittelbar mit dem Mikrocontroller verbunden ist. Bei Aktivierung des Tasters initiiert dieser den Start der Stoppuhrfunktion im Mikrocontroller, um die Zeitmessung zu beginnen.

Nach erfolgreicher Zeitmessung wird der/die Spieler/in aufgefordert, eine Entfernung von 10 cm +-1 cm zu schätzen. Zur Entfernungsmessung wird ein IR-Sensor verwendet, der ebenfalls direkt mit dem Mikrocontroller verbunden ist. Um dem/der Spieler/in anzuzeigen, dass die Entfernungsmessung erfolgen soll, beginnt eine LED über dem IR-Sensor zu blinken. Diese LED ist ebenfalls an den Mikrocontroller angeschlossen und sorgt für eine visuelle Rückmeldung, wann der nächste Schritt – die Entfernungsschätzung – erfolgen muss. Für die Gewichtsschätzung wird ein Drucksensor verwendet. Ist die Entfernungsschätzung korrekt, soll eine weitere LED über dem Drucksensor für die Gewichtsschätzung blinken. Auch hierbei soll die LED als eine visuelle Rückmeldung fungieren, um den nächsten Schritt anzuzeigen.

Um das Spielergebnis – sei es die gemessene Zeit, die geschätzte Entfernung, das geschätzte Gewicht oder der freizuschaltende Code, abhängig vom Erfolg des/der Spieler/s – adäquat darzustellen, werden drei 7-Segment-Displays verwendet. Vor diesen Displays wird ein 7-Segment-Decoder geschaltet, um die Anzahl der notwendigen Verbindungen zum Mikrocontroller möglichst gering zu halten und so die Effizienz des Systems zu optimieren.

Zusätzlich wird ein Buzzer in das System integriert, um eine auditive Rückmeldung in Form einer Melodie zu ermöglichen, wie in der Einleitung beschrieben. Dieses Element trägt zur interaktiven und ansprechenden Gestaltung des Spielerlebnisses bei, indem es den/die Spieler/in sowohl bei Erfolg als auch bei Misserfolg über den Spielstatus informiert.

Materialliste

Die Materialliste gibt einen Überblick der benötigten Komponenten. Zusätzlich wird der Bestellstatus festgehalten.

Tabelle 2: Materialliste
Nr. Anz. Beschreibung
1 1 Funduino Arduino Mega
2 1 Taster
3 3 7-Segment-Display
4 1 (Lochrasterplatine)
5 1 Verbindungskabel
6 3 7-Segment-Decoder
7 1 Summer
8 2 LED grün
9 2 Widerstand 10kOhm
10 1 Netzteil + Kabel
11 1 Gehäuse 3D-Druck
12 2 Widerstand 150Ohm
13 1 IR-Sensor
14 1 Drucksensor

Komponentenspezifikation

Stückliste (BOM)

Die Bill of Materials befindet sich in der Dokumentation, diese ist in der Zusammenfassung hinterlegt.

Da alle weiteren Komponenten bei Reichelt bestellt werden können fallen dafür einmalig Versandkosten von 5,95€ an.
Tabelle 3: BOM
ID Anzahl Kosten pro Stück € Summe Bezeichnung / Komponente technische Bezeichnung Beschreibung Datenblatt Abbildung
1 1x 19,30€ 19,30€ Arduino Mega ARD MEGA2560 R3 Arduino kompatibles Mega 2560 R3 Board Der Mirkocontroller mit dem ATmega2560 verfügt über 54digitale I/O - Schnittstellen. Des weiteren sind 16 analoge Eingänge die die Verarbeitung analoger Signale vorhanden. ARD MEGA2560 R3 Arduino kompatibles Mega 2560 R3 Board
Abb. 04: Arduino Mega
2 1x 11,56€ 11,56€ + 4,95€ Versand Taster Pilztaster Not-Aus Pilz Taster IP65 Der Taster kann mit bis zu 24V belastet werden. Datenblatt Taster
Abb. 05: Taster
3 3x 0,99€ 2,97€ 7 Segment Display Single-7-Segment-Anzeige, rot, 14,2mm, 6,4 mcd, gem. Anode Ein 7-Segment-Display stellt eine elektronische Anzeigevorrichtung dar, die primär für die Visualisierung numerischer Daten verwendet wird. 7 Segment Display
Abb. 06: 7 Segment Display
4 3x 0,84€ 2,52€ BCD-to-7-Segment-Decoder CD 74HC4511E TEX Latch, 7-Segment, 2 ... 6 V, DIL-16 Ein 7-Segment-Decoder ist ein digitales Logikschaltkreis-Element, das digitale Eingangssignale in eine entsprechende 7-Segment-Anzeige umwandelt und die Anzahl der Anschlüsse von 7 Segment anzeigen auf die hälfte Reduzieren. BCD-to-7-Segment-Decoder
Abb. 07: 7 Segment Decoder
5 2x 0,07€ 0,14€ Pullup Widerstand 10kOhm METALL 2,10K Widerstand, Metallschicht, 2,10 kOhm, 0207, 0,6 W, 1% Der Pullup-Widerstand dient dazu den Eingang am Arduino auf einem definierten Wert zu halten und somit ein eindeutiges Zustand zu gewährleisten. Pullup Widerstand 10kOhm
Abb. 08: Widerstand
6 1x 1,50€ 1,50€ Summer CMI-1295-0585T Buzzer, 85dB, 2300 Hz, 5 V Ein Summer wandelt elektrische in akustische Signale um, indem er bei Anlegung einer Spannung zu vibrieren beginnt und so Töne erzeugt. Summer
Abb. 09: Summer
7 2x 0,08€ 0,16€ LED Grün EVL 333-2SYGT/S5 LED, 5 mm, bedrahtet, grün, 400 mcd, 10° Die LED hat eine Vorwärtsspannung von 2 V und darf bei maximal 20mA betrieben werden. LED
Abb. 10: LED
8 2x 0,07€ 0,14€ Widerstand 150Ohm METALL 150 Widerstand, Metallschicht, 150 Ohm, 0207, 0,6 W, 1% Der Widerstand dient als Vorwiderstand der LEDs. Widerstand 150Ohm
Abb. 08: Widerstand
9 1x 5,15€ 5,15€ Drucksensor ARD SEN PRESSURE Arduino - Drucksensor, 20 g bis 10 kg Der Drucksensor ist in der Lage, Gewichte im Bereich von 0 bis 10 kg zu erfassen und gibt in Abhängigkeit vom gemessenen Gewicht ein analoges Signal im Bereich von 0 bis 5 Volt aus. Drucksensor
Abb. 11: Drucksensor
10 1x 32,95 € 32,95 € IR-Sensor IR Abstandssensor, 40- 300mm, analog, inkl. Kabel Der GP2Y0A21YK0F-K Distanzsensor misst Entfernungen im Bereich von 40 mm bis 300 mm und gibt ein analoges Ausgangssignal proportional zur erfassten Distanz aus. Das Signal kann direkt zur weiteren Verarbeitung genutzt werden. Der Sensor wird mit einem Kabel geliefert, das eine einfache Integration ermöglicht. IR-Sensor
Abb. 12: SHARP IR GP2Y0A41SK0F
10 1x 9,20€ 9,20€ Steckernetzteil 9V für ARD Mega HNP 18-090V2 Steckernetzteil, 18 W, 9 V, 2 A 18 W Steckerschaltnetzteil mit Universaleingang 90 - 264 V AC für Spannungsversorgung des ARD Mega. Steckernetzteil
Abb. 13: Steckernetzteil

Technische Daten der Sensoren

Die technischen Daten (Tabelle 4) der Sensoren geben Aufschluss über den Einsatzbereich und die Anforderungen, die erfüllt werden müssen, um diese in die Messumgebung zu integrieren.

Tabelle 4: Technische Daten der Sensoren
GP2Y0A41SK0F ARD SENPRESSURE
Messbereich 4 - 30 cm 0 - 10 kg
Versorgungsspannung 4.5 V - 5.5 V 3,3 V - 5 V
Versorgungsstrom typ. 12 mA -
Genauigkeit - +-2,5%
Arbeitstemperatur -10 °C - +60 °C -20 °C - +60 °C

In Tabelle 5 wird die Pinbelegung der Sensoren erläutert, wobei beide Sensoren über drei Pins verfügen, die die Stromversorgung, den analogen Ausgang und die Erdung bereitstellen.

Tabelle 5: Pinbelegung der Sensoren
GP2Y0A41SK0F ARD SENPRESSURE
Pin 1 Versorgungsspannung VCC; 5 V Versorgungsspannung VCC; 5 V
Pin 2 Analoger Ausgang; 0 V .. 5 V Analoger Ausgang; 0 V .. 5 V
Pin 3 Masse (GND); 0 V Masse (GND); 0 V

Funktionsweise und Kalibrierung der Sensoren

Drucksensor

Der ARD SEN PRESSURE Drucksensor für Arduino funktioniert auf Basis piezoresistiver Technologie, was bedeutet, dass er Druckkräfte über eine Widerstandsänderung misst und in ein elektrisches Signal umwandelt. Wenn eine Kraft auf den Sensor ausgeübt wird, verformt sich ein empfindliches Material im Inneren des Sensors, was zu einer Änderung des elektrischen Widerstands führt. Dieser Widerstand variiert also direkt in Abhängigkeit von der aufgebrachten Kraft.

Diese Widerstandsänderung erzeugt ein elektrisches Signal, das als analoge Spannung ausgegeben wird. Die Spannung ist proportional zur Kraft, die auf den Sensor wirkt. Je höher der ausgeübte Druck, desto stärker verändert sich der Widerstand und damit auch das Ausgangssignal des Sensors. Bei Verbindung des Sensors mit einem analogen Eingang eines Arduino-Boards kann dieser die analoge Spannung lesen und in einen digitalen Wert umwandeln, der die Stärke des Drucks repräsentiert.

Da der Sensor für einen Messbereich von 20 g bis 10 kg ausgelegt ist, kann die analoge Spannung durch Kalibrierung in eine konkrete Gewichtskraft umgerechnet werden. Dazu muss eine Lookup-Tabelle erstellt werden, welche die verschiedenen Spannungswerte in die entsprechenden Gewichtswerte umwandelt. Um diese Tabelle zu erstellen, müssen zu bestimmten Gewichten die entsprechenden Spannungswerte notiert werden.

Tabelle 6: Kalibrierung des Drucksensors
Gewicht in kg Spannung in V
- -
- -
- -
- -

IR-Sensor

Der IR-Abstandssensor mit einem Messbereich von 40 bis 300 mm nutzt Infrarottechnologie, um den Abstand zu einem Objekt zu messen. Der Sensor sendet einen Infrarotstrahl aus, der von einem Objekt in seinem Erfassungsbereich reflektiert wird. Ein integrierter Empfänger im Sensor erfasst das reflektierte Infrarotlicht. Basierend auf der Zeit und dem Winkel, unter dem das Licht reflektiert wird, berechnet der Sensor die Entfernung zum Objekt.

Der Abstandssensor gibt eine analoge Spannung aus, die proportional zur gemessenen Entfernung ist. Wenn der Abstand zum Objekt geringer ist, ist die ausgegebene Spannung höher; bei größerem Abstand ist die Spannung niedriger. Diese analoge Spannung kann an einen analogen Eingang eines Arduino-Boards angeschlossen werden. Der Arduino liest die Spannung, wandelt sie in einen digitalen Wert um und berechnet daraus die Distanz zum Objekt.

Für eine genaue Messung ist eine Kalibrierung erforderlich, da sich die analoge Spannung je nach reflektiertem Signal leicht verändern kann. Indem man bekannte Abstände misst und die Spannungen erfasst, kann eine Zuordnung erstellt werden, die dem Arduino hilft, die Spannung korrekt in eine Entfernung umzurechnen. Daraus lässt sich dann ein Lookup-Tabelle erstellen, die die Spannungswerte in die entsprechenden Entfernungen umwandelt.

Tabelle 7: Kalibrierung des IR-Sensors
Entfernung in cm Spannung in V
- -
- -
- -
- -

Umsetzung HW (mechanisch)

Umsetzung HW (elektrisch)

Verdrahtungsplan und Schaltplan

Abb. 14: Verdrahtungsplan
Abb. 16: Schaltplan (mit Multisim (siehe Versionen))


In dem gezeigten Schaltplan in Abbildung 16 dienen die Netzbezeichnungen zur logischen Verbindung und Organisation der Signale zwischen verschiedenen Bauteilen. Diese Netzbezeichnungen ermöglichen es, dass elektrische Signale klar und übersichtlich an verschiedenen Stellen des Schaltplans verwendet werden können, ohne dass jede Leitung physisch durchgezeichnet werden muss. Dadurch wird der Schaltplan übersichtlicher, da wichtige Signalpfade und Verbindungen benannt und nachvollziehbar gestaltet werden. Die einzelnen Komponenten wurden zu Gruppen geordnet und mit deren Funktion beschriftet.

Anbindung des Tasters

Abb. XX: Pullup-Widerstand [2]

Im Schaltplan ist die Anbindung des Tasters dargestellt. Um im nicht-geschaltetem Zustand ein definiertes Potential zu gewährleisten, wird ein Pullup-Widerstand von 10 kOhm verwendet, die die Leitung auf einen logischen High-Pegel bzw. 5V ziehen. Bei Betätigung des Tasters wird die Spannung auf GND gezogen, was einen logischen LOW-Pegel am entsprechenden digitalen Pin des Arduinos Mega bewirkt, wie es in Abbildung XX dargestellt ist [2].

Berechnung der Vorwiderstände der LEDs

Um den Strom, der durch die LED fließt, zu begrenzen, wird ein Vorwiderstand benötigt. Dieser Vorwiderstand schützt die LED vor Beschädigung durch Überstrom und sorgt dafür, dass der Strom innerhalb der zulässigen Grenzen bleibt. Die Berechnung des Vorwiderstands erfolgt nach folgender Formel [1]:

Aus den Datenblättern des Arduino Mega und der LEDs lassen diese Werte ermitteln:

  • die Betriebsspannung (hier 5V),
  • die Vorwärtsspannung der LED (hier 2V),
  • der Strom durch die LED (hier 20 mA).

Der benötigte Vorwiderstand beträgt also 150 Ohm.

Umsetzung SW

Verwendete Toolbox: DSP System Toolbox, Simulink Support Package für Arduino Hardware

Zusammenspiel der Komponenten und Module

Simulink Modell
Abb. XX: PaP von der Zeit-,Entfernungs- und Gewichtsschätzung (hier hinterlegt)

Umrechnung des Digitalwerts in Volt der beiden Sensoren (Drucksensor und IR-Sensor)

Im Simulink-Modell werden die analogen Sensorwerte als Digitalwert erfasst und durch ein Gain, innerhalb von Matlab Simulink, in Volt umgerechnet. Die Sensoren liefern einen 10-Bit-Digitalwert, der von 0 bis 1023 reicht und mit einer Referenzspannung von 5V arbeitet. Dieser Wert wird vom Analog-Digital-Wandler (ADC) des Arduino aufgenommen. Um den Digitalwert in Volt umzurechnen, wird folgender Berechnungsschritt durchgeführt:


Der resultierende V-Wert wird anschließend gefiltert und im Modell für weitere Berechnungen verwendet.

Signalverarbeitung für den IR-Sensor (GP2Y0A41SK0F)

Abb. XX: Simulink Modell der Abstandssensorik
Abb. XX: Zusammenhang zwischen Spannung und Distanz des GP2Y0A41SK0F

Das analoge Ausgangssignal des Sensors wird vom Arduino am Pin 2 in ein Digitalwort umgewandelt, wie es in der Abbildung XX dargestellt ist. Dieses Digitalwort wird anschließend in eine Spannung konvertiert, wie zuvor beschrieben. Um das Signal zu glätten und Störspitzen zu eliminieren, erfolgt eine Filterung mithilfe eines Medianfilters. Im nächsten Schritt wird die Spannung unter Zuhilfenahme des Sensors-Datenblatts in einen Abstand in Zentimetern umgerechnet. Das Datenblatt enthält eine Kennlinie (siehe Abbildung XX), die den Zusammenhang zwischen Spannung und Distanz beschreibt. Dieser Zusammenhang wird in Simulink durch eine 1D-Lookup-Tabelle abgebildet, welche die Zuordnung der gemessenen Spannung zur entsprechenden Distanz vornimmt.

Werte für die Lookup Table (in diesem Fall wird die Kennlinie für das graue Messobjekt verwendet):

% Daten für die Distanz
IR_distances = [2.9, 3.1, 4, 5, 6, 7, 8, 9, 10, 11.9, 14, 16, 18, 20, 25, 30, 35, 40]; % in cm
% Spannung für weißes Messobjekt
IR_voltages_white = [3.03, 2.99, 2.71, 2.33, 2.02, 1.75, 1.56, 1.395, 1.275, 1.05, 0.861, 0.8, 0.7125, 0.65, 0.52, 0.42, 0.325, 0.3]; % in V
% Spannung für graues Messobjekt
IR_voltages_gray = [3.03, 2.99, 2.71, 2.33, 2.02, 1.75, 1.56, 1.395, 1.275, 1.05, 0.861, 0.8, 0.7, 0.63, 0.5, 0.4, 0.3, 0.28]; % in V

Signalverarbeitung des Tasters

Abb. XX: Simulink Modell der Tasterauswertung
Abb. XX: Eingangssignal des Tasters mit und ohne Entprellung [2]
Abb. XX: Taster-Signal

Das vorgestellte Modell "Tasterauswertung.slx" dient der Auswertung eines mechanischen Tasters, der an einem Arduino-Mikrocontroller angeschlossen ist. Dabei wird das analoge Signal des Tasters am Pin A0 eingelesen und in eine digitale Ausgabe übersetzt. Zunächst erfolgt eine Umwandlung des digitalen Eingangswerts (Bereich 0–1023) in eine Spannung in Volt, indem das Signal mit einem Faktor von 5/1023 skaliert wird. Anschließend wird der umgerechnete Spannungswert in einer Statusabfrage mit einem Schwellenwert von 2V verglichen. Wenn der Spannungswert kleiner oder gleich 2V ist, wird ein LOW-Zustand erkannt, andernfalls ein HIGH-Zustand. Das Ergebnis wird als digitales Signal weitergegeben und kann für die Steuerung anderer Prozesse genutzt werden.

Eine zusätzliche Entprellung des Tasters ist in diesem Modell nicht implementiert, da der verwendete Taster bereits durch einen 10-kOhm-Pullup-Widerstand hardwareseitig entprellt wird. Dieser Pullup-Widerstand sorgt dafür, dass der Eingang des Mikrocontrollers im unbetätigten Zustand zuverlässig auf HIGH gezogen wird und beim Betätigen des Tasters auf LOW schaltet. Mechanische Prellvorgänge, die durch Vibrationen der Tasterkontakte entstehen können, werden durch die Stabilisierung des Signals mithilfe des Widerstands minimiert. Da die durch den Widerstand erreichte Stabilisierung ausreicht, wird das Signal bereits so geglättet, dass der Mikrocontroller keine Mehrfachimpulse registriert. Daher ist eine zusätzliche Entprellung in der Software überflüssig. Das daraus entstehende Signal des Tasters ist aus Abbildung XX zu entnehmen. Diese effiziente Hardwarelösung spart Speicherplatz und Rechenleistung, während sie gleichzeitig eine zuverlässige Funktionalität gewährleistet [2].

Signalverarbeitung des Drucksensors

Abb. XX: Simulink Modell der Gewichtsmessung

Das gezeigte Simulink-Modell dient der Verarbeitung von Drucksensor-Daten, die über einen Arduino eingelesen werden, um sie in Gewichtswerte umzuwandeln. Zunächst wird das analoge Signal des Sensors vom Arduino als digitaler Wert erfasst (0–1023). Dieser Wert wird dann mithilfe eines Gain-Blocks in eine Spannung von 0V bis 5V umgerechnet. Um Messrauschen zu reduzieren, durchläuft das Signal anschließend einen Median-Filter, der unerwünschte Störimpulse entfernt und das Signal glättet. Die gefilterte Spannung wird schließlich durch eine 1-D Lookup Table in ein Gewicht umgewandelt. Diese Tabelle weist Spannungswerten von 0V bis 5V lineare Gewichtswerte von 0 kg bis 10 kg zu, sodass eine einfache und präzise Kalibrierung erfolgt. Das resultierende Gewichtssignal ist stabil und kann weiterverwendet oder angezeigt werden.

Ansteuerung der 7-Segment-Anzeigen

Die Ansteuerung der 7-Segment-Anzeige erfolgt über einen 7-Segment-Decoder, wie den 74HC47, der in Abbildung 14 des Schaltbildes dargestellt ist. Diese Decoder sind dafür konzipiert, binäre Eingaben (BCD – Binary Coded Decimal) in Steuersignale für die sieben Segmente (1-8) der Anzeige umzuwandeln. Die genaue Zuordnung und Ansteuerung der Pins ist in Tabelle 03 aufgeführt.

Die Tabelle zeigt die Steuerung einer 7-Segment-Anzeige. Sie enthält Binärwerte (D3, D2, D1, D0), die die verschiedenen Ziffern von 0 bis 9 darstellen, und gibt an, welche Segmente (a bis g) der Anzeige aktiviert ("H" = High) oder deaktiviert ("L" = Low) sind, um die jeweilige Ziffer anzuzeigen.

  • D3 bis D0 sind die BCD-Eingaben (binär codierte Dezimalzahlen).
  • a bis g repräsentieren die Segmente der 7-Segment-Anzeige, die durch die jeweilige Kombination von High- und Low-Signalen angesteuert werden.
  • Die letzte Spalte „Display“ zeigt die entsprechende Zahl, die auf der Anzeige dargestellt wird.

Zum Beispiel:

  • Für „0“ (D3: L, D2: L, D1: L, D0: L) werden die Segmente a, b, c, d, e und f aktiviert, g bleibt deaktiviert.
  • Für „1“ (D3: L, D2: L, D1: L, D0: H) sind nur die Segmente b und c aktiviert.
Tabelle XX: Funktionale Tabelle zur Ansteuerung
D3 D2 D1 D0 a b c d e f g Display
L L L L H H H H H H L 0
L L L H L H H L L L L 1
L L H L H H L H H L H 2
L L H H H H H H L L H 3
L H L L L H H L L H H 4
L H L H H L H H L H H 5
L H H L L L H H H H H 6
L H H H H H H L L L L 7
H L L L H H H H H H H 8
H L L H H H H L L H H 9
H L H L L L L L L L L blank

Diese Tabelle wird mithilfe einer S-Funktion in Matlab-Simulink umgesetzt, dazu wird das S-Function Basic Template (sfuntmpl_basic.c) von Simulink verwendet und erweitert. Die erweiterte Funktion mit der Bezeichnung sfun_SetLogicalValueForSevenSegementDisp ließt eine Zahl ein, und separiert die einzelnen Ziffern und setzt daraufhin die Bits. Hier ist der C-Code der S-Function hinterlegt:

//%*************************************************************** *
//%                   Hochschule Hamm-Lippstadt                    *
//%*************************************************************** *
//% Modul	        : sfun_SetLogicalValueForSevenSegementDisp.c   *
//%                                                                *
//% Datum           : 18.11.2024                                   *
//%                                                                *
//% Funktion        : Drei 7-Segment-Decoder steuern und die       *
//%                   jeweiligen vier Bits setzten für das Output  *
//%                                                                *
//% Implementation  : MATLAB 2023b                                 *
//%                                                                *
//% Req. Toolbox    : -                                            *
//%                                                                *
//% Author          : Oliver Scholze, Niklas Reeker, Johann Kismann*
//%                                                                *
//% Anpassung in    : mdlInitializeSizes(SimStruct *S)             *
//%                   mdlOutputs(SimStruct *S, int_T tid)          *
//%                                                                *
//% Letzte Änderung : 18.11.2024                                   *
//%****************************************************************


/*
 * Modul: sfun_SetLogicalValueForSevenSegementDisp
 * Funktion: Vier Bits der 7-Segement-Decoder setzen 
 * Angepasste Funktionen: static void mdlInitializeSizes(SimStruct *S); 
 */


/*
 * You must specify the S_FUNCTION_NAME as the name of your S-function
 * (i.e. replace sfuntmpl_basic with the name of your S-function).
 */

#define S_FUNCTION_NAME  sfun_SetLogicalValueForSevenSegementDisp
#define S_FUNCTION_LEVEL 2

/*
 * Need to include simstruc.h for the definition of the SimStruct and
 * its associated macro definitions.
 */
#include "simstruc.h"



/* Error handling
 * --------------
 *
 * You should use the following technique to report errors encountered within
 * an S-function:
 *
 *       ssSetErrorStatus(S,"Error encountered due to ...");
 *       return;
 *
 * Note that the 2nd argument to ssSetErrorStatus must be persistent memory.
 * It cannot be a local variable. For example the following will cause
 * unpredictable errors:
 *
 *      mdlOutputs()
 *      {
 *         char msg[256];         {ILLEGAL: to fix use "static char msg[256];"}
 *         sprintf(msg,"Error due to %s", string);
 *         ssSetErrorStatus(S,msg);
 *         return;
 *      }
 *
 */

/*====================*
 * S-function methods *
 *====================*/

/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *    The sizes information is used by Simulink to determine the S-function
 *    block's characteristics (number of inputs, outputs, states, etc.).
 */
static void mdlInitializeSizes(SimStruct *S)
{
    ssSetNumSFcnParams(S, 0);  /* Number of expected parameters */
    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
        /* Return if number of expected != number of actual parameters */
        return;
    }

    ssSetNumContStates(S, 0);
    ssSetNumDiscStates(S, 0);

    if (!ssSetNumInputPorts(S, 1)) return;
    ssSetInputPortWidth(S, 0, 1);
    ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/
    /*
     * Set direct feedthrough flag (1=yes, 0=no).
     * A port has direct feedthrough if the input is used in either
     * the mdlOutputs or mdlGetTimeOfNextVarHit functions.
     */
    ssSetInputPortDirectFeedThrough(S, 0, 1);

    if (!ssSetNumOutputPorts(S, 12)) return;
    ssSetOutputPortWidth(S, 0, 1);
    ssSetOutputPortWidth(S, 1, 1);
    ssSetOutputPortWidth(S, 2, 1);
    ssSetOutputPortWidth(S, 3, 1);

    ssSetOutputPortWidth(S, 3, 1);
    ssSetOutputPortWidth(S, 5, 1);
    ssSetOutputPortWidth(S, 6, 1);
    ssSetOutputPortWidth(S, 7, 1);

    ssSetOutputPortWidth(S, 8, 1);
    ssSetOutputPortWidth(S, 9, 1);
    ssSetOutputPortWidth(S, 10, 1);
    ssSetOutputPortWidth(S, 11, 1);

    ssSetNumSampleTimes(S, 1);
    ssSetNumRWork(S, 0);
    ssSetNumIWork(S, 0);
    ssSetNumPWork(S, 0);
    ssSetNumModes(S, 0);
    ssSetNumNonsampledZCs(S, 0);

    /* Specify the operating point save/restore compliance to be same as a 
     * built-in block */
    ssSetOperatingPointCompliance(S, USE_DEFAULT_OPERATING_POINT);

    ssSetOptions(S, 0);
}



/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    This function is used to specify the sample time(s) for your
 *    S-function. You must register the same number of sample times as
 *    specified in ssSetNumSampleTimes.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
    ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME);
    ssSetOffsetTime(S, 0, 0.0);

}



#define MDL_INITIALIZE_CONDITIONS   /* Change to #undef to remove function */
#if defined(MDL_INITIALIZE_CONDITIONS)
  /* Function: mdlInitializeConditions ========================================
   * Abstract:
   *    In this function, you should initialize the continuous and discrete
   *    states for your S-function block.  The initial states are placed
   *    in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S).
   *    You can also perform any other initialization activities that your
   *    S-function may require. Note, this routine will be called at the
   *    start of simulation and if it is present in an enabled subsystem
   *    configured to reset states, it will be call when the enabled subsystem
   *    restarts execution to reset the states.
   */
  static void mdlInitializeConditions(SimStruct *S)
  {
  }
#endif /* MDL_INITIALIZE_CONDITIONS */



#define MDL_START  /* Change to #undef to remove function */
#if defined(MDL_START) 
  /* Function: mdlStart =======================================================
   * Abstract:
   *    This function is called once at start of model execution. If you
   *    have states that should be initialized once, this is the place
   *    to do it.
   */
  static void mdlStart(SimStruct *S)
  {
  }
#endif /*  MDL_START */



/* Function: mdlOutputs =======================================================
 * Abstract:
 *    In this function, you compute the outputs of your S-function
 *    block.
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
    const real_T *number = (const real_T*) ssGetInputPortSignal(S,0);

    real_T       *Xxx_D3 = ssGetOutputPortSignal(S,0);
    real_T       *Xxx_D2 = ssGetOutputPortSignal(S,1);
    real_T       *Xxx_D1 = ssGetOutputPortSignal(S,2);
    real_T       *Xxx_D0 = ssGetOutputPortSignal(S,3);

    real_T       *xXx_D3 = ssGetOutputPortSignal(S,4);
    real_T       *xXx_D2 = ssGetOutputPortSignal(S,5);
    real_T       *xXx_D1 = ssGetOutputPortSignal(S,6);
    real_T       *xXx_D0 = ssGetOutputPortSignal(S,7);

    real_T       *xxX_D3 = ssGetOutputPortSignal(S,8);
    real_T       *xxX_D2 = ssGetOutputPortSignal(S,9);
    real_T       *xxX_D1 = ssGetOutputPortSignal(S,10);
    real_T       *xxX_D0 = ssGetOutputPortSignal(S,11);

    /* Nummer in ihre Ziffern aufteilen und Gleitkommazahl zu Ganzzahl casten */
    int num_Xxx = (int)number[0] / 100;          // Erste Ziffer (Hunderterstelle)
    int num_xXx = ((int)number[0] / 10) % 10;    // Zweite Ziffer (Zehnerstelle)
    int num_xxX = (int)number[0] % 10;           // Dritte Ziffer (Einerstelle)

   /* Switch Case Anweisung für die erste Zahl Xxx */  
    switch (num_Xxx) {
        case 0:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 0;
           break;
        case 1:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 1;
           break;
        case 2:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 1;
           Xxx_D0[0] = 0;
           break;
        case 3:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 1;
           Xxx_D0[0] = 1;
           break;
        case 4:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 1;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 0;
           break;
        case 5:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 1;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 1;
           break;
        case 6:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 1;
           Xxx_D1[0] = 1;
           Xxx_D0[0] = 0;
           break;
        case 7:
           Xxx_D3[0] = 0;
           Xxx_D2[0] = 1;
           Xxx_D1[0] = 1;
           Xxx_D0[0] = 1;
           break;
        case 8:
           Xxx_D3[0] = 1;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 0;
           break;
        case 9:
           Xxx_D3[0] = 1;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 0;
           Xxx_D0[0] = 1;
           break;
       default:
           /* Bei ungültiger Zahl blank Anzeigen */
           Xxx_D3[0] = 1;
           Xxx_D2[0] = 0;
           Xxx_D1[0] = 1;
           Xxx_D0[0] = 0;
           break;}

     /* Switch Case Anweisung für die zweite Zahl xXx */                                           
     switch (num_xXx) {
        case 0:
           xXx_D3[0] = 0;
           xXx_D2[0] = 0;
           xXx_D1[0] = 0;
           xXx_D0[0] = 0;
           break;
        case 1:
           xXx_D3[0] = 0;
           xXx_D2[0] = 0;
           xXx_D1[0] = 0;
           xXx_D0[0] = 1;
           break;
        case 2:
           xXx_D3[0] = 0;
           xXx_D2[0] = 0;
           xXx_D1[0] = 1;
           xXx_D0[0] = 0;
           break;
        case 3:
           xXx_D3[0] = 0;
           xXx_D2[0] = 0;
           xXx_D1[0] = 1;
           xXx_D0[0] = 1;
           break;
        case 4:
           xXx_D3[0] = 0;
           xXx_D2[0] = 1;
           xXx_D1[0] = 0;
           xXx_D0[0] = 0;
           break;
        case 5:
           xXx_D3[0] = 0;
           xXx_D2[0] = 1;
           xXx_D1[0] = 0;
           xXx_D0[0] = 1;
           break;
        case 6:
           xXx_D3[0] = 0;
           xXx_D2[0] = 1;
           xXx_D1[0] = 1;
           xXx_D0[0] = 0;
           break;
        case 7:
           xXx_D3[0] = 0;
           xXx_D2[0] = 1;
           xXx_D1[0] = 1;
           xXx_D0[0] = 1;
           break;
        case 8:
           xXx_D3[0] = 1;
           xXx_D2[0] = 0;
           xXx_D1[0] = 0;
           xXx_D0[0] = 0;
           break;
        case 9:
           xXx_D3[0] = 1;
           xXx_D2[0] = 0;
           xXx_D1[0] = 0;
           xXx_D0[0] = 1;
           break;
       default:
           /* Bei ungültiger Zahl blank Anzeigen */
           xXx_D3[0] = 1;
           xXx_D2[0] = 0;
           xXx_D1[0] = 1;
           xXx_D0[0] = 0;
           break;}


     /* Switch Case Anweisung für die dritte Zahl xxX */                                           
     switch (num_xxX) {
        case 0: 
           xxX_D3[0] = 0;
           xxX_D2[0] = 0;
           xxX_D1[0] = 0;
           xxX_D0[0] = 0;
           break;
        case 1:
           xxX_D3[0] = 0;
           xxX_D2[0] = 0;
           xxX_D1[0] = 0;
           xxX_D0[0] = 1;
           break;
        case 2:
           xxX_D3[0] = 0;
           xxX_D2[0] = 0;
           xxX_D1[0] = 1;
           xxX_D0[0] = 0;
           break;
        case 3:
           xxX_D3[0] = 0;
           xxX_D2[0] = 0;
           xxX_D1[0] = 1;
           xxX_D0[0] = 1;
           break;
        case 4:
           xxX_D3[0] = 0;
           xxX_D2[0] = 1;
           xxX_D1[0] = 0;
           xxX_D0[0] = 0;
           break;
        case 5:
           xxX_D3[0] = 0;
           xxX_D2[0] = 1;
           xxX_D1[0] = 0;
           xxX_D0[0] = 1;
           break;
        case 6:
           xxX_D3[0] = 0;
           xxX_D2[0] = 1;
           xxX_D1[0] = 1;
           xxX_D0[0] = 0;
           break;
        case 7:
           xxX_D3[0] = 0;
           xxX_D2[0] = 1;
           xxX_D1[0] = 1;
           xxX_D0[0] = 1;
           break;
        case 8:
           xxX_D3[0] = 1;
           xxX_D2[0] = 0;
           xxX_D1[0] = 0;
           xxX_D0[0] = 0;
           break;
        case 9:
           xxX_D3[0] = 1;
           xxX_D2[0] = 0;
           xxX_D1[0] = 0;
           xxX_D0[0] = 1;
           break;
       default:
           /* Bei ungültiger Zahl blank Anzeigen */
           xxX_D3[0] = 1;
           xxX_D2[0] = 0;
           xxX_D1[0] = 1;
           xxX_D0[0] = 0;
           break;}
}



#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)
  /* Function: mdlUpdate ======================================================
   * Abstract:
   *    This function is called once for every major integration time step.
   *    Discrete states are typically updated here, but this function is useful
   *    for performing any tasks that should only take place once per
   *    integration step.
   */
  static void mdlUpdate(SimStruct *S, int_T tid)
  {
  }
#endif /* MDL_UPDATE */



#define MDL_DERIVATIVES  /* Change to #undef to remove function */
#if defined(MDL_DERIVATIVES)
  /* Function: mdlDerivatives =================================================
   * Abstract:
   *    In this function, you compute the S-function block's derivatives.
   *    The derivatives are placed in the derivative vector, ssGetdX(S).
   */
  static void mdlDerivatives(SimStruct *S)
  {
  }
#endif /* MDL_DERIVATIVES */



/* Function: mdlTerminate =====================================================
 * Abstract:
 *    In this function, you should perform any actions that are necessary
 *    at the termination of a simulation.  For example, if memory was
 *    allocated in mdlStart, this is the place to free it.
 */
static void mdlTerminate(SimStruct *S)
{
}


/*=============================*
 * Required S-function trailer *
 *=============================*/

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif



Komponententest

In den Komponententests werden sämtliche Funktionalitäten des Projekts einzeln geprüft, um sicherzustellen, dass jede Komponente ordnungsgemäß funktioniert, bevor der Stateflow validiert werden kann. Die Tabelle XX dokumentiert die einzelnen Komponententests, einschließlich der jeweiligen Komponente, der durchgeführten Testmethoden, der erwarteten Ergebnisse sowie der gemessenen Ergebnisse. Dies ermöglicht eine umfassende Überprüfung der Funktionalität jeder Komponente.

Die Tests werden von einem Erstprüfer durchgeführt, wobei die Freigabe durch einen Zweitprüfer erfolgt. Zur besseren Nachvollziehbarkeit und Verständlichkeit des Prüfprozesses wird außerdem der Messaufbau detailliert dokumentiert.

Tabelle XX: Durchführung der Komponententest
Komponente Durchführung Erwartendes Ergebnis Gemessenes Ergebnis Erstprüfer Zweitprüfer Messaufbau
Taster Überprüfung der Betätigungsdauer eines mechanischen Tasters und Vergleich der gemessenen Zeiten zwischen einem externen Timer und der Softwaremessung. 5s+-10%, 10s+-10%, 15s+-10% Johann Kismann Niklas Reeker
IR-Sensor Überprüfung der Genauigkeit eines Infrarot-Abstandssensors durch Vergleich der gemessenen Abstände zwischen einem externen Messgerät (Lineal) und der Softwaremessung des Sensors. 8cm+-10%, 10cm+-10%, 15cm+-10% Johann Kismann Oliver Scholze
Drucksensor Überprüfung der Gewichtsmessung eines Drucksensors durch den Vergleich der gemessenen Gewichte mit externen Referenzgewichten und der Softwaremessung des Drucksensors. 50g+-10%, 150g+-10%, 200g+-10% Niklas Reeker Oliver Scholze
LEDs Überprüfung der Funktionalität von LEDs in dem System, um sicherzustellen, dass sie ordnungsgemäß leuchten. zwei LEDs leuchten Oliver Scholze Johann Kismann
7-Segment-Anzeigen Überprüfung der korrekten Ausgabe einer dreistelligen Zahl durch das System, um sicherzustellen, dass die Zahl korrekt dargestellt und ohne Fehler übergeben wird. 580 Oliver Scholze Niklas Reeker
Ton Überprüfung der Tonausgabe eines Buzzers, indem eine Gewinner- und eine Verlierer-Melodie abgespielt wird. Ziel ist es sicherzustellen, dass der Buzzer die Melodien korrekt und klar wiedergibt. Melodie gewonnen und verloren Niklas Reeker Johann Kismann

Anschließend erfolgt die Integration des Stateflows und ein vollständiger Systemtest mit allen Funktionen.

Ergebnis

Zusammenfassung

Lessons Learned

Projektunterlagen

Abb. XX: Gantt Projektplan für das Projekt "Zeit-, Entfernungs- und Gewichtsschätzung“

SVN-Projektdaten

  1. Dokumentation
    1. Projektplan
    2. Lastenheft/ Anforderungsliste
    3. Programmablaufplan
  2. HW Elektrotechnik
    1. Schaltplan
    2. Fritzing Verdrahtungsplan
  3. HW Mechanik
  4. Software
    1. Bibliotheken
    2. Darstellung
    3. Funktionen
    4. Parameter
    5. start.m
  5. Unterlagen und Datenblätter

Projektplan

Der Projektplan in Abbildung XX zeigt den zeitlichen Ablauf eines Projekts von Oktober 2024 bis Januar 2025. Verschiedene Aufgaben sind in einem Gantt-Diagramm als Balken dargestellt, die die Start- und Enddaten visualisieren. Aufgaben wie die mechanische Vorinstallation, die Installation des Schutzhauses und Systemtests sind aufgeführt. Abhängigkeiten zwischen den Aufgaben werden durch Pfeile verdeutlicht. Das Projekt endet Anfang Januar 2025 mit der abschließenden Dokumentation und der Vorbereitung für die Projektmesse. Der Projektplan ist hier hinterlegt.

Projektdurchführung

YouTube Video

Weblinks

Literatur


→ zurück zur Übersicht: WS 24/25: Escape Game